Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rush] Revise command line selection operations #2422

Merged
merged 26 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d5badbb
Add Selection helpers
dmichon-msft Jan 29, 2021
40a0371
Include local optionalDependencies in downstream
dmichon-msft Jan 29, 2021
d3bf6a5
Use sets, rework selection mechanics
dmichon-msft Jan 29, 2021
22db410
Report critical path length in verbose logs
dmichon-msft Jan 29, 2021
fd78cdd
Add --to-except
dmichon-msft Jan 29, 2021
51ce22f
rush change
dmichon-msft Jan 29, 2021
ff09f4e
Update API
dmichon-msft Jan 29, 2021
ee5b119
Add `--affected-by`, `--affected-by-except`
dmichon-msft Jan 30, 2021
2bd1d41
Update snapshots
dmichon-msft Jan 30, 2021
2612c09
Update changefile
dmichon-msft Jan 30, 2021
b0065db
Add --only, revise docs
dmichon-msft Jan 30, 2021
297098d
Update snapshots
dmichon-msft Jan 30, 2021
93c0b6d
Merge remote-tracking branch 'remotes/origin/master' into dmichon/rew…
octogonz Jan 30, 2021
945f273
Revise names
dmichon-msft Jan 30, 2021
be52f21
Update API, snapshot
dmichon-msft Jan 30, 2021
8343173
Improve wording of changelogs
octogonz Jan 30, 2021
964c69b
Class-ify Selection
dmichon-msft Jan 30, 2021
02e23a5
Adjust names, revert some generators
dmichon-msft Jan 30, 2021
0652a86
Revert task runner logging detail
dmichon-msft Jan 30, 2021
fea3850
Fix comments
dmichon-msft Jan 30, 2021
2b7ca63
Fix other missing rename
dmichon-msft Jan 30, 2021
4dee059
Merge branch 'dmichon/rework-deps' of https://github.com/dmichon-msft…
octogonz Feb 1, 2021
c533efa
Revise documentation comments
dmichon-msft Feb 1, 2021
4cc060f
Some improvements for the CLI descriptions
octogonz Feb 1, 2021
862ca53
Merge branch 'dmichon/rework-deps' of https://github.com/dmichon-msft…
octogonz Feb 1, 2021
2605f50
Add an underscore prefix to @internal method
octogonz Feb 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/rush-lib/src/api/RushConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,7 @@ export class RushConfiguration {
// Compute the downstream dependencies within the list of Rush projects.
this._populateDownstreamDependencies(project.packageJson.dependencies, project.packageName);
this._populateDownstreamDependencies(project.packageJson.devDependencies, project.packageName);
this._populateDownstreamDependencies(project.packageJson.optionalDependencies, project.packageName);
this._versionPolicyConfiguration.validate(this.projectsByName);
}
}
Expand Down Expand Up @@ -1668,7 +1669,7 @@ export class RushConfiguration {
const depProject: RushConfigurationProject | undefined = this.projectsByName.get(dependencyName);

if (depProject) {
depProject.downstreamDependencyProjects.push(packageName);
depProject._consumingProjectNames.add(packageName);
}
});
}
Expand Down
100 changes: 80 additions & 20 deletions apps/rush-lib/src/api/RushConfigurationProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { PackageJsonEditor } from './PackageJsonEditor';
import { RushConstants } from '../logic/RushConstants';
import { PackageNameParsers } from './PackageNameParsers';
import { DependencySpecifier, DependencySpecifierType } from '../logic/DependencySpecifier';
import { Selection } from '../logic/Selection';

/**
* This represents the JSON data object for a project entry in the rush.json configuration file.
Expand Down Expand Up @@ -54,10 +55,19 @@ export class RushConfigurationProject {
private _shouldPublish: boolean;
private _skipRushCheck: boolean;
private _publishFolder: string;
private _downstreamDependencyProjects: string[];
private _localDependencyProjects: ReadonlyArray<RushConfigurationProject> | undefined;
private _dependencyProjects: ReadonlySet<RushConfigurationProject> | undefined;
private _consumingProjects: ReadonlySet<RushConfigurationProject> | undefined;
private readonly _rushConfiguration: RushConfiguration;

/**
* A set of projects within the Rush configuration which directly consume this package.
*
* @remarks
* Writable because it is mutated by RushConfiguration during initialization.
* @internal
*/
public readonly _consumingProjectNames: Set<string>;

