From fb7c71264de78d6e5f3b6f73c866a30ca5762319 Mon Sep 17 00:00:00 2001 From: Ahmed ElMallah Date: Thu, 18 Jun 2026 11:51:18 -0700 Subject: [PATCH] Revise release lifecycle yanking workflow and docs --- .github/workflows/notify-landing-yank.yml | 93 ++++++++++++++++++++++- docs/development/CI.md | 10 ++- docs/development/RELEASE_CHECKLIST.md | 4 +- 3 files changed, 101 insertions(+), 6 deletions(-) diff --git a/.github/workflows/notify-landing-yank.yml b/.github/workflows/notify-landing-yank.yml index 2543670..47d4f6f 100644 --- a/.github/workflows/notify-landing-yank.yml +++ b/.github/workflows/notify-landing-yank.yml @@ -1,9 +1,11 @@ -name: Notify landing page (release lifecycle) +name: Release lifecycle sync # Dispatches to bomly-landing-page whenever a release is published (so docs and # changelog sync), or deleted/unpublished (so the version is yanked from the -# version selector and changelog). Docs are synced at publish time rather than -# at draft creation so the changelog script can find the release via the API. +# version selector and changelog). Yanked releases also attempt to remove the +# corresponding WinGet version manifest when it exists. Docs are synced at +# publish time rather than at draft creation so the changelog script can find +# the release via the API. on: release: @@ -13,7 +15,7 @@ permissions: contents: read jobs: - notify: + landing-page: runs-on: ubuntu-latest timeout-minutes: 5 steps: @@ -55,3 +57,86 @@ jobs: --input - <> "${GITHUB_OUTPUT}" + + if [[ ! -d "${MANIFEST_DIR}" ]]; then + echo "No WinGet manifest exists for Bomly.BomlyCLI ${VERSION}; skipping removal." + echo "removed=false" >> "${GITHUB_OUTPUT}" + exit 0 + fi + + git config user.name "bomly-release-bot" + git config user.email "release-bot@bomly.dev" + git checkout -b "${BRANCH}" + rm -rf "${MANIFEST_DIR}" + git add "manifests/b/Bomly/BomlyCLI" + git commit -m "Remove Bomly CLI ${VERSION}" + + echo "removed=true" >> "${GITHUB_OUTPUT}" + + - name: Push WinGet removal branch + if: steps.winget-yank.outputs.removed == 'true' + working-directory: winget-pkgs + env: + WINGET_GITHUB_TOKEN: ${{ secrets.WINGET_GITHUB_TOKEN }} + BRANCH: ${{ steps.winget-yank.outputs.branch }} + run: | + set -euo pipefail + git remote add bomly "https://x-access-token:${WINGET_GITHUB_TOKEN}@github.com/bomly-dev/winget-pkgs.git" + git fetch bomly "${BRANCH}:refs/remotes/bomly/${BRANCH}" || true + git push --force-with-lease bomly "HEAD:${BRANCH}" + + - name: Open WinGet removal PR + if: steps.winget-yank.outputs.removed == 'true' + working-directory: winget-pkgs + env: + GH_TOKEN: ${{ secrets.WINGET_GITHUB_TOKEN }} + VERSION: ${{ steps.winget-yank.outputs.version }} + BRANCH: ${{ steps.winget-yank.outputs.branch }} + run: | + set -euo pipefail + + if gh pr view --repo microsoft/winget-pkgs --head "bomly-dev:${BRANCH}" >/dev/null 2>&1; then + echo "WinGet removal PR already exists for Bomly.BomlyCLI ${VERSION}." + exit 0 + fi + + gh pr create \ + --repo microsoft/winget-pkgs \ + --base master \ + --head "bomly-dev:${BRANCH}" \ + --title "Remove Bomly.BomlyCLI version ${VERSION}" \ + --body "Remove the Bomly.BomlyCLI WinGet manifest for yanked release ${VERSION}." diff --git a/docs/development/CI.md b/docs/development/CI.md index d23242b..00479fb 100644 --- a/docs/development/CI.md +++ b/docs/development/CI.md @@ -181,10 +181,18 @@ Release packaging is driven by `.goreleaser.yaml`. The release workflow uses GoR 6. GoReleaser generates `SHA256SUMS` and Linux packages. 7. GoReleaser publishes the GitHub Release, using the configured GoReleaser header plus GitHub-native generated release notes, and uploads archives, packages, and checksums. 8. GoReleaser opens or updates package-manager manifest PRs for Homebrew, Scoop, and WinGet. -9. After the release is published, the `Notify landing page (release lifecycle)` workflow dispatches the landing-page docs and changelog sync with the published timestamp. +9. After the release is published, the `Release lifecycle sync` workflow dispatches the landing-page docs and changelog sync with the published timestamp. The manual approval point for a release is the `Auto Version` workflow that creates the release tag. The GitHub Release is intentionally published automatically after validation so package-manager manifest PRs can reference public release assets and checksums. +## Yanking Releases + +Deleting or unpublishing a GitHub Release automatically starts the yanking path in the `Release lifecycle sync` workflow. The workflow dispatches a landing-page removal event so the yanked version is removed from the version selector and changelog. + +Package-manager cleanup depends on where the manifest lives. Homebrew and Scoop are maintained as current manifests in `bomly-dev/homebrew-tap` and `bomly-dev/scoop-bucket`, so closing stale package-manager PRs and publishing a replacement release is normally sufficient. WinGet stores versioned manifests in `microsoft/winget-pkgs`, so the workflow also checks for `Bomly.BomlyCLI` under `manifests/b/Bomly/BomlyCLI/`. When that version directory exists, it pushes a deletion branch to `bomly-dev/winget-pkgs` and opens a PR against `microsoft/winget-pkgs:master`. + +GoReleaser continues to own normal package-manager publication for new releases. WinGet yanking is handled by the release lifecycle workflow because it is a deletion PR, not a release publication step. + Version bump rules are chosen explicitly when running `Auto Version`: | Selected bump | Result | diff --git a/docs/development/RELEASE_CHECKLIST.md b/docs/development/RELEASE_CHECKLIST.md index d4fd989..62034be 100644 --- a/docs/development/RELEASE_CHECKLIST.md +++ b/docs/development/RELEASE_CHECKLIST.md @@ -53,4 +53,6 @@ scoop install bomly - Merge package-manager PRs after their generated manifests pass review. - Confirm the landing-page docs sync PR opened. -- If a release must be pulled, mark the GitHub release as a prerelease or delete it, close package-manager PRs that reference the bad tag, and tag a replacement patch release when appropriate. +- If a release must be pulled, delete or unpublish the GitHub Release to trigger the automatic yanking workflow. +- Close Homebrew and Scoop package-manager PRs that reference the bad tag, then tag a replacement patch release when appropriate. +- For WinGet, confirm the release lifecycle workflow either skipped cleanup because no version manifest existed or opened a removal PR against `microsoft/winget-pkgs`.