Skip to content
Closed
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
25 changes: 25 additions & 0 deletions SENTRY.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,31 @@ bundle shape as shipped releases. Manual runs can override the Sentry release
name and environment; tag runs default the release name to the tag, and manual
runs without a release input default to the commit SHA.

Owner-side manual verification can be run from a checkout with GitHub access:

```sh
gh workflow run sentry-release-artifacts.yml \
--ref main \
-f release=manual-sentry-artifact-smoke-$(git rev-parse --short HEAD) \
-f environment=production
```

Before dispatching, verify the repository has `SENTRY_AUTH_TOKEN`,
`SENTRY_ORG`, `SENTRY_PROJECT`, and `VITE_SENTRY_DSN` configured as Actions
secrets. After the run completes, verify in Sentry that:

- the selected release exists and has frontend sourcemaps/artifacts uploaded;
- an intentional frontend stack frame symbolicates to source instead of built
`dist` chunks;
- Linux, macOS, Windows, and current iOS simulator debug files appear under
Debug Files with source context where supported;
- Android ProGuard/R8 mapping and native symbol uploads completed for the
release artifact build;
- Android Size Analysis has a build for the selected release/run, with the
expected base SHA comparison;
- GitHub uploaded the frontend, Linux, Apple, Windows, and Android size-report
artifacts for auditability.

Sentry Size Analysis currently receives Android builds only. The current iOS CI
path builds an unsigned simulator debug app, while Sentry accepts XCArchive or
IPA inputs for iOS size analysis; wire that upload once a signed device-release
Expand Down
71 changes: 71 additions & 0 deletions src/observability/sentryReleaseArtifactsWorkflow.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { describe, expect, it } from "vitest";

describe("Sentry release artifact workflow", () => {
const root = process.cwd();
const workflow = readFileSync(
resolve(root, ".github/workflows/sentry-release-artifacts.yml"),
"utf8",
);
const viteConfig = readFileSync(resolve(root, "vite.config.ts"), "utf8");
const releaseEnvScript = readFileSync(
resolve(root, ".github/scripts/configure-sentry-release-env.sh"),
"utf8",
);
const androidAppBuild = readFileSync(
resolve(root, "src-tauri/gen/android/app/build.gradle.kts"),
"utf8",
);

Comment on lines +1 to +20
it("keeps manual release and environment inputs available", () => {
expect(workflow).toContain("workflow_dispatch:");
expect(workflow).toMatch(/release:\r?\n\s+description: "Sentry release name\./);
expect(workflow).toMatch(/environment:\r?\n\s+description: "Sentry environment tag/);
Comment on lines +23 to +24
expect(workflow).toContain("default: production");
});

it("requires Sentry owner secrets before upload jobs run", () => {
for (const secret of ["SENTRY_AUTH_TOKEN", "SENTRY_ORG", "SENTRY_PROJECT", "VITE_SENTRY_DSN"]) {
expect(workflow).toContain(`secrets.${secret}`);
}

expect(releaseEnvScript).toContain("required=(SENTRY_AUTH_TOKEN SENTRY_ORG SENTRY_PROJECT)");
expect(releaseEnvScript).toContain("required+=(VITE_SENTRY_DSN)");
expect(releaseEnvScript).toContain("Missing required Sentry secret(s)");
});

it("uploads frontend sourcemaps only from explicit Sentry release builds", () => {
expect(workflow).toContain('REQUIRE_VITE_SENTRY_DSN: "true"');
expect(workflow).toContain('WRITE_FRONTEND_UPLOAD_ENV: "true"');
expect(releaseEnvScript).toContain("SENTRY_UPLOAD=true");
expect(viteConfig).toContain('procEnv.SENTRY_UPLOAD === "true"');
expect(viteConfig).toContain(
"SENTRY_UPLOAD=true requires SENTRY_AUTH_TOKEN, SENTRY_ORG, and SENTRY_PROJECT",
);
expect(viteConfig).toContain("filesToDeleteAfterUpload");
expect(viteConfig).toContain("dist/**/*.map");
expect(workflow).toContain("Sentry sourcemap upload left .map files in dist");
});

it("uploads desktop and Apple debug files with source context and release debuginfo", () => {
expect(workflow).toContain('WRITE_RUST_DEBUG_ENV: "true"');
expect(releaseEnvScript).toContain("CARGO_PROFILE_RELEASE_DEBUG=1");
expect(workflow).toMatch(/pnpm dlx @sentry\/cli@3\.5\.1 debug-files upload/);
expect(workflow).toContain("--include-sources");
expect(workflow).toContain("--wait");
expect(workflow).toContain("pnpm tauri build");
expect(workflow).toContain("pnpm tauri ios build --target aarch64-sim --debug --ci");
});

it("keeps Android mapping, native-symbol, and size-analysis uploads wired", () => {
expect(workflow).toContain('SENTRY_ANDROID_UPLOAD: "true"');
expect(workflow).toContain("pnpm tauri android build --ci");
expect(androidAppBuild).toContain('System.getenv("SENTRY_ANDROID_UPLOAD") == "true"');
expect(androidAppBuild).toContain("autoUploadProguardMapping.set(true)");
expect(androidAppBuild).toContain("autoUploadNativeSymbols.set(true)");
expect(androidAppBuild).toContain("includeNativeSources.set(true)");
expect(workflow).toContain("pnpm dlx @sentry/cli@3.5.1 build upload");
expect(workflow).toContain("--base-sha");
});
});
Loading