feat(core): support yarn berry in CNW (#11528)

This commit is contained in:
Miroslav Jonaš 2022-08-11 19:37:53 +02:00 committed by GitHub
parent 164111b793
commit 36213b71fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 26 deletions

View File

@ -70,7 +70,37 @@ To publish packages to a local registry, do the following:
- Run `cd ./tmp` in Terminal 2 - Run `cd ./tmp` in Terminal 2
- Run `npx create-nx-workspace@999.9.9` in Terminal 2 - Run `npx create-nx-workspace@999.9.9` in Terminal 2
If you have problems publishing, make sure you use Node 14 and NPM 6 instead of Node 15 and NPM 7. If you have problems publishing, make sure you use Node 16 and NPM 6 or 8.
### Publishing for Yarn 2+ (Berry)
Yarn Berry operates slightly differently than Yarn Classic. In order to publish packages for Berry follow next steps:
- Run `yarn set version berry` to switch to latest Yarn version.
- Create `.yarnrc.yml` in root with following contents:
```yml
nodeLinker: node-modules
npmRegistryServer: 'http://localhost:4873'
unsafeHttpWhitelist:
- localhost
```
- Run `yarn local-registry start` in Terminal 1 (keep it running)
- If you are creating nx workspace outside of your nx repo, make sure to add npm registry info to your root yarnrc (usually in ~/.yarnrc.yml). The file should look something like this:
```yml
npmRegistries:
'https://registry.yarnpkg.com':
npmAuthToken: npm_******************
yarnPath: .yarn/releases/yarn-3.2.2.cjs
npmRegistryServer: 'http://localhost:4873'
unsafeHttpWhitelist:
- localhost
```
- Run `yarn nx-release --local` in Terminal 2 to publish next minor version. If this version already exists, you can bump the minor version in `lerna.json` to toggle the next minor. The output will report the version of published packages.
- Go to your target folder (e.g. `cd ./tmp`) in Terminal 2
- Run `yarn dlx create-nx-workspace@123.4.5` in Terminal 2 (replace `123.4.5` with the version that got published).
### Running Unit Tests ### Running Unit Tests

View File

@ -13,6 +13,7 @@ import {
getPackageManagerVersion, getPackageManagerVersion,
PackageManager, PackageManager,
packageManagerList, packageManagerList,
generatePackageManagerFiles,
} from './package-manager'; } from './package-manager';
import { validateNpmPackage } from './validate-npm-package'; import { validateNpmPackage } from './validate-npm-package';
import { deduceDefaultBase } from './default-base'; import { deduceDefaultBase } from './default-base';
@ -720,8 +721,9 @@ async function createSandbox(packageManager: PackageManager) {
license: 'MIT', license: 'MIT',
}) })
); );
generatePackageManagerFiles(tmpDir, packageManager);
await execAndWait(`${install} --silent --ignore-scripts`, tmpDir); await execAndWait(install, tmpDir);
installSpinner.succeed(); installSpinner.succeed();
} catch (e) { } catch (e) {

View File

@ -1,5 +1,5 @@
import { execSync } from 'child_process'; import { execSync } from 'child_process';
import { existsSync } from 'fs'; import { existsSync, writeFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
/* /*
@ -37,21 +37,27 @@ export function getPackageManagerCommand(
install: string; install: string;
exec: string; exec: string;
} { } {
const [pmMajor, pmMinor] =
getPackageManagerVersion(packageManager).split('.');
switch (packageManager) { switch (packageManager) {
case 'yarn': case 'yarn':
const useBerry = +pmMajor >= 2;
const installCommand = 'yarn install --silent';
return { return {
install: 'yarn', install: useBerry
? installCommand
: `${installCommand} --ignore-scripts`,
exec: 'yarn', exec: 'yarn',
}; };
case 'pnpm': case 'pnpm':
const [major, minor] = getPackageManagerVersion('pnpm').split('.');
let useExec = false; let useExec = false;
if ((+major >= 6 && +minor >= 13) || +major >= 7) { if ((+pmMajor >= 6 && +pmMinor >= 13) || +pmMajor >= 7) {
useExec = true; useExec = true;
} }
return { return {
install: 'pnpm install --no-frozen-lockfile', // explicitly disable in case of CI install: 'pnpm install --no-frozen-lockfile --silent --ignore-scripts',
exec: useExec ? 'pnpm exec' : 'pnpx', exec: useExec ? 'pnpm exec' : 'pnpx',
}; };
@ -59,12 +65,29 @@ export function getPackageManagerCommand(
process.env.npm_config_legacy_peer_deps = process.env.npm_config_legacy_peer_deps =
process.env.npm_config_legacy_peer_deps ?? 'true'; process.env.npm_config_legacy_peer_deps ?? 'true';
return { return {
install: 'npm install', install: 'npm install --silent --ignore-scripts',
exec: 'npx', exec: 'npx',
}; };
} }
} }
export function generatePackageManagerFiles(
root: string,
packageManager: PackageManager = detectPackageManager()
) {
const [pmMajor] = getPackageManagerVersion(packageManager).split('.');
switch (packageManager) {
case 'yarn':
if (+pmMajor >= 2) {
writeFileSync(
join(root, '.yarnrc.yml'),
'nodeLinker: node-modules\nenableScripts: false'
);
}
break;
}
}
export function getPackageManagerVersion( export function getPackageManagerVersion(
packageManager: PackageManager packageManager: PackageManager
): string { ): string {

View File

@ -13,7 +13,17 @@ import { ProjectConverter } from './project-converter';
/** /**
* Don't run actual child_process implementation of installPackagesTask() * Don't run actual child_process implementation of installPackagesTask()
*/ */
jest.mock('child_process'); jest.mock('child_process', () => {
return {
...jest.requireActual<any>('child_process'),
execSync: jest.fn((command: string) => {
if (command.includes('yarn --version')) {
return '1.22.0';
}
return;
}),
};
});
/** /**
* Don't run the conversion util, it touches the file system and has its own tests * Don't run the conversion util, it touches the file system and has its own tests

View File

@ -4,8 +4,8 @@ import { remove } from 'fs-extra';
import { dirname, join } from 'path'; import { dirname, join } from 'path';
import { dirSync } from 'tmp'; import { dirSync } from 'tmp';
import { promisify } from 'util'; import { promisify } from 'util';
import { readJsonFile, writeJsonFile } from './fileutils'; import { writeJsonFile } from './fileutils';
import { PackageJson, readModulePackageJson } from './package-json'; import { readModulePackageJson } from './package-json';
import { gte, lt } from 'semver'; import { gte, lt } from 'semver';
const execAsync = promisify(exec); const execAsync = promisify(exec);
@ -49,16 +49,23 @@ export function getPackageManagerCommand(
packageManager: PackageManager = detectPackageManager() packageManager: PackageManager = detectPackageManager()
): PackageManagerCommands { ): PackageManagerCommands {
const commands: { [pm in PackageManager]: () => PackageManagerCommands } = { const commands: { [pm in PackageManager]: () => PackageManagerCommands } = {
yarn: () => ({ yarn: () => {
const yarnVersion = getPackageManagerVersion('yarn');
const useBerry = gte(yarnVersion, '2.0.0');
return {
install: 'yarn', install: 'yarn',
ciInstall: 'yarn --frozen-lockfile', ciInstall: useBerry
add: 'yarn add -W', ? 'yarn install --immutable'
addDev: 'yarn add -D -W', : 'yarn install --frozen-lockfile',
add: useBerry ? 'yarn add' : 'yarn add -W',
addDev: useBerry ? 'yarn add -D' : 'yarn add -D -W',
rm: 'yarn remove', rm: 'yarn remove',
exec: 'yarn', exec: useBerry ? 'yarn exec' : 'yarn',
run: (script: string, args: string) => `yarn ${script} ${args}`, run: (script: string, args: string) => `yarn ${script} ${args}`,
list: 'yarn list', list: useBerry ? 'yarn info --name-only' : 'yarn list',
}), };
},
pnpm: () => { pnpm: () => {
const pnpmVersion = getPackageManagerVersion('pnpm'); const pnpmVersion = getPackageManagerVersion('pnpm');
const useExec = gte(pnpmVersion, '6.13.0'); const useExec = gte(pnpmVersion, '6.13.0');

View File

@ -28,7 +28,7 @@ jobs:
pool: pool:
vmImage: 'ubuntu-latest' vmImage: 'ubuntu-latest'
steps: steps:
- script: yarn --frozen-lockfile - script: yarn install --frozen-lockfile
displayName: NPM Install Dependencies displayName: NPM Install Dependencies
- script: npx nx-cloud start-agent - script: npx nx-cloud start-agent
displayName: Start Nx-Cloud agent displayName: Start Nx-Cloud agent
@ -38,7 +38,7 @@ jobs:
pool: pool:
vmImage: 'ubuntu-latest' vmImage: 'ubuntu-latest'
steps: steps:
- script: yarn --frozen-lockfile - script: yarn install --frozen-lockfile
displayName: NPM Install Dependencies displayName: NPM Install Dependencies
- script: yarn nx-cloud start-ci-run - script: yarn nx-cloud start-ci-run
displayName: Start CI run displayName: Start CI run
@ -75,7 +75,7 @@ jobs:
- checkout - checkout
- run: - run:
name: Install dependencies name: Install dependencies
command: yarn --frozen-lockfile command: yarn install --frozen-lockfile
- run: - run:
name: Start the agent << parameters.ordinal >> name: Start the agent << parameters.ordinal >>
command: yarn nx-cloud start-agent command: yarn nx-cloud start-agent
@ -89,7 +89,7 @@ jobs:
- checkout - checkout
- run: - run:
name: Install dependencies name: Install dependencies
command: yarn --frozen-lockfile command: yarn install --frozen-lockfile
- nx/set-shas: - nx/set-shas:
main-branch-name: 'main' main-branch-name: 'main'
- run: - run:

View File

@ -6,6 +6,8 @@ import {
names, names,
writeJson, writeJson,
formatFiles, formatFiles,
getPackageManagerVersion,
PackageManager,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { Schema } from './schema'; import { Schema } from './schema';
import { import {
@ -94,6 +96,14 @@ function createNpmrc(host: Tree, options: Schema) {
); );
} }
// ensure that yarn (berry) install uses classic node linker
function createYarnrcYml(host: Tree, options: Schema) {
host.write(
join(options.directory, '.yarnrc.yml'),
'nodeLinker: node-modules\n'
);
}
function formatWorkspaceJson(host: Tree, options: Schema) { function formatWorkspaceJson(host: Tree, options: Schema) {
const path = join( const path = join(
options.directory, options.directory,
@ -151,8 +161,13 @@ export async function workspaceGenerator(host: Tree, options: Schema) {
if (options.cli === 'angular') { if (options.cli === 'angular') {
decorateAngularClI(host, options); decorateAngularClI(host, options);
} }
if (options.packageManager === 'pnpm') { const [packageMajor] = getPackageManagerVersion(
options.packageManager as PackageManager
).split('.');
if (options.packageManager === 'pnpm' && +packageMajor >= 7) {
createNpmrc(host, options); createNpmrc(host, options);
} else if (options.packageManager === 'yarn' && +packageMajor >= 2) {
createYarnrcYml(host, options);
} }
setPresetProperty(host, options); setPresetProperty(host, options);
addNpmScripts(host, options); addNpmScripts(host, options);