forked from microsoft/rushstack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRushConfigurationProject.ts
More file actions
293 lines (261 loc) · 10 KB
/
RushConfigurationProject.ts
File metadata and controls
293 lines (261 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import * as path from 'path';
import {
JsonFile,
IPackageJson,
PackageName,
FileSystem,
FileConstants
} from '@microsoft/node-core-library';
import { RushConfiguration } from '../api/RushConfiguration';
import { VersionPolicy, LockStepVersionPolicy } from './VersionPolicy';
import { PackageJsonEditor } from './PackageJsonEditor';
import { RushConstants } from '../logic/RushConstants';
/**
* This represents the JSON data object for a project entry in the rush.json configuration file.
*/
export interface IRushConfigurationProjectJson {
packageName: string;
projectFolder: string;
reviewCategory?: string;
cyclicDependencyProjects: string[];
versionPolicyName?: string;
shouldPublish?: boolean;
skipRushCheck?: boolean;
}
/**
* This represents the configuration of a project that is built by Rush, based on
* the Rush.json configuration file.
* @public
*/
export class RushConfigurationProject {
private _packageName: string;
private _projectFolder: string;
private _projectRelativeFolder: string;
private _projectRushTempFolder: string;
private _reviewCategory: string;
private _packageJson: IPackageJson;
private _packageJsonEditor: PackageJsonEditor;
private _tempProjectName: string;
private _unscopedTempProjectName: string;
private _cyclicDependencyProjects: Set<string>;
private _versionPolicyName: string | undefined;
private _versionPolicy: VersionPolicy;
private _shouldPublish: boolean;
private _skipRushCheck: boolean;
private _downstreamDependencyProjects: string[];
private readonly _rushConfiguration: RushConfiguration;
/** @internal */
constructor(
projectJson: IRushConfigurationProjectJson,
rushConfiguration: RushConfiguration,
tempProjectName: string
) {
this._rushConfiguration = rushConfiguration;
this._packageName = projectJson.packageName;
this._projectRelativeFolder = projectJson.projectFolder;
// For example, the depth of "a/b/c" would be 3. The depth of "a" is 1.
const projectFolderDepth: number = projectJson.projectFolder.split('/').length;
if (projectFolderDepth < rushConfiguration.projectFolderMinDepth) {
throw new Error(`To keep things organized, this repository has a projectFolderMinDepth policy`
+ ` requiring project folders to be at least ${rushConfiguration.projectFolderMinDepth} levels deep.`
+ ` Problem folder: "${projectJson.projectFolder}"`);
}
if (projectFolderDepth > rushConfiguration.projectFolderMaxDepth) {
throw new Error(`To keep things organized, this repository has a projectFolderMaxDepth policy`
+ ` preventing project folders from being deeper than ${rushConfiguration.projectFolderMaxDepth} levels.`
+ ` Problem folder: "${projectJson.projectFolder}"`);
}
this._projectFolder = path.join(rushConfiguration.rushJsonFolder, projectJson.projectFolder);
if (!FileSystem.exists(this._projectFolder)) {
throw new Error(`Project folder not found: ${projectJson.projectFolder}`);
}
this._projectRushTempFolder = path.join(
this._projectFolder,
RushConstants.projectRushFolderName,
RushConstants.rushTempFolderName
);
// Are we using a package review file?
if (rushConfiguration.approvedPackagesPolicy.enabled) {
// If so, then every project needs to have a reviewCategory that was defined
// by the reviewCategories array.
if (!projectJson.reviewCategory) {
throw new Error(`The "approvedPackagesPolicy" feature is enabled rush.json, but a reviewCategory` +
` was not specified for the project "${projectJson.packageName}".`);
}
if (!rushConfiguration.approvedPackagesPolicy.reviewCategories.has(projectJson.reviewCategory)) {
throw new Error(`The project "${projectJson.packageName}" specifies its reviewCategory as`
+ `"${projectJson.reviewCategory}" which is not one of the defined reviewCategories.`);
}
this._reviewCategory = projectJson.reviewCategory;
}
const packageJsonFilename: string = path.join(this._projectFolder, FileConstants.PackageJson);
this._packageJson = JsonFile.load(packageJsonFilename);
if (this._packageJson.name !== this._packageName) {
throw new Error(`The package name "${this._packageName}" specified in rush.json does not`
+ ` match the name "${this._packageJson.name}" from package.json`);
}
this._packageJsonEditor = PackageJsonEditor.load(packageJsonFilename);
this._tempProjectName = tempProjectName;
// The "rushProject.tempProjectName" is guaranteed to be unique name (e.g. by adding the "-2"
// suffix). Even after we strip the NPM scope, it will still be unique.
// Example: "my-project-2"
this._unscopedTempProjectName = PackageName.getUnscopedName(tempProjectName);
this._cyclicDependencyProjects = new Set<string>();
if (projectJson.cyclicDependencyProjects) {
for (const cyclicDependencyProject of projectJson.cyclicDependencyProjects) {
this._cyclicDependencyProjects.add(cyclicDependencyProject);
}
}
this._shouldPublish = !!projectJson.shouldPublish;
this._skipRushCheck = !!projectJson.skipRushCheck;
this._downstreamDependencyProjects = [];
this._versionPolicyName = projectJson.versionPolicyName;
}
/**
* The name of the NPM package. An error is reported if this name is not
* identical to packageJson.name.
*
* Example: `@scope/MyProject`
*/
public get packageName(): string {
return this._packageName;
}
/**
* The full path of the folder that contains the project to be built by Rush.
*
* Example: `C:\MyRepo\libraries\my-project`
*/
public get projectFolder(): string {
return this._projectFolder;
}
/**
* The relative path of the folder that contains the project to be built by Rush.
*
* Example: `libraries\my-project`
*/
public get projectRelativeFolder(): string {
return this._projectRelativeFolder;
}
/**
* The project-specific Rush temp folder. This folder is used to store Rush-specific temporary files.
*
* Example: `C:\MyRepo\libraries\my-project\.rush\temp`
*/
public get projectRushTempFolder(): string {
return this._projectRushTempFolder;
}
/**
* The review category name, or undefined if no category was assigned.
* This name must be one of the valid choices listed in RushConfiguration.reviewCategories.
*/
public get reviewCategory(): string {
return this._reviewCategory;
}
/**
* A list of local projects that appear as devDependencies for this project, but cannot be
* locally linked because it would create a cyclic dependency; instead, the last published
* version will be installed in the Common folder.
*
* These are package names that would be found by RushConfiguration.getProjectByName().
*/
public get cyclicDependencyProjects(): Set<string> {
return this._cyclicDependencyProjects;
}
/**
* A list of projects within the Rush configuration which directly depend on this package.
*/
public get downstreamDependencyProjects(): string[] {
return this._downstreamDependencyProjects;
}
/**
* The parsed NPM "package.json" file from projectFolder.
* @deprecated Use packageJsonEditor instead
*/
public get packageJson(): IPackageJson {
return this._packageJson;
}
/**
* A useful wrapper around the package.json file for making modifications
* @beta
*/
public get packageJsonEditor(): PackageJsonEditor {
return this._packageJsonEditor;
}
/**
* The unique name for the temporary project that will be generated in the Common folder.
* For example, if the project name is `@scope/MyProject`, the temporary project name
* might be `@rush-temp/MyProject-2`.
*
* Example: `@rush-temp/MyProject-2`
*/
public get tempProjectName(): string {
return this._tempProjectName;
}
/**
* The unscoped temporary project name
*
* Example: `my-project-2`
*/
public get unscopedTempProjectName(): string {
return this._unscopedTempProjectName;
}
/**
* A flag which indicates whether changes to this project should be published. This controls
* whether or not the project would show up when running `rush change`, and whether or not it
* should be published during `rush publish`.
*/
public get shouldPublish(): boolean {
return this._shouldPublish || !!this._versionPolicyName;
}
/**
* If true, then this project will be ignored by the "rush check" command.
* The default value is false.
*/
public get skipRushCheck(): boolean {
return this._skipRushCheck;
}
/**
* Name of the version policy used by this project.
* @beta
*/
public get versionPolicyName(): string | undefined {
return this._versionPolicyName;
}
/**
* Version policy of the project
* @beta
*/
public get versionPolicy(): VersionPolicy | undefined {
if (!this._versionPolicy) {
if (this.versionPolicyName && this._rushConfiguration.versionPolicyConfiguration) {
this._versionPolicy = this._rushConfiguration.versionPolicyConfiguration.getVersionPolicy(
this.versionPolicyName);
}
}
return this._versionPolicy;
}
/**
* Indicate whether this project is the main project for the related version policy.
*
* False if the project is not for publishing.
* True if the project is individually versioned or if its lockstep version policy does not specify main project.
* False if the project is lockstepped and is not the main project for its version policy.
*
* @beta
*/
public get isMainProject(): boolean {
if (!this.shouldPublish) {
return false;
}
let isMain: boolean = true;
if (this.versionPolicy && this.versionPolicy.isLockstepped) {
const lockStepPolicy: LockStepVersionPolicy = this.versionPolicy as LockStepVersionPolicy;
if (lockStepPolicy.mainProject && lockStepPolicy.mainProject !== this.packageName) {
isMain = false;
}
}
return isMain;
}
}