Skip to content

Commit 6ca76cd

Browse files
BYKcodex
andcommitted
Fix CLI release and compatibility workflows
Co-Authored-By: OpenAI Codex <noreply@openai.com>
1 parent f71b0dd commit 6ca76cd

14 files changed

Lines changed: 364 additions & 62 deletions

File tree

‎.github/workflows/cli-build.yml‎

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- release/cli/**
8+
workflow_dispatch:
9+
10+
concurrency:
11+
group: cli-build-${{ github.ref }}
12+
cancel-in-progress: false
13+
14+
permissions:
15+
contents: read
16+
packages: write
17+
18+
env:
19+
SENTRY_CLIENT_ID: ${{ vars.SENTRY_CLIENT_ID || 'ci-release-dummy' }}
20+
NODE_VERSION_20: "20.20.2"
21+
NODE_VERSION_22: "22.23.1"
22+
NODE_VERSION_24: "24.18.0"
23+
24+
jobs:
25+
build-binary:
26+
name: Build Binary (${{ matrix.target }})
27+
runs-on: ${{ matrix.os }}
28+
environment: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/cli/')) && 'production' || '' }}
29+
strategy:
30+
fail-fast: false
31+
matrix:
32+
include:
33+
- target: darwin-arm64
34+
os: macos-latest
35+
- target: darwin-x64
36+
os: ubuntu-latest
37+
- target: linux-x64
38+
os: ubuntu-latest
39+
- target: linux-arm64
40+
os: ubuntu-latest
41+
- target: windows-x64
42+
os: ubuntu-latest
43+
steps:
44+
- uses: actions/checkout@v4
45+
- uses: pnpm/action-setup@v4
46+
- uses: actions/setup-node@v4
47+
with:
48+
node-version: ${{ env.NODE_VERSION_22 }}
49+
cache: pnpm
50+
- name: Install dependencies
51+
run: pnpm install --frozen-lockfile
52+
- name: Setup codesign dependencies
53+
env:
54+
APPLE_CERT_DATA: ${{ secrets.APPLE_CERT_DATA }}
55+
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
56+
shell: bash
57+
run: |
58+
if [[ "$RUNNER_OS" == "macOS" && "$RUNNER_ARCH" == "ARM64" ]]; then
59+
RCODESIGN_ARCHIVE="apple-codesign-0.29.0-aarch64-apple-darwin.tar.gz"
60+
RCODESIGN_SHA256="d1a532150adaf90048260d76359261aa716abafc45c53c5dc18845029184334a"
61+
elif [[ "$RUNNER_OS" == "macOS" ]]; then
62+
RCODESIGN_ARCHIVE="apple-codesign-0.29.0-x86_64-apple-darwin.tar.gz"
63+
RCODESIGN_SHA256="14ef11bedd51a8d95eafd767939ae96d5900e5a61511bef75bb21db6e7c74140"
64+
else
65+
RCODESIGN_ARCHIVE="apple-codesign-0.29.0-x86_64-unknown-linux-musl.tar.gz"
66+
RCODESIGN_SHA256="dbe85cedd8ee4217b64e9a0e4c2aef92ab8bcaaa41f20bde99781ff02e600002"
67+
fi
68+
if [[ "$RUNNER_OS" == "macOS" ]]; then
69+
BASE64_DECODE="-D"
70+
else
71+
BASE64_DECODE="--decode"
72+
fi
73+
curl -fsSL "https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.29.0/${RCODESIGN_ARCHIVE}" -o rcodesign.tar.gz
74+
echo "${RCODESIGN_SHA256} rcodesign.tar.gz" | shasum -a 256 -c
75+
tar -xzf rcodesign.tar.gz --strip-components=1
76+
sudo mv rcodesign /usr/local/bin/rcodesign
77+
rm rcodesign.tar.gz
78+
if [[ -n "$APPLE_CERT_DATA" ]]; then
79+
echo "$APPLE_CERT_DATA" | base64 "$BASE64_DECODE" > /tmp/certs.p12
80+
{
81+
echo 'APPLE_CERT_PATH=/tmp/certs.p12'
82+
} >> "$GITHUB_ENV"
83+
fi
84+
if [[ -n "$APPLE_API_KEY" ]]; then
85+
echo "$APPLE_API_KEY" | base64 "$BASE64_DECODE" > /tmp/apple_key.json
86+
jq -r .private_key /tmp/apple_key.json > /tmp/apple_key.pem
87+
{
88+
echo "APPLE_API_KEY_ISSUER_ID=$(jq -r .issuer_id /tmp/apple_key.json | tr -d '\n\r')"
89+
echo "APPLE_API_KEY_ID=$(jq -r .key_id /tmp/apple_key.json | tr -d '\n\r')"
90+
echo 'APPLE_API_KEY_P8_PATH=/tmp/apple_key.pem'
91+
echo 'APPLE_API_KEY_PATH=/tmp/apple_key.json'
92+
} >> "$GITHUB_ENV"
93+
fi
94+
- name: Build
95+
env:
96+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
97+
RELEASE_BUILD: "1"
98+
FOSSILIZE_SIGN: ${{ (github.ref_name == 'main' || startsWith(github.ref_name, 'release/cli/')) && 'y' || 'n' }}
99+
APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }}
100+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
101+
run: pnpm --filter sentry run build -- --target ${{ matrix.target }}
102+
- name: Smoke test
103+
if: matrix.target == 'linux-x64'
104+
env:
105+
SENTRY_AUTH_TOKEN: ""
106+
SENTRY_TOKEN: ""
107+
SENTRY_CONFIG_DIR: ${{ runner.temp }}/.sentry-smoke
108+
run: |
109+
packages/cli/dist-bin/sentry-linux-x64 --help
110+
output=$(packages/cli/dist-bin/sentry-linux-x64 auth status 2>&1) && status=$? || status=$?
111+
test "$status" -eq 10
112+
printf '%s\n' "$output" | grep -qi 'not authenticated'
113+
- name: Upload binary artifact
114+
uses: actions/upload-artifact@v4
115+
with:
116+
name: sentry-${{ matrix.target }}
117+
path: |
118+
packages/cli/dist-bin/sentry-*
119+
!packages/cli/dist-bin/*.gz
120+
- name: Upload compressed artifact
121+
uses: actions/upload-artifact@v4
122+
with:
123+
name: sentry-${{ matrix.target }}-gz
124+
path: packages/cli/dist-bin/*.gz
125+
126+
build-npm:
127+
name: Build npm Package
128+
runs-on: ubuntu-latest
129+
environment: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/cli/')) && 'production' || '' }}
130+
steps:
131+
- uses: actions/checkout@v4
132+
- uses: pnpm/action-setup@v4
133+
- uses: actions/setup-node@v4
134+
with:
135+
node-version: ${{ env.NODE_VERSION_22 }}
136+
cache: pnpm
137+
- name: Install dependencies
138+
run: pnpm install --frozen-lockfile
139+
- name: Bundle
140+
env:
141+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
142+
run: pnpm --filter sentry run bundle
143+
- name: Smoke test
144+
env:
145+
SENTRY_AUTH_TOKEN: ""
146+
SENTRY_TOKEN: ""
147+
SENTRY_CONFIG_DIR: ${{ runner.temp }}/.sentry-smoke
148+
run: node packages/cli/dist/bin.cjs --help
149+
- name: Pack
150+
working-directory: packages/cli
151+
run: npm pack
152+
- name: Upload npm artifact
153+
uses: actions/upload-artifact@v4
154+
with:
155+
name: npm-package
156+
path: packages/cli/*.tgz
157+
158+
test-npm:
159+
name: Test npm Package (Node ${{ matrix.node }})
160+
needs: build-npm
161+
runs-on: ubuntu-latest
162+
strategy:
163+
fail-fast: false
164+
matrix:
165+
node: [20, 22, 24]
166+
steps:
167+
- uses: actions/checkout@v4
168+
- uses: actions/setup-node@v4
169+
with:
170+
node-version: ${{ matrix.node == 24 && env.NODE_VERSION_24 || matrix.node == 20 && env.NODE_VERSION_20 || env.NODE_VERSION_22 }}
171+
- name: Download npm artifact
172+
uses: actions/download-artifact@v4
173+
with:
174+
name: npm-package
175+
path: packages/cli
176+
- name: Test packaged CLI
177+
env:
178+
SENTRY_AUTH_TOKEN: ""
179+
SENTRY_TOKEN: ""
180+
SENTRY_CONFIG_DIR: ${{ runner.temp }}/.sentry-smoke
181+
run: |
182+
package_file=$(find packages/cli -maxdepth 1 -name 'sentry-*.tgz' -print -quit)
183+
test -n "$package_file"
184+
npm install --ignore-scripts --prefix "$RUNNER_TEMP/npm-smoke" "$GITHUB_WORKSPACE/$package_file"
185+
node "$RUNNER_TEMP/npm-smoke/node_modules/sentry/dist/bin.cjs" --help
186+
187+
build-docs:
188+
name: Build Docs
189+
needs: build-binary
190+
runs-on: ubuntu-latest
191+
environment: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/cli/')) && 'production' || '' }}
192+
env:
193+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
194+
steps:
195+
- uses: actions/checkout@v4
196+
- uses: pnpm/action-setup@v4
197+
- uses: actions/setup-node@v4
198+
with:
199+
node-version: ${{ env.NODE_VERSION_24 }}
200+
cache: pnpm
201+
- name: Install dependencies
202+
run: pnpm install --frozen-lockfile
203+
- name: Generate CLI docs
204+
run: pnpm --filter sentry run generate:schema && pnpm --filter sentry run generate:docs
205+
- name: Build docs
206+
run: pnpm --filter sentry-cli-docs run build
207+
- name: Download Linux binary
208+
uses: actions/download-artifact@v4
209+
with:
210+
name: sentry-linux-x64
211+
path: dist-bin
212+
- name: Inject debug IDs and upload sourcemaps
213+
if: github.event_name == 'push' && env.SENTRY_AUTH_TOKEN != ''
214+
env:
215+
SENTRY_ORG: sentry
216+
SENTRY_PROJECT: cli-website
217+
run: |
218+
chmod +x dist-bin/sentry-linux-x64
219+
./dist-bin/sentry-linux-x64 sourcemap inject apps/cli-docs/dist/
220+
# shellcheck disable=SC2088
221+
./dist-bin/sentry-linux-x64 sourcemap upload apps/cli-docs/dist/ \
222+
--release "$(node -p 'require("./packages/cli/package.json").version')" \
223+
--url-prefix "~/"
224+
- name: Remove sourcemaps
225+
run: find apps/cli-docs/dist -name '*.map' -delete
226+
- name: Package docs
227+
run: |
228+
output_dir="$RUNNER_TEMP/vercel-output"
229+
rm -rf "$output_dir"
230+
mkdir -p "$output_dir/.vercel/output/static"
231+
cp -R apps/cli-docs/dist/. "$output_dir/.vercel/output/static/"
232+
printf '%s\n' '{"version":3}' > "$output_dir/.vercel/output/config.json"
233+
(cd "$output_dir" && zip -qr "$GITHUB_WORKSPACE/vercel.zip" .vercel)
234+
- name: Upload docs artifact
235+
uses: actions/upload-artifact@v4
236+
with:
237+
name: vercel
238+
path: vercel.zip

‎.github/workflows/deploy.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151

5252
# === BUILD AND DEPLOY CANARY WORKER ===
5353
- name: Build
54-
run: pnpm --filter '@sentry/mcp-cloudflare...' --if-present run build
54+
run: pnpm --filter '@sentry/mcp-cloudflare...' run build
5555
env:
5656
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
5757
VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }}

‎.github/workflows/token-cost.yml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ on:
66
paths:
77
- ".github/workflows/token-cost.yml"
88
- "packages/mcp-core/src/tools/**"
9+
- "packages/mcp-core/src/schema.ts"
10+
- "packages/mcp-core/src/constants.ts"
911
- "packages/mcp-core/src/skills.ts"
1012
- "packages/mcp-core/src/toolDefinitions.json"
1113
- "packages/mcp-core/src/skillDefinitions.json"
@@ -19,6 +21,8 @@ on:
1921
paths:
2022
- ".github/workflows/token-cost.yml"
2123
- "packages/mcp-core/src/tools/**"
24+
- "packages/mcp-core/src/schema.ts"
25+
- "packages/mcp-core/src/constants.ts"
2226
- "packages/mcp-core/src/skills.ts"
2327
- "packages/mcp-core/src/toolDefinitions.json"
2428
- "packages/mcp-core/src/skillDefinitions.json"

‎apps/cli-docs/src/content/docs/library-usage.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ const dashboard = await sdk.dashboard.view({}, "acme/", "my-dashboard");
8282

8383
// Nested widget commands
8484
await sdk.dashboard.widget.add(
85-
{ display: "line", query: "count" },
86-
"acme/", "my-dashboard"
85+
{ display: "line", query: ["count"] },
86+
"acme/", "my-dashboard", "Errors over time"
8787
);
8888
```
8989

@@ -233,7 +233,7 @@ When using streaming flags, methods return an `AsyncIterable` instead of a `Prom
233233
const sdk = createSentrySDK({ token: "sntrys_..." });
234234

235235
// Stream logs as they arrive (polls every 5 seconds)
236-
for await (const log of sdk.log.list({ follow: "5", orgProject: "acme/backend" })) {
236+
for await (const log of sdk.log.list({ follow: "5" }, "acme/backend")) {
237237
console.log(log);
238238
}
239239

‎apps/cli-docs/src/content/docs/migrating-from-v3.md‎

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,10 @@ sentry-cli() {
163163
local envs=() lead=() headers="" allow_failure=""
164164
while [ "$#" -gt 0 ]; do
165165
case "$1" in
166-
--auth-token) envs+=("SENTRY_AUTH_TOKEN=$2"); shift 2 2>/dev/null || shift ;;
167-
--auth-token=*) envs+=("SENTRY_AUTH_TOKEN=${1#*=}"); shift ;;
168-
--url) envs+=("SENTRY_URL=$2"); shift 2 2>/dev/null || shift ;;
169-
--url=*) envs+=("SENTRY_URL=${1#*=}"); shift ;;
166+
--auth-token) envs+=("SENTRY_AUTH_TOKEN=$2" "SENTRY_FORCE_ENV_TOKEN=1"); shift 2 2>/dev/null || shift ;;
167+
--auth-token=*) envs+=("SENTRY_AUTH_TOKEN=${1#*=}" "SENTRY_FORCE_ENV_TOKEN=1"); shift ;;
168+
--url) envs+=("SENTRY_HOST=$2" "SENTRY_URL=$2"); shift 2 2>/dev/null || shift ;;
169+
--url=*) envs+=("SENTRY_HOST=${1#*=}" "SENTRY_URL=${1#*=}"); shift ;;
170170
# Multiple --header flags merge into one semicolon-separated var.
171171
--header) headers="${headers:+$headers; }$2"; shift 2 2>/dev/null || shift ;;
172172
--header=*) headers="${headers:+$headers; }${1#*=}"; shift ;;
@@ -192,9 +192,20 @@ sentry-cli() {
192192
# environment/name as positionals, not v3's `-e`/`-n` flags — so flag those.
193193
local deploy_msg='sentry-cli: `deploys new` changed in v4 — environment/name are positionals now:\n sentry release deploy <version> <environment> [name] [--url … --started … --finished …]\n'
194194
_scli_deploys() {
195-
local a dargs=()
195+
local a release="" dargs=()
196196
for a in "$@"; do [ "$a" = "new" ] && { printf '%b' "$deploy_msg" >&2; return 64; }; done
197-
for a in "$@"; do [ "$a" = "list" ] || dargs+=("$a"); done # drop v3 `list`
197+
while [ "$#" -gt 0 ]; do
198+
case "$1" in
199+
list) shift ;;
200+
-r|--release)
201+
release="${2:-}"
202+
shift 2 2>/dev/null || shift
203+
;;
204+
--release=*) release="${1#*=}"; shift ;;
205+
*) dargs+=("$1"); shift ;;
206+
esac
207+
done
208+
[ -n "$release" ] && dargs=("$release" "${dargs[@]}")
198209
"${run[@]}" release deploys "${dargs[@]}"
199210
}
200211

@@ -303,8 +314,9 @@ Command-specific flags changed more than the global ones, and some v3 flags
303314
don't exist in v4 yet. A few notable ones:
304315

305316
- `release set-commits` drops `--ignore-missing` and `--ignore-empty`.
306-
- `release deploy` takes the environment and name as part of the positional
307-
target (`org/version/env/name`), not `--env`/`--name`.
317+
- `release deploy` takes separate positional arguments for the release,
318+
environment, and optional name (`[<org>/]<version> <environment> [name]`),
319+
not `--env`/`--name`.
308320
- `sourcemap upload`/`inject` drop several flags (see [Sourcemaps](#sourcemaps)).
309321

310322
Before relying on a flag, confirm it with `sentry <command> --help` — that's the
@@ -361,7 +373,7 @@ Mapping:
361373
| `cli.releases.finalize(v)` | `sdk.release.finalize({ orgVersion: v })` |
362374
| `cli.releases.setCommits(v, o)` | `sdk.release["set-commits"]({ orgVersion: v, ...o })` |
363375
| `cli.releases.uploadSourceMaps(v, { include })` | `sdk.sourcemap.upload({ directory, release: v })` |
364-
| `cli.releases.newDeploy(v, { env, name, url })` | `sdk.run("release", "deploy", v, env, name, "--url", url)` (the typed `sdk.release.deploy` can only pass one positional, so it can't supply the required environment — use the `run()` escape hatch for the raw args) |
376+
| `cli.releases.newDeploy(v, { env, name, url })` | `sdk.release.deploy({ orgVersion: v, environment: env, name, url })` |
365377
| `cli.releases.proposeVersion()` | `sdk.release["propose-version"]()` |
366378
| `cli.execute(args)` | `sdk.run(...args)` |
367379

@@ -441,9 +453,9 @@ export SENTRY_AUTH_TOKEN=sntrys_…
441453
sentry auth status
442454
```
443455

444-
`SENTRY_AUTH_TOKEN` works exactly as before and takes precedence over stored
445-
credentials, so existing CI pipelines don't need changes. (v4 also accepts
446-
`SENTRY_TOKEN` as an alias for it.)
456+
Stored OAuth credentials take precedence over `SENTRY_AUTH_TOKEN` by default.
457+
Set `SENTRY_FORCE_ENV_TOKEN=1` when an environment token must override a stored
458+
login. (v4 also accepts `SENTRY_TOKEN` as an alias for it.)
447459

448460
Note: there is **no `--auth-token` flag** in v4 — authentication comes from
449461
`sentry auth login`, `SENTRY_AUTH_TOKEN`, or `.sentryclirc`. See

‎apps/cli-docs/src/content/docs/self-hosted.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ SENTRY_CLIENT_ID=your-client-id sentry auth login --url https://sentry.example.c
3333
Or pass the instance URL via environment variable:
3434

3535
```bash
36-
SENTRY_HOST=https://sentry.example.com SENTRY_CLIENT_ID=your-client-id sentry auth login
36+
SENTRY_HOST=https://sentry.example.com SENTRY_CLIENT_ID=your-client-id sentry auth login --url https://sentry.example.com
3737
```
3838

3939
:::tip
@@ -61,7 +61,7 @@ If your instance is on an older version or you prefer not to create an OAuth app
6161
3. Pass it to the CLI:
6262

6363
```bash
64-
SENTRY_HOST=https://sentry.example.com sentry auth login --token YOUR_TOKEN
64+
SENTRY_HOST=https://sentry.example.com sentry auth login --token YOUR_TOKEN --url https://sentry.example.com
6565
```
6666

6767
## After Login

‎package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
"docs:check": "node scripts/check-doc-links.mjs",
2626
"dev": "pnpm --filter '@sentry/mcp-cloudflare...' --if-present run build && dotenv -e .env -e .env.local -- pnpm --parallel --filter @sentry/mcp-cloudflare --filter @sentry/mcp-core --filter @sentry/mcp-server-mocks --if-present run dev",
2727
"dev:stdio": "pnpm --filter '@sentry/mcp-server...' --if-present run build && dotenv -e .env -e .env.local -- pnpm --parallel --filter @sentry/mcp-server --filter @sentry/mcp-core --filter @sentry/mcp-server-mocks --if-present run dev",
28-
"build": "pnpm --filter sentry run build && pnpm -r --filter '!sentry' --filter '!sentry-cli-docs' --if-present run build && pnpm --filter sentry-cli-docs run build",
28+
"build": "dotenv -e .env -e .env.local -- pnpm --filter sentry run build && pnpm -r --filter '!sentry' --filter '!sentry-cli-docs' --if-present run build && pnpm --filter sentry-cli-docs run build",
2929
"check:generated": "pnpm --filter @sentry/mcp-core generate-definitions && git diff --exit-code -- packages/mcp-core/src/toolDefinitions.json packages/mcp-core/src/skillDefinitions.json plugins/sentry-mcp/agents/sentry-mcp.md plugins/sentry-mcp-experimental/agents/sentry-mcp.md",
3030
"deploy": "pnpm --filter '@sentry/mcp-cloudflare...' --if-present run build && pnpm --filter @sentry/mcp-cloudflare run deploy",
31-
"deploy:docs": "pnpm --filter sentry-cli-docs run build && pnpm --filter sentry-cli-docs run deploy",
31+
"deploy:docs": "pnpm --filter sentry run generate:schema && pnpm --filter sentry run generate:docs && pnpm --filter sentry-cli-docs run build && pnpm --filter sentry-cli-docs run deploy",
3232
"eval": "dotenv -e .env -e .env.local -- pnpm --filter @sentry/mcp-server-evals run eval",
3333
"eval:ci": "CI=true dotenv -e .env -e .env.local -- pnpm --stream -r run eval:ci",
3434
"format": "biome format --write",

0 commit comments

Comments
 (0)