Skip to content
Open
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
36 changes: 23 additions & 13 deletions .github/workflows/release-policy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name: Release policy
# Job matrix:
# pr-target-policy PR β†’ main | head_ref must be staging, release/*, or hotfix/*
# version-sync PR β†’ staging | NO version field changed (skipped for backmerge/*)
# version-bump PR β†’ main | all 5 version fields bumped, in sync, valid semver, strictly greater
# version-bump PR β†’ main | all 7 version fields bumped, in sync, valid semver, strictly greater
# changelog-entry PR β†’ main | top-most CHANGELOG section matches new version, has bullets
# staging-up-to-date PR β†’ staging | PR head contains every commit on main
# (passes naturally for backmerge/* PRs)
Expand Down Expand Up @@ -86,20 +86,26 @@ jobs:

HEAD_VERSIONS=(
"$(jq -r '.version' plugins/winui/agent-plugin/plugin.json)"
"$(jq -r '.version' plugins/winui/.claude-plugin/plugin.json)"
"$(jq -r '.version' plugins/winui/.codex-plugin/plugin.json)"
"$(jq -r '.metadata.version' .github/plugin/marketplace.json)"
"$(jq -r '.plugins[0].version' .github/plugin/marketplace.json)"
"$(jq -r '.version' .claude-plugin/marketplace.json)"
"$(jq -r '.plugins[0].version' .claude-plugin/marketplace.json)"
)
BASE_VERSIONS=(
"$(read_base_plugin_version)"
"$(git show "$BASE_SHA":plugins/winui/.claude-plugin/plugin.json | jq -r '.version')"
"$(git show "$BASE_SHA":plugins/winui/.codex-plugin/plugin.json | jq -r '.version')"
"$(git show "$BASE_SHA":.github/plugin/marketplace.json | jq -r '.metadata.version')"
"$(git show "$BASE_SHA":.github/plugin/marketplace.json | jq -r '.plugins[0].version')"
"$(git show "$BASE_SHA":.claude-plugin/marketplace.json | jq -r '.version')"
"$(git show "$BASE_SHA":.claude-plugin/marketplace.json | jq -r '.plugins[0].version')"
)
LABELS=(
"portable plugin"
"Claude client plugin"
"Codex client plugin"
"GitHub marketplace metadata"
"GitHub marketplace plugin"
"Claude marketplace"
Expand Down Expand Up @@ -158,7 +164,7 @@ jobs:
echo "::notice::PR head contains every commit on 'main' β€” OK."

version-bump:
name: Version bump (5 fields in sync)
name: Version bump (7 fields in sync)
if: github.event.pull_request.base.ref == 'main'
runs-on: ubuntu-latest
steps:
Expand All @@ -178,12 +184,14 @@ jobs:
# Extract every version field from PR head and from main.
# PR-head versions:
PR_PLUGIN=$(jq -r '.version' plugins/winui/agent-plugin/plugin.json)
PR_CLAUDE_CLIENT=$(jq -r '.version' plugins/winui/.claude-plugin/plugin.json)
PR_CODEX_CLIENT=$(jq -r '.version' plugins/winui/.codex-plugin/plugin.json)
PR_GH_META=$(jq -r '.metadata.version' .github/plugin/marketplace.json)
PR_GH_PLUGIN=$(jq -r '.plugins[0].version' .github/plugin/marketplace.json)
PR_CLAUDE_TOP=$(jq -r '.version' .claude-plugin/marketplace.json)
PR_CLAUDE_PLUGIN=$(jq -r '.plugins[0].version' .claude-plugin/marketplace.json)

# main-side versions: read all 5 and require they're already in sync
# main-side versions: read all 7 and require they're already in sync
# (defends against a previously-bad release leaving main inconsistent).
if git cat-file -e "$BASE_SHA:plugins/winui/agent-plugin/plugin.json" 2>/dev/null; then
MAIN_PLUGIN=$(git show "$BASE_SHA":plugins/winui/agent-plugin/plugin.json | jq -r '.version')
Expand All @@ -192,29 +200,31 @@ jobs:
# the portable manifest at its former path on main.
MAIN_PLUGIN=$(git show "$BASE_SHA":plugins/winui/plugin.json | jq -r '.version')
fi
MAIN_CLAUDE_CLIENT=$(git show "$BASE_SHA":plugins/winui/.claude-plugin/plugin.json | jq -r '.version')
MAIN_CODEX_CLIENT=$(git show "$BASE_SHA":plugins/winui/.codex-plugin/plugin.json | jq -r '.version')
MAIN_GH_META=$(git show "$BASE_SHA":.github/plugin/marketplace.json | jq -r '.metadata.version')
MAIN_GH_PLUGIN=$(git show "$BASE_SHA":.github/plugin/marketplace.json | jq -r '.plugins[0].version')
MAIN_CLAUDE_TOP=$(git show "$BASE_SHA":.claude-plugin/marketplace.json | jq -r '.version')
MAIN_CLAUDE_PLUGIN=$(git show "$BASE_SHA":.claude-plugin/marketplace.json | jq -r '.plugins[0].version')

MAIN_ALL=("$MAIN_PLUGIN" "$MAIN_GH_META" "$MAIN_GH_PLUGIN" "$MAIN_CLAUDE_TOP" "$MAIN_CLAUDE_PLUGIN")
MAIN_ALL=("$MAIN_PLUGIN" "$MAIN_CLAUDE_CLIENT" "$MAIN_CODEX_CLIENT" "$MAIN_GH_META" "$MAIN_GH_PLUGIN" "$MAIN_CLAUDE_TOP" "$MAIN_CLAUDE_PLUGIN")
for v in "${MAIN_ALL[@]}"; do
if [[ "$v" != "$MAIN_PLUGIN" ]]; then
echo "::error::main-side version fields are out of sync: ${MAIN_ALL[*]}"
echo "::error::A previous release left main in an inconsistent state. Fix all 5 fields in this PR before continuing."
break
echo "::error::A previous release left main in an inconsistent state. Fix all 7 fields in this PR before continuing."
exit 1
fi
done

echo "PR head: plugin=$PR_PLUGIN gh.meta=$PR_GH_META gh.plugin=$PR_GH_PLUGIN claude.top=$PR_CLAUDE_TOP claude.plugin=$PR_CLAUDE_PLUGIN"
echo "main: plugin=$MAIN_PLUGIN gh.meta=$MAIN_GH_META gh.plugin=$MAIN_GH_PLUGIN claude.top=$MAIN_CLAUDE_TOP claude.plugin=$MAIN_CLAUDE_PLUGIN"
echo "PR head: plugin=$PR_PLUGIN claude.client=$PR_CLAUDE_CLIENT codex.client=$PR_CODEX_CLIENT gh.meta=$PR_GH_META gh.plugin=$PR_GH_PLUGIN claude.top=$PR_CLAUDE_TOP claude.plugin=$PR_CLAUDE_PLUGIN"
echo "main: plugin=$MAIN_PLUGIN claude.client=$MAIN_CLAUDE_CLIENT codex.client=$MAIN_CODEX_CLIENT gh.meta=$MAIN_GH_META gh.plugin=$MAIN_GH_PLUGIN claude.top=$MAIN_CLAUDE_TOP claude.plugin=$MAIN_CLAUDE_PLUGIN"

# Rule 1: all 5 PR-head versions identical.
ALL=("$PR_PLUGIN" "$PR_GH_META" "$PR_GH_PLUGIN" "$PR_CLAUDE_TOP" "$PR_CLAUDE_PLUGIN")
# Rule 1: all 7 PR-head versions identical.
ALL=("$PR_PLUGIN" "$PR_CLAUDE_CLIENT" "$PR_CODEX_CLIENT" "$PR_GH_META" "$PR_GH_PLUGIN" "$PR_CLAUDE_TOP" "$PR_CLAUDE_PLUGIN")
for v in "${ALL[@]}"; do
if [[ "$v" != "$PR_PLUGIN" ]]; then
echo "::error::Version fields are out of sync. All 5 fields must match. Got: ${ALL[*]}"
echo "::error::Files to fix: plugins/winui/agent-plugin/plugin.json, .github/plugin/marketplace.json, .claude-plugin/marketplace.json"
echo "::error::Version fields are out of sync. All 7 fields must match. Got: ${ALL[*]}"
echo "::error::Files to fix: plugins/winui/{agent-plugin,.claude-plugin,.codex-plugin}/plugin.json, .github/plugin/marketplace.json, .claude-plugin/marketplace.json"
exit 1
fi
done
Expand Down Expand Up @@ -242,7 +252,7 @@ jobs:
fi

echo "VERSION=$PR_PLUGIN" >> "$GITHUB_ENV"
echo "::notice::Version bump $MAIN_PLUGIN β†’ $PR_PLUGIN, all 5 fields in sync."
echo "::notice::Version bump $MAIN_PLUGIN β†’ $PR_PLUGIN, all 7 fields in sync."

changelog-entry:
name: CHANGELOG entry matches new version
Expand Down
8 changes: 5 additions & 3 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ The script:
either client-specific agent copy, removes a skill directory, or changes the plugin
manifest schema).
4. Lets you accept or override the suggested version.
5. Writes the bumped version into all five version fields:
5. Writes the bumped version into all seven version fields:
- `plugins/winui/agent-plugin/plugin.json` β†’ `version`
- `plugins/winui/.claude-plugin/plugin.json` β†’ `version`
- `plugins/winui/.codex-plugin/plugin.json` β†’ `version`
- `.github/plugin/marketplace.json` β†’ `metadata.version` and `plugins[0].version`
- `.claude-plugin/marketplace.json` β†’ `version` and `plugins[0].version`
6. Drafts a `## [X.Y.Z] β€” YYYY-MM-DD` CHANGELOG section by promoting bullets
Expand All @@ -68,7 +70,7 @@ The script:
If the helper doesn't work for some reason:

