348 lines
13 KiB
TypeScript
348 lines
13 KiB
TypeScript
import { NxJsonConfiguration } from '@nx/devkit';
|
|
import {
|
|
cleanupProject,
|
|
getPackageManagerCommand,
|
|
newProject,
|
|
readJson,
|
|
runCLI,
|
|
runCommandAsync,
|
|
tmpProjPath,
|
|
uniq,
|
|
updateFile,
|
|
updateJson,
|
|
} from '@nx/e2e/utils';
|
|
import { execSync } from 'node:child_process';
|
|
import { join } from 'node:path';
|
|
|
|
expect.addSnapshotSerializer({
|
|
serialize(str: string) {
|
|
return (
|
|
str
|
|
// Remove all output unique to specific projects to ensure deterministic snapshots
|
|
.replaceAll(/my-pkg-\d+/g, '{project-name}')
|
|
.replaceAll(
|
|
/integrity:\s*.*/g,
|
|
'integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
|
)
|
|
.replaceAll(/\b[0-9a-f]{40}\b/g, '{SHASUM}')
|
|
.replaceAll(/\d*B index\.js/g, 'XXB index.js')
|
|
.replaceAll(/\d*B\s+project\.json/g, 'XXB project.json')
|
|
.replaceAll(/\d*B\s+package\.json/g, 'XXXB package.json')
|
|
.replaceAll(/size:\s*\d*\s?B/g, 'size: XXXB')
|
|
.replaceAll(/\d*\.\d*\s?kB/g, 'XXX.XXX kb')
|
|
.replaceAll(/\d*B\s+src\//g, 'XXB src/')
|
|
.replaceAll(/\d*B\s+index/g, 'XXB index')
|
|
.replaceAll(/total files:\s+\d*/g, 'total files: X')
|
|
.replaceAll(/\d*B\s+README.md/g, 'XXB README.md')
|
|
.replaceAll(/Test @[\w\d]+/g, 'Test @{COMMIT_AUTHOR}')
|
|
.replaceAll(/(\w+) lock file/g, 'PM lock file')
|
|
// Normalize the version title date.
|
|
.replaceAll(/\(\d{4}-\d{2}-\d{2}\)/g, '(YYYY-MM-DD)')
|
|
// We trim each line to reduce the chances of snapshot flakiness
|
|
|
|
// Slightly different handling needed for bun (length can be 8)
|
|
.replaceAll(/[a-fA-F0-9]{7,8}/g, '{COMMIT_SHA}')
|
|
.replaceAll(/bun publish v\d+\.\d+\.\d+/g, 'bun publish vX.X.X')
|
|
.replaceAll(
|
|
/Integrity:\s*.*/g,
|
|
'Integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
|
)
|
|
|
|
.split('\n')
|
|
.map((r) => r.trim())
|
|
.filter(Boolean)
|
|
.join('\n')
|
|
);
|
|
},
|
|
test(val: string) {
|
|
return val != null && typeof val === 'string';
|
|
},
|
|
});
|
|
|
|
describe('nx release preserve local dependency protocols', () => {
|
|
let previousPackageManager: string;
|
|
let e2eRegistryUrl: string;
|
|
|
|
beforeAll(() => {
|
|
previousPackageManager = process.env.SELECTED_PM;
|
|
// This is the verdaccio instance that the e2e tests themselves are working from
|
|
e2eRegistryUrl = execSync('npm config get registry').toString().trim();
|
|
});
|
|
|
|
afterEach(() => cleanupProject());
|
|
|
|
afterAll(() => {
|
|
process.env.SELECTED_PM = previousPackageManager;
|
|
});
|
|
|
|
/**
|
|
* Initialize each test with a fresh workspace using the specified
|
|
* package manager.
|
|
*/
|
|
const initializeProject = async (packageManager: 'pnpm' | 'bun') => {
|
|
process.env.SELECTED_PM = packageManager;
|
|
|
|
console.log(`Creating workspace with package manager: ${packageManager}`);
|
|
|
|
newProject({
|
|
packages: ['@nx/js'],
|
|
packageManager,
|
|
});
|
|
|
|
const pkg1 = uniq('my-pkg-1');
|
|
runCLI(`generate @nx/workspace:npm-package ${pkg1}`);
|
|
const pkg2 = uniq('my-pkg-2');
|
|
runCLI(`generate @nx/workspace:npm-package ${pkg2}`);
|
|
|
|
// Set up a workspace dependency using the workspace protocol
|
|
updateJson(join(pkg1, 'package.json'), (packageJson) => {
|
|
packageJson.dependencies = {
|
|
[`@proj/${pkg2}`]: 'workspace:*',
|
|
};
|
|
return packageJson;
|
|
});
|
|
|
|
// Add workspaces config
|
|
if (packageManager === 'pnpm') {
|
|
updateFile('pnpm-workspace.yaml', `packages:\n - ${pkg1}\n - ${pkg2}\n`);
|
|
} else {
|
|
updateJson('package.json', (packageJson) => {
|
|
packageJson.workspaces = [pkg1, pkg2];
|
|
return packageJson;
|
|
});
|
|
}
|
|
|
|
// workaround for NXC-143
|
|
runCLI('reset');
|
|
|
|
await runCommandAsync(getPackageManagerCommand({ packageManager }).install);
|
|
|
|
return { workspacePath: tmpProjPath(), pkg1, pkg2 };
|
|
};
|
|
|
|
it('should replace local dependency protocols with the actual version number when version.preserveLocalDependencyProtocols is set to false', async () => {
|
|
// The package manager currently does not matter for the versioning behavior, it's imperatively controlled by the user
|
|
const { workspacePath } = await initializeProject('pnpm');
|
|
|
|
updateJson<NxJsonConfiguration>('nx.json', (nxJson) => {
|
|
nxJson.release = {
|
|
version: {
|
|
preserveLocalDependencyProtocols: false,
|
|
},
|
|
};
|
|
return nxJson;
|
|
});
|
|
|
|
// Show the dependency being updated
|
|
expect(runCLI(`release version minor -d --verbose`, { cwd: workspacePath }))
|
|
.toMatchInlineSnapshot(`
|
|
NX Running release version for project: {project-name}
|
|
{project-name} 📄 Resolved the current version as 0.0.0 from manifest: {project-name}/package.json
|
|
{project-name} ❓ Applied semver relative bump "minor", from the given specifier, to get new version 0.1.0
|
|
{project-name} ✍️ New version 0.1.0 written to manifest: {project-name}/package.json
|
|
{project-name} ✍️ Updated 1 dependency in manifest: {project-name}/package.json
|
|
NX Running release version for project: {project-name}
|
|
{project-name} 📄 Resolved the current version as 0.0.0 from manifest: {project-name}/package.json
|
|
{project-name} ❓ Applied version 0.1.0 directly, because the project is a member of a fixed release group containing {project-name}
|
|
{project-name} ✍️ New version 0.1.0 written to manifest: {project-name}/package.json
|
|
"name": "@proj/{project-name}",
|
|
- "version": "0.0.0",
|
|
+ "version": "0.1.0",
|
|
"scripts": {
|
|
"dependencies": {
|
|
- "@proj/{project-name}": "workspace:*"
|
|
+ "@proj/{project-name}": "0.1.0"
|
|
}
|
|
}
|
|
+
|
|
"name": "@proj/{project-name}",
|
|
- "version": "0.0.0",
|
|
+ "version": "0.1.0",
|
|
"scripts": {
|
|
NX Updating PM lock file
|
|
Would update pnpm-lock.yaml with the following command, but --dry-run was set:
|
|
pnpm install --lockfile-only
|
|
NX Staging changed files with git
|
|
Would stage files in git with the following command, but --dry-run was set:
|
|
git add {project-name}/package.json {project-name}/package.json
|
|
`);
|
|
});
|
|
|
|
it('should preserve local dependency protocols when version.preserveLocalDependencyProtocols is not set to false', async () => {
|
|
// The package manager currently does not matter for the versioning behavior, it's imperatively controlled by the user
|
|
const { workspacePath } = await initializeProject('pnpm');
|
|
|
|
updateJson<NxJsonConfiguration>('nx.json', (nxJson) => {
|
|
nxJson.release = {
|
|
version: {},
|
|
};
|
|
return nxJson;
|
|
});
|
|
|
|
// Show that the dependency has not been updated
|
|
expect(runCLI(`release version minor -d --verbose`, { cwd: workspacePath }))
|
|
.toMatchInlineSnapshot(`
|
|
NX Running release version for project: {project-name}
|
|
{project-name} 📄 Resolved the current version as 0.0.0 from manifest: {project-name}/package.json
|
|
{project-name} ❓ Applied semver relative bump "minor", from the given specifier, to get new version 0.1.0
|
|
{project-name} ✍️ New version 0.1.0 written to manifest: {project-name}/package.json
|
|
NX Running release version for project: {project-name}
|
|
{project-name} 📄 Resolved the current version as 0.0.0 from manifest: {project-name}/package.json
|
|
{project-name} ❓ Applied version 0.1.0 directly, because the project is a member of a fixed release group containing {project-name}
|
|
{project-name} ✍️ New version 0.1.0 written to manifest: {project-name}/package.json
|
|
"name": "@proj/{project-name}",
|
|
- "version": "0.0.0",
|
|
+ "version": "0.1.0",
|
|
"scripts": {
|
|
}
|
|
+
|
|
"name": "@proj/{project-name}",
|
|
- "version": "0.0.0",
|
|
+ "version": "0.1.0",
|
|
"scripts": {
|
|
NX Updating PM lock file
|
|
Would update pnpm-lock.yaml with the following command, but --dry-run was set:
|
|
pnpm install --lockfile-only
|
|
NX Staging changed files with git
|
|
Would stage files in git with the following command, but --dry-run was set:
|
|
git add {project-name}/package.json {project-name}/package.json
|
|
`);
|
|
});
|
|
|
|
describe('pnpm publish', () => {
|
|
it('should replace local dependency protocols dynamically during publishing', async () => {
|
|
const { workspacePath, pkg1 } = await initializeProject('pnpm');
|
|
|
|
// Prove that the local dependency protocol is present in the pkg1 package.json
|
|
expect(readJson(join(workspacePath, pkg1, 'package.json')))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
dependencies: {
|
|
@proj/{project-name}: workspace:*,
|
|
},
|
|
name: @proj/{project-name},
|
|
scripts: {
|
|
test: node index.js,
|
|
},
|
|
version: 0.0.0,
|
|
}
|
|
`);
|
|
|
|
// Publish the packages
|
|
expect(
|
|
runCLI(`release publish`, { silenceError: true, cwd: workspacePath })
|
|
).toMatchInlineSnapshot(`
|
|
NX Running target nx-release-publish for 2 projects:
|
|
- {project-name}
|
|
- {project-name}
|
|
> nx run {project-name}:nx-release-publish
|
|
📦 @proj/{project-name}@0.0.0
|
|
=== Tarball Contents ===
|
|
XXXXB index.js
|
|
XXXB package.json
|
|
XXB project.json
|
|
=== Tarball Details ===
|
|
name: @proj/{project-name}
|
|
version: 0.0.0
|
|
filename: proj-{project-name}-0.0.0.tgz
|
|
package size: XXXB
|
|
unpacked size: XXXB
|
|
shasum: {SHASUM}
|
|
integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
total files: X
|
|
Published to ${e2eRegistryUrl} with tag "latest"
|
|
> nx run {project-name}:nx-release-publish
|
|
📦 @proj/{project-name}@0.0.0
|
|
=== Tarball Contents ===
|
|
XXXXB index.js
|
|
XXXB package.json
|
|
XXB project.json
|
|
=== Tarball Details ===
|
|
name: @proj/{project-name}
|
|
version: 0.0.0
|
|
filename: proj-{project-name}-0.0.0.tgz
|
|
package size: XXXB
|
|
unpacked size: XXXB
|
|
shasum: {SHASUM}
|
|
integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
total files: X
|
|
Published to ${e2eRegistryUrl} with tag "latest"
|
|
NX Successfully ran target nx-release-publish for 2 projects
|
|
`);
|
|
|
|
// Ensure that the dependency on pkg2 specified on the registry was replaced with the actual version number during publishing
|
|
expect(
|
|
(await runCommandAsync(`npm view @proj/${pkg1} dependencies`))
|
|
.combinedOutput
|
|
).toMatchInlineSnapshot(`{ '@proj/{project-name}': '0.0.0' }`);
|
|
});
|
|
});
|
|
|
|
describe('bun publish', () => {
|
|
it('should replace local dependency protocols dynamically during publishing', async () => {
|
|
const { workspacePath, pkg1 } = await initializeProject('bun');
|
|
|
|
// Prove that the local dependency protocol is present in the pkg1 package.json
|
|
expect(readJson(join(workspacePath, pkg1, 'package.json')))
|
|
.toMatchInlineSnapshot(`
|
|
{
|
|
dependencies: {
|
|
@proj/{project-name}: workspace:*,
|
|
},
|
|
name: @proj/{project-name},
|
|
scripts: {
|
|
test: node index.js,
|
|
},
|
|
version: 0.0.0,
|
|
}
|
|
`);
|
|
|
|
// Publish the packages
|
|
expect(
|
|
runCLI(`release publish`, { silenceError: true, cwd: workspacePath })
|
|
).toMatchInlineSnapshot(`
|
|
NX Running target nx-release-publish for 2 projects:
|
|
- {project-name}
|
|
- {project-name}
|
|
> nx run {project-name}:nx-release-publish
|
|
bun publish vX.X.X ({COMMIT_SHA})
|
|
packed XXXB package.json
|
|
packed XXB index.js
|
|
packed XXB project.json
|
|
Total files: 3
|
|
Shasum: {SHASUM}
|
|
Integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
Unpacked size: XXXB
|
|
Packed size: XXXB
|
|
Tag: latest
|
|
Access: default
|
|
Registry: ${e2eRegistryUrl}
|
|
+ @proj/{project-name}@0.0.0
|
|
Published to ${e2eRegistryUrl} with tag "latest"
|
|
> nx run {project-name}:nx-release-publish
|
|
bun publish vX.X.X ({COMMIT_SHA})
|
|
packed XXXB package.json
|
|
packed XXB index.js
|
|
packed XXB project.json
|
|
Total files: 3
|
|
Shasum: {SHASUM}
|
|
Integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
Unpacked size: XXXB
|
|
Packed size: XXXB
|
|
Tag: latest
|
|
Access: default
|
|
Registry: ${e2eRegistryUrl}
|
|
+ @proj/{project-name}@0.0.0
|
|
Published to ${e2eRegistryUrl} with tag "latest"
|
|
NX Successfully ran target nx-release-publish for 2 projects
|
|
`);
|
|
|
|
// Ensure that the dependency on pkg2 specified on the registry was replaced with the actual version number during publishing
|
|
expect(
|
|
(await runCommandAsync(`npm view @proj/${pkg1} dependencies`))
|
|
.combinedOutput
|
|
).toMatchInlineSnapshot(`{ '@proj/{project-name}': '0.0.0' }`);
|
|
});
|
|
});
|
|
});
|