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

Add --since flag to all commands that accept --scope #822

Merged
merged 6 commits into from
Jun 28, 2017

Conversation

treshugart
Copy link
Contributor

@treshugart treshugart commented May 18, 2017

Description

The --since option applies to all commands that accept --scope.

By default --since will scope the command to all packages that have been updated since the latest tag. If a ref is passed (i.e. --since ref), then it will scope the command to all packages that have been updated since the specified ref.

Motivation and Context

Currently we have a fairly large repo of packages (currently 68) and the builds take quite awhile to complete because when CI runs, it uses lerna run and that executes on all packages. This means our build only gets slower as we add more packages.

Since we only care about packages that have actually changed, we can theoretically use --scope to filter the packages that should be run. However, in practice, this isn't very simple because we have to figure out which packages have been updated in the branch and then pass them off to this argument. This means we have to create a separate command outside of Lerna that then proxies lerna run --scope.

The problem with creating a separate script means that we're no longer directly using Lerna. Any new scripts we add to packages must now be run through this separate script and it creates what seems like unnecessary indirection when Lerna already has the facilities to do this internally. We felt the most elegant way would be to create a flag like --scope that follows the same naming convention and can even be used in conjunction with it, but that allows the caller to also specify a ref to scope the filtered packages to. If a ref isn't provided, it defaults to the latest tag, as it already does internally.

How Has This Been Tested?

The changes were tested at the main Command level in the .runValidations() test by adding a section for .filteredPackages. I felt this was the best place for a few reasons:

  • It can apply to most commands and packages are filtered in the base Command class.
  • It seemed like there were other places the behaviour of --scope was integration tested, but I'm not sure if that would have been too much duplication for the testing of this since it would be testing pretty much the same thing every time. This also keeps the surface area of the changes smaller.

There was one change to the Command test file which was required in order to get the expected packages after updating the fixtures. It appears that whole modules were being mocked via Jest but not actually being used because the mocks that were being used were being manually done later in the file in *Each() blocks. I ended up just removing the global mocks and everything worked.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

Related issues

No original issue was provided but this also:

@evocateur
Copy link
Member

I just merged #726, does that cover your use case?


class TestCommand extends Command {}

function cli(cmd, ...args) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I saw similar helpers in the tests for the updated command, however, in order to reduce the amount of changes, I decided to write a few extra lines of code rather than refactoring them out into a common lib.

Copy link
Member

Choose a reason for hiding this comment

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

Ideally, this would be the approach used for all unit tests of commands. The .run() method really needs to return a Promise, already... (out of scope for this PR, clearly)

@@ -1,7 +1,7 @@
{
"name": "package-5",
"version": "1.0.0",
"private": "true",
"private": true,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good samaritan fix.

test/Command.js Outdated
expect(filteredPackages[1].name).toEqual("package-3");
});

// it("should respect --scope and --scoped-updated when used together", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO

return cmd;
}