/** @internal */
public constructor(
projectJson: IRushConfigurationProjectJson,
Expand Down Expand Up @@ -144,7 +154,7 @@ export class RushConfigurationProject {
}
this._shouldPublish = !!projectJson.shouldPublish;
this._skipRushCheck = !!projectJson.skipRushCheck;
this._downstreamDependencyProjects = [];
this._consumingProjectNames = new Set();
this._versionPolicyName = projectJson.versionPolicyName;

this._publishFolder = this._projectFolder;
Expand Down Expand Up @@ -175,7 +185,7 @@ export class RushConfigurationProject {
/**
* The relative path of the folder that contains the project to be built by Rush.
*
* Example: `libraries\my-project`
* Example: `libraries/my-project`
*/
public get projectRelativeFolder(): string {
return this._projectRelativeFolder;
Expand Down Expand Up @@ -226,24 +236,54 @@ export class RushConfigurationProject {
}

/**
* A list of projects within the Rush configuration which directly depend on this package.
* An array of projects within the Rush configuration which directly depend on this package.
* @deprecated Use `consumingProjectNames` instead, as it has Set semantics, which better reflect the nature
* of the data.
*/
public get downstreamDependencyProjects(): string[] {
return this._downstreamDependencyProjects;
return [...this._consumingProjectNames];
}

/**
* A map of projects within the Rush configuration which are directly depended on by this project
* An array of projects within the Rush configuration which this project declares as dependencies.
* @deprecated Use `dependencyProjects` instead, as it has Set semantics, which better reflect the nature
* of the data.
*/
public get localDependencyProjects(): ReadonlyArray<RushConfigurationProject> {
if (!this._localDependencyProjects) {
this._localDependencyProjects = [
...this._getLocalDependencyProjects(this.packageJson.dependencies),
...this._getLocalDependencyProjects(this.packageJson.devDependencies),
...this._getLocalDependencyProjects(this.packageJson.optionalDependencies)
];
return [...this.dependencyProjects];
}

/**
* The set of projects within the Rush configuration which this project declares as dependencies.
*
* @remarks
* Can be used recursively to walk the project dependency graph to find all projects that are directly or indirectly
* referenced from this project.
*/
public get dependencyProjects(): ReadonlySet<RushConfigurationProject> {
if (!this._dependencyProjects) {
this._dependencyProjects = Selection.union(
this._getDependencyProjects(this.packageJson.dependencies),
this._getDependencyProjects(this.packageJson.devDependencies),
this._getDependencyProjects(this.packageJson.optionalDependencies)
);
}
return this._localDependencyProjects;
return this._dependencyProjects;
}

/**
* The set of projects within the Rush configuration which declare this project as a dependency.
* Excludes those that declare this project as a `cyclicDependencyProject`.
*
* @remarks
* This field is the counterpart to `dependencyProjects`, and can be used recursively to walk the project dependency
* graph to find all projects which will be impacted by changes to this project.
*/
public get consumingProjects(): ReadonlySet<RushConfigurationProject> {
if (!this._consumingProjects) {
this._consumingProjects = this._getConsumingProjects();
}
return this._consumingProjects;
}

/**
Expand Down Expand Up @@ -358,10 +398,14 @@ export class RushConfigurationProject {
return isMain;
}

private _getLocalDependencyProjects(
/**
* Compute the local rush projects that this project immediately depends on,
* according to the specific dependency group from package.json
*/
private _getDependencyProjects(
dependencies: IPackageJsonDependencyTable = {}
): RushConfigurationProject[] {
const localDependencyProjects: RushConfigurationProject[] = [];
): Set<RushConfigurationProject> {
const dependencyProjects: Set<RushConfigurationProject> = new Set();
for (const dependency of Object.keys(dependencies)) {
// Skip if we can't find the local project or it's a cyclic dependency
const localProject: RushConfigurationProject | undefined = this._rushConfiguration.getProjectByName(
Expand All @@ -377,15 +421,31 @@ export class RushConfigurationProject {
case DependencySpecifierType.Version:
case DependencySpecifierType.Range:
if (semver.satisfies(localProject.packageJson.version, dependencySpecifier.versionSpecifier)) {
localDependencyProjects.push(localProject);
dependencyProjects.add(localProject);
}
break;
case DependencySpecifierType.Workspace:
localDependencyProjects.push(localProject);
dependencyProjects.add(localProject);
break;
}
}
}
return localDependencyProjects;
return dependencyProjects;
}

/**
* Compute the local rush projects that declare this project as a dependency
*/
private _getConsumingProjects(): Set<RushConfigurationProject> {
const consumingProjects: Set<RushConfigurationProject> = new Set();
for (const projectName of this._consumingProjectNames) {
const localProject: RushConfigurationProject | undefined = this._rushConfiguration.getProjectByName(
projectName
);
if (localProject && localProject.dependencyProjects.has(this)) {
consumingProjects.add(localProject);
}
}
return consumingProjects;
}
}
24 changes: 12 additions & 12 deletions apps/rush-lib/src/cli/actions/BaseRushAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,11 @@ export abstract class BaseRushAction extends BaseConfiglessRushAction {
return super.onExecute();
}

protected mergeProjectsWithVersionPolicy(
projectsParameters: CommandLineStringListParameter,
versionPoliciesParameters: CommandLineStringListParameter
): RushConfigurationProject[] {
protected *evaluateProjectParameter(
projectsParameters: CommandLineStringListParameter
): Iterable<RushConfigurationProject> {
const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup();

const projects: RushConfigurationProject[] = [];
for (const projectParameter of projectsParameters.values) {
if (projectParameter === '.') {
const packageJson: IPackageJson | undefined = packageJsonLookup.tryLoadPackageJsonFor(process.cwd());
Expand All @@ -146,7 +144,7 @@ export abstract class BaseRushAction extends BaseConfiglessRushAction {
packageJson.name
);
if (project) {
projects.push(project);
yield project;
} else {
console.log(
colors.red(
Expand Down Expand Up @@ -174,21 +172,23 @@ export abstract class BaseRushAction extends BaseConfiglessRushAction {
throw new AlreadyReportedError();
}

projects.push(project);
yield project;
}
}
}

protected *evaluateVersionPolicyProjects(
versionPoliciesParameters: CommandLineStringListParameter
): Iterable<RushConfigurationProject> {
if (versionPoliciesParameters.values && versionPoliciesParameters.values.length > 0) {
this.rushConfiguration.projects.forEach((project) => {
for (const project of this.rushConfiguration.projects) {
const matches: boolean = versionPoliciesParameters.values.some((policyName) => {
return project.versionPolicyName === policyName;
});
if (matches) {
projects.push(project);
yield project;
}
});
}
}

return projects;
}
}
15 changes: 13 additions & 2 deletions apps/rush-lib/src/cli/actions/InstallAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { CommandLineStringListParameter } from '@rushstack/ts-command-line';
import { BaseInstallAction } from './BaseInstallAction';
import { IInstallManagerOptions } from '../../logic/base/BaseInstallManager';
import { RushCommandLineParser } from '../RushCommandLineParser';
import { RushConfigurationProject } from '../../api/RushConfigurationProject';
import { Selection } from '../../logic/Selection';

export class InstallAction extends BaseInstallAction {
protected _toFlag!: CommandLineStringListParameter;
Expand Down Expand Up @@ -73,6 +75,15 @@ export class InstallAction extends BaseInstallAction {
}

protected buildInstallOptions(): IInstallManagerOptions {
const toProjects: Set<RushConfigurationProject> = Selection.union<RushConfigurationProject>(
this.evaluateProjectParameter(this._toFlag),
this.evaluateVersionPolicyProjects(this._toVersionPolicy)
);
const fromProjects: Set<RushConfigurationProject> = Selection.union<RushConfigurationProject>(
this.evaluateProjectParameter(this._fromFlag),
this.evaluateVersionPolicyProjects(this._fromVersionPolicy)
);

return {
debug: this.parser.isDebug,
allowShrinkwrapUpdates: false,
Expand All @@ -86,8 +97,8 @@ export class InstallAction extends BaseInstallAction {
// Because the 'defaultValue' option on the _maxInstallAttempts parameter is set,
// it is safe to assume that the value is not null
maxInstallAttempts: this._maxInstallAttempts.value!,
toProjects: this.mergeProjectsWithVersionPolicy(this._toFlag, this._toVersionPolicy),
fromProjects: this.mergeProjectsWithVersionPolicy(this._fromFlag, this._fromVersionPolicy)
toProjects,
fromProjects
};
}
}
4 changes: 2 additions & 2 deletions apps/rush-lib/src/cli/actions/UpdateAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ export class UpdateAction extends BaseInstallAction {
// Because the 'defaultValue' option on the _maxInstallAttempts parameter is set,
// it is safe to assume that the value is not null
maxInstallAttempts: this._maxInstallAttempts.value!,
toProjects: [],
fromProjects: []
toProjects: new Set(),
fromProjects: new Set()
};
}
}
Loading