Files

182 lines
7.1 KiB
YAML

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."