# Release: create a GitHub Release with packaged plugin assets # Triggered on version tags (v*). # # Produces: # - pstack-.zip — portable plugin package # - Release body from CHANGELOG section for that version name: release on: push: tags: - "v*" permissions: contents: write env: UPSTREAM_PIN: c47b12849e43f18d5c374c7069c744cc55b0ea00 jobs: build: runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: persist-credentials: false # release.yml previously carried its own copy of the build prologue AND was # missing the "Verify pinned SHA" step that ci.yml # had, so a release could be cut from a pin that silently failed to # resolve. The shared action gives every caller the verified-pin behaviour. - name: Build package from pin uses: ./.github/actions/build-package with: upstream-pin: ${{ env.UPSTREAM_PIN }} - name: Verify release source and published package shell: bash run: | set -euo pipefail git fetch origin master dist source_sha="$(git rev-parse HEAD)" git merge-base --is-ancestor "$source_sha" origin/master package_sha="$(git rev-parse origin/dist)" published="$RUNNER_TEMP/release-dist" mkdir -p "$published" git archive "$package_sha" | tar -x -C "$published" # Ignore dist-only compatibility metadata when comparing the package. rm -rf "$published/.github" "$published/.gitattributes" # The timestamp is volatile; all other provenance fields must match. test -f "$published/.build-provenance.txt" test -f .build-provenance.txt grep -q '^converted_at: ' "$published/.build-provenance.txt" grep -q '^converted_at: ' .build-provenance.txt sed '/^converted_at: /d' "$published/.build-provenance.txt" > "$RUNNER_TEMP/dist-provenance" sed '/^converted_at: /d' .build-provenance.txt > "$RUNNER_TEMP/build-provenance" diff -u "$RUNNER_TEMP/dist-provenance" "$RUNNER_TEMP/build-provenance" rm -f "$published/.build-provenance.txt" mkdir -p "$RUNNER_TEMP/release-built" cp -a plugin.json skills config assets README.md after-install.md LICENSE .build-provenance.txt "$RUNNER_TEMP/release-built" rm -f "$RUNNER_TEMP/release-built/.build-provenance.txt" diff -qr "$RUNNER_TEMP/release-built" "$published" echo "PACKAGE_SHA=$package_sha" >> "$GITHUB_ENV" echo "SOURCE_SHA=$source_sha" >> "$GITHUB_ENV" - name: Package plugin run: | zip -r pstack-"${TAG_NAME}".zip plugin.json skills/ config/ assets/ README.md after-install.md LICENSE .build-provenance.txt sha256sum pstack-"${TAG_NAME}".zip > SHA256SUMS env: TAG_NAME: ${{ github.ref_name }} - name: Extract release notes run: | # Strip leading 'v' from tag to match CHANGELOG version format VERSION="${TAG_NAME#v}" # Extract the section for this version from CHANGELOG.md awk -v ver="[$VERSION]" ' /^## / { if (seen) exit; if (index($0, ver)) seen=1; next } seen { print } ' CHANGELOG.md > RELEASE_NOTES.md if [ ! -s RELEASE_NOTES.md ]; then echo "No CHANGELOG section found for $VERSION" >&2 echo "## $VERSION" > RELEASE_NOTES.md echo "" >> RELEASE_NOTES.md echo "See [CHANGELOG.md](CHANGELOG.md) for details." >> RELEASE_NOTES.md fi { echo "" echo "## Verified package" echo "Source commit: $SOURCE_SHA" echo "Package commit: $PACKAGE_SHA" echo '```sh' echo "hermes plugins install ${GITHUB_REPOSITORY} --ref $PACKAGE_SHA --enable" echo '```' echo "To move an existing pinned install to this release:" echo '```sh' echo "hermes plugins install ${GITHUB_REPOSITORY} --ref $PACKAGE_SHA --force --enable" echo '```' echo "Unpinned installs: hermes plugins update pstack" echo "Verify the ZIP with: sha256sum --check SHA256SUMS" } >> RELEASE_NOTES.md env: TAG_NAME: ${{ github.ref_name }} - name: Create GitHub Release env: GH_TOKEN: ${{ github.token }} TAG_NAME: ${{ github.ref_name }} run: | gh release create "$TAG_NAME" \ pstack-"$TAG_NAME".zip SHA256SUMS \ --title "pstack $TAG_NAME" \ --notes-file RELEASE_NOTES.md \ --verify-tag