Repository navigation
151 lines (143 loc) · 6.34 KB
/
Copy pathsentry-deploy.yml
File metadata and controls
151 lines (143 loc) · 6.34 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
name: Sentry Deploy
# Additive only: after a green CI run on main, attach a production *deploy*
# record for the botfleet Sentry project using the full git SHA. Vercel hosts
# apps/site (and related web surfaces); org Vercel integration 494377 does not
# currently mark production deploys. Does NOT call `releases new`.
#
# The deploy record also carries a "seat:<seat> pr:#<number>" tag in its
# --name field, so the Sentry deploy UI shows which PR shipped this deploy
# and the prefix of the branch it came from. That prefix is often a fleet
# seat (claude/, grok/, minimax/, ...) but not always -- some BotFleet
# branches use a bot-persona or fix-type prefix instead (instinct/, fixer/,
# fix/, ...), so read it as "branch prefix," not a guaranteed seat name.
# Derived by looking up the PR that produced the merge commit (this workflow
# runs on `workflow_run` after CI on `main`, so
# `github.event.workflow_run.head_branch` is just "main" -- the originating
# branch has to be recovered via the GitHub API). Pattern and rationale:
# Simple-With-Us/Usage-Monitor docs/rollouts/2026-09-24-deploy-seat-tagging.md
# (also implemented there in .github/workflows/sentry-deploy.yml, PR #1536).
#
# Soft-fail: sentry-cli errors warn and exit 0 so this never blocks merges.
# The seat/PR lookup is best-effort too -- a lookup failure just omits the
# --name tag, it never fails the build.
#
# SENTRY_AUTH_TOKEN comes from Infisical prod through the shared composite
# action (.github/actions/infisical-secrets), with the synced GitHub secret
# as a fallback during the cutover.
on:
workflow_run:
workflows:
- CI
types: [completed]
permissions:
contents: read
pull-requests: read
concurrency:
group: sentry-deploy-${{ github.event.workflow_run.head_sha }}
cancel-in-progress: false
jobs:
record-production-deploy:
if: >
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.event == 'push'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
# Deliberately no `ref:` override -- actions/checkout defaults
# workflow_run events to the repo's default branch (main), not the
# head ref of the triggering run, so this always runs the trusted,
# merged copy of the composite action and its script.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Derive deploying seat and PR number
id: pr-info
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SHA: ${{ github.event.workflow_run.head_sha }}
run: |
set +e
PR_JSON="$(gh api "repos/${{ github.repository }}/commits/${SHA}/pulls" --jq '.[0] // empty' 2>/dev/null)"
if [ -z "$PR_JSON" ]; then
echo "::notice::No merged PR found for ${SHA} (e.g. a direct push to main); skipping seat/PR deploy tag"
{
echo "pr_number="
echo "seat="
} >> "$GITHUB_OUTPUT"
exit 0
fi
PR_NUMBER="$(echo "$PR_JSON" | jq -r '.number // empty')"
HEAD_REF="$(echo "$PR_JSON" | jq -r '.head.ref // empty')"
if [ -z "$PR_NUMBER" ]; then
echo "::notice::PR lookup for ${SHA} returned no PR number; skipping seat/PR deploy tag"
{
echo "pr_number="
echo "seat="
} >> "$GITHUB_OUTPUT"
exit 0
fi
# Fleet convention: branch prefixes are lowercase "<seat>/<slug>"
# (Slack/board tags are ALL CAPS, e.g. [CLAUDE] -- that casing is
# not used here, since this value comes straight off the branch).
SEAT="unknown"
case "$HEAD_REF" in
*/*) SEAT="${HEAD_REF%%/*}" ;;
esac
# Sentry's deploy `name` field caps at 64 chars (DeploySerializer
# max_length=64); SEAT is an unbounded branch prefix, so cap it well
# short of that to guarantee "seat:<seat> pr:#<number>" always fits
# and never turns a working untagged deploy record into a 400.
SEAT="${SEAT:0:24}"
echo "Deploying PR #${PR_NUMBER} from branch '${HEAD_REF}' (seat=${SEAT})"
{
echo "pr_number=${PR_NUMBER}"
echo "seat=${SEAT}"
} >> "$GITHUB_OUTPUT"
exit 0
# SENTRY_AUTH_TOKEN is a non-identity name behind Infisical, with the
# synced GitHub secret as a GH_FALLBACK_ during the cutover. Not
# `required` -- this workflow is soft-fail by design (see header).
- name: Load the Sentry auth token
uses: ./.github/actions/infisical-secrets
with:
names: SENTRY_AUTH_TOKEN
project-id: ${{ secrets.INFISICAL_PROJECT_ID }}
token: ${{ secrets.INFISICAL_SENTRY_DEPLOY_READ_TOKEN }}
env:
GH_FALLBACK_SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
- name: Attach Sentry production deploy
env:
SENTRY_AUTH_TOKEN: ${{ env.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: simple-with-us
SENTRY_PROJECT: botfleet
VERSION: ${{ github.event.workflow_run.head_sha }}
PR_NUMBER: ${{ steps.pr-info.outputs.pr_number }}
SEAT: ${{ steps.pr-info.outputs.seat }}
run: |
set +e
if [ -z "${SENTRY_AUTH_TOKEN:-}" ]; then
echo "::warning::SENTRY_AUTH_TOKEN missing; skipping sentry deploy record"
exit 0
fi
if [ -z "${VERSION:-}" ]; then
echo "::warning::empty VERSION; skipping sentry deploy record"
exit 0
fi
DEPLOY_NAME_ARGS=()
if [ -n "${PR_NUMBER:-}" ]; then
DEPLOY_NAME_ARGS=(-n "seat:${SEAT} pr:#${PR_NUMBER}")
fi
echo "Recording production deploy for release=${VERSION} project=${SENTRY_PROJECT} ${DEPLOY_NAME_ARGS[*]:-(no seat/PR tag)}"
ok=0
for i in 1 2 3 4 5; do
npx --yes @sentry/cli@2.58.6 releases deploys "$VERSION" new -e production "${DEPLOY_NAME_ARGS[@]}"
if [ $? -eq 0 ]; then
ok=1
break
fi
echo "attempt ${i} failed; sleeping 30s (release may still be in flight)"
sleep 30
done
if [ "$ok" -ne 1 ]; then
echo "::warning::sentry-cli releases deploys failed after retries; leaving workflow green"
fi
exit 0