Repository navigation
169 lines (153 loc) · 6.09 KB
/
Copy pathrelease.yml
File metadata and controls
169 lines (153 loc) · 6.09 KB
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
name: Release
# Tag-triggered, and the only way a release is published. This repository receives
# squashed release snapshots of an internal tree that has already been tested and
# released there, so a tag here means "this is ready" -- run the suite once more, build
# the image, and cut the GitHub Release from CHANGELOG.md, with no manual step.
#
# The tag must agree with VERSION; a mismatch fails before anything is published.
on:
push:
tags: ["v*"]
permissions:
contents: write # create the GitHub Release
packages: write # push to ghcr.io
# Never publish two releases at once -- they would race for the :MAJOR / :MINOR / :latest
# tags and the last writer would win regardless of version order.
concurrency:
group: release
cancel-in-progress: false
jobs:
# Run the very same suite the push workflow runs, rather than a copy that can drift.
test:
uses: ./.github/workflows/test.yml
# A called workflow gets no secrets unless they are passed; test.yml logs in to Docker Hub.
secrets: inherit
release:
needs: test
runs-on: ubuntu-24.04
timeout-minutes: 60
# The `secrets` context is NOT available in a step-level `if`, so the Docker Hub
# credentials are surfaced as env here -- `env` is available there -- and the login
# step keys off these rather than off secrets directly.
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
# The image build runs `rails db:schema:load` and connects to redis, so the build
# needs both reachable. They are published on localhost and the build runs with
# host networking, which is what the Dockerfile's ARG defaults already point at.
services:
postgres:
image: postgres:18-alpine
env:
POSTGRES_USER: cstacks
POSTGRES_PASSWORD: cstacks
POSTGRES_DB: cstacks
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
steps:
- name: Checkout repository
uses: actions/checkout@v5
# VERSION is what the running app reports and what `rake version:check` compares
# against CHANGELOG.md. If the tag disagrees, the release would be labelled one
# thing and behave as another -- stop before anything is pushed.
- name: Check the tag matches VERSION
id: v
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
version="$(tr -d '[:space:]' < VERSION)"
if [ "${tag#v}" != "$version" ]; then
echo "::error::tag ${tag} does not match VERSION (${version})"
exit 1
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
# A prerelease (v9.8.0-rc1) must not move :latest, :MAJOR or :MINOR -- those
# point at the newest STABLE release.
if [[ "$tag" == *-* ]]; then
echo "prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "prerelease=false" >> "$GITHUB_OUTPUT"
fi
- name: Extract release notes from CHANGELOG.md
run: ./script/changelog-extract.sh "${GITHUB_REF_NAME}" | tee /tmp/notes.md
- name: Set up Docker buildx
uses: docker/setup-buildx-action@v4
with:
buildkitd-flags: "--allow-insecure-entitlement network.host"
driver-opts: network=host
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Docker Hub is optional: if the credentials are not configured the release still
# publishes to ghcr.io rather than failing. Set DOCKERHUB_USERNAME +
# DOCKERHUB_TOKEN in repository secrets to enable it.
- name: Log in to Docker Hub
id: dockerhub
if: ${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }}
uses: docker/login-action@v4
with:
username: ${{ env.DOCKERHUB_USERNAME }}
password: ${{ env.DOCKERHUB_TOKEN }}
- name: Work out the image tags
id: tags
env:
VERSION: ${{ steps.v.outputs.version }}
PRERELEASE: ${{ steps.v.outputs.prerelease }}
DOCKERHUB: ${{ steps.dockerhub.outcome == 'success' }}
run: |
set -euo pipefail
major="${VERSION%%.*}"
minor="${VERSION%.*}"
registries="ghcr.io/computestacks/controller"
# A bare `[ ... ] && x=y` would abort the whole step under `set -e` whenever
# the test is false, which is the normal case when Docker Hub is unconfigured.
if [ "$DOCKERHUB" = "true" ]; then
registries="$registries cmptstks/controller"
fi
tags=""
for r in $registries; do
tags="${tags}${r}:${VERSION}"$'\n'
if [ "$PRERELEASE" != "true" ]; then
tags="${tags}${r}:${minor}"$'\n'
tags="${tags}${r}:${major}"$'\n'
tags="${tags}${r}:latest"$'\n'
fi
done
{ echo "tags<<EOF"; printf '%s' "$tags"; echo "EOF"; } >> "$GITHUB_OUTPUT"
printf 'publishing:\n%s' "$tags"
- name: Build and push the image
uses: docker/build-push-action@v7
with:
context: .
push: true
allow: network.host
network: host
tags: ${{ steps.tags.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Create the GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${GITHUB_REF_NAME}" \
--repo "${{ github.repository }}" \
--title "${GITHUB_REF_NAME}" \
--notes-file /tmp/notes.md \
${{ steps.v.outputs.prerelease == 'true' && '--prerelease' || '' }}