Skip to content

Commit edfe7af

Browse files
committed
Extract the .npmrc environment variable expansion into a new utility copyAndTrimNpmrcFile() which will be used during publishing, since syncNpmrc()'s "syncing" (i.e. deleting the target if the source is missing) is awkward with a custom .npmrc filename
1 parent a481fa7 commit edfe7af

File tree

5 files changed

+109
-93
lines changed

5 files changed

+109
-93
lines changed

apps/rush-lib/src/api/RushConfiguration.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ const MINIMUM_SUPPORTED_RUSH_JSON_VERSION: string = '0.0.0';
3737
* To avoid confusion/mistakes, any extra files will be reported as an error.
3838
*/
3939
const knownRushConfigFilenames: string[] = [
40-
'.npmrc',".npmrc-publish",
40+
'.npmrc',
41+
'.npmrc-publish',
4142
RushConstants.pinnedVersionsFilename,
4243
RushConstants.commonVersionsFilename,
4344
RushConstants.browserApprovedPackagesFilename,

apps/rush-lib/src/cli/actions/PublishAction.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { VersionControl } from '../../utilities/VersionControl';
2828
import { PolicyValidator } from '../../logic/policy/PolicyValidator';
2929
import { VersionPolicy } from '../../api/VersionPolicy';
3030
import { DEFAULT_PACKAGE_UPDATE_MESSAGE } from './VersionAction';
31+
import { Utilities } from '../../utilities/Utilities';
3132

3233
export class PublishAction extends BaseRushAction {
3334
private _addCommitDetails: CommandLineFlagParameter;
@@ -372,19 +373,25 @@ export class PublishAction extends BaseRushAction {
372373
const userConfig: string = (process.platform === 'win32') ? 'USERPROFILE' : 'HOME';
373374

374375
if (this.rushConfiguration.projectsByName.get(packageName)!.shouldPublish) {
375-
const srcNpmrcPublishPath: string = path.join(this.rushConfiguration.commonRushConfigFolder, '.npmrc-publish');
376-
const targetNmprcPublishFolder: string = path.join(this.rushConfiguration.commonTempFolder, 'publish-home');
376+
// Example: "common\config\rush\.npmrc-publish"
377+
const sourceNpmrcPublishPath: string = path.join(this.rushConfiguration.commonRushConfigFolder, '.npmrc-publish');
378+
379+
// Example: "common\temp\publish-home"
380+
const targetNpmrcPublishFolder: string = path.join(this.rushConfiguration.commonTempFolder, 'publish-home');
381+
382+
// Example: "common\temp\publish-home\.npmrc"
383+
const targetNpmrcPublishPath: string = path.join(targetNpmrcPublishFolder, '.npmrc');
377384

378385
// Check if .npmrc-publish file exists to use for publishing
379-
if (FileSystem.exists(srcNpmrcPublishPath)) {
386+
if (FileSystem.exists(sourceNpmrcPublishPath)) {
380387
// Sync "common\config\rush\.npmrc-publish" --> "common\temp\publish-home\.npmrc"
381-
PublishUtilities.syncNpmrcPublish(
382-
this.rushConfiguration.commonRushConfigFolder,
383-
this.rushConfiguration.commonTempFolder
384-
);
388+
Utilities.createFolderWithRetry(targetNpmrcPublishFolder);
389+
390+
// Use Utilities.syncNpmrc to copy down the committed .npmrc-publish file, if there is one
391+
Utilities.copyAndTrimNpmrcFile(sourceNpmrcPublishPath, targetNpmrcPublishPath);
385392

386393
// Update userconfig, NPM will use config in "common\temp\publish-home\.npmrc"
387-
env[userConfig] = targetNmprcPublishFolder;
394+
env[userConfig] = targetNpmrcPublishFolder;
388395
} else {
389396
// Update userconfig, NPM will use config in "common\temp\.npmrc"
390397
env[userConfig] = this.rushConfiguration.commonTempFolder;

apps/rush-lib/src/logic/PublishUtilities.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -182,18 +182,6 @@ export class PublishUtilities {
182182
});
183183
return env;
184184
}
185-
186-
/**
187-
* A helper function that uses utilities.syncNpmrc() to validate environment variables in .npmrc-publish
188-
* Errors wil be written to file if environment variable is not set
189-
*/
190-
public static syncNpmrcPublish(sourceNpmrcFolder: string, destNpmrcFolder: string): void {
191-
const targetNpmrcPublishFolder: string = path.join(destNpmrcFolder, 'publish-home');
192-
Utilities.createFolderWithRetry(targetNpmrcPublishFolder);
193-
194-
// Use Utilities.syncNpmrc to copy down the committed .npmrc-publish file, if there is one
195-
Utilities.syncNpmrc(sourceNpmrcFolder, targetNpmrcPublishFolder, true);
196-
}
197185

198186
public static execCommand(
199187
shouldExecute: boolean,

apps/rush-lib/src/scripts/install-run.ts

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ function _parsePackageSpecifier(rawPackageSpecifier: string): IPackageSpecifier
5252
}
5353

5454
/**
55-
* As a workaround, _syncNpmrc() copies the .npmrc file to the target folder, and also trims
56-
* unusable lines from the .npmrc file. If the source .npmrc file not exist, then _syncNpmrc()
57-
* will delete an .npmrc that is found in the target folder.
55+
* As a workaround, copyAndTrimNpmrcFile() copies the .npmrc file to the target folder, and also trims
56+
* unusable lines from the .npmrc file.
5857
*
5958
* Why are we trimming the .npmrc lines? NPM allows environment variables to be specified in
6059
* the .npmrc file to provide different authentication tokens for different registry.
@@ -63,45 +62,57 @@ function _parsePackageSpecifier(rawPackageSpecifier: string): IPackageSpecifier
6362
* we'd prefer to skip that line and continue looking in other places such as the user's
6463
* home directory.
6564
*
66-
* IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH Utilities._syncNpmrc()
65+
* IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH _copyNpmrcFile() FROM scripts/install-run.ts
6766
*/
68-
function _syncNpmrc(sourceNpmrcFolder: string, targetNpmrcFolder: string, useNpmrcPublish?: boolean): void {
69-
const sourceNpmrcPath: string = path.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish');
70-
const targetNpmrcPath: string = path.join(targetNpmrcFolder, '.npmrc');
71-
try {
72-
if (fs.existsSync(sourceNpmrcPath)) {
73-
let npmrcFileLines: string[] = fs.readFileSync(sourceNpmrcPath).toString().split('\n');
74-
npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim());
75-
const resultLines: string[] = [];
76-
// Trim out lines that reference environment variables that aren't defined
77-
for (const line of npmrcFileLines) {
78-
// This finds environment variable tokens that look like "${VAR_NAME}"
79-
const regex: RegExp = /\$\{([^\}]+)\}/g;
80-
const environmentVariables: string[] | null = line.match(regex);
81-
let lineShouldBeTrimmed: boolean = false;
82-
if (environmentVariables) {
83-
for (const token of environmentVariables) {
84-
// Remove the leading "${" and the trailing "}" from the token
85-
const environmentVariableName: string = token.substring(2, token.length - 1);
86-
if (!process.env[environmentVariableName]) {
87-
lineShouldBeTrimmed = true;
88-
break;
89-
}
90-
}
91-
}
92-
93-
if (lineShouldBeTrimmed) {
94-
// Example output:
95-
// "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}"
96-
resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line);
97-
} else {
98-
resultLines.push(line);
67+
function _copyAndTrimNpmrcFile(sourceNpmrcPath: string, targetNpmrcPath: string): void {
68+
console.log(`Copying ${sourceNpmrcPath} --> ${targetNpmrcPath}`);
69+
let npmrcFileLines: string[] = fs.readFileSync(sourceNpmrcPath).toString().split('\n');
70+
npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim());
71+
const resultLines: string[] = [];
72+
// Trim out lines that reference environment variables that aren't defined
73+
for (const line of npmrcFileLines) {
74+
// This finds environment variable tokens that look like "${VAR_NAME}"
75+
const regex: RegExp = /\$\{([^\}]+)\}/g;
76+
const environmentVariables: string[] | null = line.match(regex);
77+
let lineShouldBeTrimmed: boolean = false;
78+
if (environmentVariables) {
79+
for (const token of environmentVariables) {
80+
// Remove the leading "${" and the trailing "}" from the token
81+
const environmentVariableName: string = token.substring(2, token.length - 1);
82+
if (!process.env[environmentVariableName]) {
83+
lineShouldBeTrimmed = true;
84+
break;
9985
}
10086
}
87+
}
88+
89+
if (lineShouldBeTrimmed) {
90+
// Example output:
91+
// "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}"
92+
resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line);
93+
} else {
94+
resultLines.push(line);
95+
}
96+
}
10197

102-
fs.writeFileSync(targetNpmrcPath, resultLines.join(os.EOL));
98+
fs.writeFileSync(targetNpmrcPath, resultLines.join(os.EOL));
99+
}
100+
101+
/**
102+
* syncNpmrc() copies the .npmrc file to the target folder, and also trims unusable lines from the .npmrc file.
103+
* If the source .npmrc file not exist, then syncNpmrc() will delete an .npmrc that is found in the target folder.
104+
*
105+
* IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH _syncNpmrc() FROM scripts/install-run.ts
106+
*/
107+
function _syncNpmrc(sourceNpmrcFolder: string, targetNpmrcFolder: string): void {
108+
const sourceNpmrcPath: string = path.join(sourceNpmrcFolder, '.npmrc');
109+
const targetNpmrcPath: string = path.join(targetNpmrcFolder, '.npmrc');
110+
try {
111+
if (fs.existsSync(sourceNpmrcPath)) {
112+
_copyAndTrimNpmrcFile(sourceNpmrcPath, targetNpmrcPath);
103113
} else if (fs.existsSync(targetNpmrcPath)) {
104114
// If the source .npmrc doesn't exist and there is one in the target, delete the one in the target
115+
console.log(`Deleting ${targetNpmrcPath}`);
105116
fs.unlinkSync(targetNpmrcPath);
106117
}
107118
} catch (e) {

apps/rush-lib/src/utilities/Utilities.ts

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -497,9 +497,8 @@ export class Utilities {
497497
}
498498

499499
/**
500-
* As a workaround, syncNpmrc() copies the .npmrc file to the target folder, and also trims
501-
* unusable lines from the .npmrc file. If the source .npmrc file not exist, then syncNpmrc()
502-
* will delete an .npmrc that is found in the target folder.
500+
* As a workaround, copyAndTrimNpmrcFile() copies the .npmrc file to the target folder, and also trims
501+
* unusable lines from the .npmrc file.
503502
*
504503
* Why are we trimming the .npmrc lines? NPM allows environment variables to be specified in
505504
* the .npmrc file to provide different authentication tokens for different registry.
@@ -508,44 +507,54 @@ export class Utilities {
508507
* we'd prefer to skip that line and continue looking in other places such as the user's
509508
* home directory.
510509
*
510+
* IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH _copyNpmrcFile() FROM scripts/install-run.ts
511+
*/
512+
public static copyAndTrimNpmrcFile(sourceNpmrcPath: string, targetNpmrcPath: string): void {
513+
console.log(`Copying ${sourceNpmrcPath} --> ${targetNpmrcPath}`);
514+
let npmrcFileLines: string[] = FileSystem.readFile(sourceNpmrcPath).split('\n');
515+
npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim());
516+
const resultLines: string[] = [];
517+
// Trim out lines that reference environment variables that aren't defined
518+
for (const line of npmrcFileLines) {
519+
// This finds environment variable tokens that look like "${VAR_NAME}"
520+
const regex: RegExp = /\$\{([^\}]+)\}/g;
521+
const environmentVariables: string[] | null = line.match(regex);
522+
let lineShouldBeTrimmed: boolean = false;
523+
if (environmentVariables) {
524+
for (const token of environmentVariables) {
525+
// Remove the leading "${" and the trailing "}" from the token
526+
const environmentVariableName: string = token.substring(2, token.length - 1);
527+
if (!process.env[environmentVariableName]) {
528+
lineShouldBeTrimmed = true;
529+
break;
530+
}
531+
}
532+
}
533+
534+
if (lineShouldBeTrimmed) {
535+
// Example output:
536+
// "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}"
537+
resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line);
538+
} else {
539+
resultLines.push(line);
540+
}
541+
}
542+
543+
FileSystem.writeFile(targetNpmrcPath, resultLines.join(os.EOL));
544+
}
545+
546+
/**
547+
* syncNpmrc() copies the .npmrc file to the target folder, and also trims unusable lines from the .npmrc file.
548+
* If the source .npmrc file not exist, then syncNpmrc() will delete an .npmrc that is found in the target folder.
549+
*
511550
* IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH _syncNpmrc() FROM scripts/install-run.ts
512551
*/
513-
public static syncNpmrc(sourceNpmrcFolder: string, targetNpmrcFolder: string, useNpmrcPublish?: boolean): void {
514-
const sourceNpmrcPath: string = path.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish');
552+
public static syncNpmrc(sourceNpmrcFolder: string, targetNpmrcFolder: string): void {
553+
const sourceNpmrcPath: string = path.join(sourceNpmrcFolder, '.npmrc');
515554
const targetNpmrcPath: string = path.join(targetNpmrcFolder, '.npmrc');
516555
try {
517556
if (FileSystem.exists(sourceNpmrcPath)) {
518-
console.log(`Copying ${sourceNpmrcPath} --> ${targetNpmrcPath}`);
519-
let npmrcFileLines: string[] = FileSystem.readFile(sourceNpmrcPath).split('\n');
520-
npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim());
521-
const resultLines: string[] = [];
522-
// Trim out lines that reference environment variables that aren't defined
523-
for (const line of npmrcFileLines) {
524-
// This finds environment variable tokens that look like "${VAR_NAME}"
525-
const regex: RegExp = /\$\{([^\}]+)\}/g;
526-
const environmentVariables: string[] | null = line.match(regex);
527-
let lineShouldBeTrimmed: boolean = false;
528-
if (environmentVariables) {
529-
for (const token of environmentVariables) {
530-
// Remove the leading "${" and the trailing "}" from the token
531-
const environmentVariableName: string = token.substring(2, token.length - 1);
532-
if (!process.env[environmentVariableName]) {
533-
lineShouldBeTrimmed = true;
534-
break;
535-
}
536-
}
537-
}
538-
539-
if (lineShouldBeTrimmed) {
540-
// Example output:
541-
// "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}"
542-
resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line);
543-
} else {
544-
resultLines.push(line);
545-
}
546-
}
547-
548-
FileSystem.writeFile(targetNpmrcPath, resultLines.join(os.EOL));
557+
Utilities.copyAndTrimNpmrcFile(sourceNpmrcPath, targetNpmrcPath);
549558
} else if (FileSystem.exists(targetNpmrcPath)) {
550559
// If the source .npmrc doesn't exist and there is one in the target, delete the one in the target
551560
console.log(`Deleting ${targetNpmrcPath}`);

0 commit comments

Comments
 (0)