Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion bin/create-draft-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
# RELEASE_DATE=$(date +%Y-%m-%d) ./create-draft-release.sh
# RELEASE_DATE=2026-06-30 npm run create-draft-release
# npm run create-draft-release
#
# Any plugin slugs given are forwarded to `npm run prepare-release-notes`, which then reads
# each plugin's changelog straight from its readme.txt rather than looking for a release
# milestone. Use this for a release that does not use milestones:
#
# RELEASE_DATE=2026-06-30 npm run create-draft-release -- auto-sizes speculation-rules

set -e

Expand Down Expand Up @@ -60,13 +66,28 @@ if github_token="$(gh auth token 2> /dev/null)" && [ -n "$github_token" ]; then
fi

echo "Generating release notes for $tag..." >&2
npm run prepare-release-notes --silent -- "${notes_args[@]}" > "$notes_file"
npm run prepare-release-notes --silent -- "${notes_args[@]}" "$@" > "$notes_file"

if [ ! -s "$notes_file" ]; then
echo "Error: No release notes were generated; aborting." >&2
exit 1
fi

# Guard against notes that cover only some of what is being released. Without plugin slugs
# the selection comes from release milestones, and a plugin missing its milestone is simply
# skipped, which would otherwise yield a release whose notes quietly omit it.
if [ $# -gt 0 ]; then
for plugin_slug in "$@"; do
if ! grep -qF "## \`$plugin_slug\`" "$notes_file"; then
echo "Error: No release notes were generated for \"$plugin_slug\"; aborting." >&2
exit 1
fi
done
else
echo "Note: No plugin slugs were given, so the release notes cover only plugins with an open, dated release milestone. Check that every plugin being released is present below." >&2
grep -oE '^## `[^`]+` .*' "$notes_file" | sed 's/^/ /' >&2
fi

echo "Creating draft release \"$tag\" targeting \"$target\"..." >&2
gh release create "$tag" \
--draft \
Expand Down
55 changes: 49 additions & 6 deletions bin/generate-pending-release-diffs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,17 @@ for plugin_slug in $( if [ $# -gt 0 ]; then echo "$@"; else jq '.plugins[]' -r p
remote_stable_tag=$( grep "Stable tag:" "$stable_dir/$plugin_slug/readme.txt" | awk '{print $3}' )
local_stable_tag=$( grep "Stable tag:" "build/$plugin_slug/readme.txt" | awk '{print $3}' )

# Exclude minified assets: they are build artifacts derived from their sources, so
# diffing them just adds noise. Excluding them here also protects the stable copies
# from --delete, so svn status/diff below will not report them.
rsync -avz --delete --exclude=".svn" --exclude="*.min.js" --exclude="*.min.css" "build/$plugin_slug/" "$stable_dir/$plugin_slug/" >&2
# Copy everything, including generated assets. They are excluded from the *diff* further
# below rather than from the copy, so that "svn status" reports the true set of files
# being added, removed, and modified. Excluding them here instead would protect them
# from --delete and make them invisible to svn entirely: a stray minified asset dropped
# into an already-tracked directory would then be reported nowhere at all.
#
# Compare by checksum (-c) and stamp copied files with a fresh mtime (--no-times).
# Both are required: "Tested up to: 7.0" -> "7.1" is a same-length edit, and rsync's
# default quick check (size+mtime) as well as SVN's own stat cache would each conclude
# the file is unchanged, so the plugin gets wrongly reported as having nothing to release.
rsync -avzc --no-times --delete --exclude=".svn" "build/$plugin_slug/" "$stable_dir/$plugin_slug/" >&2

cd "$stable_dir/$plugin_slug/"

Expand All @@ -67,13 +74,49 @@ for plugin_slug in $( if [ $# -gt 0 ]; then echo "$@"; else jq '.plugins[]' -r p

echo "\`svn status\`:"
echo '```'
svn status
# SVN reports an unversioned directory without listing what is inside it, so a batch
# of added files would otherwise surface only as their parent directory. Expand those
# so every file being added is named.
svn status | while IFS= read -r status_line; do
echo "$status_line"
if [ "${status_line:0:1}" = "?" ]; then
status_path="${status_line:8}"
if [ -d "$status_path" ]; then
find "$status_path" -type f | sort | sed 's|^|? |'
fi
fi
done
echo '```'
echo
echo '<details><summary><code>svn diff</code></summary>'
echo
echo '```diff'
svn diff
# Keep generated files in the diff so it is clear they changed, but replace their
# contents with a placeholder. They are minified or bundled build output, so their
# diffs are unreadable and enormous: the two web-vitals bundles alone were 35% of
# the entire report, for what amounts to a library version bump. The sibling
# *.asset.php is left intact, since its 'version' is the readable signal of that.
svn diff | awk '
/^Index: / {
path = substr( $0, 8 )
suppress = ( path ~ /\.min\.(js|css)$/ || path ~ /(^|\/)build\// )
if ( path ~ /\.asset\.php$/ ) {
suppress = 0
}
placed = 0
print
next
}
suppress && /^(=+|--- |\+\+\+ )/ { print; next }
suppress {
if ( ! placed ) {
print "(Built file content suppressed.)"
placed = 1
}
next
}
{ print }
'
echo '```'
echo '</details>'
fi
Expand Down
11 changes: 7 additions & 4 deletions bin/plugin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,22 @@ withOptions( program.command( 'verify-version-consistency' ), versionsOptions )
.description( 'Verifies consistency of versions in plugins' )
.action( catchException( versionsHandler ) );

withOptions( program.command( 'bump-plugin-versions' ), bumpVersionsOptions )
withOptions(
program.command( 'bump-plugin-versions [plugins...]' ),
bumpVersionsOptions
)
.alias( 'bump-versions' )
.description(
'Bumps plugin versions based on open, dated release milestones (titled "$plugin_slug $version" without "n.e.x.t")'
'Bumps plugin versions based on open, dated release milestones (titled "$plugin_slug $version" without "n.e.x.t"); pass --increment or --set-version with a list of plugin slugs to bump without a milestone'
)
.action( catchException( bumpVersionsHandler ) );

withOptions(
program.command( 'prepare-release-notes' ),
program.command( 'prepare-release-notes [plugins...]' ),
prepareReleaseNotesOptions
)
.description(
'Prints the combined per-plugin changelogs (release notes) for plugins with an open, dated release milestone; progress goes to STDERR so STDOUT can be piped'
'Prints the combined per-plugin changelogs (release notes) for plugins with an open, dated release milestone, or for a list of plugin slugs given without a milestone; progress goes to STDERR so STDOUT can be piped'
)
.action( catchException( prepareReleaseNotesHandler ) );

Expand Down
Loading
Loading