1. `git checkout -b release/X.Y.Z origin/staging`
2. Edit all five version fields (use `git grep -n '"version"'` to find them).
2. Edit all seven version fields (use `git grep -n '"version"'` to find them).
3. Edit `CHANGELOG.md`: rename `## [Unreleased]` to `## [X.Y.Z] β€” YYYY-MM-DD`
and add a fresh empty `## [Unreleased]` section above it.
4. Commit, push, `gh pr create --base main --head release/X.Y.Z`.
Expand Down Expand Up @@ -143,7 +145,7 @@ skips that prefix so the version-bump diff doesn't trip the gate.
If a release on `main` is broken:

1. `git revert -m 1 <merge-commit-sha>` on a new branch from `main`.
2. Bump the patch version (`0.X.Y β†’ 0.X.Y+1`) in all five fields.
2. Bump the patch version (`0.X.Y β†’ 0.X.Y+1`) in all seven fields.
3. Add a CHANGELOG entry under the new version explaining what was reverted
and why.
4. PR against `main` directly β€” this is treated like a hotfix.
Expand Down
12 changes: 8 additions & 4 deletions scripts/open-release-pr.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
2. Lists the commits going into the release.
3. Suggests a semver bump (patch by default; minor on heuristic triggers).
4. Lets you accept or override the version.
5. Writes the version into all 5 manifest fields.
5. Writes the version into all 7 manifest fields.
6. Promotes [Unreleased] CHANGELOG bullets into a new dated section.
7. Pushes a release/X.Y.Z branch and opens the PR via gh.

