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

feat(build-cli): Add exec command #14635

Merged
merged 7 commits into from
Mar 21, 2023
Merged

Conversation

tylerbutler
Copy link
Member

@tylerbutler tylerbutler commented Mar 18, 2023

This PR adds an exec command to build-cli, which can be used to execute shell commands in the context of packages or release groups in the repo.

The following example runs pnpm -r remove @rushstack/eslint-config on all independent packages and all release group root packages:

flub exec --all --releaseGroupRoots "pnpm -r remove @rushstack/eslint-config"

I think that for this command to be useful, one needs to be able to scope the packages that it runs on to the following groups:

  1. All independent packages in the repo - use the --packages flag.
  2. All packages in the repo using a particular scope - use the --scope and --skipScope flags.
  3. A single package in a directory - use the --dir flag.
  4. All individual packages in a release group - use the --releaseGroup flag.
  5. All release group root packages - use the --releaseGroup and --releaseGroupRoots flags together.
  6. All release group root packages and independent packages - use the --all and --releaseGroupRoots flags together.
  7. All release group packages and independent packages - use the --all flag.

I implemented this by adding two new flags to the BasePackageCommand class, --all and --releaseGroupRoots. Most of the code change was in the base class. This means that the typetest command can also benefit from the new flags. That said, releaseGroupRoots in particular doesn't make sense for typetests, so perhaps the new flags shouldn't be on the base class? Feedback welcome.

@github-actions github-actions bot added the base: main PRs targeted against main branch label Mar 18, 2023
@tylerbutler tylerbutler marked this pull request as ready for review March 20, 2023 17:25
@tylerbutler tylerbutler requested a review from a team as a code owner March 20, 2023 17:25
@CraigMacomber
Copy link
Contributor

Making the new options work for everything (what you did) seems like the best choice. I think it would be fine to normalize type test information across all release packages after a tooling update for example.

@tylerbutler
Copy link
Member Author

Making the new options work for everything (what you did) seems like the best choice. I think it would be fine to normalize type test information across all release packages after a tooling update for example.

That's a great scenario that I had not considered. Cool!

"Run on the package in this directory. Cannot be used with --releaseGroup or --packages.",
exclusive: ["packages", "releaseGroup"],
"Run on the package in this directory. Cannot be used with --all, --packages, or --releaseGroup.",
exclusive: ["packages", "releaseGroup", "all"],
}),
packages: Flags.boolean({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably leave it for a separate PR if we change it, but I find "packages" a confusing option. Renaming this to "independent" or "separate" or "non-grouped" seems like it would be better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'll do that in a separate PR.

/**
* Package is part of a release group
*/
| "releaseGroupPackage"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means release group, but not the root of it right? Someone could think that this refers to the package for a release group, which is the root. I think "releaseGroupChild" would be more clear.

Also since all of these are about packages, we should probably make all their names include "package" or none of them, for consistency.

* Package is being loaded from a directory. The package may be one of the other three kinds. This kind is only used
* when running on a package diurectly using its directory.
*/
| "packageDir";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoiding abbreviations is preferable for readability and reduced ambiguity. calling this "fromPath" or "directory" might be more clear.

/**
* Runs processPackage for each package in a release group, exlcuding the root.
*/
private async processReleaseGroup(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think separating the concerns of finding the right packages, and running an operation on them would be cleaner. Having this return a list of packages, then having the user of this add it to the full set its going to process would accomplish this.

This approach would also make actions like detecting duplicates, or applying multiple different operations to a set of packages easier.

It would also allow parallelizing across multiple release groups while having a single scheduler to avoid having too many in progress tasks and mixed status reporting.

Copy link
Contributor

@CraigMacomber CraigMacomber Mar 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also making async methods have useful return values (like the list of packahes) instead of just having sideeffects tends to help reduce the risk or unawaited promises or unexpected concurrency.

/**
* Runs processPackage for each independent package in the repo.
*/
private async processIndependentPackages(): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: I think having this return the list of found packages would be better.

return [{ directory: rg.repoPath, kind: "releaseGroupRootPackage" }];
}

return ctx.packagesInReleaseGroup(releaseGroup).map((p) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, for another PR, but I think a decent amount of logic over in monoRepo.ts could be replaced by a call to releaseGroups to find these packages.

@tylerbutler tylerbutler merged commit 5898496 into microsoft:main Mar 21, 2023
@tylerbutler tylerbutler deleted the flub-exec branch March 21, 2023 16:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
base: main PRs targeted against main branch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants