1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
name: Release
# Publishes a release with the staged artefacts whenever a tag v* is pushed —
# what ./01-release.tag.sh does at its last line. They are staged by
# ./02-build-releases.sh, the same script one runs on a laptop, so a local
# staging and a published one are the same pipeline.
#
# turbo-core is a library, so the tag alone already publishes the module: the
# proxy serves `go get …@TAG` the moment 01 has run, with or without this
# workflow. What this adds is the page a person reads, and an archive of the
# tagged source with a checksum to verify it against.
#
# Rickub runs this as an ordinary GitHub Actions workflow. Two platform facts
# matter here: the job's GITHUB_TOKEN is the ONLY credential the release API
# (the /gh shim behind $GITHUB_API_URL) accepts — a personal token is refused —
# and it is read-only unless the workflow asks for `contents: write` below.
# That is why there is no longer a token file to keep out of git.
#
# No workflow_dispatch on purpose: Rickub's dispatch API fires EVERY
# dispatchable workflow of a ref, so a repository should declare at most one.
on:
push:
tags:
- "v*"
permissions:
contents: write
concurrency:
group: release-${{ github.ref_name }}
cancel-in-progress: false
jobs:
release:
name: publish ${{ github.ref_name }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# The whole history and the tags: the release notes below are read
# from the annotated tag's message, and ./02-build-releases.sh takes
# its archive from the commit the tag is on.
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: go test
# The suite includes tests that run ./01-release.tag.sh against a
# throwaway clone. They skip themselves when they see this, exactly as
# they do when the script itself calls make check — without it, a
# release job would start a release inside itself.
env:
TURBO_CORE_RELEASING: "1"
run: go test ./... -count=1
- name: Stage the release
# release.env is git-ignored, so the tag is passed explicitly and the
# script falls back to "Turbo Core <tag>" for the description.
run: bash ./02-build-releases.sh "${GITHUB_REF_NAME}"
- name: Release notes
id: notes
# The message ./01-release.tag.sh put on the annotated tag (ABOUT in
# release.env), then the one line that installs the module and the
# links to the documentation AT THAT TAG — a release page is not inside
# the repository tree, so a relative path from it 404s, and a link to
# the branch would rot as the branch moves. A lightweight tag has no
# message: the tag name stands in.
run: |
set -euo pipefail
message="$(git for-each-ref "refs/tags/${GITHUB_REF_NAME}" --format='%(contents)' | sed '/^-----BEGIN PGP SIGNATURE-----/,$d')"
if [ -z "$(printf '%s' "${message}" | tr -d '[:space:]')" ]; then
message="Turbo Core ${GITHUB_REF_NAME}"
fi
tree="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/blob/${GITHUB_REF_NAME}"
{
printf '%s\n\n' "${message}"
echo '```bash'
echo "go get $(go list -m)@${GITHUB_REF_NAME}"
echo '```'
echo
echo "Documentation: [English](${tree}/docs/en/README.md) · [Français](${tree}/docs/fr/README.md)"
echo
echo "- Commit: \`${GITHUB_SHA}\`"
echo "- Published by the Release workflow, run #${GITHUB_RUN_NUMBER}, with $(go env GOVERSION)"
echo
echo '## Checksums'
echo
echo 'The archive below is the tagged source. `go get` does not download it — the module proxy serves the module straight from the tag — so it is here to verify against, and for anyone who cannot reach the proxy.'
echo
echo '```'
cat "release/${GITHUB_REF_NAME}/SHA256SUMS"
echo '```'
} > "${RUNNER_TEMP}/notes.md"
echo "path=${RUNNER_TEMP}/notes.md" >> "$GITHUB_OUTPUT"
- name: Keep the artefacts as a run artifact
# Downloadable from the run page even if the publish step below fails
# (an old CI node that does not forward /gh answers 403 there).
uses: actions/upload-artifact@v4
with:
name: turbo-core-${{ github.ref_name }}
path: release/${{ github.ref_name }}/
if-no-files-found: error
retention-days: 14
- name: Publish the release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
body_path: ${{ steps.notes.outputs.path }}
draft: false
prerelease: ${{ contains(github.ref_name, '-') }}
files: |
release/${{ github.ref_name }}/turbo-core-*.tar.gz
release/${{ github.ref_name }}/SHA256SUMS
release/${{ github.ref_name }}/README.md
fail_on_unmatched_files: true
|