-
Notifications
You must be signed in to change notification settings - Fork 0
110 lines (101 loc) · 4.7 KB
/
Copy pathstlc_promote.yaml
File metadata and controls
110 lines (101 loc) · 4.7 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
name: Promote SDK to production
# Fast-forwards production `main` up to the staging trunk, preserving commit
# SHAs, so the two trunks stay identical and linear and the sealed custom-code
# commit stays an ancestor of both.
#
# Runs nightly (00:15 UTC, matching the retired Stainless cloud's release
# cadence) plus manual dispatch for ship-it-now moments. Both are idempotent:
# no-op when production already has staging's content, hard refusal if the
# trunks have somehow forked.
#
# This file is sealed into every two-repo staging SDK repo as custom code and
# reaches the production repo via the promote itself; the `if` guards route so
# only the staging copy runs. Source of truth: dev-docs stainless/sdk-workflows/.
on:
schedule:
- cron: '15 0 * * *'
workflow_dispatch: {}
permissions:
contents: read
concurrency:
group: stlc-promote
cancel-in-progress: false
jobs:
promote:
runs-on: runs-on=${{ github.run_id }}/image=ubuntu24-full-x64/runner=2cpu-linux-x64/spot=false/tag=sdk-promote
# Staging repos only; csharp is generate-only while its generator bugs are
# open with Stainless.
if: >-
endsWith(github.repository, '-staging') &&
github.repository != 'orbcorp/orb-csharp-staging'
steps:
- name: Derive repo names
id: repos
run: |
short="${GITHUB_REPOSITORY#*/}"
echo "staging=$short" >> "$GITHUB_OUTPUT"
echo "production=${short%-staging}" >> "$GITHUB_OUTPUT"
- name: Mint app token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.STLC_APP_ID }}
private-key: ${{ secrets.STLC_APP_PRIVATE_KEY }}
owner: orbcorp
repositories: ${{ steps.repos.outputs.staging }},${{ steps.repos.outputs.production }}
- name: Check out staging
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Fetch production main
id: fetch
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PRODUCTION_REPO: orbcorp/${{ steps.repos.outputs.production }}
run: |
git remote add production \
"https://x-access-token:${GH_TOKEN}@github.com/${PRODUCTION_REPO}.git"
# A brand-new production repo has no main yet (first promote for a
# new SDK): skip the diff and let the promote push bootstrap it. A
# transient ls-remote failure lands here too, and then the plain
# (non-force) push below surfaces the real error.
if git ls-remote --exit-code production refs/heads/main >/dev/null 2>&1; then
git fetch production main
echo "has_main=true" >> "$GITHUB_OUTPUT"
else
echo "Production main does not exist yet; will bootstrap it from staging."
echo "has_main=false" >> "$GITHUB_OUTPUT"
fi
- name: Check whether production already has staging's content
id: diff
if: steps.fetch.outputs.has_main == 'true'
run: |
# After a release, production carries release-please's version and
# changelog commits that staging lacks. Ask whether merging staging
# into production would change production's tree: if not, production
# already has staging's content.
MERGED=$(git merge-tree --write-tree production/main origin/main) || MERGED=conflict
PRODUCTION_TREE=$(git rev-parse 'production/main^{tree}')
if [ "$MERGED" = "$PRODUCTION_TREE" ]; then
echo "Production already contains staging's content. Nothing to promote."
echo "synced=true" >> "$GITHUB_OUTPUT"
else
echo "synced=false" >> "$GITHUB_OUTPUT"
fi
- name: Promote staging to production (fast-forward)
if: steps.fetch.outputs.has_main == 'false' || steps.diff.outputs.synced == 'false'
run: |
# Refuse unless production/main is an ancestor of staging/main. If it
# is not, the trunks have forked (someone advanced production out of
# band without back-syncing first) and a fast-forward is unsafe.
# When production main doesn't exist yet there is nothing to compare
# — the plain push below can only create, never rewrite.
if git rev-parse -q --verify production/main >/dev/null; then
if ! git merge-base --is-ancestor production/main origin/main; then
echo "::error title=Promote blocked::production/main is not an ancestor of staging main. Back-sync production into staging first."
exit 1
fi
fi
git push production origin/main:refs/heads/main
echo "Fast-forwarded production/main to staging/main."