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(cli): add --staged flag #2300

Merged
merged 9 commits into from
Apr 12, 2024
Merged

Conversation

castarco
Copy link
Contributor

@castarco castarco commented Apr 4, 2024

Summary

This PR introduces a new --staged flag that allows biome to select only the files that are staged to be committed.

Motivation

Long version

TLDR

There is some semblance with --changed, but its behaviour is different:

  • --changed is useful to run certain checks in CI environment, selecting only the files that changed between two git "refs" (they can be explicit or implicit).
  • In contrast, --staged is useful in local environments, to be used in git hooks such as pre-commit.

Test Plan

  • I introduced new unit tests covering basic behaviour changes
  • I tested the generated binary manually to verify that it works exactly as expected

"Mixed" Performance Results

What follows is for a very small repository.

When there are no changes

Performance is slightly better

Screenshot 2024-04-04 at 14 28 49

When there is a small number of changes

Performance is slightly worse 🤔, I suspect that this because of the extra git call.

Screenshot 2024-04-04 at 14 28 28

I hypothesize that this extra overhead should be "absorbed" in bigger repositories with many more files.

@github-actions github-actions bot added A-CLI Area: CLI A-Core Area: core labels Apr 4, 2024
Copy link

netlify bot commented Apr 4, 2024

Deploy Preview for biomejs ready!

Name Link
🔨 Latest commit 40d812b
🔍 Latest deploy log https://app.netlify.com/sites/biomejs/deploys/6618ee6ad4c97f0008823723
😎 Deploy Preview https://deploy-preview-2300--biomejs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 99 (🟢 up 4 from production)
Accessibility: 97 (no change from production)
Best Practices: 100 (no change from production)
SEO: 93 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify site configuration.

@github-actions github-actions bot added the A-Changelog Area: changelog label Apr 4, 2024
@castarco castarco marked this pull request as ready for review April 4, 2024 10:35
@github-actions github-actions bot added the A-Website Area: website label Apr 4, 2024
@castarco castarco changed the title feat: add --staged flag feat(cli): add --staged flag Apr 4, 2024
@castarco castarco force-pushed the feat-staged-flag branch 2 times, most recently from 31a28a9 to c5c773b Compare April 5, 2024 10:06
Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

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

I had a quick look, and it seems that the CI command isn't covered?

I know that the new option shouldn't work in CI, but we should at least terminate the process and raise a diagnostic, saying that this option isn't valid in the CI environments

Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

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

I only noticed now that the new options were added only for specific commands, so you can discard my previous comment. I left few suggestions, and I think we can merge the PR once they are addressed

Comment on lines 162 to 166
if since.is_some() {
if !changed {
return Err(CliDiagnostic::incompatible_arguments("since", "changed"));
}
if staged {
return Err(CliDiagnostic::incompatible_arguments("since", "staged"));
}
}

if changed {
if staged {
return Err(CliDiagnostic::incompatible_arguments("changed", "staged"));
}
paths = get_changed_files(&session.app.fs, &configuration, since)?;
} else if staged {
paths = get_staged_files(&session.app.fs)?;
}
Copy link
Member

Choose a reason for hiding this comment

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

Considering how the code is repeated, maybe it makes more sense to have a function in commands/mod.rs that does the check, and each command imports it and calls it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Extracted 🏗️ .

CHANGELOG.md Outdated Show resolved Hide resolved
website/src/content/docs/internals/changelog.md Outdated Show resolved Hide resolved
Signed-off-by: Andres Correa Casablanca <[email protected]>
Signed-off-by: Andres Correa Casablanca <[email protected]>
Signed-off-by: Andres Correa Casablanca <[email protected]>
Signed-off-by: Andres Correa Casablanca <[email protected]>
return error when --since and --staged are set at the same time.

Signed-off-by: Andres Correa Casablanca <[email protected]>
Signed-off-by: Andres Correa Casablanca <[email protected]>
Signed-off-by: Andres Correa Casablanca <[email protected]>
Signed-off-by: Andres Correa Casablanca <[email protected]>
Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

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

This is a great addition; thank you!

@ematipico ematipico merged commit af121e3 into biomejs:main Apr 12, 2024
15 checks passed
@Conaclos
Copy link
Member

While I was writing the blog post for the Biome 1.7, I wonder if we should not rename --staged to --staged-files to highlight the fact that unstated changes in staged files are not ignored.

