Skip to content

Commit f7fa46e

Browse files
committed
migrate pipeline from circleci to github actions
1 parent f687011 commit f7fa46e

26 files changed

Lines changed: 374 additions & 456 deletions

.circleci/config.yml

Lines changed: 0 additions & 176 deletions
This file was deleted.

.github/workflows/main.yaml

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
name: Main
2+
on:
3+
push:
4+
branches:
5+
- main
6+
7+
permissions:
8+
contents: read
9+
10+
# Concurrency is JOB-level, on prerelease + release only (shared group), NOT
11+
# workflow-level: a run waiting on the release approval counts as the group's
12+
# in-progress occupant, so a workflow-level group would freeze ALL main CI
13+
# (check/test/prerelease of later pushes) for up to the 30-day approval
14+
# window. The approval itself lives on the slot-free release-gate job, so a
15+
# pending approval holds no slot. queue: max keeps every queued publish (the
16+
# default keeps only the newest pending) so close-together merges serialise
17+
# FIFO on tag operations instead of cancelling each other.
18+
# 'queue: max' — GA 2026-05-07: https://github.blog/changelog/2026-05-07-github-actions-concurrency-groups-now-allow-larger-queues/
19+
# Gate/slot split pattern: https://github.com/orgs/community/discussions/17401
20+
21+
jobs:
22+
skip-ci-check:
23+
runs-on: ubuntu-latest
24+
timeout-minutes: 5
25+
outputs:
26+
should_skip_ci: ${{ steps.skip_ci_check.outputs.should_skip_ci }}
27+
steps:
28+
- id: skip_ci_check
29+
env:
30+
HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
31+
run: |
32+
if [[ "$HEAD_COMMIT_MESSAGE" == *"[no ci]"* ]] \
33+
|| [[ "$HEAD_COMMIT_MESSAGE" == *"[skip ci]"* ]] \
34+
|| [[ "$HEAD_COMMIT_MESSAGE" == *"[ci skip]"* ]]; then
35+
echo "should_skip_ci=true" >> "$GITHUB_OUTPUT"
36+
else
37+
echo "should_skip_ci=false" >> "$GITHUB_OUTPUT"
38+
fi
39+
40+
check:
41+
needs: [skip-ci-check]
42+
if: needs.skip-ci-check.outputs.should_skip_ci != 'true'
43+
runs-on: ubuntu-latest
44+
timeout-minutes: 30
45+
steps:
46+
- uses: actions/checkout@v4
47+
- name: Install tools
48+
uses: infrablocks/github-actions/asdf_install@v1
49+
- name: Check
50+
run: ./go test:code:check
51+
- name: Notify Slack
52+
if: ${{ !cancelled() }}
53+
continue-on-error: true
54+
run: ./go "slack:notify[${{ job.status }}]"
55+
env:
56+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
57+
58+
test:
59+
needs: [skip-ci-check]
60+
if: needs.skip-ci-check.outputs.should_skip_ci != 'true'
61+
runs-on: ubuntu-latest
62+
timeout-minutes: 30
63+
steps:
64+
- uses: actions/checkout@v4
65+
with:
66+
fetch-depth: 0
67+
- name: Install tools
68+
uses: infrablocks/github-actions/asdf_install@v1
69+
- name: Ensure docker-compose is available
70+
# Pinned + checksum-verified: this runs as root on runners that later
71+
# hold secrets; the checksum is from the release's own .sha256 asset.
72+
run: |
73+
if ! command -v docker-compose >/dev/null 2>&1; then
74+
sudo curl -fsSL \
75+
"https://github.com/docker/compose/releases/download/v5.3.1/docker-compose-linux-x86_64" \
76+
-o /usr/local/bin/docker-compose
77+
echo "f9ebc6ebdb19d769b793c245a736caaeb198c62587f13b25c660c13b4987f959 /usr/local/bin/docker-compose" \
78+
| sha256sum -c -
79+
sudo chmod +x /usr/local/bin/docker-compose
80+
fi
81+
- name: Test
82+
run: ./go test:integration
83+
- name: Notify Slack
84+
if: ${{ !cancelled() }}
85+
continue-on-error: true
86+
run: ./go "slack:notify[${{ job.status }}]"
87+
env:
88+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
89+
90+
prerelease:
91+
needs: [check, test]
92+
runs-on: ubuntu-latest
93+
timeout-minutes: 30
94+
concurrency:
95+
group: main-tags
96+
cancel-in-progress: false
97+
queue: max
98+
permissions:
99+
contents: write
100+
steps:
101+
- uses: actions/checkout@v4
102+
with:
103+
fetch-depth: 0
104+
- name: Install tools
105+
uses: infrablocks/github-actions/asdf_install@v1
106+
- name: Install secrets tools
107+
run: sudo apt-get update && sudo apt-get install -y git-crypt gnupg
108+
- name: Unlock git-crypt
109+
run: ./go git_crypt:unlock_with_encrypted_gpg_key
110+
env:
111+
ENCRYPTION_PASSPHRASE: ${{ secrets.ENCRYPTION_PASSPHRASE }}
112+
- name: Set CI git author
113+
run: ./go repository:set_ci_author
114+
- name: Prerelease
115+
run: ./go "version:bump[rc]" && ./go image:publish
116+
- name: Notify Slack of release hold
117+
continue-on-error: true
118+
run: ./go "slack:notify[success,on_hold]"
119+
env:
120+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
121+
- name: Notify Slack
122+
if: ${{ !cancelled() }}
123+
continue-on-error: true
124+
run: ./go "slack:notify[${{ job.status }}]"
125+
env:
126+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
127+
128+
release-gate:
129+
# Approval-only job: carries the environment but NO concurrency group, so
130+
# a pending approval never occupies the main-tags slot. Multiple pushes
131+
# can await approval independently.
132+
needs: [prerelease]
133+
runs-on: ubuntu-latest
134+
timeout-minutes: 10
135+
environment: release
136+
steps:
137+
- name: Release approved
138+
run: "true"
139+
140+
release:
141+
needs: [release-gate]
142+
runs-on: ubuntu-latest
143+
timeout-minutes: 30
144+
concurrency:
145+
group: main-tags
146+
cancel-in-progress: false
147+
queue: max
148+
permissions:
149+
contents: write
150+
steps:
151+
- uses: actions/checkout@v4
152+
with:
153+
ref: main
154+
fetch-depth: 0
155+
- name: Pull latest main
156+
# Approval can land long after the run starts; release publishes main
157+
# as of approval time, not the tested SHA — parity with the old
158+
# release.sh, which also pulled. prerelease.sh never pulled, so the
159+
# prerelease job deliberately has no pull.
160+
run: git pull
161+
- name: Install tools
162+
uses: infrablocks/github-actions/asdf_install@v1
163+
- name: Install secrets tools
164+
run: sudo apt-get update && sudo apt-get install -y git-crypt gnupg
165+
- name: Unlock git-crypt
166+
run: ./go git_crypt:unlock_with_encrypted_gpg_key
167+
env:
168+
ENCRYPTION_PASSPHRASE: ${{ secrets.ENCRYPTION_PASSPHRASE }}
169+
- name: Set CI git author
170+
run: ./go repository:set_ci_author
171+
- name: Release
172+
run: ./go version:release && ./go image:publish
173+
- name: Notify Slack
174+
if: ${{ !cancelled() }}
175+
continue-on-error: true
176+
run: ./go "slack:notify[${{ job.status }}]"
177+
env:
178+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

0 commit comments

Comments
 (0)