-
Notifications
You must be signed in to change notification settings - Fork 1
130 lines (126 loc) · 5.13 KB
/
Copy pathauto-release.yml
File metadata and controls
130 lines (126 loc) · 5.13 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
# Boatstack-owned control plane.
name: Publish verified Boatstack release
on:
schedule:
- cron: "0 2 * * *"
workflow_dispatch:
permissions:
actions: read
contents: read
concurrency:
group: auto-release-boatstack
cancel-in-progress: false
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false
- name: Verify exact current main and CI
id: source
env:
GH_TOKEN: ${{ github.token }}
RELEASE_SOURCE: ${{ github.sha }}
shell: bash
run: |
[[ "$GITHUB_REF" == "refs/heads/main" ]] || {
echo "BLOCKED: stable releases must run from main, not $GITHUB_REF." >&2
exit 2
}
checked_out="$(git rev-parse HEAD)"
[[ "$checked_out" == "$RELEASE_SOURCE" ]] || {
echo "BLOCKED: checked-out source $checked_out does not match $RELEASE_SOURCE." >&2
exit 2
}
remote_main="$(git ls-remote origin refs/heads/main | awk 'NR == 1 {print $1}')"
[[ -n "$remote_main" && "$remote_main" == "$RELEASE_SOURCE" ]] || {
echo "BLOCKED: main moved from $RELEASE_SOURCE to ${remote_main:-unknown}." >&2
exit 2
}
verified_sha="$(gh run list \
--repo "$GITHUB_REPOSITORY" \
--workflow .github/workflows/ci.yml \
--branch main \
--event push \
--commit "$RELEASE_SOURCE" \
--status success \
--limit 1 \
--json headSha \
--jq '.[0].headSha // ""')"
[[ "$verified_sha" == "$RELEASE_SOURCE" ]] || {
echo "BLOCKED: exact source $RELEASE_SOURCE has no successful main push CI run." >&2
exit 2
}
echo "sha=$RELEASE_SOURCE" >> "$GITHUB_OUTPUT"
- name: Detect pending release-bearing changes
id: classify
env:
RELEASE_SOURCE: ${{ steps.source.outputs.sha }}
run: >-
python3 .github/scripts/release_candidate.py
--repo .
--source "$RELEASE_SOURCE"
--github-output "$GITHUB_OUTPUT"
- name: Report current release state
if: steps.classify.outputs.release_required != 'true'
run: echo "Boatstack has no verified unreleased changes; no release was created."
- name: Create repository automation token
if: steps.classify.outputs.release_required == 'true'
id: app-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ vars.BOATSTACK_APP_CLIENT_ID }}
private-key: ${{ secrets.BOATSTACK_APP_PRIVATE_KEY }}
owner: operatorstack
repositories: boatstack
permission-contents: write
- uses: actions/checkout@v7
if: steps.classify.outputs.release_required == 'true'
with:
ref: ${{ steps.source.outputs.sha }}
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Create next verified patch tag
if: steps.classify.outputs.release_required == 'true'
env:
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
EXPECTED_LATEST_TAG: ${{ steps.classify.outputs.latest_tag }}
EXPECTED_NEXT_TAG: ${{ steps.classify.outputs.next_tag }}
RELEASE_SOURCE: ${{ steps.source.outputs.sha }}
shell: bash
run: |
checked_out="$(git rev-parse HEAD)"
[[ "$checked_out" == "$RELEASE_SOURCE" ]] || {
echo "BLOCKED: checked-out source changed before publication." >&2
exit 2
}
remote_main="$(git ls-remote origin refs/heads/main | awk 'NR == 1 {print $1}')"
[[ -n "$remote_main" && "$remote_main" == "$RELEASE_SOURCE" ]] || {
echo "BLOCKED: main moved before publication; retry against the new head." >&2
exit 2
}
git fetch --force --tags origin
candidate="$(python3 .github/scripts/release_candidate.py --repo . --source "$RELEASE_SOURCE")"
release_required="$(jq -r .release_required <<< "$candidate")"
latest_tag="$(jq -r .latest_tag <<< "$candidate")"
next_tag="$(jq -r .next_tag <<< "$candidate")"
[[ "$release_required" == true ]] || {
echo "BLOCKED: no unreleased change remains after refreshing tags." >&2
exit 2
}
[[ "$latest_tag" == "$EXPECTED_LATEST_TAG" && "$next_tag" == "$EXPECTED_NEXT_TAG" ]] || {
echo "BLOCKED: stable release tags changed during this run." >&2
exit 2
}
if git ls-remote --exit-code --tags origin "refs/tags/$next_tag" >/dev/null 2>&1; then
echo "BLOCKED: tag already exists: $next_tag" >&2
exit 2
fi
git config user.name "${APP_SLUG}[bot]"
git config user.email "${APP_SLUG}[bot]@users.noreply.github.com"
git tag -a "$next_tag" -m "Boatstack $next_tag" "$RELEASE_SOURCE"
git push origin "refs/tags/$next_tag"
echo "Published verified release tag $next_tag from $RELEASE_SOURCE."