Skip to content
Draft
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .agents/skills/e2e/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ All tests completed successfully. Your SDK changes work correctly with this test

- **No tarballs found**: Run `yarn build && yarn build:tarball` at repository root
- **Test app not found**: List available apps and ask user to clarify
- **Verdaccio not running**: Tests should start Verdaccio automatically, but if issues occur, check Docker
- **Packed tarballs missing**: Run `yarn build:tarball` at the repo root, then `yarn test:prepare` in `dev-packages/e2e-tests`
- **Build failures**: Fix build errors before running tests

## Common Test Applications
Expand Down
28 changes: 20 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -959,18 +959,24 @@ jobs:
if: steps.restore-tarball-cache.outputs.cache-hit != 'true'
run: yarn build:tarball

- name: Validate Verdaccio
run: yarn test:validate
- name: Prepare e2e tests
run: yarn test:prepare
working-directory: dev-packages/e2e-tests

- name: Prepare Verdaccio
run: yarn test:prepare
- name: Validate e2e tests setup
run: yarn test:validate
working-directory: dev-packages/e2e-tests

- name: Copy to temp
run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application
working-directory: dev-packages/e2e-tests

- name: Add pnpm overrides
run:
yarn ci:pnpm-overrides ${{ runner.temp }}/test-application ${{ github.workspace
}}/dev-packages/e2e-tests/packed
working-directory: dev-packages/e2e-tests

- name: Build E2E app
working-directory: ${{ runner.temp }}/test-application
timeout-minutes: 7
Expand Down Expand Up @@ -1069,18 +1075,24 @@ jobs:
if: steps.restore-tarball-cache.outputs.cache-hit != 'true'
run: yarn build:tarball

- name: Validate Verdaccio
run: yarn test:validate
- name: Prepare E2E tests
run: yarn test:prepare
working-directory: dev-packages/e2e-tests

- name: Prepare Verdaccio
run: yarn test:prepare
- name: Validate test setup
run: yarn test:validate
working-directory: dev-packages/e2e-tests

- name: Copy to temp
run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application
working-directory: dev-packages/e2e-tests

- name: Add pnpm overrides
run:
yarn ci:pnpm-overrides ${{ runner.temp }}/test-application ${{ github.workspace
}}/dev-packages/e2e-tests/packed
working-directory: dev-packages/e2e-tests

- name: Build E2E app
working-directory: ${{ runner.temp }}/test-application
timeout-minutes: 7
Expand Down
14 changes: 10 additions & 4 deletions .github/workflows/canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,18 +140,24 @@ jobs:
path: ${{ env.CACHED_BUILD_PATHS }}
key: canary-${{ env.HEAD_COMMIT }}

- name: Validate Verdaccio
run: yarn test:validate
- name: Prepare e2e tests
run: yarn test:prepare
working-directory: dev-packages/e2e-tests

- name: Prepare Verdaccio
run: yarn test:prepare
- name: Validate test setup
run: yarn test:validate
working-directory: dev-packages/e2e-tests

- name: Copy to temp
run: yarn ci:copy-to-temp ./test-applications/${{ matrix.test-application }} ${{ runner.temp }}/test-application
working-directory: dev-packages/e2e-tests

- name: Add pnpm overrides
run:
yarn ci:pnpm-overrides ${{ runner.temp }}/test-application ${{ github.workspace
}}/dev-packages/e2e-tests/packed
working-directory: dev-packages/e2e-tests

- name: Build E2E app
working-directory: ${{ runner.temp }}/test-application
timeout-minutes: 7
Expand Down
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ local.log

.rpt2_cache

# verdaccio local registry (e2e tests)
dev-packages/e2e-tests/verdaccio-config/storage/

lint-results.json
trace.zip

Expand Down
1 change: 1 addition & 0 deletions dev-packages/e2e-tests/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ tmp
.tmp_build_stderr
pnpm-lock.yaml
.last-run.json
packed
18 changes: 18 additions & 0 deletions dev-packages/e2e-tests/ciPnpmOverrides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* eslint-disable no-console */

import { addPnpmOverrides } from './lib/pnpmOverrides';
import * as path from 'path';

async function run(): Promise<void> {
const tmpDirPath = process.argv[2];
const packedDirPath = process.argv[3];

if (!tmpDirPath || !packedDirPath) {
throw new Error('Tmp dir path and packed dir path are required');
}

await addPnpmOverrides(path.resolve(tmpDirPath), path.resolve(packedDirPath));
}

// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();
69 changes: 69 additions & 0 deletions dev-packages/e2e-tests/lib/packedTarballUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import * as path from 'path';
import * as fs from 'fs';
import { sync as globSync } from 'glob';

const E2E_TESTS_ROOT = path.resolve(__dirname, '..');
const REPOSITORY_ROOT = path.resolve(E2E_TESTS_ROOT, '../..');

/**
* Workspace @sentry and @sentry-internal packages that have a built tarball for the E2E version.
* @returns The names of the published Sentry tarball packages.
*/
export function getPublishedSentryTarballPackageNames(): string[] {
const version = getE2eTestsPackageVersion();
const names: string[] = [];

for (const packageJsonPath of globSync('packages/*/package.json', {
cwd: REPOSITORY_ROOT,
absolute: true,
})) {
const pkg = readJson<{ name?: string }>(packageJsonPath);
const name = pkg.name;
if (!name || (!name.startsWith('@sentry/') && !name.startsWith('@sentry-internal/'))) {
continue;
}
const packageDir = path.dirname(packageJsonPath);
const tarball = path.join(packageDir, versionedTarballFilename(name, version));
if (fs.existsSync(tarball)) {
names.push(name);
}
}

return names.sort();
}

/** Stable symlink name in `packed/` (no version segment). */
export function packedSymlinkFilename(packageName: string): string {
return `${npmPackBasename(packageName)}-packed.tgz`;
}

/**
* Versioned tarball filename produced by `npm pack` in a package directory.
*/
export function versionedTarballFilename(packageName: string, version: string): string {
return `${npmPackBasename(packageName)}-${version}.tgz`;
}

/**
* Relative POSIX path from `dev-packages/e2e-tests/packed/<symlink>` to
* `packages/<pkgDir>/<versionedTarball>`.
*/
export function relativeTarballPathFromPackedDir(packageDirName: string, packageName: string, version: string): string {
const file = versionedTarballFilename(packageName, version);
return path.posix.join('..', '..', '..', 'packages', packageDirName, file);
}

