Release / release (push) Successful in 6s
A plugin installed as a bare git+https URL is pinned to a commit, so with no tags there is nothing for `dsh plugin update` to move to. The workflow reads the commit subjects since the last tag, bumps package.json, prepends CHANGELOG.md, tags vX.Y.Z, and publishes the Gitea release with those subjects as the body. The decision logic lives in .gitea/scripts/release.sh so it runs and is tested without a runner (`npm run test:release`).
150 lines
6.0 KiB
YAML
150 lines
6.0 KiB
YAML
# Publish a release every time master moves.
|
|
#
|
|
# What this is for, beyond tidiness: a dsh plugin installed as a bare
|
|
# `git+https://…/repo.git` is resolved to a commit and pinned in the profile's
|
|
# lockfile. With no tags, there is nothing for `dsh plugin update` to move to —
|
|
# which is why updating appeared to do nothing and a reinstall was the only way
|
|
# through. Tags are what make an update possible; this workflow is what creates
|
|
# them.
|
|
#
|
|
# The work lives in `.gitea/scripts/release.sh` so it can be run and tested
|
|
# without a runner (`bash .gitea/scripts/release.test.sh`, or `npm run
|
|
# test:release`).
|
|
#
|
|
# The bump comes from the commit subjects in the range being released:
|
|
# `feat` is a minor, `!:` (or an explicit `[major]`) is a major, and everything
|
|
# else — `fix:`, `docs:`, prose — is a patch. `[skip release]` in a subject
|
|
# suppresses the release for that push.
|
|
|
|
name: Release
|
|
|
|
on:
|
|
push:
|
|
branches: [master]
|
|
# Manual runs, for the first release (no tags yet) or to publish a release
|
|
# whose push failed after the tag was created.
|
|
workflow_dispatch:
|
|
|
|
# One release at a time. Two pushes in quick succession would otherwise race to
|
|
# tag the same commit and one of them would lose.
|
|
concurrency:
|
|
group: release-master
|
|
cancel-in-progress: false
|
|
|
|
permissions:
|
|
# The job token is what pushes the version commit, the tag, and the release.
|
|
contents: write
|
|
|
|
jobs:
|
|
release:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
BRANCH: master
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
# Tags are the whole point, so the clone must carry them.
|
|
fetch-depth: 0
|
|
ref: master
|
|
# Gitea mints a token for every job and exposes it as
|
|
# secrets.GITEA_TOKEN; `permissions: contents: write` above is what
|
|
# lets it push. No hand-made secret is needed.
|
|
token: ${{ secrets.GITEA_TOKEN }}
|
|
|
|
- name: Decide whether this push releases
|
|
id: decide
|
|
run: |
|
|
set -euo pipefail
|
|
tag="$(bash .gitea/scripts/release.sh last-tag)"
|
|
range="$(bash .gitea/scripts/release.sh range)"
|
|
echo "range=${range}" >> "$GITHUB_OUTPUT"
|
|
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
|
|
verdict="$(bash .gitea/scripts/release.sh should-release "$range")"
|
|
echo "release=${verdict}" >> "$GITHUB_OUTPUT"
|
|
echo "last tag: ${tag:-none} range: ${range:-everything} release: ${verdict}"
|
|
|
|
- name: Work out the version and the notes
|
|
if: steps.decide.outputs.release == 'yes'
|
|
id: version
|
|
run: |
|
|
set -euo pipefail
|
|
bump="$(bash .gitea/scripts/release.sh bump "${{ steps.decide.outputs.range }}")"
|
|
version="$(bash .gitea/scripts/release.sh next-version "$bump")"
|
|
bash .gitea/scripts/release.sh notes "${{ steps.decide.outputs.range }}" > /tmp/notes.md
|
|
echo "version=${version}" >> "$GITHUB_OUTPUT"
|
|
echo "bump=${bump}" >> "$GITHUB_OUTPUT"
|
|
echo "releasing v${version} (${bump})"
|
|
cat /tmp/notes.md
|
|
|
|
- name: Bump, changelog, commit and tag
|
|
if: steps.decide.outputs.release == 'yes'
|
|
env:
|
|
VERSION: ${{ steps.version.outputs.version }}
|
|
run: |
|
|
set -euo pipefail
|
|
git config user.name "gitea-actions"
|
|
git config user.email "actions@notexpectedyet.com"
|
|
|
|
# Idempotency: a run that pushed the tag and then failed at the
|
|
# release call must not fail here on the re-run.
|
|
if git rev-parse -q --verify "refs/tags/v${VERSION}" >/dev/null; then
|
|
echo "tag v${VERSION} already exists — publishing the release for it"
|
|
exit 0
|
|
fi
|
|
|
|
bash .gitea/scripts/release.sh set-version "$VERSION"
|
|
bash .gitea/scripts/release.sh changelog-prepend "$VERSION" "$(date -u +%Y-%m-%d)" /tmp/notes.md
|
|
git add package.json CHANGELOG.md
|
|
# `[skip release]` is the guard that has to hold, because the script
|
|
# is what decides. `[skip actions]` is the cheap extra: Gitea reads it
|
|
# and can skip queueing a run for this commit at all.
|
|
git commit -m "Release v${VERSION} [skip release] [skip actions]"
|
|
git tag "v${VERSION}"
|
|
git push origin "HEAD:${BRANCH}"
|
|
git push origin "v${VERSION}"
|
|
|
|
- name: Publish the release
|
|
if: steps.decide.outputs.release == 'yes'
|
|
env:
|
|
VERSION: ${{ steps.version.outputs.version }}
|
|
SERVER: ${{ github.server_url }}
|
|
REPO: ${{ github.repository }}
|
|
TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
# The body is built by an encoder rather than by string interpolation:
|
|
# release notes are multi-line markdown and quoting them into JSON by
|
|
# hand is a reliable way to publish a malformed release.
|
|
python3 - <<'PY' > /tmp/release.json
|
|
import json, os
|
|
with open('/tmp/notes.md', encoding='utf-8') as handle:
|
|
body = handle.read()
|
|
version = os.environ['VERSION']
|
|
print(json.dumps({
|
|
'tag_name': 'v' + version,
|
|
'name': 'v' + version,
|
|
'body': body,
|
|
'draft': False,
|
|
'prerelease': False,
|
|
}))
|
|
PY
|
|
|
|
status="$(curl -sS -o /tmp/release-response.json -w '%{http_code}' \
|
|
-X POST "${SERVER}/api/v1/repos/${REPO}/releases" \
|
|
-H "Authorization: token ${TOKEN}" \
|
|
-H 'Content-Type: application/json' \
|
|
--data-binary @/tmp/release.json)"
|
|
|
|
# 409 is "a release for this tag already exists": the job has nothing
|
|
# left to do rather than something to report.
|
|
if [ "$status" = "409" ]; then
|
|
echo "v${VERSION} is already released"
|
|
exit 0
|
|
fi
|
|
if [ "$status" != "201" ] && [ "$status" != "200" ]; then
|
|
echo "release creation failed (HTTP ${status})" >&2
|
|
cat /tmp/release-response.json >&2
|
|
exit 1
|
|
fi
|
|
echo "published v${VERSION}"
|