-
Notifications
You must be signed in to change notification settings - Fork 0
141 lines (127 loc) · 5.64 KB
/
Copy pathrelease-on-upstream.yml
File metadata and controls
141 lines (127 loc) · 5.64 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
name: release-on-upstream
# Cut this SDK's next release when busbar core ships. Refresh openapi.json from the new core
# release, regenerate the client, and IF the generated client changed, bump + tag v* — release.yml
# then publishes to npm via OIDC trusted publishing (no stored token). If regen is a no-op, no tag.
#
# RUNAWAY-SAFE: no plain `push:` trigger, so merging this file cannot cut a release.
# - repository_dispatch [upstream-release]: acts on the dispatched core tag (client_payload).
# - schedule: reads GetBusbar/busbar's latest release and acts ONLY if its spec version is newer
# than the committed openapi.json — an idle day is a no-op, so cron can never runaway-publish.
# - workflow_dispatch: always acts (a human explicitly asked).
# The final publish gate is a real git diff of the generated client: an identical regen never tags.
on:
repository_dispatch:
types: [upstream-release]
schedule:
- cron: "29 5 * * *" # daily; minute staggered across the fleet so crons don't all fire at once
workflow_dispatch:
inputs:
tag:
description: "busbar core tag to build against (e.g. v1.6.0). Blank = core's latest release."
required: false
type: string
permissions:
contents: write
concurrency:
group: release-on-upstream-${{ github.repository }}
cancel-in-progress: false
jobs:
cut:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
persist-credentials: true
token: ${{ secrets.RELEASE_DISPATCH_TOKEN }}
- name: Configure git identity
run: |
git config user.name "busbar-bot"
git config user.email "bot@getbusbar.com"
- uses: actions/setup-node@v4
with:
node-version: "24"
- name: Resolve target core release
id: resolve
env:
GH_TOKEN: ${{ secrets.RELEASE_DISPATCH_TOKEN }}
EVENT_NAME: ${{ github.event_name }}
DISPATCH_TAG: ${{ github.event.client_payload.tag }}
INPUT_TAG: ${{ github.event.inputs.tag }}
run: |
set -euo pipefail
committed="$(jq -r '.info.version' openapi.json)"
echo "committed spec version: $committed"
tag=""
case "$EVENT_NAME" in
repository_dispatch) tag="${DISPATCH_TAG:-}" ;;
workflow_dispatch) tag="${INPUT_TAG:-}" ;;
esac
if [ -z "$tag" ]; then
tag="$(gh api repos/GetBusbar/busbar/releases/latest --jq .tag_name 2>/dev/null || true)"
fi
if [ -z "$tag" ]; then
echo "::notice::could not resolve a core release tag -> nothing to do"
echo "proceed=no" >> "$GITHUB_OUTPUT"; exit 0
fi
ver="${tag#v}"
echo "target core tag: $tag (spec version $ver)"
proceed=no
if [ "$EVENT_NAME" = workflow_dispatch ]; then
proceed=yes
elif [ "$(printf '%s\n%s\n' "$committed" "$ver" | sort -V | tail -1)" = "$ver" ] && [ "$ver" != "$committed" ]; then
proceed=yes
else
echo "::notice::core spec v$ver not newer than committed v$committed -> nothing to do"
fi
{
echo "proceed=$proceed"
echo "tag=$tag"
echo "ver=$ver"
} >> "$GITHUB_OUTPUT"
- name: Refresh spec, regenerate, and cut a release if the client changed
if: steps.resolve.outputs.proceed == 'yes'
env:
GH_TOKEN: ${{ secrets.RELEASE_DISPATCH_TOKEN }}
CORE_TAG: ${{ steps.resolve.outputs.tag }}
CORE_VER: ${{ steps.resolve.outputs.ver }}
run: |
set -euo pipefail
ops() { jq -r '[.paths[] | (.get,.put,.post,.delete,.patch,.options,.head) | .operationId?] | map(select(. != null)) | sort | @json' "$1"; }
ops_old="$(ops openapi.json)"
gh release download "$CORE_TAG" --repo GetBusbar/busbar \
--pattern "busbar-openapi-v${CORE_VER}.json" --output openapi.json.new
mv openapi.json.new openapi.json
ops_new="$(ops openapi.json)"
npm ci
npm run generate
if git diff --quiet -- src; then
if git diff --quiet -- openapi.json; then
echo "::notice::spec + client identical -> idempotent no-op"
else
git add openapi.json
git commit -m "spec: refresh openapi.json to busbar ${CORE_TAG} (generated client unchanged)"
git push origin HEAD:main
echo "::notice::spec refreshed to ${CORE_TAG}; client unchanged, no release cut"
fi
exit 0
fi
latest="$(git tag -l 'v*' --sort=-v:refname | head -1)"
base="${latest#v}"; IFS=. read -r MA MI PA <<< "$base"
if [ "$ops_old" != "$ops_new" ]; then
next="v${MA}.$((MI + 1)).0"; echo "::notice::operationId surface changed -> minor bump"
else
next="v${MA}.${MI}.$((PA + 1))"; echo "::notice::client changed, surface stable -> patch bump"
fi
nver="${next#v}"
if git rev-parse -q --verify "refs/tags/${next}" >/dev/null; then
echo "::notice::${next} already exists -> idempotent no-op"; exit 0
fi
npm version "$nver" --no-git-tag-version --allow-same-version >/dev/null
git add openapi.json src package.json package-lock.json
git commit -m "release: ${next} — regenerate against busbar ${CORE_TAG} spec"
git push origin HEAD:main
git tag "$next"
git push origin "refs/tags/${next}"
echo "::notice::pushed ${next} — release.yml will publish to npm (OIDC)"