Expand Down Expand Up @@ -71,7 +71,7 @@ if ([int]$behind -gt 0) {
# ---- 2. Enumerate commits going into the release -------------------------

$commits = git log --pretty=format:'%H%x09%s' "origin/main..origin/staging"
$commitLines = $commits -split "`n" | Where-Object { $_ }
$commitLines = @($commits -split "`n" | Where-Object { $_ })
Info "`nCommits in this release ($($commitLines.Count)):"
$commitLines | ForEach-Object {
$parts = $_ -split "`t", 2
Expand Down Expand Up @@ -169,7 +169,7 @@ $branch = "release/$Version"
Info "`nCreating local branch $branch from origin/staging..."
git checkout -B $branch origin/staging | Out-Null

# ---- 5. Bump 5 version fields --------------------------------------------
# ---- 5. Bump 7 version fields --------------------------------------------

function Set-JsonField([string]$file, [string[]]$path, [string]$value) {
$json = Get-Content $file -Raw | ConvertFrom-Json
Expand All @@ -183,8 +183,10 @@ function Set-JsonField([string]$file, [string[]]$path, [string]$value) {
($json | ConvertTo-Json -Depth 32) | Set-Content $file -Encoding UTF8
}

Info "Writing version into 5 fields..."
Info "Writing version into 7 fields..."
Set-JsonField 'plugins/winui/agent-plugin/plugin.json' @('version') $Version
Set-JsonField 'plugins/winui/.claude-plugin/plugin.json' @('version') $Version
Set-JsonField 'plugins/winui/.codex-plugin/plugin.json' @('version') $Version
Set-JsonField '.github/plugin/marketplace.json' @('metadata','version') $Version
Set-JsonField '.github/plugin/marketplace.json' @('plugins','[0]','version') $Version
Set-JsonField '.claude-plugin/marketplace.json' @('version') $Version
Expand Down Expand Up @@ -246,6 +248,8 @@ Set-Content CHANGELOG.md -Value $newCl -Encoding UTF8
# ---- 7. Commit, push, open PR --------------------------------------------

git add plugins/winui/agent-plugin/plugin.json `
plugins/winui/.claude-plugin/plugin.json `
plugins/winui/.codex-plugin/plugin.json `
.github/plugin/marketplace.json `
.claude-plugin/marketplace.json `
CHANGELOG.md
Expand Down
Loading