-
Notifications
You must be signed in to change notification settings - Fork 1
132 lines (128 loc) · 5.24 KB
/
Copy pathauto-release.yml
File metadata and controls
132 lines (128 loc) · 5.24 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
# 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 pair
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_MODULE_TAG: ${{ steps.classify.outputs.module_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")"
module_tag="$(jq -r .module_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" && "$module_tag" == "$EXPECTED_MODULE_TAG" ]] || {
echo "BLOCKED: stable release tags changed during this run." >&2
exit 2
}
git config user.name "${APP_SLUG}[bot]"
git config user.email "${APP_SLUG}[bot]@users.noreply.github.com"
python3 .github/scripts/publish_release_tags.py \
--repo . \
--remote origin \
--source "$RELEASE_SOURCE" \
--root-tag "$next_tag" \
--module-tag "$module_tag"
echo "Published verified release tags $next_tag and $module_tag from $RELEASE_SOURCE."