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:subspace] Add BaseFlag and --ignore-scripts #4448
base: main
Are you sure you want to change the base?
Conversation
common/config/rush/experiments.json
Outdated
* If true, rush install or rush update implicitly specify --ignore-scripts during pnpm install, | ||
* and run install lifecycle scripts by pnpm rebuild --pending after pnpm install successfully. | ||
*/ | ||
/* "deferredInstallationScripts": true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there no schema for this file? Surprised this is allowed without upgrading Rush.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works because it's commented out. I'm going to temporarily delete this, since our convention is to introduce these lines when upgrading Rush itself. For this PR the appropriate place to add it is in the the rush-init
template.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
* If true, rush install or rush update implicitly specify --ignore-scripts during pnpm install, | ||
* and run install lifecycle scripts by pnpm rebuild --pending after pnpm install successfully. | ||
*/ | ||
deferredInstallationScripts?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems weird that this would be specified as an experiment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be added as an official feature instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think it can be an official feature. At the time when @chengcyber originally implemented it, it was an untested idea, but we have been using it successfully in our monorepo for over a year.
We can move this setting to pnpm-config.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
/** | ||
* Current package manager name | ||
*/ | ||
packageManager: PackageManagerName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
packageManager: PackageManagerName; | |
packageManagerName: PackageManagerName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This property maps to the packageManager
field in the RushConfiguration class, so I think it would be confusing to call it packageManagerName
here, and packageManager
in rushConfig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(see my other note)
/** | ||
* Current rush json folder | ||
*/ | ||
rushJsonFolder: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rushJsonFolder: string; | |
rushJsonFolderPath: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, this maps to rushConfig's rushJsonFolder
so I also think it would be confusing to call it differently in this class compared to rushconfig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(see my other note)
} | ||
|
||
try { | ||
Utilities.executeCommand({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Async?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file should have an
"additionalProperties": false,
property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it does at the bottom of the file, line 62
libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts
Outdated
Show resolved
Hide resolved
* Performs a partial deep comparison between `obj` and `source` to | ||
* determine if `obj` contains equivalent property values. | ||
*/ | ||
export function isMatch<TObject>(obj: TObject, source: TObject): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this? It seems to be only used by this method of BaseFlag
:
/**
* Merge new data into current state by "merge"
*/
public mergeFromObject(data: JsonObject): void {
if (isMatch(this._state, data)) {
return;
}
merge(this._state, data);
this._isModified = true;
}
However I don't see anything calling mergeFromObject()
, and the use case seems unclear. In general the last-install.flag
file may have been written by a Rush release that is much older or much newer than the current Rush, which may write different fields to that file. Can we safely merge them?
@@ -82,16 +92,26 @@ export abstract class BaseInstallManager { | |||
this.options = options; | |||
|
|||
this._commonTempLinkFlag = LastLinkFlagFactory.getCommonTempFlag(rushConfiguration); | |||
this.commonTempInstallFlag = LastInstallFlagFactory.getCommonTempFlag(rushConfiguration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constructor creates this.commonTempInstallFlag
here, however further down in this file we have doInstallAsync()
doing this:
// This marker file indicates that the last "rush install" completed successfully.
// Always perform a clean install if filter flags were provided. Additionally, if
// "--purge" was specified, or if the last install was interrupted, then we will
// need to perform a clean install. Otherwise, we can do an incremental install.
const commonTempInstallFlag: LastInstallFlag = LastInstallFlagFactory.getCommonTempFlag(
this.rushConfiguration,
{ npmrcHash: npmrcHash || '<NO NPMRC>' }
);
And then WorkspaceInstallManager.ts does this:
// Always save after pnpm rebuild to update timestamp of last install flag file.
this.commonTempInstallFlag.create();
The flag file is a synchronization mechanism -- if rush install
gets killed halfway through an operation, we need to determine where we left off, and whether node_modules is in a usable state or not. That is determined by the presence/absence of the flag file, and whether its contents match Rush's current configuration. When dealing with synchronization, we can expect race conditions (code that "mostly" works but crashes randomly in situations that are very difficult to reproduce). Thus, the review of such code will generally focus on looking for guarantees of correctness, e.g. we delete the file before starting the operation, and our "finally" block guarantees its creation at the end, and the Rush commands that access this file use a reliable LockFile
mutex to ensure two processes cannot ever be running simultaneously, etc.
This PR is changing the behavior of the flag file. We need some code comments explaining the new behavior of the flag file: How do we track whether install scripts have been run yet or not? Are we updating the flag file twice? I wasn't able to figure that out easily from looking at the GitHub diff.
Co-authored-by: Ian Clanton-Thuon <[email protected]>
…nager.ts Co-authored-by: Pete Gonzalez <[email protected]>
176107d
to
cb26659
Compare
…subspace # Conflicts: # build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml
…nts.json to pnpm-config.json
Summary
This MR adds many useful changes introduced in the split-workspace PR (#3481) such as the creation of the
BaseFlag
class as well as the addition of the --ignore-scripts parameter, which allows for installation without having to run the post-install scripts.Note that the --ignore-scripts feature is also introduced here: #3537 but the PR is a bit outdated but it was also referenced for this PR.
Both of these features will be very helpful for the installation implementation of subspaces, so I thought it would be easier to introduce them first.
Details
How it was tested
Impacted documentation