Skip to content

Commit 9f64eb5

Browse files
committed
chore(e2e-tests): Use tarball symlinks for E2E tests instead of verdaccio
1 parent 313cf82 commit 9f64eb5

310 files changed

Lines changed: 643 additions & 2127 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/e2e/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ All tests completed successfully. Your SDK changes work correctly with this test
116116

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

122122
## Common Test Applications

.github/workflows/build.yml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -959,18 +959,22 @@ jobs:
959959
if: steps.restore-tarball-cache.outputs.cache-hit != 'true'
960960
run: yarn build:tarball
961961

962-
- name: Validate Verdaccio
962+
- name: Validate packed tarball setup
963963
run: yarn test:validate
964964
working-directory: dev-packages/e2e-tests
965965

966-
- name: Prepare Verdaccio
966+
- name: Prepare e2e tests
967967
run: yarn test:prepare
968968
working-directory: dev-packages/e2e-tests
969969

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

974+
- name: Add pnpm overrides
975+
run: yarn ci:pnpm-overrides ${{ runner.temp }}/test-application ${{ github.workspace }}/dev-packages/e2e-tests/packed
976+
working-directory: dev-packages/e2e-tests
977+
974978
- name: Build E2E app
975979
working-directory: ${{ runner.temp }}/test-application
976980
timeout-minutes: 7
@@ -1069,12 +1073,12 @@ jobs:
10691073
if: steps.restore-tarball-cache.outputs.cache-hit != 'true'
10701074
run: yarn build:tarball
10711075

1072-
- name: Validate Verdaccio
1073-
run: yarn test:validate
1076+
- name: Prepare E2E tests
1077+
run: yarn test:prepare
10741078
working-directory: dev-packages/e2e-tests
10751079

1076-
- name: Prepare Verdaccio
1077-
run: yarn test:prepare
1080+
- name: Validate test setup
1081+
run: yarn test:validate
10781082
working-directory: dev-packages/e2e-tests
10791083

10801084
- name: Copy to temp

.github/workflows/canary.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,18 +140,22 @@ jobs:
140140
path: ${{ env.CACHED_BUILD_PATHS }}
141141
key: canary-${{ env.HEAD_COMMIT }}
142142

143-
- name: Validate Verdaccio
144-
run: yarn test:validate
143+
- name: Prepare e2e tests
144+
run: yarn test:prepare
145145
working-directory: dev-packages/e2e-tests
146146

147-
- name: Prepare Verdaccio
148-
run: yarn test:prepare
147+
- name: Validate test setup
148+
run: yarn test:validate
149149
working-directory: dev-packages/e2e-tests
150150

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

155+
- name: Add pnpm overrides
156+
run: yarn ci:pnpm-overrides ${{ runner.temp }}/test-application ${{ github.workspace }}/dev-packages/e2e-tests/packed
157+
working-directory: dev-packages/e2e-tests
158+
155159
- name: Build E2E app
156160
working-directory: ${{ runner.temp }}/test-application
157161
timeout-minutes: 7

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ local.log
3939

4040
.rpt2_cache
4141

42-
# verdaccio local registry (e2e tests)
43-
dev-packages/e2e-tests/verdaccio-config/storage/
44-
4542
lint-results.json
4643
trace.zip
4744

