Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 124 additions & 1 deletion .github/workflows/cli-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ concurrency:

permissions:
contents: read
packages: write

env:
SENTRY_CLIENT_ID: ${{ vars.SENTRY_CLIENT_ID }}
Expand All @@ -22,8 +21,20 @@ env:
NODE_VERSION_24: "24.18.0"

jobs:
nightly-version:
name: Compute nightly version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- name: Compute version from the commit timestamp
id: version
run: node scripts/cli-nightly-version.mjs

build-binary:
name: Build Binary (${{ matrix.target }})
needs: nightly-version
runs-on: ${{ matrix.os }}
environment: ${{ github.ref == 'refs/heads/main' && 'production' || startsWith(github.ref, 'refs/heads/release/cli/') && 'cli-release' || '' }}
strategy:
Expand All @@ -49,6 +60,14 @@ jobs:
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Stamp the nightly binary version
if: github.ref == 'refs/heads/main'
env:
NIGHTLY_VERSION: ${{ needs.nightly-version.outputs.version }}
shell: bash
run: |
jq --arg version "$NIGHTLY_VERSION" '.version = $version' packages/cli/package.json > "$RUNNER_TEMP/cli-package.json"
mv "$RUNNER_TEMP/cli-package.json" packages/cli/package.json
- name: Setup codesign dependencies
env:
APPLE_CERT_DATA: ${{ secrets.APPLE_CERT_DATA }}
Expand Down Expand Up @@ -105,8 +124,12 @@ jobs:
SENTRY_AUTH_TOKEN: ""
SENTRY_TOKEN: ""
SENTRY_CONFIG_DIR: ${{ runner.temp }}/.sentry-smoke
NIGHTLY_VERSION: ${{ needs.nightly-version.outputs.version }}
run: |
packages/cli/dist-bin/sentry-linux-x64 --help
if [[ "$GITHUB_REF" == 'refs/heads/main' ]]; then
test "$(packages/cli/dist-bin/sentry-linux-x64 --version)" = "$NIGHTLY_VERSION"
fi
output=$(packages/cli/dist-bin/sentry-linux-x64 auth status 2>&1) && status=$? || status=$?
test "$status" -eq 10
printf '%s\n' "$output" | grep -qi 'not authenticated'
Expand All @@ -123,6 +146,106 @@ jobs:
name: sentry-${{ matrix.target }}-gz
path: packages/cli/dist-bin/*.gz

generate-patches:
name: Generate nightly delta patches
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: [nightly-version, build-binary]
runs-on: ubuntu-latest
continue-on-error: true
permissions:
contents: read
packages: read
outputs:
from-version: ${{ steps.generate.outputs.from-version }}
steps:
- name: Download binaries and compressed artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: sentry-*-*
path: new-binaries
merge-multiple: true
- name: Generate patches against the preceding Toolkit nightly
id: generate
uses: BYK/binpatch/action@9ba6bbb8227fcbd2521852d2311c82afac5e9573 # 0.4.2
with:
mode: generate-ghcr
version: ${{ needs.nightly-version.outputs.version }}
registry: ghcr.io
repo: getsentry/toolkit
binary-glob: 'sentry-*'
new-binaries-dir: new-binaries
new-gz-dir: new-binaries
patches-dir: patches
- name: Upload patches
if: steps.generate.outputs.has-patches == 'true'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: sentry-patches
path: patches/*.patch

publish-nightly:
name: Publish Toolkit nightly to GHCR
if: >-
always() && github.ref == 'refs/heads/main' && github.event_name == 'push' &&
needs.nightly-version.result == 'success' && needs.build-binary.result == 'success' &&
(needs.generate-patches.result == 'success' || needs.generate-patches.result == 'failure')
needs: [nightly-version, build-binary, generate-patches]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Download compressed binaries
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: sentry-*-gz
path: artifacts
merge-multiple: true
- name: Download binaries for patch integrity annotations
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: sentry-*-*
path: binaries
merge-multiple: true
- name: Download optional delta patches
id: patches
continue-on-error: true
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: sentry-patches
path: patches
- name: Publish rolling and versioned manifests
uses: BYK/binpatch/action@9ba6bbb8227fcbd2521852d2311c82afac5e9573 # 0.4.2
with:
mode: publish-ghcr
version: ${{ needs.nightly-version.outputs.version }}
registry: ghcr.io
repo: getsentry/toolkit
binary-glob: 'sentry-*'
artifacts-dir: artifacts
binaries-dir: binaries
patches-dir: patches
from-version: ${{ needs.generate-patches.outputs.from-version }}
- name: Verify public nightly and immutable version tag
env:
NIGHTLY_VERSION: ${{ needs.nightly-version.outputs.version }}
shell: bash
run: |
set -euo pipefail
token=$(curl -fsS 'https://ghcr.io/token?scope=repository:getsentry/toolkit:pull' | jq -er '.token')
for tag in nightly "nightly-${NIGHTLY_VERSION}"; do
manifest=$(curl -fsS \
-H "Authorization: Bearer ${token}" \
-H 'Accept: application/vnd.oci.image.manifest.v1+json' \
"https://ghcr.io/v2/getsentry/toolkit/manifests/${tag}")
jq -e --arg version "$NIGHTLY_VERSION" '
.annotations.version == $version and
.annotations["org.opencontainers.image.source"] == "https://github.com/getsentry/toolkit" and
([.layers[].annotations["org.opencontainers.image.title"]] | sort) ==
(["sentry-darwin-arm64.gz", "sentry-darwin-x64.gz", "sentry-linux-arm64.gz", "sentry-linux-x64.gz", "sentry-windows-x64.exe.gz"] | sort)
' <<< "$manifest" > /dev/null
done

build-npm:
name: Build npm Package
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"scripts": {
"docs:check": "node scripts/check-doc-links.mjs",
"test:ci-projects": "node --test scripts/ci-projects.test.mjs scripts/cloudflare-deployment.test.mjs scripts/deploy-workflow.test.mjs",
"test:ci-projects": "node --test scripts/ci-projects.test.mjs scripts/cli-nightly-version.test.mjs scripts/cloudflare-deployment.test.mjs scripts/deploy-workflow.test.mjs",
"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",
"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",
"build": "dotenv -e .env -e .env.local -- pnpm -r --filter '!sentry' --filter '!sentry-cli-docs' --if-present run build",
Expand Down
36 changes: 36 additions & 0 deletions scripts/cli-nightly-version.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { execFileSync } from "node:child_process";
import { appendFileSync, readFileSync } from "node:fs";
import { pathToFileURL } from "node:url";

export function computeNightlyVersion(version, timestamp) {
const base = /^(\d+\.\d+\.\d+)(?:-dev\.\d+)?$/.exec(version);
if (
!base ||
!/^[1-9]\d*$/.test(timestamp) ||
!Number.isSafeInteger(Number(timestamp))
) {
throw new Error(
"Invalid CLI version or commit timestamp for nightly build",
);
}
return `${base[1]}-dev.${timestamp}`;
}

if (
process.argv[1] &&
import.meta.url === pathToFileURL(process.argv[1]).href
) {
const { version } = JSON.parse(
readFileSync("packages/cli/package.json", "utf8"),
);
const timestamp = execFileSync(
"git",
["show", "-s", "--format=%ct", "HEAD"],
{ encoding: "utf8" },
).trim();
const nightly = computeNightlyVersion(version, timestamp);
if (process.env.GITHUB_OUTPUT) {
appendFileSync(process.env.GITHUB_OUTPUT, `version=${nightly}\n`);
}
console.log(`Nightly version: ${nightly}`);
}
26 changes: 26 additions & 0 deletions scripts/cli-nightly-version.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import assert from "node:assert/strict";
import test from "node:test";
import { computeNightlyVersion } from "./cli-nightly-version.mjs";

test("stamps development and release versions with the same commit timestamp", () => {
assert.equal(
computeNightlyVersion("0.47.0-dev.0", "1791028800"),
"0.47.0-dev.1791028800",
);
assert.equal(
computeNightlyVersion("0.47.0", "1791028800"),
"0.47.0-dev.1791028800",
);
});

test("rejects invalid inputs before they can become OCI tags", () => {
for (const [version, timestamp] of [
["0.47.0-dev.bad", "1791028800"],
["0.47.0-rc.1", "1791028800"],
["0.47.0", "0"],
["0.47.0", "1791028800\nmalicious"],
["0.47.0", "9007199254740992"],
]) {
assert.throws(() => computeNightlyVersion(version, timestamp));
}
});
Loading