/**
* npm pack tarball basename (without version and .tgz), e.g. `@sentry/core` -> `sentry-core`.
*/
function npmPackBasename(packageName: string): string {
return packageName.replace(/^@/, '').replace(/\//g, '-');
}

function readJson<T>(filePath: string): T {
return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T;
}

function getE2eTestsPackageVersion(): string {
return readJson<{ version: string }>(path.join(E2E_TESTS_ROOT, 'package.json')).version;
}
38 changes: 38 additions & 0 deletions dev-packages/e2e-tests/lib/pnpmOverrides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { readFile, writeFile } from 'fs/promises';
import * as path from 'path';
import { getPublishedSentryTarballPackageNames, packedSymlinkFilename } from './packedTarballUtils';

/**
* For a given temp test application directory, add pnpm.overrides to pin the internal Sentry packages to the packed tarballs.
* This is used to ensure that the test application uses the correct version of the internal Sentry packages.
* @param tmpDirPath - The temporary directory path of the test application.
* @param packedDirPath - The path to the packed tarballs.
* @param packageNames - The names of the internal Sentry packages to pin to the packed tarballs.
* @returns
*/
export async function addPnpmOverrides(tmpDirPath: string, packedDirPath: string): Promise<void> {
const packageJsonPath = path.join(tmpDirPath, 'package.json');
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as {
pnpm?: { overrides?: Record<string, string> };
};

const overrides: Record<string, string> = {};

const packageNames = getPublishedSentryTarballPackageNames();

for (const packageName of packageNames) {
overrides[packageName] = `file:${packedDirPath}/${packedSymlinkFilename(packageName)}`;
}

packageJson.pnpm = {
overrides: {
...packageJson.pnpm?.overrides,
...overrides,
},
};

// oxlint-disable-next-line no-console
console.log(`Added ${packageNames.length} internal Sentry packages to pnpm.overrides`);

await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
}
52 changes: 0 additions & 52 deletions dev-packages/e2e-tests/lib/publishPackages.ts

This file was deleted.

71 changes: 71 additions & 0 deletions dev-packages/e2e-tests/lib/syncPackedTarballSymlinks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* eslint-disable no-console */
import * as fs from 'fs';
import * as path from 'path';
import { sync as globSync } from 'glob';
import {
packedSymlinkFilename,
relativeTarballPathFromPackedDir,
versionedTarballFilename,
} from './packedTarballUtils';

const e2eTestsRoot = path.resolve(__dirname, '..');
const repositoryRoot = path.resolve(e2eTestsRoot, '../..');
const packedDir = path.join(e2eTestsRoot, 'packed');

function readJson<T>(filePath: string): T {
return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T;
}

/**
* Ensures `packed/<name>-packed.tgz` symlinks point at the current versioned tarballs under `packages/*`.
* Run after `yarn build:tarball` at the repo root (or from CI after restoring the tarball cache).
*/
export function syncPackedTarballSymlinks(): void {
const { version } = readJson<{ version: string }>(path.join(e2eTestsRoot, 'package.json'));

fs.mkdirSync(packedDir, { recursive: true });

for (const entry of fs.readdirSync(packedDir, { withFileTypes: true })) {
if (!entry.name.endsWith('-packed.tgz')) {
continue;
}
fs.rmSync(path.join(packedDir, entry.name), { recursive: true, force: true });
}

const packageJsonPaths = globSync('packages/*/package.json', {
cwd: repositoryRoot,
absolute: true,
});

let linked = 0;
for (const packageJsonPath of packageJsonPaths) {
const pkg = readJson<{ name?: string }>(packageJsonPath);
const name = pkg.name;
if (!name || (!name.startsWith('@sentry/') && !name.startsWith('@sentry-internal/'))) {
continue;
}

const packageDir = path.dirname(packageJsonPath);
const packageDirName = path.basename(packageDir);
const expectedTarball = path.join(packageDir, versionedTarballFilename(name, version));

if (!fs.existsSync(expectedTarball)) {
continue;
}

const linkName = packedSymlinkFilename(name);
const linkPath = path.join(packedDir, linkName);
const target = relativeTarballPathFromPackedDir(packageDirName, name, version);

fs.symlinkSync(target, linkPath);
linked++;
}

if (linked === 0) {
throw new Error(
`No packed tarballs found for version ${version} under packages/*/. Run "yarn build:tarball" at the repository root.`,
);
}

console.log(`Linked ${linked} tarball symlinks in ${path.relative(repositoryRoot, packedDir) || 'packed'}.`);
}
14 changes: 5 additions & 9 deletions dev-packages/e2e-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@
"lint:fix": "OXLINT_TSGOLINT_DANGEROUSLY_SUPPRESS_PROGRAM_DIAGNOSTICS=true oxlint . --fix --type-aware",
"lint": "OXLINT_TSGOLINT_DANGEROUSLY_SUPPRESS_PROGRAM_DIAGNOSTICS=true oxlint . --type-aware",
"lint:ts": "tsc --noEmit",
"test:e2e": "run-s test:validate-configuration test:validate-test-app-setups test:run",
"test:e2e": "run-s test:prepare test:validate test:run",
"test:run": "ts-node run.ts",
"test:validate-configuration": "ts-node validate-verdaccio-configuration.ts",
"test:validate-test-app-setups": "ts-node validate-test-app-setups.ts",
"test:prepare": "ts-node prepare.ts",
"test:validate": "run-s test:validate-configuration test:validate-test-app-setups",
"clean:verdaccio": "sh -c 'pkill -f verdaccio-runner.mjs 2>/dev/null || true'",
"clean": "yarn clean:verdaccio && rimraf tmp node_modules verdaccio-config/storage && yarn clean:test-applications && yarn clean:pnpm",
"test:validate": "ts-node validate-packed-tarball-setup.ts",
"clean": "rimraf tmp node_modules packed && yarn clean:test-applications && yarn clean:pnpm",
"ci:build-matrix": "ts-node ./lib/getTestMatrix.ts",
"ci:build-matrix-optional": "ts-node ./lib/getTestMatrix.ts --optional=true",
"ci:copy-to-temp": "ts-node ./ciCopyToTemp.ts",
"ci:pnpm-overrides": "ts-node ./ciPnpmOverrides.ts",
"clean:test-applications": "rimraf --glob test-applications/**/{node_modules,dist,build,.next,.nuxt,.sveltekit,.react-router,.astro,.output,pnpm-lock.yaml,.last-run.json,test-results,.angular,event-dumps}",
"clean:pnpm": "pnpm store prune"
},
Expand All @@ -28,9 +26,7 @@
"eslint-plugin-regexp": "^1.15.0",
"glob": "^13.0.6",
"rimraf": "^6.1.3",
"ts-node": "10.9.2",
"verdaccio": "6.5.0",
"yaml": "2.8.3"
"ts-node": "10.9.2"
},
"volta": {
"extends": "../../package.json"
Expand Down
Loading
Loading