Hold release PR merge until BRAT validation

This commit is contained in:
vorotamoroz
2026-07-14 08:45:23 +09:00
parent eb3abc71b4
commit 804103693f
4 changed files with 64 additions and 11 deletions
+20 -3
View File
@@ -21,6 +21,7 @@ jobs:
runs-on: ubuntu-latest
environment: release
permissions:
actions: write
contents: write
steps:
- name: Resolve release branch
@@ -78,6 +79,22 @@ jobs:
git tag "${VERSION}-cli"
git push origin "${VERSION}" "${VERSION}-cli"
- name: Dispatch release workflows
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
gh workflow run release.yml \
--ref "${VERSION}" \
--field tag="${VERSION}" \
--field draft=true \
--field prerelease=false
gh workflow run cli-docker.yml \
--ref "${VERSION}-cli" \
--field dry_run=false \
--field force=false
- name: Summarise next steps
env:
VERSION: ${{ inputs.version }}
@@ -85,8 +102,8 @@ jobs:
{
echo "Created tags \`${VERSION}\` and \`${VERSION}-cli\`."
echo ""
echo "The plug-in release workflow is triggered by the \`${VERSION}\` tag and creates a draft release by default."
echo "The CLI Docker workflow is triggered by the \`${VERSION}-cli\` tag and publishes the version, major-minor, latest, and SHA-qualified image tags."
echo "Dispatched the plug-in release workflow for \`${VERSION}\`. After approval for the release environment, it creates a draft GitHub Release."
echo "Dispatched the CLI Docker workflow for \`${VERSION}-cli\`. It publishes the version, major-minor, latest, and SHA-qualified image tags."
echo ""
echo "To create a pre-release instead of the default draft flow, run \`Release Obsidian Plugin\` manually with \`tag=${VERSION}\`, \`draft=false\`, and \`prerelease=true\`."
echo "Keep the release pull request in draft after publishing the GitHub Release as the latest stable release. Mark it ready and merge it only after BRAT validation succeeds."
} >> "$GITHUB_STEP_SUMMARY"
+9 -1
View File
@@ -91,6 +91,11 @@ jobs:
RELEASE_BRANCH: ${{ steps.prepare.outputs.branch }}
run: |
cat > /tmp/release-pr-body.md <<EOF
> [!IMPORTANT]
> **Merge intentionally on hold**
>
> Publishing the GitHub Release does not unblock this pull request. Keep this pull request in draft, and leave \`main\` on the previous release, until the published build has passed BRAT validation.
## Release checklist
- [ ] Review and polish \`updates.md\`
@@ -98,7 +103,10 @@ jobs:
- [ ] Confirm \`manifest.json\`, \`versions.json\`, workspace package versions, and generated \`_types\`
- [ ] Confirm CI has passed
- [ ] Run the finalise release workflow with this PR's fixed head SHA
- [ ] Merge this PR with a merge commit after the draft or pre-release has been created
- [ ] Confirm the draft GitHub Release assets and the published CLI image
- [ ] Publish the GitHub Release as the latest stable release while keeping this pull request in draft
- [ ] Validate the published release with BRAT
- [ ] Mark this pull request ready and merge it with a merge commit
EOF
gh pr create \
+14 -7
View File
@@ -274,9 +274,12 @@ The `Finalise Release Tags` and `Release Obsidian Plugin` workflows use the `rel
- Run the `Prepare Release PR` workflow with the target version. It creates the release branch, updates versions, regenerates the `_types` fallback definitions used by the community plug-in scan, moves the `## Unreleased` notes to the target version, commits the release preparation, pushes the branch, and opens a draft release PR.
- Do not tag the release branch when the PR is first created. Polish the release PR first, especially `updates.md`.
- Once the release PR head is fixed, run the `Finalise Release Tags` workflow with its full head commit SHA. It validates the release branch and pushes both the plug-in tag (for example, `0.25.81`) and the CLI tag (for example, `0.25.81-cli`) to that commit.
- The plug-in tag triggers the release workflow and creates a draft GitHub Release by default. The CLI tag triggers the Docker workflow and publishes the fixed version tag, the major-minor moving tag (for example, `0.25-cli`), `latest`, and the SHA-qualified tag.
- Merge the release PR with a merge commit after the draft or pre-release has been created. This keeps the tagged release commit in the `main` history.
- Once the release PR head is fixed, run the `Finalise Release Tags` workflow with its full head commit SHA. It validates the release branch, pushes both the plug-in tag (for example, `0.25.81`) and the CLI tag (for example, `0.25.81-cli`) to that commit, and explicitly dispatches the plug-in and CLI publishing workflows. An explicit dispatch is required because tags pushed with `GITHUB_TOKEN` do not trigger tag-push workflows.
- Approve the `Release Obsidian Plugin` workflow for the `release` environment, then inspect the generated draft GitHub Release. Confirm that the CLI workflow has published the fixed version tag, the major-minor moving tag (for example, `0.25-cli`), `latest`, and the SHA-qualified tag.
- Publish the draft GitHub Release as the latest stable release while keeping the release PR in draft and leaving `main` unchanged. Record the state in the PR with: 'Release `<version>` has been published as the latest stable release. This pull request intentionally remains in draft, and `main` has not yet been updated. Merge is on hold until BRAT validation is complete.'
- Validate the published release through BRAT. Confirm start-up, ordinary bidirectional synchronisation, and any regression scenario relevant to the release.
- After BRAT validation succeeds, mark the release PR ready and merge it with a merge commit. This keeps the tagged release commit in the `main` history.
- If BRAT validation fails, keep the release PR in draft. Do not move published tags; prepare and publish a new patch release instead.
- If a pre-release is needed, run the `Release Obsidian Plugin` workflow manually with the target tag, `draft=false`, and `prerelease=true`.
### Release Cheat Sheet
@@ -297,10 +300,14 @@ The `Finalise Release Tags` and `Release Obsidian Plugin` workflows use the `rel
- `version`: the same target version.
- `release_branch`: leave blank unless the release branch used a custom name.
- `expected_head_sha`: the full head commit SHA reviewed in the release PR.
5. Check the generated draft GitHub Release for the plug-in tag.
6. Check the CLI Docker workflow started from the `*-cli` tag.
7. Publish the draft GitHub Release when ready, then merge the release PR into `main` with a merge commit.
8. If the release should be a pre-release instead of a draft release, run `Release Obsidian Plugin` manually with the target `tag`, `draft=false`, and `prerelease=true`.
5. Approve the `Release Obsidian Plugin` workflow for the `release` environment, then check the generated draft GitHub Release.
6. Confirm that the explicitly dispatched CLI Docker workflow has published the expected image tags.
7. Publish the draft GitHub Release as the latest stable release, but keep the release PR in draft and leave `main` unchanged.
8. Update the PR state message to say that the release is now the latest stable release and that merging is intentionally on hold until BRAT validation is complete.
9. Validate the published release through BRAT, including start-up, ordinary bidirectional synchronisation, and any release-specific regression scenario.
10. After BRAT validation succeeds, mark the release PR ready and merge it into `main` with a merge commit.
11. If validation fails, leave the PR in draft and prepare a new patch release without moving the published tags.
12. If the release should be a pre-release instead of a draft release, run `Release Obsidian Plugin` manually with the target `tag`, `draft=false`, and `prerelease=true`.
## Contribution Guidelines
+21
View File
@@ -10,6 +10,7 @@ const versionBumpScript =
process.env.VERSION_BUMP_SCRIPT || fileURLToPath(new URL("../version-bump.mjs", import.meta.url));
const workspaceUpdateScript = fileURLToPath(new URL("../update-workspaces.mjs", import.meta.url));
const prepareReleaseWorkflow = fileURLToPath(new URL("../.github/workflows/prepare-release.yml", import.meta.url));
const finaliseReleaseWorkflow = fileURLToPath(new URL("../.github/workflows/finalise-release.yml", import.meta.url));
const temporaryDirectories: string[] = [];
afterEach(() => {
@@ -111,6 +112,26 @@ describe("release workflow", () => {
expect(workflow).toContain("npm run build:lib:types");
expect(workflow).toMatch(/git add[^\n]*_types/);
});
it("keeps the release PR in draft until BRAT validation", () => {
const workflow = readFileSync(prepareReleaseWorkflow, "utf8");
expect(workflow).toContain("Merge intentionally on hold");
expect(workflow).toContain(
"Publish the GitHub Release as the latest stable release while keeping this pull request in draft"
);
expect(workflow).toContain("Validate the published release with BRAT");
expect(workflow).toContain("Mark this pull request ready and merge it with a merge commit");
});
it("explicitly dispatches publishing workflows after creating tags", () => {
const workflow = readFileSync(finaliseReleaseWorkflow, "utf8");
expect(workflow).toContain("actions: write");
expect(workflow).toContain("gh workflow run release.yml");
expect(workflow).toContain("gh workflow run cli-docker.yml");
expect(workflow).toContain("dry_run=false");
});
});
describe("version bump", () => {