name: release # Manual, path-scoped release helper for master. # # `master` is BOTH the distribution branch (users download the script here) # AND the default branch that hosts the scheduled CI workflows # (autoupdate / stale / vuln-watch). `source-build` is a build-OUTPUT branch. # # We therefore never merge source-build into master: that would drag source-build's # whole tree, including the *absence* of the master-only workflows. # Instead we copy only the assembled artifact files across, and cut GitHub # releases from master directly. # # Two independent manual actions to run against the `master` branch: # # 1. sync-from-source-build : open a PR against master carrying the assembled # files (everything on source-build EXCEPT # .github/). Nothing lands on master until the PR # is reviewed and merged. # 2. draft-github-release : create a DRAFT GitHub release from the script # currently on master, with an auto-drafted # changelog. on: workflow_dispatch: inputs: action: description: What to do type: choice required: true default: sync-from-source-build options: - sync-from-source-build - draft-github-release permissions: contents: write pull-requests: write concurrency: group: release-master cancel-in-progress: false jobs: # --------------------------------------------------------------------------- # 1. Copy assembled files from source-build onto master (no .github/), # as a pull request. # --------------------------------------------------------------------------- sync-from-source-build: if: inputs.action == 'sync-from-source-build' runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: ref: master fetch-depth: 0 persist-credentials: true - name: sync assembled files from source-build id: sync run: | set -eu git fetch --no-tags origin source-build # Every top-level entry on source-build EXCEPT .github/ (master keeps # its own CI). Computed dynamically so any new top-level artifact is # picked up automatically. readarray -t paths < <(git ls-tree --name-only origin/source-build | grep -vxF '.github') echo "Syncing: ${paths[*]}" # Mirror source-build exactly for those paths, removing first so that # deletions/renames inside doc/ etc. propagate too. for p in "${paths[@]}"; do rm -rf -- "$p"; done git checkout origin/source-build -- "${paths[@]}" git add --all -- "${paths[@]}" if git diff --cached --quiet; then echo "master already up to date with source-build; nothing to sync." echo "changed=false" >> "$GITHUB_OUTPUT" exit 0 fi { echo "changed=true" echo "version=$(grep -m1 "^VERSION=" spectre-meltdown-checker.sh | cut -d"'" -f2)" echo "sb=$(git rev-parse origin/source-build)" echo "sbdate=$(git log -1 --format=%ai origin/source-build)" } >> "$GITHUB_OUTPUT" # Note: the repo must have "Allow GitHub Actions to create and approve # pull requests" enabled for this to work. - name: open the sync pull request if: steps.sync.outputs.changed == 'true' uses: peter-evans/create-pull-request@v7 with: base: master branch: release/sync-from-source-build delete-branch: true committer: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" author: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" title: "release: sync v${{ steps.sync.outputs.version }} from source-build" commit-message: | release: sync v${{ steps.sync.outputs.version }} from source-build built from source-build commit ${{ steps.sync.outputs.sb }} dated ${{ steps.sync.outputs.sbdate }} body: | Assembled files copied from `source-build` onto `master` (everything except `.github/`, which stays master-only). - version: `${{ steps.sync.outputs.version }}` - built from source-build commit: ${{ steps.sync.outputs.sb }} - dated: ${{ steps.sync.outputs.sbdate }} Once merged, run this workflow again with the `draft-github-release` action to cut the release, if required. # --------------------------------------------------------------------------- # 2. Draft a GitHub release from the script currently on master. # --------------------------------------------------------------------------- draft-github-release: if: inputs.action == 'draft-github-release' runs-on: ubuntu-latest env: GH_TOKEN: ${{ github.token }} steps: - uses: actions/checkout@v6 with: ref: master fetch-depth: 0 persist-credentials: true - name: draft a release from the current master script run: | set -eu ver=$(grep -m1 "^VERSION=" spectre-meltdown-checker.sh | cut -d"'" -f2) tag="v${ver}" if gh release view "$tag" >/dev/null 2>&1; then echo "A release for $tag already exists; refusing to recreate." >&2 echo "Delete it first if needed." >&2 exit 1 fi # Draft the changelog from the source-build commits assembled since the # previous published release. We locate the source-build commit whose # built VERSION equals the last release tag, then list what came after. git fetch --no-tags origin source-build last_tag=$(gh release list --exclude-drafts --limit 1 --json tagName --jq '.[0].tagName // empty') old_ver="${last_tag#v}" base="" if [ -n "$old_ver" ]; then while read -r h; do v=$(git show "$h:spectre-meltdown-checker.sh" 2>/dev/null | grep -m1 "^VERSION=" | cut -d"'" -f2 || true) if [ "$v" = "$old_ver" ]; then base="$h"; break; fi done < <(git rev-list --max-count=500 origin/source-build) fi { echo "## ${tag}" echo if [ -n "$base" ]; then git log --no-merges --format='- %s' "${base}..origin/source-build" else echo "_Could not determine the previous release point automatically — please fill in the changelog. Last 30 assembled commits below as a starting point:_" echo git log --no-merges --format='- %s' --max-count=30 origin/source-build fi } > notes.md echo "----- draft notes -----"; cat notes.md; echo "-----------------------" gh release create "$tag" \ --draft \ --target "$GITHUB_SHA" \ --title "$tag" \ --notes-file notes.md \ spectre-meltdown-checker.sh echo "Draft release $tag created."