dev-packages/e2e-tests/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ tmp
44
.tmp_build_stderr
55
pnpm-lock.yaml
66
.last-run.json
7+
packed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* eslint-disable no-console */
2+
3+
import { addPnpmOverrides } from './lib/pnpmOverrides';
4+
import * as path from 'path';
5+
6+
7+
async function run(): Promise<void> {
8+
const tmpDirPath = process.argv[2];
9+
const packedDirPath = process.argv[3];
10+
11+
if (!tmpDirPath || !packedDirPath) {
12+
throw new Error('Tmp dir path and packed dir path are required');
13+
}
14+
15+
await addPnpmOverrides(path.resolve(tmpDirPath), path.resolve(packedDirPath));
16+
}
17+
18+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
19+
run();
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import * as path from 'path';
2+
import * as fs from 'fs';
3+
import { sync as globSync } from 'glob';
4+
5+
const E2E_TESTS_ROOT = path.resolve(__dirname, '..');
6+
const REPOSITORY_ROOT = path.resolve(E2E_TESTS_ROOT, '../..');
7+
8+
/**
9+
* Workspace @sentry and @sentry-internal packages that have a built tarball for the E2E version.
10+
* @returns The names of the published Sentry tarball packages.
11+
*/
12+
export function getPublishedSentryTarballPackageNames(): string[] {
13+
const version = getE2eTestsPackageVersion();
14+
const names: string[] = [];
15+
16+
for (const packageJsonPath of globSync('packages/*/package.json', {
17+
cwd: REPOSITORY_ROOT,
18+
absolute: true,
19+
})) {
20+
const pkg = readJson<{ name?: string }>(packageJsonPath);
21+
const name = pkg.name;
22+
if (!name || (!name.startsWith('@sentry/') && !name.startsWith('@sentry-internal/'))) {
23+
continue;
24+
}
25+
const packageDir = path.dirname(packageJsonPath);
26+
const tarball = path.join(packageDir, versionedTarballFilename(name, version));
27+
if (fs.existsSync(tarball)) {
28+
names.push(name);
29+
}
30+
}
31+
32+
return names.sort();
33+
}
34+
35+
/** Stable symlink name in `packed/` (no version segment). */
36+
export function packedSymlinkFilename(packageName: string): string {
37+
return `${npmPackBasename(packageName)}-packed.tgz`;
38+
}
39+
40+
/**
41+
* Versioned tarball filename produced by `npm pack` in a package directory.
42+
*/
43+
export function versionedTarballFilename(packageName: string, version: string): string {
44+
return `${npmPackBasename(packageName)}-${version}.tgz`;
45+
}
46+
47+
/**
48+
* Relative POSIX path from `dev-packages/e2e-tests/packed/<symlink>` to
49+
* `packages/<pkgDir>/<versionedTarball>`.
50+
*/
51+
export function relativeTarballPathFromPackedDir(packageDirName: string, packageName: string, version: string): string {
52+
const file = versionedTarballFilename(packageName, version);
53+
return path.posix.join('..', '..', '..', 'packages', packageDirName, file);
54+
}
55+
56+
/**
57+
* npm pack tarball basename (without version and .tgz), e.g. `@sentry/core` -> `sentry-core`.
58+
*/
59+
function npmPackBasename(packageName: string): string {
60+
return packageName.replace(/^@/, '').replace(/\//g, '-');
61+
}
62+
63+
function readJson<T>(filePath: string): T {
64+
return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T;
65+
}
66+
67+
function getE2eTestsPackageVersion(): string {
68+
return readJson<{ version: string }>(path.join(E2E_TESTS_ROOT, 'package.json')).version;
69+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { readFile, writeFile } from 'fs/promises';
2+
import * as path from 'path';
3+
import { getPublishedSentryTarballPackageNames, packedSymlinkFilename } from './packedTarballUtils';
4+
5+
/**
6+
* For a given temp test application directory, add pnpm.overrides to pin the internal Sentry packages to the packed tarballs.
7+
* This is used to ensure that the test application uses the correct version of the internal Sentry packages.
8+
* @param tmpDirPath - The temporary directory path of the test application.
9+
* @param packedDirPath - The path to the packed tarballs.
10+
* @param packageNames - The names of the internal Sentry packages to pin to the packed tarballs.
11+
* @returns
12+
*/
13+
export async function addPnpmOverrides(tmpDirPath: string, packedDirPath: string): Promise<void> {
14+
const packageJsonPath = path.join(tmpDirPath, 'package.json');
15+
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as {
16+
pnpm?: { overrides?: Record<string, string> };
17+
};
18+
19+
const overrides: Record<string, string> = {};
20+
21+
const packageNames = getPublishedSentryTarballPackageNames();
22+
23+
for (const packageName of packageNames) {
24+
overrides[packageName] = `file:${packedDirPath}/${packedSymlinkFilename(packageName)}`;
25+
}
26+
27+
packageJson.pnpm = {
28+
overrides: {
29+
...packageJson.pnpm?.overrides,
30+
...overrides,
31+
},
32+
};
33+
34+
// oxlint-disable-next-line no-console
35+
console.log(`Added ${packageNames.length} internal Sentry packages to pnpm.overrides`);
36+
37+
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
38+
}

dev-packages/e2e-tests/lib/publishPackages.ts

Lines changed: 0 additions & 52 deletions
This file was deleted.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/* eslint-disable no-console */
2+
import * as fs from 'fs';
3+
import * as path from 'path';
4+
import { sync as globSync } from 'glob';
5+
import {
6+
packedSymlinkFilename,
7+
relativeTarballPathFromPackedDir,
8+
versionedTarballFilename,
9+
} from './packedTarballUtils';
10+
11+
const e2eTestsRoot = path.resolve(__dirname, '..');
12+
const repositoryRoot = path.resolve(e2eTestsRoot, '../..');
13+
const packedDir = path.join(e2eTestsRoot, 'packed');
14+
15+
function readJson<T>(filePath: string): T {
16+
return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T;
17+
}
18+
19+
/**
20+
* Ensures `packed/<name>-packed.tgz` symlinks point at the current versioned tarballs under `packages/*`.
21+
* Run after `yarn build:tarball` at the repo root (or from CI after restoring the tarball cache).
22+
*/
23+
export function syncPackedTarballSymlinks(): void {
24+
const { version } = readJson<{ version: string }>(path.join(e2eTestsRoot, 'package.json'));
25+
26+
fs.mkdirSync(packedDir, { recursive: true });
27+
28+
for (const entry of fs.readdirSync(packedDir, { withFileTypes: true })) {
29+
if (!entry.name.endsWith('-packed.tgz')) {
30+
continue;
31+
}
32+
fs.rmSync(path.join(packedDir, entry.name), { recursive: true, force: true });
33+
}
34+
35+
const packageJsonPaths = globSync('packages/*/package.json', {
36+
cwd: repositoryRoot,
37+
absolute: true,
38+
});
39+
40+
let linked = 0;
41+
for (const packageJsonPath of packageJsonPaths) {
42+
const pkg = readJson<{ name?: string }>(packageJsonPath);
43+
const name = pkg.name;
44+
if (!name || (!name.startsWith('@sentry/') && !name.startsWith('@sentry-internal/'))) {
45+
continue;
46+
}
47+
48+
const packageDir = path.dirname(packageJsonPath);
49+
const packageDirName = path.basename(packageDir);
50+
const expectedTarball = path.join(packageDir, versionedTarballFilename(name, version));
51+
52+
if (!fs.existsSync(expectedTarball)) {
53+
continue;
54+
}
55+
56+
const linkName = packedSymlinkFilename(name);
57+
const linkPath = path.join(packedDir, linkName);
58+
const target = relativeTarballPathFromPackedDir(packageDirName, name, version);
59+
60+
fs.symlinkSync(target, linkPath);
61+
linked++;
62+
}
63+
64+
if (linked === 0) {
65+
throw new Error(
66+
`No packed tarballs found for version ${version} under packages/*/. Run "yarn build:tarball" at the repository root.`,
67+
);
68+
}
69+
70+
console.log(`Linked ${linked} tarball symlinks in ${path.relative(repositoryRoot, packedDir) || 'packed'}.`);
71+
}

0 commit comments

Comments
 (0)