diff --git a/.github/workflows/it-tests.yml b/.github/workflows/it-tests.yml index 5d9ede1f26..577c97f22c 100644 --- a/.github/workflows/it-tests.yml +++ b/.github/workflows/it-tests.yml @@ -54,7 +54,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - packageManager: [yarn, npm] + packageManager: [yarn, npm, yarn1] testEnvironment: [o3r-project-with-app] runs-on: ${{ matrix.os }} env: @@ -104,9 +104,19 @@ jobs: npx --yes wait-on http://127.0.0.1:4873 -t 180000 fi shell: bash + - name: Rename .npmrc for yarn 1 + if: matrix.packageManager == 'yarn1' + id: rename-npmrc + run: mv -f .npmrc .npmrc-backup + shell: bash - name: Test id: it-tests run: yarn test-int + - name: Revert .npmrc rename for yarn 1 + if: matrix.packageManager == 'yarn1' + id: revert-rename-npmrc + run: mv -f .npmrc-backup .npmrc + shell: bash - name: Zip generated app on failure if: failure() && steps.it-tests.conclusion == 'failure' run: | diff --git a/packages/@ama-sdk/create/src/index.it.spec.ts b/packages/@ama-sdk/create/src/index.it.spec.ts index 7178fd41e4..078b42a45c 100644 --- a/packages/@ama-sdk/create/src/index.it.spec.ts +++ b/packages/@ama-sdk/create/src/index.it.spec.ts @@ -3,13 +3,14 @@ * @jest-environment @o3r/test-helpers/jest-environment * @jest-environment-o3r-app-folder test-create-sdk * @jest-environment-o3r-type blank + * @jest-environment-o3r-package-scope ama-sdk-create */ const o3rEnvironment = globalThis.o3rEnvironment; import { getDefaultExecSyncOptions, getPackageManager, - getYarnVersionFromRoot, + isYarn1Enforced, packageManagerCreate, packageManagerExec, packageManagerInstall, @@ -26,10 +27,20 @@ const execAppOptions = getDefaultExecSyncOptions(); const packageManager = getPackageManager(); describe('Create new sdk command', () => { - beforeEach(() => { + + const setupLocalTest = (_sdkFolderIndex: number) => { const isYarnTest = packageManager.startsWith('yarn'); - const yarnVersion = isYarnTest ? getYarnVersionFromRoot(process.cwd()) || 'latest' : undefined; + const yarnVersion = o3rEnvironment.testEnvironment.packageManagerConfig.yarnVersion; + // const yarnVersion = isYarnTest ? getYarnVersionFromRoot(process.cwd()) || 'latest' : undefined; sdkFolderPath = o3rEnvironment.testEnvironment.workspacePath; + // const yarnVersion = isYarnTest ? getYarnVersionFromRoot(process.cwd()) || 'latest' : undefined; + // const yarnVersion = globalThis.testEnvironment.packageManagerConfig.yarnVersion; + // sdkFolderPath = globalThis.testEnvironment.workspacePath; + + // const isYarnTest = packageManager.startsWith('yarn'); + // const testEnv = await prepareTestEnv(projectName + sdkFolderIndex, { type: 'blank', packageScope: 'ama-sdk-create' }); + // sdkFolderPath = testEnv.workspacePath; + // const yarnVersion = testEnv.packageManagerConfig.yarnVersion; sdkPackagePath = path.join(sdkFolderPath, sdkPackageName.replace(/^@/, '')); execAppOptions.cwd = sdkFolderPath; @@ -38,32 +49,32 @@ describe('Create new sdk command', () => { packageManagerInstall(execAppOptions); // copy yarnrc config to generated SDK - mkdirSync(sdkPackagePath, {recursive: true}); - cpSync(path.join(sdkFolderPath, '.yarnrc.yml'), path.join(sdkPackagePath, '.yarnrc.yml')); - cpSync(path.join(sdkFolderPath, '.yarn'), path.join(sdkPackagePath, '.yarn'), {recursive: true}); + mkdirSync(sdkPackagePath, { recursive: true }); + const yarnConfigFile = isYarn1Enforced() ? '.yarnrc' : '.yarnrc.yml'; + cpSync(path.join(sdkFolderPath, yarnConfigFile), path.join(sdkPackagePath, yarnConfigFile)); + cpSync(path.join(sdkFolderPath, '.yarn'), path.join(sdkPackagePath, '.yarn'), { recursive: true }); fs.writeFileSync(path.join(sdkPackagePath, 'yarn.lock'), ''); } else { // copy npmrc config to generated SDK mkdirSync(sdkPackagePath, { recursive: true }); cpSync(path.join(sdkFolderPath, '.npmrc'), path.join(sdkPackagePath, '.npmrc')); } - }); - - beforeEach(() => { cpSync(path.join(__dirname, '..', 'testing', 'mocks', 'MOCK_swagger_updated.yaml'), path.join(sdkFolderPath, 'swagger-spec.yml')); - }); + }; test('should generate a full SDK when the specification is provided', () => { + setupLocalTest(1); expect(() => packageManagerCreate({ script: '@ama-sdk', args: ['typescript', sdkPackageName, '--package-manager', packageManager, '--spec-path', path.join(sdkFolderPath, 'swagger-spec.yml')] - }, execAppOptions) + }, execAppOptions, !isYarn1Enforced() ? 'npm' : undefined) ).not.toThrow(); - expect(() => packageManagerRun({script: 'build'}, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow(); + expect(() => packageManagerRun({ script: 'build' }, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow(); }); test('should generate an SDK with no package scope', () => { + setupLocalTest(2); const packageName = sdkPackageName.replace('@', '').split('/')[1]; const newSdkPackagePath = path.join(sdkFolderPath, packageName); renameSync(sdkPackagePath, newSdkPackagePath); @@ -77,7 +88,11 @@ describe('Create new sdk command', () => { }); test('should generate an empty SDK ready to be used', () => { - expect(() => packageManagerCreate({script: '@ama-sdk', args: ['typescript', sdkPackageName]}, execAppOptions)).not.toThrow(); + setupLocalTest(3); + expect(() => packageManagerCreate({ + script: '@ama-sdk', + args: ['typescript', sdkPackageName, '--package-manager', packageManager] + }, execAppOptions, !isYarn1Enforced() ? 'npm' : undefined)).not.toThrow(); expect(() => packageManagerRun({script: 'build'}, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow(); expect(() => packageManagerExec({ @@ -90,20 +105,23 @@ describe('Create new sdk command', () => { }); test('should fail when there is an error', () => { + setupLocalTest(4); expect(() => packageManagerCreate({ script: '@ama-sdk', - args: ['typescript', sdkPackageName, '--package-manager', packageManager, '--spec-path','./missing-file.yml'] - }, execAppOptions) + args: ['typescript', sdkPackageName, '--package-manager', packageManager, '--spec-path', './missing-file.yml'] + }, execAppOptions, !isYarn1Enforced() ? 'npm' : undefined) ).toThrow(); }); test('should use pinned versions when --exact-o3r-version is used', () => { + setupLocalTest(5); + const versionToInstall = isYarn1Enforced() ? '' : `@${o3rEnvironment.testEnvironment.o3rVersion}`; expect(() => packageManagerCreate({ - script: `@ama-sdk@${o3rEnvironment.testEnvironment.o3rVersion}`, + script: `@ama-sdk${versionToInstall}`, args: ['typescript', sdkPackageName, '--exact-o3r-version', '--package-manager', packageManager, '--spec-path', path.join(sdkFolderPath, 'swagger-spec.yml')] - }, execAppOptions) + }, execAppOptions, !isYarn1Enforced() ? 'npm' : undefined) ).not.toThrow(); expect(() => packageManagerRun({script: 'build'}, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow(); const packageJson = JSON.parse(fs.readFileSync(path.join(sdkPackagePath, 'package.json'), 'utf-8')); diff --git a/packages/@o3r/create/src/index.it.spec.ts b/packages/@o3r/create/src/index.it.spec.ts index bde9e52255..5179f9f5ec 100644 --- a/packages/@o3r/create/src/index.it.spec.ts +++ b/packages/@o3r/create/src/index.it.spec.ts @@ -3,12 +3,14 @@ * @jest-environment @o3r/test-helpers/jest-environment * @jest-environment-o3r-app-folder test-create-app * @jest-environment-o3r-type blank + * @jest-environment-o3r-package-scope o3r-create */ const o3rEnvironment = globalThis.o3rEnvironment; import { getDefaultExecSyncOptions, getPackageManager, + isYarn1Enforced, packageManagerCreate, packageManagerExec, packageManagerInstall, @@ -23,7 +25,7 @@ const workspaceProjectName = 'my-project'; describe('Create new otter project command', () => { test('should generate a project with an application', async () => { - const { workspacePath, packageManagerConfig, o3rVersion } = o3rEnvironment.testEnvironment; + const { workspacePath, packageManagerConfig } = o3rEnvironment.testEnvironment; const inAppPath = path.join(workspacePath, workspaceProjectName); const execWorkspaceOptions = {...defaultExecOptions, cwd: workspacePath }; const execInAppOptions = {...defaultExecOptions, cwd: inAppPath }; @@ -33,7 +35,7 @@ describe('Create new otter project command', () => { await fs.mkdir(inAppPath, { recursive: true }); setPackagerManagerConfig(packageManagerConfig, execInAppOptions); - expect(() => packageManagerCreate({ script: `@o3r@${o3rVersion}`, args: [workspaceProjectName, ...createOptions] }, execWorkspaceOptions, 'npm')).not.toThrow(); + expect(() => packageManagerCreate({ script: `@o3r`, args: [workspaceProjectName, ...createOptions] }, execWorkspaceOptions, !isYarn1Enforced() ? 'npm' : undefined)).not.toThrow(); expect(existsSync(path.join(inAppPath, 'angular.json'))).toBe(true); expect(existsSync(path.join(inAppPath, 'package.json'))).toBe(true); expect(() => packageManagerInstall(execInAppOptions)).not.toThrow(); @@ -57,7 +59,7 @@ describe('Create new otter project command', () => { await fs.mkdir(inAppPath, { recursive: true }); setPackagerManagerConfig(packageManagerConfig, execInAppOptions); - expect(() => packageManagerCreate({ script: `@o3r@${o3rVersion}`, args: [workspaceProjectName, ...createOptions] }, execWorkspaceOptions, 'npm')).not.toThrow(); + expect(() => packageManagerCreate({ script: `@o3r`, args: [workspaceProjectName, ...createOptions] }, execWorkspaceOptions, !isYarn1Enforced() ? 'npm' : undefined)).not.toThrow(); expect(existsSync(path.join(inAppPath, 'angular.json'))).toBe(true); expect(existsSync(path.join(inAppPath, 'package.json'))).toBe(true); expect(() => packageManagerInstall(execInAppOptions)).not.toThrow(); diff --git a/packages/@o3r/create/src/index.ts b/packages/@o3r/create/src/index.ts index b67f3fc6d1..f5f50b5c1c 100644 --- a/packages/@o3r/create/src/index.ts +++ b/packages/@o3r/create/src/index.ts @@ -201,14 +201,14 @@ const prepareWorkspace = (relativeDirectory = '.', projectPackageManager = 'npm' cwd })); }; - +const isYarn1 = packageManager === 'yarn' && argv['yarn-version']?.split('.')[0] === '1'; const addOtterFramework = (relativeDirectory = '.', projectPackageManager = 'npm') => { const cwd = resolve(process.cwd(), relativeDirectory); const runner = process.platform === 'win32' ? `${projectPackageManager}.cmd` : projectPackageManager; const options = schematicsCliOptions .flat(); - - exitProcessIfErrorInSpawnSync(3, spawnSync(runner, ['exec', 'ng', 'add', `@o3r/core@${exactO3rVersion ? '' : '~'}${version}`, ...(projectPackageManager === 'npm' ? ['--'] : []), ...options], { + exitProcessIfErrorInSpawnSync(3, spawnSync(runner, [isYarn1 ? 'run' : 'exec', 'ng', 'add', `@o3r/core@${exactO3rVersion ? '' : '~'}${version}`, + ...((projectPackageManager === 'npm' || isYarn1) ? ['--'] : []), ...options], { stdio: 'inherit', cwd, env: exactO3rVersion && projectPackageManager === 'npm' ? { diff --git a/packages/@o3r/telemetry/src/environment/index.ts b/packages/@o3r/telemetry/src/environment/index.ts index 56ca1b96e3..7efd419b43 100644 --- a/packages/@o3r/telemetry/src/environment/index.ts +++ b/packages/@o3r/telemetry/src/environment/index.ts @@ -4,14 +4,14 @@ import { execSync } from 'node:child_process'; import * as path from 'node:path'; /** Support NPM package managers */ -type SupportedPackageManagers = 'npm' | 'yarn'; +type SupportedPackageManagers = 'npm' | 'yarn' | 'yarn1'; /** * Determine if the given packager manager is supported * @param name Name of the package manager */ function isSupportedPackageManager(name?: any): name is SupportedPackageManagers { - return name === 'yarn' || name === 'npm'; + return ['yarn', 'yarn1', 'npm'].includes(name); } /** @@ -19,7 +19,7 @@ function isSupportedPackageManager(name?: any): name is SupportedPackageManagers */ function getPackageManager() { if (isSupportedPackageManager(process.env?.ENFORCED_PACKAGE_MANAGER)) { - return process.env.ENFORCED_PACKAGE_MANAGER; + return (process.env.ENFORCED_PACKAGE_MANAGE === 'npm') ? 'npm' : 'yarn'; } return (process.env?.npm_execpath?.includes('yarn') && 'yarn') || 'npm'; } diff --git a/packages/@o3r/test-helpers/src/jest-environment/index.ts b/packages/@o3r/test-helpers/src/jest-environment/index.ts index 6f81ce0abd..da43646b9f 100644 --- a/packages/@o3r/test-helpers/src/jest-environment/index.ts +++ b/packages/@o3r/test-helpers/src/jest-environment/index.ts @@ -48,12 +48,16 @@ export class JestEnvironmentO3r extends NodeTestEnvironment { */ private readonly testEnvironments: Record = {}; + /** identifier of the package on which the tests are run */ + private readonly packageScope: string | undefined; + constructor(config: JestEnvironmentConfig, context: EnvironmentContext) { super(config, context); // testEnvironment is undefined now but will be defined when test runs this.global.o3rEnvironment = {} as typeof this.global.o3rEnvironment; this.appFolder = context.docblockPragmas['jest-environment-o3r-app-folder'] as string; this.prepareTestEnvType = context.docblockPragmas['jest-environment-o3r-type'] as PrepareTestEnvType | undefined; + this.packageScope = context.docblockPragmas['jest-environment-o3r-package-scope'] as string | undefined; } /** @@ -87,7 +91,7 @@ export class JestEnvironmentO3r extends NodeTestEnvironment { // Create test environment before test starts if (event.name === 'test_start') { const appFolder = `${this.appFolder}${this.appIndex++ || ''}`; - this.testEnvironments[event.test.name] = await prepareTestEnv(appFolder, {type: this.prepareTestEnvType}); + this.testEnvironments[event.test.name] = await prepareTestEnv(appFolder, {type: this.prepareTestEnvType, packageScope: this.packageScope}); this.global.o3rEnvironment.testEnvironment = this.testEnvironments[event.test.name]; } // Cleanup test environment after test succeeds diff --git a/packages/@o3r/test-helpers/src/prepare-test-env.ts b/packages/@o3r/test-helpers/src/prepare-test-env.ts index afeb31a167..4a0eea9f5a 100644 --- a/packages/@o3r/test-helpers/src/prepare-test-env.ts +++ b/packages/@o3r/test-helpers/src/prepare-test-env.ts @@ -3,7 +3,7 @@ import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statS import * as path from 'node:path'; import type { PackageJson } from 'type-fest'; import { createTestEnvironmentBlank } from './test-environments/create-test-environment-blank'; -import { createWithLock, getPackageManager, type Logger, packageManagerInstall, setPackagerManagerConfig, setupGit } from './utilities/index'; +import { createWithLock, getVersionedPackageManager, isYarn1Enforced, type Logger, packageManagerInstall, setPackagerManagerConfig, setupGit } from './utilities/index'; import { createTestEnvironmentOtterProjectWithApp } from './test-environments/create-test-environment-otter-project'; import { O3rCliError } from '@o3r/schematics'; @@ -15,8 +15,7 @@ export type PrepareTestEnvType = 'blank' | 'o3r-project-with-app'; /** * Retrieve the version used by yarn and setup at root level - * @param rootFolderPath: path to the folder where to take the configuration from - * @param rootFolderPath + * @param rootFolderPath path to the folder where to take the configuration from */ export function getYarnVersionFromRoot(rootFolderPath: string) { const o3rPackageJson: PackageJson & { generatorDependencies?: Record } = @@ -31,6 +30,11 @@ export interface PrepareTestEnvOptions { yarnVersion?: string; /** Logger to use for logging */ logger?: Logger; + /** + * Scope of package used to run the create command + * Used on yarn1 tests, because it is not able to differetiate from which package scope to run the create + */ + packageScope?: string; } /** @@ -43,14 +47,15 @@ export async function prepareTestEnv(folderName: string, options?: PrepareTestEn const logger = options?.logger || console; const yarnVersionParam = options?.yarnVersion; const rootFolderPath = process.cwd(); - const itTestsFolderPath = path.resolve(rootFolderPath, '..', 'it-tests'); + const itTestsFolderPath = path.resolve(rootFolderPath, '..', 'it-tests', options?.packageScope || ''); const workspacePath = path.resolve(itTestsFolderPath, folderName); const globalFolderPath = path.resolve(rootFolderPath, '.cache', 'test-app'); const cacheFolderPath = path.resolve(globalFolderPath, 'cache'); const o3rVersion = '999.0.0'; JSON.parse(readFileSync(path.join(rootFolderPath, 'packages', '@o3r', 'core', 'package.json')).toString()); - const yarnVersion: string = yarnVersionParam || getYarnVersionFromRoot(rootFolderPath); + const yarn1Version = execSync('npm view yarn version', { encoding: 'utf8' }).trim(); + const yarnVersion: string = yarnVersionParam || (isYarn1Enforced() && yarn1Version) || getYarnVersionFromRoot(rootFolderPath); const execAppOptions: ExecSyncOptions = { cwd: workspacePath, stdio: 'inherit', @@ -77,17 +82,18 @@ export async function prepareTestEnv(folderName: string, options?: PrepareTestEn const packageManagerConfig = { yarnVersion, globalFolderPath, - registry: 'http://127.0.0.1:4873' + registry: 'http://127.0.0.1:4873', + ...(isYarn1Enforced() ? {packageScope: options?.packageScope} : {}) }; // Create it-tests folder if (!existsSync(itTestsFolderPath)) { logger.debug?.(`Creating it-tests folder`); await createWithLock(() => { - mkdirSync(itTestsFolderPath); + mkdirSync(itTestsFolderPath, { recursive: true }); setPackagerManagerConfig(packageManagerConfig, {...execAppOptions, cwd: itTestsFolderPath}); return Promise.resolve(); - }, {lockFilePath: `${itTestsFolderPath}.lock`, cwd: path.join(rootFolderPath, '..'), appDirectory: 'it-tests'}); + }, {lockFilePath: `${itTestsFolderPath}.lock`, cwd: path.join(rootFolderPath, '..'), appDirectory: path.join('it-tests', options?.packageScope || '')}); } // Remove existing app @@ -109,7 +115,7 @@ export async function prepareTestEnv(folderName: string, options?: PrepareTestEn let isInWorkspace = false; let untouchedProject: undefined | string; let untouchedProjectPath: undefined | string; - const appDirectory = `${type}-${getPackageManager()}`; + const appDirectory = `${type}-${getVersionedPackageManager()}`; switch (type) { case 'blank': { await createTestEnvironmentBlank({ diff --git a/packages/@o3r/test-helpers/src/test-environments/create-test-environment-otter-project.ts b/packages/@o3r/test-helpers/src/test-environments/create-test-environment-otter-project.ts index 47fe03b3f0..7d1b1bdad5 100644 --- a/packages/@o3r/test-helpers/src/test-environments/create-test-environment-otter-project.ts +++ b/packages/@o3r/test-helpers/src/test-environments/create-test-environment-otter-project.ts @@ -5,6 +5,7 @@ import { createWithLock, CreateWithLockOptions, getPackageManager, + isYarn1Enforced, type Logger, PackageManagerConfig, packageManagerCreate, @@ -74,9 +75,10 @@ export async function createTestEnvironmentOtterProjectWithApp(inputOptions: Par try { mkdirSync(appFolderPath, { recursive: true }); } catch { } setPackagerManagerConfig(options, execAppOptions); + const versionToInstall = isYarn1Enforced() ? '' : `@${o3rVersion}`; // Create Project const createOptions = ['--package-manager', getPackageManager(), '--skip-confirmation', ...(options.yarnVersion ? ['--yarn-version', options.yarnVersion] : [])]; - packageManagerCreate({ script: `@o3r@${o3rVersion}`, args: [options.appDirectory, ...createOptions] }, { ...execAppOptions, cwd: options.cwd}, 'npm'); + packageManagerCreate({ script: `@o3r${versionToInstall}`, args: [options.appDirectory, ...createOptions] }, { ...execAppOptions, cwd: options.cwd}, !isYarn1Enforced() ? 'npm' : undefined); const gitIgnorePath = path.join(appFolderPath, '.gitignore'); if (existsSync(gitIgnorePath)) { const gitIgnore = readFileSync(gitIgnorePath, { encoding: 'utf8' }); diff --git a/packages/@o3r/test-helpers/src/utilities/locker.ts b/packages/@o3r/test-helpers/src/utilities/locker.ts index 262662dc92..41836a968b 100644 --- a/packages/@o3r/test-helpers/src/utilities/locker.ts +++ b/packages/@o3r/test-helpers/src/utilities/locker.ts @@ -1,4 +1,4 @@ -import { existsSync, readFileSync, rmSync, statSync, watch, writeFileSync } from 'node:fs'; +import { existsSync, mkdirSync, readFileSync, rmSync, statSync, watch, writeFileSync } from 'node:fs'; import * as path from 'node:path'; export interface LockerOptions { @@ -39,6 +39,10 @@ export class Locker { public lock(): boolean { const pid = String(process.pid); try { + const locDirPath = path.dirname(this.options.lockFilePath); + if (!existsSync(locDirPath)) { + mkdirSync(locDirPath, {recursive: true}); + } writeFileSync(this.options.lockFilePath, pid, {flag: this.isLockExpired() ? 'w' : 'wx'}); // Need to check if the file was created by this process return readFileSync(this.options.lockFilePath, {encoding: 'utf8'}) === pid; diff --git a/packages/@o3r/test-helpers/src/utilities/package-manager.ts b/packages/@o3r/test-helpers/src/utilities/package-manager.ts index 02a1d82c90..b62203dc9e 100644 --- a/packages/@o3r/test-helpers/src/utilities/package-manager.ts +++ b/packages/@o3r/test-helpers/src/utilities/package-manager.ts @@ -1,6 +1,6 @@ import { execFileSync, ExecSyncOptions } from 'node:child_process'; -import { existsSync, rmSync } from 'node:fs'; -import { join } from 'node:path'; +import { appendFileSync, existsSync, readFileSync, rmSync } from 'node:fs'; +import { join, posix, sep } from 'node:path'; import { performance } from 'node:perf_hooks'; declare global { @@ -30,6 +30,15 @@ const PACKAGE_MANAGERS_CMD = { run: ['yarn', 'run'], workspaceExec: ['yarn', 'workspace'], workspaceRun: ['yarn', 'workspace'] + }, + yarn1: { + add: ['yarn', 'add'], + create: ['yarn', 'create'], + exec: ['yarn', 'run'], + install: ['yarn', 'install', '--mutex', 'network'], + run: ['yarn', 'run'], + workspaceExec: ['yarn', 'workspace'], + workspaceRun: ['yarn', 'workspace'] } }; @@ -41,14 +50,30 @@ type CommandArguments = { }; /** - * Get the package manager to be used for the tests by reading environment variable ENFORCED_PACKAGE_MANAGER + * Get the package manager with its version to be used for the tests by reading environment variable ENFORCED_PACKAGE_MANAGER + * 'yarn', 'yarn1', 'npm' */ -export function getPackageManager() { +export function getVersionedPackageManager() { return (process.env.ENFORCED_PACKAGE_MANAGER && process.env.ENFORCED_PACKAGE_MANAGER in PACKAGE_MANAGERS_CMD) ? process.env.ENFORCED_PACKAGE_MANAGER as keyof typeof PACKAGE_MANAGERS_CMD : 'yarn'; } +/** + * Get the package manager to be used for the tests based on env ENFORCED_PACKAGE_MANAGER + * 'yarn', 'npm' + */ +export function getPackageManager() { + return getVersionedPackageManager() === 'npm' ? 'npm' : 'yarn'; +} + +/** + * is Yarn 1 enforced + */ +export function isYarn1Enforced() { + return process.env.ENFORCED_PACKAGE_MANAGER === 'yarn1'; +} + /** * Need to add additional dashes when running command like exec on npm * Convert `npm exec test --param` to `npm exec test -- --param` @@ -90,7 +115,7 @@ function execCmd(args: string[], execOptions: ExecSyncOptions) { * @param options */ export function packageManagerAdd(packages: string, options: ExecSyncOptions) { - return execCmd([...PACKAGE_MANAGERS_CMD[getPackageManager()].add, packages], options); + return execCmd([...PACKAGE_MANAGERS_CMD[getVersionedPackageManager()].add, packages], options); } /** @@ -101,7 +126,7 @@ export function packageManagerAdd(packages: string, options: ExecSyncOptions) { */ export function packageManagerCreate(command: CommandArguments, options: ExecSyncOptions, packageManagerOverride?: keyof typeof PACKAGE_MANAGERS_CMD) { const { script, args } = command; - const packageManager = packageManagerOverride || getPackageManager(); + const packageManager = packageManagerOverride || getVersionedPackageManager(); return execCmd([...PACKAGE_MANAGERS_CMD[packageManager].create, script, ...addDashesForNpmCommand(args, packageManager)], options); } @@ -112,7 +137,7 @@ export function packageManagerCreate(command: CommandArguments, options: ExecSyn */ export function packageManagerExec(command: CommandArguments, options: ExecSyncOptions) { const { script, args } = command; - return execCmd([...PACKAGE_MANAGERS_CMD[getPackageManager()].exec, script, ...addDashesForNpmCommand(args)], options); + return execCmd([...PACKAGE_MANAGERS_CMD[getVersionedPackageManager()].exec, script, ...addDashesForNpmCommand(args)], options); } /** @@ -123,7 +148,7 @@ export function packageManagerExec(command: CommandArguments, options: ExecSyncO */ export function packageManagerWorkspaceExec(workspaceProjectName: string, command: CommandArguments, options: ExecSyncOptions) { const { script, args } = command; - return execCmd([...PACKAGE_MANAGERS_CMD[getPackageManager()].workspaceExec, workspaceProjectName, script, ...addDashesForNpmCommand(args)], options); + return execCmd([...PACKAGE_MANAGERS_CMD[getVersionedPackageManager()].workspaceExec, workspaceProjectName, script, ...addDashesForNpmCommand(args)], options); } /** @@ -142,7 +167,7 @@ export function packageManagerExecOnProject(projectName: string, isInWorkspace: * @param options */ export function packageManagerInstall(options: ExecSyncOptions) { - return execCmd(PACKAGE_MANAGERS_CMD[getPackageManager()].install, options); + return execCmd(PACKAGE_MANAGERS_CMD[getVersionedPackageManager()].install, options); } /** @@ -152,7 +177,7 @@ export function packageManagerInstall(options: ExecSyncOptions) { */ export function packageManagerRun(command: CommandArguments, options: ExecSyncOptions) { const { script, args } = command; - return execCmd([...PACKAGE_MANAGERS_CMD[getPackageManager()].run, script, ...addDashesForNpmCommand(args)], options); + return execCmd([...PACKAGE_MANAGERS_CMD[getVersionedPackageManager()].run, script, ...addDashesForNpmCommand(args)], options); } /** @@ -163,7 +188,7 @@ export function packageManagerRun(command: CommandArguments, options: ExecSyncOp */ export function packageManagerWorkspaceRun(workspaceProjectName: string, command: CommandArguments, options: ExecSyncOptions) { const { script, args } = command; - return execCmd([...PACKAGE_MANAGERS_CMD[getPackageManager()].workspaceRun, workspaceProjectName, script, ...addDashesForNpmCommand(args)], options); + return execCmd([...PACKAGE_MANAGERS_CMD[getVersionedPackageManager()].workspaceRun, workspaceProjectName, script, ...addDashesForNpmCommand(args)], options); } /** @@ -192,6 +217,12 @@ export interface PackageManagerConfig { * Custom registry used to fetch local packages */ registry: string; + + /** + * Scope of package used to run the create command + * Used on yarn1 tests, because it is not able to differetiate from which package scope to run the create + */ + packageScope?: string; } /** @@ -209,7 +240,7 @@ export function setPackagerManagerConfig(options: PackageManagerConfig, execAppO const packageJsonPath = join(execOptions.cwd as string, 'package.json'); const shouldCleanPackageJson = !existsSync(packageJsonPath); - switch (getPackageManager()) { + switch (getVersionedPackageManager()) { case 'yarn': { // Set yarn version if (options.yarnVersion) { @@ -231,6 +262,34 @@ export function setPackagerManagerConfig(options: PackageManagerConfig, execAppO execFileSync('yarn', ['config', 'set', 'unsafeHttpWhitelist', '127.0.0.1'], execOptions); break; } + case 'yarn1': { + if (options.yarnVersion) { + execFileSync('yarn', ['set', 'version', options.yarnVersion], execOptions); + execFileSync('yarn', ['config', 'set', '@ama-sdk:registry', options.registry], execOptions); + execFileSync('yarn', ['config', 'set', '@ama-terasu:registry', options.registry], execOptions); + execFileSync('yarn', ['config', 'set', '@o3r:registry', options.registry], execOptions); + execFileSync('yarn', ['config', 'set', 'unsafeHttpWhitelist', '127.0.0.1'], execOptions); + } + const ignoreRootCheckConfig = '--add.ignore-workspace-root-check'; + const yarnRcPath = join(execOptions.cwd as string, '.yarnrc'); + + if (existsSync(yarnRcPath)) { + const content = readFileSync(yarnRcPath, { encoding: 'utf8' }); + if (!content.includes(ignoreRootCheckConfig)) { + appendFileSync(yarnRcPath, `\n${ignoreRootCheckConfig} true`); + } + if (options.globalFolderPath) { + ['cache-folder', 'global-folder'].forEach(folder => { + if (!content.includes(folder)) { + appendFileSync(yarnRcPath, `\n${folder} "${posix.join(options.globalFolderPath!.split(sep).join(posix.sep), `yarn1-${folder}`, options.packageScope || '')}"`); + } + }); + } + } else { + console.warn(`File not found at '${yarnRcPath}'.`); + } + break; + } } execFileSync('npm', ['config', 'set', 'audit=false', '-L=project'], execOptions);