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
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 @@ -961,18 +961,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 @@ -1071,18 +1077,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
6 changes: 4 additions & 2 deletions dev-packages/e2e-tests/ciCopyToTemp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ async function run(): Promise<void> {
await copyToTemp(originalPath, tmpDirPath);
}

// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();
run().catch(error => {
console.error(error);
process.exit(1);
});
20 changes: 20 additions & 0 deletions dev-packages/e2e-tests/ciPnpmOverrides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* 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));
}

run().catch(error => {
console.error(error);
process.exit(1);
});
29 changes: 18 additions & 11 deletions dev-packages/e2e-tests/lib/copyToTemp.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-console */
import { readFileSync, writeFileSync } from 'fs';
import { cp } from 'fs/promises';
import { join } from 'path';
import { isAbsolute, join, resolve } from 'path';

export async function copyToTemp(originalPath: string, tmpDirPath: string): Promise<void> {
// copy files to tmp dir
Expand Down Expand Up @@ -35,7 +35,7 @@ function fixPackageJson(cwd: string): void {
const extendsPath = packageJson.volta.extends;
// We add a virtual dir to ensure that the relative depth is consistent
// dirPath is relative to ./../test-applications/xxx
const newPath = join(__dirname, 'virtual-dir/', extendsPath);
const newPath = resolve(__dirname, 'virtual-dir/', extendsPath);
packageJson.volta.extends = newPath;
console.log(`Fixed volta.extends to ${newPath}`);
} else {
Expand All @@ -45,17 +45,24 @@ function fixPackageJson(cwd: string): void {
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
}

function fixFileLinkDependencies(dependencyObj: Record<string, string>): void {
// Exported for pnpmOverrides as well
export function fixFileLinkDependencies(dependencyObj: Record<string, string>): void {
for (const [key, value] of Object.entries(dependencyObj)) {
if (value.startsWith('link:')) {
const dirPath = value.replace('link:', '');

// We add a virtual dir to ensure that the relative depth is consistent
// dirPath is relative to ./../test-applications/xxx
const newPath = join(__dirname, 'virtual-dir/', dirPath);
const prefix = value.startsWith('link:') ? 'link:' : value.startsWith('file:') ? 'file:' : null;
if (!prefix) {
continue;
}

dependencyObj[key] = `link:${newPath}`;
console.log(`Fixed ${key} dependency to ${newPath}`);
const dirPath = value.slice(prefix.length);
if (isAbsolute(dirPath)) {
continue;
}

// We add a virtual dir to ensure that the relative depth is consistent
// dirPath is relative to ./../test-applications/xxx
const absPath = resolve(__dirname, 'virtual-dir', dirPath);

dependencyObj[key] = `${prefix}${absPath}`;
console.log(`Fixed ${key} dependency to ${absPath}`);
}
}
60 changes: 60 additions & 0 deletions dev-packages/e2e-tests/lib/packedTarballUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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`;
}

/**
* 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;
}
43 changes: 43 additions & 0 deletions dev-packages/e2e-tests/lib/pnpmOverrides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { readFile, writeFile } from 'fs/promises';
import * as path from 'path';
import { getPublishedSentryTarballPackageNames, packedSymlinkFilename } from './packedTarballUtils';
import { fixFileLinkDependencies } from './copyToTemp';

/**
* 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)}`;
}

const fixedOverrides = packageJson.pnpm?.overrides ?? {};
fixFileLinkDependencies(fixedOverrides);

packageJson.pnpm = {
...packageJson.pnpm,
overrides: {
...overrides,
...fixedOverrides,
},
Comment on lines +33 to +36
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The merge order for pnpm.overrides is incorrect. Existing overrides from package.json are applied after the new tarball overrides, causing the new ones to be ignored on key conflicts.
Severity: MEDIUM

Suggested Fix

Reverse the spread operator order in the overrides object to be { ...fixedOverrides, ...overrides }. This ensures that the newly generated tarball overrides will correctly take precedence over any pre-existing overrides in the test application's package.json.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: dev-packages/e2e-tests/lib/pnpmOverrides.ts#L33-L36

Potential issue: In `dev-packages/e2e-tests/lib/pnpmOverrides.ts`, the function
responsible for injecting pnpm overrides merges objects in an incorrect order. The newly
generated tarball overrides (`overrides`) are spread into the final object before the
existing overrides from the test application's `package.json` (`fixedOverrides`). Due to
how JavaScript's spread syntax works, properties from the last object overwrite earlier
ones. This causes existing overrides in test applications to incorrectly take precedence
over the intended tarball overrides, which undermines the goal of testing with packed
tarballs.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is expected, we need to be able to override this.

};
Comment thread
cursor[bot] marked this conversation as resolved.

// 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.

Loading
Loading