Skip to content

Commit

Permalink
fix(@angular/cli): handle YARN_ environment variables during `ng up…
Browse files Browse the repository at this point in the history
…date` and `ng add`

With this change we handle yarn specific environment variables during `ng update` and `ng add`. This is a follow up of #21297
  • Loading branch information
alan-agius4 committed Jul 21, 2021
1 parent f75a584 commit c1eddbd
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 28 deletions.
44 changes: 20 additions & 24 deletions packages/angular/cli/utilities/package-metadata.ts
Expand Up @@ -131,7 +131,7 @@ function readOptions(
logger.info(`Locating potential ${baseFilename} files:`);
}

let options: PackageManagerOptions = {};
let rcOptions: PackageManagerOptions = {};
for (const location of [...defaultConfigLocations, ...projectConfigLocations]) {
if (existsSync(location)) {
if (showPotentials) {
Expand All @@ -143,25 +143,33 @@ function readOptions(
// See: https://github.com/npm/npm-registry-fetch/blob/ebddbe78a5f67118c1f7af2e02c8a22bcaf9e850/index.js#L99-L126
const rcConfig: PackageManagerOptions = yarn ? lockfile.parse(data) : ini.parse(data);

options = normalizeOptions(rcConfig, location);
rcOptions = normalizeOptions(rcConfig, location);
}
}

const envVariablesOptions: PackageManagerOptions = {};
for (const [key, value] of Object.entries(process.env)) {
if (!value || !key.toLowerCase().startsWith('npm_config_')) {
if (!value) {
continue;
}

const normalizedName = key
.substr(11)
.replace(/(?!^)_/g, '-') // don't replace _ at the start of the key
.toLowerCase();
options[normalizedName] = value;
}
let normalizedName = key.toLowerCase();
if (normalizedName.startsWith('npm_config_')) {
normalizedName = normalizedName.substring(11);
} else if (yarn && normalizedName.startsWith('yarn_')) {
normalizedName = normalizedName.substring(5);
} else {
continue;
}

options = normalizeOptions(options);
normalizedName = normalizedName.replace(/(?!^)_/g, '-'); // don't replace _ at the start of the key.s
envVariablesOptions[normalizedName] = value;
}

return options;
return {
...rcOptions,
...normalizeOptions(envVariablesOptions),
};
}

function normalizeOptions(
Expand Down Expand Up @@ -302,7 +310,6 @@ export async function fetchPackageManifest(
} = {},
): Promise<PackageManifest> {
const { usingYarn = false, verbose = false, registry } = options;

ensureNpmrc(logger, usingYarn, verbose);

const response = await pacote.manifest(name, {
Expand All @@ -329,18 +336,7 @@ export function getNpmPackageJson(
}

const { usingYarn = false, verbose = false, registry } = options;

if (!npmrc) {
try {
npmrc = readOptions(logger, false, verbose);
} catch {}

if (usingYarn) {
try {
npmrc = { ...npmrc, ...readOptions(logger, true, verbose) };
} catch {}
}
}
ensureNpmrc(logger, usingYarn, verbose);

const resultPromise: Promise<NpmRepositoryPackageJson> = pacote.packument(packageName, {
fullMetadata: true,
Expand Down
29 changes: 29 additions & 0 deletions tests/legacy-cli/e2e/tests/commands/add/yarn-env-vars.ts
@@ -0,0 +1,29 @@
import { expectFileNotToExist, expectFileToExist } from '../../../utils/fs';
import { getActivePackageManager } from '../../../utils/packages';
import { git, ng } from '../../../utils/process';
import {
createNpmConfigForAuthentication,
setNpmEnvVarsForAuthentication,
} from '../../../utils/registry';

export default async function () {
// Yarn specific test that tests YARN_ env variables.
// https://classic.yarnpkg.com/en/docs/envvars/
if (getActivePackageManager() !== 'yarn') {
return;
}
const command = ['add', '@angular/pwa', '--skip-confirmation'];

// Environment variables only
await expectFileNotToExist('src/manifest.webmanifest');
setNpmEnvVarsForAuthentication(false, true);
await ng(...command);
await expectFileToExist('src/manifest.webmanifest');
await git('clean', '-dxf');

// Mix of config file and env vars works
await expectFileNotToExist('src/manifest.webmanifest');
await createNpmConfigForAuthentication(false, true);
await ng(...command);
await expectFileToExist('src/manifest.webmanifest');
}
16 changes: 12 additions & 4 deletions tests/legacy-cli/e2e/utils/registry.ts
Expand Up @@ -61,10 +61,18 @@ export function createNpmConfigForAuthentication(
export function setNpmEnvVarsForAuthentication(
/** When true, an incorrect token is used. Use this to validate authentication failures. */
invalidToken = false,
/** When true, `YARN_REGISTRY` is used instead of `NPM_CONFIG_REGISTRY`. */
useYarnEnvVariable = false,
): void {
const token = invalidToken ? `invalid=` : VALID_TOKEN;
const registry = SECURE_REGISTRY;
delete process.env['YARN_REGISTRY'];
delete process.env['NPM_CONFIG_REGISTRY'];

const registryKey = useYarnEnvVariable ? 'YARN_REGISTRY' : 'NPM_CONFIG_REGISTRY';
process.env[registryKey] = `http:${SECURE_REGISTRY}`;

process.env['NPM_CONFIG__AUTH'] = invalidToken ? `invalid=` : VALID_TOKEN;

process.env['NPM_CONFIG_REGISTRY'] = `http:${registry}`;
process.env['NPM_CONFIG__AUTH'] = token;
// Needed for verdaccio when used with yarn
// https://verdaccio.org/docs/en/cli-registry#yarn
process.env['NPM_CONFIG_ALWAYS_AUTH'] = 'true';
}
9 changes: 9 additions & 0 deletions tests/legacy-cli/e2e_runner.ts
Expand Up @@ -141,6 +141,10 @@ testsToRun
const start = +new Date();

const module = require(absoluteName);
const originalEnvVariables = {
...process.env,
};

const fn: (skipClean?: () => void) => Promise<void> | void =
typeof module == 'function'
? module
Expand Down Expand Up @@ -188,6 +192,11 @@ testsToRun
);
}
})
.finally(() => {
// Restore env variables after each test.
console.log(' Restoring original environment variables...');
process.env = originalEnvVariables;
})
.then(
() => printFooter(currentFileName, start),
(err) => {
Expand Down

0 comments on commit c1eddbd

Please sign in to comment.