Skip to content

Commit

Permalink
fix(release): skip lock file update if workspaces are not enabled (#2…
Browse files Browse the repository at this point in the history
  • Loading branch information
fahslaj authored Mar 1, 2024
1 parent 7eec912 commit 8bde48f
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 24 deletions.
1 change: 1 addition & 0 deletions docs/generated/devkit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ It only uses language primitives and immutable objects
- [glob](../../devkit/documents/glob)
- [hashArray](../../devkit/documents/hashArray)
- [installPackagesTask](../../devkit/documents/installPackagesTask)
- [isWorkspacesEnabled](../../devkit/documents/isWorkspacesEnabled)
- [joinPathFragments](../../devkit/documents/joinPathFragments)
- [moveFilesToNewDirectory](../../devkit/documents/moveFilesToNewDirectory)
- [names](../../devkit/documents/names)
Expand Down
16 changes: 16 additions & 0 deletions docs/generated/devkit/isWorkspacesEnabled.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Function: isWorkspacesEnabled

**isWorkspacesEnabled**(`packageManager?`, `root?`): `boolean`

Returns true if the workspace is using npm workspaces, yarn workspaces, or pnpm workspaces.

#### Parameters

| Name | Type | Default value | Description |
| :--------------- | :-------------------------------------------------------- | :-------------- | :------------------------------------------------------------------------------------------ |
| `packageManager` | [`PackageManager`](../../devkit/documents/PackageManager) | `undefined` | The package manager to use. If not provided, it will be detected based on the lock file. |
| `root` | `string` | `workspaceRoot` | The directory the commands will be ran inside of. Defaults to the current workspace's root. |

#### Returns

`boolean`
1 change: 1 addition & 0 deletions docs/generated/packages/devkit/documents/nx_devkit.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ It only uses language primitives and immutable objects
- [glob](../../devkit/documents/glob)
- [hashArray](../../devkit/documents/hashArray)
- [installPackagesTask](../../devkit/documents/installPackagesTask)
- [isWorkspacesEnabled](../../devkit/documents/isWorkspacesEnabled)
- [joinPathFragments](../../devkit/documents/joinPathFragments)
- [moveFilesToNewDirectory](../../devkit/documents/moveFilesToNewDirectory)
- [names](../../devkit/documents/names)
Expand Down
28 changes: 5 additions & 23 deletions e2e/release/src/independent-projects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,6 @@ describe('nx release - independent projects', () => {
"scripts": {
NX Updating {package-manager} lock file
NX Staging changed files with git
Expand Down Expand Up @@ -174,9 +171,6 @@ describe('nx release - independent projects', () => {
+
NX Updating {package-manager} lock file
NX Staging changed files with git
Expand Down Expand Up @@ -213,9 +207,6 @@ describe('nx release - independent projects', () => {
}
NX Updating {package-manager} lock file
NX Staging changed files with git
Expand Down Expand Up @@ -255,15 +246,12 @@ describe('nx release - independent projects', () => {
"scripts": {
NX Updating {package-manager} lock file
Updating {lock-file} with the following command:
{lock-file-command}
Skipped lock file update because {package-manager} workspaces are not enabled.
NX Committing changes with git
Staging files in git with the following command:
git add {project-name}/package.json {lock-file}
git add {project-name}/package.json
Committing files in git with the following command:
git commit --message chore(release): publish --message - project: {project-name} 999.9.9-version-git-operations-test.2
Expand Down Expand Up @@ -363,20 +351,14 @@ describe('nx release - independent projects', () => {
"scripts": {
NX Updating {package-manager} lock file
Updating {lock-file} with the following command:
{lock-file-command}
NX Updating {package-manager} lock file
Skipped lock file update because {package-manager} workspaces are not enabled.
Updating {lock-file} with the following command:
{lock-file-command}
Skipped lock file update because {package-manager} workspaces are not enabled.
NX Committing changes with git
Staging files in git with the following command:
git add {project-name}/package.json {project-name}/package.json {project-name}/package.json {lock-file}
git add {project-name}/package.json {project-name}/package.json {project-name}/package.json
Committing files in git with the following command:
git commit --message chore(release): publish --message - project: {project-name} 999.9.9-version-git-operations-test.3 --message - project: {project-name} 999.9.9-version-git-operations-test.3 --message - release-group: fixed 999.9.9-version-git-operations-test.3
Expand Down
39 changes: 39 additions & 0 deletions e2e/release/src/lock-file-updates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ describe('nx release lock file updates', () => {
it('should update package-lock.json when package manager is npm', async () => {
initializeProject('npm');

updateJson('package.json', (json) => {
json.workspaces = [pkg1, pkg2, pkg3];
return json;
});

runCommand(`npm install`);

// workaround for NXC-143
Expand All @@ -116,6 +121,40 @@ describe('nx release lock file updates', () => {
`);
});

it('should not update package-lock.json when package manager is npm and workspaces are not enabled', async () => {
initializeProject('npm');

updateJson('package.json', (json) => {
delete json.workspaces;
return json;
});

runCommand(`npm install`);

// workaround for NXC-143
runCLI('reset');

runCommand(`git add .`);
runCommand(`git commit -m "chore: initial commit"`);

const versionOutput = runCLI(`release version 999.9.9 --verbose`);

expect(
versionOutput.match(
/Skipped lock file update because npm workspaces are not enabled./g
).length
).toBe(1);

const filesChanges = runCommand('git diff --name-only HEAD');

expect(filesChanges).toMatchInlineSnapshot(`
{project-name}/package.json
{project-name}/package.json
{project-name}/package.json
`);
});

it('should not update lock file when package manager is yarn classic', async () => {
initializeProject('yarn');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
detectPackageManager,
getPackageManagerCommand,
getPackageManagerVersion,
isWorkspacesEnabled,
output,
} from '@nx/devkit';
import { execSync } from 'child_process';
Expand Down Expand Up @@ -46,6 +47,16 @@ export async function updateLockFile(
return [];
}

const workspacesEnabled = isWorkspacesEnabled(packageManager, cwd);
if (!workspacesEnabled) {
if (verbose) {
console.log(
`\nSkipped lock file update because ${packageManager} workspaces are not enabled.`
);
}
return [];
}

const isDaemonEnabled = daemonClient.enabled();
if (!dryRun && isDaemonEnabled) {
// if not in dry-run temporarily stop the daemon, as it will error if the lock file is updated
Expand Down
1 change: 1 addition & 0 deletions packages/nx/src/devkit-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export {
getPackageManagerCommand,
detectPackageManager,
getPackageManagerVersion,
isWorkspacesEnabled,
} from './utils/package-manager';

/**
Expand Down
42 changes: 42 additions & 0 deletions packages/nx/src/utils/package-manager.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as fs from 'fs';
import * as configModule from '../config/configuration';
import * as projectGraphFileUtils from '../project-graph/file-utils';
import {
detectPackageManager,
isWorkspacesEnabled,
modifyYarnRcToFitNewDirectory,
modifyYarnRcYmlToFitNewDirectory,
} from './package-manager';
Expand Down Expand Up @@ -76,6 +78,46 @@ describe('package-manager', () => {
});
});

describe('isWorkspacesEnabled', () => {
it('should return true if package manager is pnpm and pnpm-workspace.yaml exists', () => {
jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true);
expect(isWorkspacesEnabled('pnpm')).toEqual(true);
});

it('should return false if package manager is pnpm and pnpm-workspace.yaml does not exist', () => {
jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false);
expect(isWorkspacesEnabled('pnpm')).toEqual(false);
});

it('should return true if package manager is yarn and workspaces exists in package.json', () => {
jest
.spyOn(projectGraphFileUtils, 'readPackageJson')
.mockReturnValueOnce({ workspaces: ['packages/*'] });
expect(isWorkspacesEnabled('yarn')).toEqual(true);
});

it('should return false if package manager is yarn and workspaces does not exist in package.json', () => {
jest
.spyOn(projectGraphFileUtils, 'readPackageJson')
.mockReturnValueOnce({});
expect(isWorkspacesEnabled('yarn')).toEqual(false);
});

it('should return true if package manager is npm and workspaces exists in package.json', () => {
jest
.spyOn(projectGraphFileUtils, 'readPackageJson')
.mockReturnValueOnce({ workspaces: ['packages/*'] });
expect(isWorkspacesEnabled('npm')).toEqual(true);
});

it('should return false if package manager is npm and workspaces does not exist in package.json', () => {
jest
.spyOn(projectGraphFileUtils, 'readPackageJson')
.mockReturnValueOnce({});
expect(isWorkspacesEnabled('npm')).toEqual(false);
});
});

describe('modifyYarnRcYmlToFitNewDirectory', () => {
it('should update paths properly', () => {
expect(
Expand Down
21 changes: 20 additions & 1 deletion packages/nx/src/utils/package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { gte, lt } from 'semver';
import { dirSync } from 'tmp';
import { promisify } from 'util';
import { readNxJson } from '../config/configuration';
import { readPackageJson } from '../project-graph/file-utils';
import { readFileIfExisting, writeJsonFile } from './fileutils';
import { readModulePackageJson } from './package-json';
import { PackageJson, readModulePackageJson } from './package-json';
import { workspaceRoot } from './workspace-root';

const execAsync = promisify(exec);
Expand Down Expand Up @@ -43,6 +44,24 @@ export function detectPackageManager(dir: string = ''): PackageManager {
);
}

/**
* Returns true if the workspace is using npm workspaces, yarn workspaces, or pnpm workspaces.
* @param packageManager The package manager to use. If not provided, it will be detected based on the lock file.
* @param root The directory the commands will be ran inside of. Defaults to the current workspace's root.
*/
export function isWorkspacesEnabled(
packageManager: PackageManager = detectPackageManager(),
root: string = workspaceRoot
): boolean {
if (packageManager === 'pnpm') {
return existsSync(join(root, 'pnpm-workspace.yaml'));
}

// yarn and pnpm both use the same 'workspaces' property in package.json
const packageJson: PackageJson = readPackageJson();
return !!packageJson?.workspaces;
}

/**
* Returns commands for the package manager used in the workspace.
* By default, the package manager is derived based on the lock file,
Expand Down

0 comments on commit 8bde48f

Please sign in to comment.