it("--scope should filter packages", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This isn't part of the functionality that I'm adding, but I wanted to make sure this behaviour was tested in this manner, especially since I'm testing the combination of --scope and --since.

test/Command.js Outdated
const { filteredPackages } = run({ scopeUpdated: "" });
expect(filteredPackages.length).toEqual(2);
expect(filteredPackages[0].name).toEqual("package-2");
expect(filteredPackages[1].name).toEqual("package-3");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why is it that package-3 appears in the list when package-2 has changed? This is the default behaviour of the UpdatedPackagesCollector.

It would appear that packages that have devDependencies on packages that have changed get added to the list. This is more of a question than anything else, I guess, so that I understand it better.

@treshugart
Copy link
Contributor Author

@evocateur

This is the same as only-updated in that it acts as a flag if no ref is provided. However, it differs in that it allows you to provide a ref. For our use case, we'd probably just use master as the target since we can't currently get the target branch for a PR in BitBucket Pipelines. However, Travis does allow this, so one would probably run it against TRAVIS_BRANCH in a PR and leave it off if run from master.

With the current functionality, it would be very easy to have a build run against packages that actually haven't changed if you don't release on every commit or push, for whatever reason be it feature branches that eventually go into master or if you accumulate commits in master and release every so often.

@treshugart
Copy link
Contributor Author

I spoke to @jameslnewell about this internally, and he seemed to think that being able to specify a ref would be useful, too. Maybe we could work on merging the two ideas into this?

@evocateur
Copy link
Member

I'm cool with --only-updated=[sinceRef] or a more explicit --since=ref, sure.

We definitely want to change the this.flags.onlyUpdated references to this.options.onlyUpdated to support "durable" config settings in lerna.json, I missed this during the previous PR.

@treshugart
Copy link
Contributor Author

treshugart commented May 22, 2017

Okay, cool. Would you prefer I bring in latest master and rework the --only-updated flag in with this functionality (so we don't lose the extra tests with the first PR)? Or do you want to revert it and then use only this one?

Either way, I'll do the following:

  • Rename --scope-updated to --since
  • Squash back to a single commit
  • Add docs (I intentionally kept this out until everything was hashed out)

@evocateur
Copy link
Member

Rebase and squash is fine, I like new tests :)

@treshugart
Copy link
Contributor Author

Merged and squashed commits after merge. Will annotate updates.

@treshugart
Copy link
Contributor Author

Hmm, I don't think that rebase went as expected. I'll fix up.

@@ -675,6 +675,22 @@ $ lerna exec --scope my-component -- ls -la
$ lerna run --scope toolbar-* test
```

#### --since [ref]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I moved this to just after the --scope arg since it relates very closely to it.

README.md Outdated
```

```
$ lerna ls --since some-branch
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I noticed while doing my updates that --since when used with lerna ls seems to make lerna updated redundant (except that one shows versions and one doesn't).

@@ -52,52 +52,45 @@ export default class UpdatedPackagesCollector {
collectUpdatedPackages() {
this.logger.info("", "Checking for updated packages...");

const hasTags = GitUtilities.hasTags(this.execOpts);
const { execOpts, options } = this;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Boyscout: Instead of accessing on this or options multiple times, I destructured here.

this.logger.warn("", "No tags found!");
this.logger.info("", "Comparing with initial commit.");
}
if (GitUtilities.hasTags(execOpts)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

While this is a boyscout, it's also a fix for the lines I added to the test to make sure that since overrides the latest tag, if there are tags present.

}

this.logger.info("", `Comparing with ${since || "initial commit"}.`);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@evocateur (mentioning since I want to place special emphasis here), I removed the warning if no tags exist because it doesn't really feel like a warning, especially with the addition of --since as an empty arg is implicitly the latest tag (or initial commit).

If there's any contention here, or it's a breaking change, I'm more than happy to add it back in.

});

it("--since \"ref\" should return packages updated since the specified ref", () => {
// We first tag, then modify master to ensure that specifying --since will override checking against
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was the addition that caught the bug where the latest tag would override the specified ref in --since. I annotated the spot above that fixes it.

@treshugart treshugart force-pushed the master branch 2 times, most recently from 3914a29 to 16f4f54 Compare May 24, 2017 20:33
packageUpdates
);
}
const { filteredPackages } = this;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Boyscout: kept assignment but destructured and converted to const instead.


this.batchedPackages = this.toposort
? PackageUtilities.topologicallyBatchPackages(filteredPackages)
: [this.filteredPackages];
: [filteredPackages];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since we're not filtering anymore, we can use the const.

packageUpdates
);
}
const { filteredPackages } = this;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Boyscout: kept assignment but destructured and converted to const instead.

@treshugart treshugart changed the title feat: Add ability to specify a --scope-updated flag that applies to a… feat: Add ability to specify a --since flag that applies to a… May 24, 2017
@evocateur
Copy link
Member

@treshugart Just a quick note to say I haven't forgotten you, I'm just swamped at work and will try to carve out some time soon!

@treshugart
Copy link
Contributor Author

treshugart commented May 26, 2017

@evocateur ready for re-review. Not sure why AppVeyor is failing. I can't seem to spot the error, but it looks like something might have timed out? I ran the tests locally and everything seemed fine. I'll also have someone from my team review, too.

EDIT

It looks like I made this comment just after you had commented. Thanks for letting me know :)

@chrisui
Copy link

chrisui commented Jun 12, 2017

This looks great! I just opened an issue requesting this elsewhere. I also mentioned the use of a --until option (or --git-to in that issue) which might be good to add here as well?

See #876

@treshugart
Copy link
Contributor Author

@chrisui I personally don't have a use case for it (yet?), but it sounds like it could be useful. I would vote for keeping this PR as is with a plan to implement --until (or whatever) after it lands.

@treshugart
Copy link
Contributor Author

Hey @evocateur, I hate to be a pest, but I was hoping I could get a review / merge soon. We're currently running off of my fork and it seems that quite a few others need this as well. Cheers for the time you've spent already.

Copy link
Member

@evocateur evocateur left a comment

Choose a reason for hiding this comment

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

Really sorry I took so long to review this.


class TestCommand extends Command {}

function cli(cmd, ...args) {
Copy link
Member

Choose a reason for hiding this comment

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

Ideally, this would be the approach used for all unit tests of commands. The .run() method really needs to return a Promise, already... (out of scope for this PR, clearly)

List the contents of packages that have changed since the latest tag:

```sh
$ lerna exec --since -- ls -la
Copy link
Member

Choose a reason for hiding this comment

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

My only complaint with this usage is that it isn't as readable as lerna exec --only-updated. The nature of the beast, I suppose. (Aliases that are distinct long options are a bit awkward, and probably better to omit entirely).

@evocateur evocateur changed the title feat: Add ability to specify a --since flag that applies to a… Add --since flag to all commands that accept --scope Jun 28, 2017
@evocateur evocateur merged commit cf11901 into lerna:master Jun 28, 2017
@treshugart
Copy link
Contributor Author

No problem. Totally understand. Thanks for the review and merge!

@chrisui
Copy link

chrisui commented Jun 28, 2017

This is great 👍 good work!

@lock
Copy link

lock bot commented Dec 27, 2018

This thread has been automatically locked because there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Dec 27, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

lerna diff against arbitrary gitref lerna bootstrap should support --only-updated flag
3 participants