Repository navigation
160 lines (155 loc) · 8.32 KB
/
Copy pathrelease.yml
File metadata and controls
160 lines (155 loc) · 8.32 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
name: Release
on:
push:
tags: ['v[0-9]*']
permissions:
contents: read
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: read
actions: read
outputs:
commit: ${{ steps.source.outputs.commit }}
tag_object: ${{ steps.source.outputs.tag_object }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: 1.27.3
cache: true
- name: Verify tagged source and successful main checks
id: source
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
set -euo pipefail
[[ "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]
COMMIT=$(git rev-parse HEAD)
test "$(git rev-parse "$GITHUB_REF^{commit}")" = "$COMMIT"
git merge-base --is-ancestor "$COMMIT" origin/main
test -f "docs/releases/$GITHUB_REF_NAME.md"
gh api "repos/$GH_REPO/actions/runs?head_sha=$COMMIT&branch=main&event=push&per_page=100" > "$RUNNER_TEMP/main-checks.json"
RELEASE_COMMIT="$COMMIT" python3 - <<'PY'
import json, os
from pathlib import Path
runs = json.loads((Path(os.environ['RUNNER_TEMP']) / 'main-checks.json').read_text())['workflow_runs']
required = {'.github/workflows/ci.yml', '.github/workflows/codeql.yml', '.github/workflows/netem.yml'}
for path in sorted(required):
matching = [r for r in runs if r['path'] == path and r['head_sha'] == os.environ['RELEASE_COMMIT']
and r['head_branch'] == 'main' and r['event'] == 'push']
if not matching:
raise SystemExit(f'missing same-commit main checks: {path}')
latest = max(matching, key=lambda r: r['id'])
if latest['status'] != 'completed' or latest['conclusion'] != 'success':
raise SystemExit(f'main checks not successful: {path}')
print(f"verified {path}: {latest['html_url']}")
PY
printf 'commit=%s\n' "$COMMIT" >> "$GITHUB_OUTPUT"
printf 'tag_object=%s\n' "$(git rev-parse "$GITHUB_REF")" >> "$GITHUB_OUTPUT"
printf 'RELEASE_COMMIT=%s\n' "$COMMIT" >> "$GITHUB_ENV"
printf 'RELEASE_BUILD_DATE=%s\n' "$(date -u -d "@$(git show -s --format=%ct HEAD)" +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV"
- name: Validate quality and build exact release archives
run: make release VERSION="$GITHUB_REF_NAME" BUILD_DATE="$RELEASE_BUILD_DATE"
- name: Test exact Linux archive, native upgrade and rollback
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/autocar-previous" "$RUNNER_TEMP/autocar-current" release-bundle/assets
gh release download v1.0.0 --pattern autocar-linux-amd64.tar.gz --dir "$RUNNER_TEMP/autocar-previous"
printf '%s %s\n' '25c48d150b6eb1a06814959b068c30cda65e6fa7685025ef787559c269356495' "$RUNNER_TEMP/autocar-previous/autocar-linux-amd64.tar.gz" | sha256sum -c -
tar -xzf "$RUNNER_TEMP/autocar-previous/autocar-linux-amd64.tar.gz" -C "$RUNNER_TEMP/autocar-previous" autocar
tar -xzf dist/autocar-linux-amd64.tar.gz -C "$RUNNER_TEMP/autocar-current" autocar
python3 scripts/release-smoke.py --current "$RUNNER_TEMP/autocar-current/autocar" \
--previous "$RUNNER_TEMP/autocar-previous/autocar" --version "$GITHUB_REF_NAME" \
--commit "$RELEASE_COMMIT" --build-date "$RELEASE_BUILD_DATE" > release-bundle/smoke.json
cp dist/autocar-linux-amd64.tar.gz dist/autocar-linux-arm64.tar.gz \
dist/autocar-darwin-arm64.tar.gz dist/autocar-windows-amd64.zip release-bundle/assets/
(cd release-bundle/assets && sha256sum autocar-darwin-arm64.tar.gz autocar-linux-amd64.tar.gz \
autocar-linux-arm64.tar.gz autocar-windows-amd64.zip > SHA256SUMS)
cp "docs/releases/$GITHUB_REF_NAME.md" release-bundle/notes.md
printf '\n发布提交:`%s`\n' "$RELEASE_COMMIT" >> release-bundle/notes.md
- name: Preserve verified bundle for publishing
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: release-bundle
path: release-bundle/
if-no-files-found: error
retention-days: 30
publish:
needs: build
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: write
actions: read
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: release-bundle
path: release-bundle
- name: Upload, download-verify, then publish
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RELEASE_COMMIT: ${{ needs.build.outputs.commit }}
RELEASE_TAG_OBJECT: ${{ needs.build.outputs.tag_object }}
run: |
set -euo pipefail
[[ "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]
test "$(gh api "repos/$GH_REPO/git/ref/tags/$GITHUB_REF_NAME" --jq '.object.sha')" = "$RELEASE_TAG_OBJECT"
(cd release-bundle/assets && sha256sum -c SHA256SUMS)
python3 - <<'PY'
import json, os
from pathlib import Path
result = json.loads(Path('release-bundle/smoke.json').read_text())
if result.get('status') != 'pass' or result.get('commit') != os.environ['RELEASE_COMMIT'] or result.get('version') != os.environ['GITHUB_REF_NAME'] or result.get('check_count') != 38:
raise SystemExit('release acceptance receipt does not match tag')
expected = {'autocar-darwin-arm64.tar.gz', 'autocar-linux-amd64.tar.gz', 'autocar-linux-arm64.tar.gz', 'autocar-windows-amd64.zip', 'SHA256SUMS'}
if {p.name for p in Path('release-bundle/assets').iterdir()} != expected:
raise SystemExit('unexpected release assets')
PY
if gh release view "$GITHUB_REF_NAME" --json isDraft,targetCommitish > "$RUNNER_TEMP/existing-release.json" 2> "$RUNNER_TEMP/release-query.err"; then
python3 - <<'PY'
import json, os
from pathlib import Path
r = json.loads((Path(os.environ['RUNNER_TEMP']) / 'existing-release.json').read_text())
if r.get('isDraft') is not True or r.get('targetCommitish') != os.environ['RELEASE_COMMIT']:
raise SystemExit('refusing to overwrite an existing published or unrelated release')
PY
else
# Creation fails closed on network/auth errors or an existing release;
# --verify-tag never invents a new tag or changes the tagged source.
gh release create "$GITHUB_REF_NAME" --draft --verify-tag --target "$RELEASE_COMMIT" \
--title "AutoCAR $GITHUB_REF_NAME" --notes-file release-bundle/notes.md
fi
gh release edit "$GITHUB_REF_NAME" --draft=true --title "AutoCAR $GITHUB_REF_NAME" \
--notes-file release-bundle/notes.md --verify-tag
gh release upload "$GITHUB_REF_NAME" release-bundle/assets/* --clobber
mkdir -p "$RUNNER_TEMP/autocar-release-readback"
gh release download "$GITHUB_REF_NAME" --dir "$RUNNER_TEMP/autocar-release-readback"
python3 - <<'PY'
import os
from pathlib import Path
local = {p.name for p in Path('release-bundle/assets').iterdir()}
remote = {p.name for p in (Path(os.environ['RUNNER_TEMP']) / 'autocar-release-readback').iterdir()}
if local != remote:
raise SystemExit('refusing to publish unexpected draft assets')
PY
for asset in release-bundle/assets/*; do
cmp "$asset" "$RUNNER_TEMP/autocar-release-readback/${asset##*/}"
done
(cd "$RUNNER_TEMP/autocar-release-readback" && sha256sum -c SHA256SUMS)
test "$(gh api "repos/$GH_REPO/git/ref/tags/$GITHUB_REF_NAME" --jq '.object.sha')" = "$RELEASE_TAG_OBJECT"
gh release edit "$GITHUB_REF_NAME" --draft=false --latest --verify-tag