-
Notifications
You must be signed in to change notification settings - Fork 3
200 lines (179 loc) · 6.31 KB
/
release-github.yml
File metadata and controls
200 lines (179 loc) · 6.31 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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
name: Create GitHub Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to release (e.g. v0.3.0). Required for manual runs.'
required: true
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
wait-for-publishes:
name: Wait for SDK publishes
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
actions: read
steps:
- name: Wait for all SDK release workflows
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
WORKFLOWS=("release-go.yml" "release-typescript.yml" "release-ruby.yml" "release-swift.yml" "release-kotlin.yml" "release-python.yml")
TAG="${GITHUB_REF#refs/tags/}"
MAX_WAIT=1800 # 30 minutes
POLL=30
ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
ALL_DONE=true
ANY_FAILED=false
STATUS_LINE=""
for WF in "${WORKFLOWS[@]}"; do
# Fetch recent runs and find the one matching this tag push
RUN_JSON=$(gh run list \
--repo "$GITHUB_REPOSITORY" \
--workflow "$WF" \
--branch "$TAG" \
--limit 5 \
--json conclusion,headSha \
--jq "[.[] | select(.headSha == \"$GITHUB_SHA\")] | .[0] // empty")
if [ -z "$RUN_JSON" ]; then
ALL_DONE=false
STATUS_LINE+=" ⏳ $WF: waiting for current run"$'\n'
continue
fi
CONCLUSION=$(echo "$RUN_JSON" | jq -r '.conclusion // empty')
if [ -z "$CONCLUSION" ]; then
ALL_DONE=false
STATUS_LINE+=" ⏳ $WF: in progress"$'\n'
elif [ "$CONCLUSION" = "success" ]; then
STATUS_LINE+=" ✅ $WF: success"$'\n'
else
ANY_FAILED=true
STATUS_LINE+=" ❌ $WF: $CONCLUSION"$'\n'
fi
done
echo "$STATUS_LINE"
if $ANY_FAILED; then
echo "::error::One or more SDK release workflows failed"
exit 1
fi
if $ALL_DONE; then
echo "All SDK release workflows completed successfully"
exit 0
fi
echo "Waiting ${POLL}s for remaining workflows... (${ELAPSED}s elapsed)"
sleep $POLL
ELAPSED=$((ELAPSED + POLL))
done
echo "::error::Timed out waiting for SDK release workflows after ${MAX_WAIT}s"
echo "Final status:"
echo "$STATUS_LINE"
exit 1
release:
name: Create Release
needs: [wait-for-publishes]
if: always() && (needs.wait-for-publishes.result == 'success' || needs.wait-for-publishes.result == 'skipped')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Resolve tag
id: tag
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_TAG: ${{ github.event.inputs.tag }}
run: |
if [ "$EVENT_NAME" = "push" ]; then
TAG="${GITHUB_REF#refs/tags/}"
else
TAG="$INPUT_TAG"
if [ -z "$TAG" ]; then
echo "::error::tag input is required for manual runs"
exit 1
fi
if [[ "$TAG" != v* ]]; then
echo "::error::tag must start with 'v' (e.g. v0.3.0), got: $TAG"
exit 1
fi
fi
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "Resolved tag: $TAG"
- name: Verify tag is on main
env:
TAG: ${{ steps.tag.outputs.tag }}
run: |
git fetch origin main
TAG_SHA=$(git rev-parse "refs/tags/${TAG}^{commit}" 2>/dev/null || git rev-parse "refs/tags/${TAG}^{}" 2>/dev/null)
git merge-base --is-ancestor "$TAG_SHA" origin/main
- name: Extract version
id: version
env:
VERSION: ${{ steps.tag.outputs.tag }}
run: |
SEMVER="${VERSION#v}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "semver=$SEMVER" >> $GITHUB_OUTPUT
- name: Checkout tag
if: github.event_name == 'workflow_dispatch'
env:
TAG: ${{ steps.tag.outputs.tag }}
run: git checkout "refs/tags/$TAG"
- name: Build installation body
env:
VERSION: ${{ steps.version.outputs.version }}
SEMVER: ${{ steps.version.outputs.semver }}
run: |
{
echo "## Installation"
echo ""
echo "**Go**"
echo '```'
echo "go get github.com/basecamp/basecamp-sdk/go@${VERSION}"
echo '```'
echo ""
echo "**TypeScript**"
echo '```'
echo "npm install @37signals/basecamp@${SEMVER}"
echo '```'
echo ""
echo "**Ruby**"
echo '```'
echo "gem install basecamp-sdk -v ${SEMVER}"
echo '```'
echo ""
echo "**Swift**"
echo '```swift'
echo ".package(url: \"https://github.com/basecamp/basecamp-sdk.git\", from: \"${SEMVER}\")"
echo '```'
echo ""
echo "**Kotlin**"
echo '```kotlin'
echo "implementation(\"com.basecamp:basecamp-sdk:${SEMVER}\")"
echo '```'
echo ""
echo "**Python**"
echo '```'
echo "pip install basecamp-sdk==${SEMVER}"
echo '```'
} > body.md
- name: Create GitHub Release
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 # zizmor: ignore[superfluous-actions] -- consider removal
with:
tag_name: ${{ steps.tag.outputs.tag }}
name: Basecamp SDK ${{ steps.version.outputs.version }}
body_path: body.md
generate_release_notes: true
draft: ${{ github.event_name == 'workflow_dispatch' }}
prerelease: ${{ contains(steps.version.outputs.version, '-') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}