Any opinion?

@ematipico
Copy link
Member

highlight the fact that unstated changes in staged files are not ignored.

I don't understand what you mean. I think --staged is fine; it's the git dialect.

@Conaclos
Copy link
Member

I don't understand what you mean. I think --staged is fine; it's the git dialect.

i mean that you can stage a file and then modify it:

❯ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   a

❯ echo "more" >> a

❯ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   a

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   a

You end with a staged file with unstaged changes.

@castarco
Copy link
Contributor Author

castarco commented Apr 12, 2024

@Conaclos Regarding your first point, you are right. Although I think it will be difficult to describe, and also to find "good solutions".

I'll try to expand what I understand you said:

  1. Let's say I have 3 staged files: A, B, and C.
  2. Let's also say that C has new changes after it has been staged.
  3. When biome format/check/lint reads the file C it will see what we have in our local filesystem (including the changes after it has been staged), and it will apply its fixes over that last version, not over what was staged.

For this I imagine 2 potential solutions:

  • When there is a discrepancy between "staged" and "local filesystem", Biome could issue a warning.
    • This one requires an extra git command to obtain the list of unstaged changes.
  • A more sophisticated and aggressive approach would involve running a pair of git stash and git stash pop commands (before and after the fixes).
    • This one requires 2 extra git commands (and they are also slower because they imply filesystem writes)

You end with a staged file with unstaged changes.

That's true, although I think it's a different problem from the previous one, and there are some relevant points that make it easier to understand and solve:

  • many people run their hooks as linters without --apply.

  • Without staged, when we perform the git command to obtain the staged files, many times "we" filter them by extension before passing them to Biome. This can be a problem because, in a way, it is equivalent to having multiple sources of truth (we have "include/exclude" filters in Biome's configuration, but also in our shell script)

  • This functionality can be further extended in the future, in two separate ways (not necessarily exclusive, but if any of them is implemented, then the other becomes irrelevant):

    • Making it possible for the biome format and biome check commands to output only the list of files they changed. This could be passed directly as arguments to git add.

      I imagine something like git add $(biome check --staged --apply --list-fixed .) (I didn't check yet if such an option already exists)

    • Internalizing the git add command inside Biome (although I prefer the previous option over this one, as it is lighter and more generic)


I'd be happy to discuss what you and other people think about these options, and if there are any other ideas floating around related to this.

@Conaclos
Copy link
Member

@castarco
I didn't suggest fixing it, just renaming the flag to be clear about that.
Any way I am also happy with --staged. I was just expressing a concern/idea.

For this I imagine 2 potential solutions:

When there is a discrepancy between "staged" and "local filesystem", Biome could issue a warning.
This one requires an extra git command to obtain the list of unstaged changes.
A more sophisticated and aggressive approach would involve running a pair of git stash and git stash pop commands (before and after the fixes).
This one requires 2 extra git commands (and they are also slower because they imply filesystem writes)

The first option might be nice :)
This seems to be a good fit for Biome.

I think the second suggestion is a bad idea, because if the user uses --apply/--write, you can end up with conflicts when reapplying the stashed changes.
This can be very confusing for users.
This sort of thing should be left to dedicated tools like git-format-staged and the like.

Without staged, when we perform the git command to obtain the staged files, many times "we" filter them by extension before passing them to Biome. This can be a problem because, in a way, it is equivalent to having multiple sources of truth (we have "include/exclude" filters in Biome's configuration, but also in our shell script)

I am unsure to follow you there. Users should rely only on a Biome configuration and --files-ignore-unknown=true to filter files.

Making it possible for the biome format and biome check commands to output only the list of files they changed. This could be passed directly as arguments to git add.

I am not sure if there is so much value for that. A user could simply run git update-index --again — assuming that there is no unstaged changes before the formatting/linting.
However, I am not opposed to the idea, it could have other applications...

Internalizing the git add command inside Biome (although I prefer the previous option over this one, as it is lighter and more generic)

I think that it is a bad idea because this could be confusing and blur the line between Biome and Git.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Changelog Area: changelog A-CLI Area: CLI A-Core Area: core A-Website Area: website
Projects
None yet
Development

Successfully merging this pull request may close these issues.

📎 Feature: --staged option to simplify the creation of git hook scripts
3 participants