Skip to content

feat: add jujutsu walker #601

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Conversation

delafthi
Copy link

@delafthi delafthi commented Jun 19, 2025

This PR introduces a new Jujutsu walker to numtide/treefmt, modeled after the existing Git walker but tailored to Jujutsu repositories. Key differences include:

  • The list command does not update the index automatically, so untracked files must be explicitly added via jj commands.

This addition enables proper handling of Jujutsu ignore rules without requiring co-located Git repos, improving integration and file traversal accuracy for Jujutsu users.

I lack Go experience and primarily copied, and adapted the existing Git walker by adjusting commands. I would welcome guidance or collaboration to develop a more idiomatic and robust implementation.

@delafthi delafthi changed the title feat(walk): add method to walk the filesystem with jujutsu feat: add jujutsu walker Jun 19, 2025
@delafthi delafthi force-pushed the push-rtxoonqmxkxy branch 2 times, most recently from 2dd1b91 to 60b2c48 Compare June 19, 2025 14:26
@delafthi
Copy link
Author

Jujutsu tests in cmd/root_test.go still fail. Needs investigation.

@delafthi delafthi force-pushed the push-rtxoonqmxkxy branch 7 times, most recently from 56904ba to 84f58f0 Compare June 21, 2025 20:29
- added jujutsu module similar to the git module, which provides the `IsInsideWorktree` function
- added jujutsu walker, with the following differences to the git walker
  - the list command does not update the index. thus, new files are not listed, the user has to add them to the index first by running a `jj` command
- added jujutsu walker test
- added jujutsu walker root test
- adapted config and docs
@delafthi delafthi force-pushed the push-rtxoonqmxkxy branch from 84f58f0 to c6d51bc Compare June 21, 2025 21:36
Copy link
Collaborator

@jfly jfly left a comment

Choose a reason for hiding this comment

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

The approach here looks good to me.

In the future, it could make sense to create some abstraction over git and jj, but IMO that's not warranted here. Copying and tweaking is good, and the tests you're adding are super valuable if we ever feel the need to do a future refactor.

@@ -329,6 +330,21 @@ func determineTreeRoot(v *viper.Viper, cfg *Config, logger *log.Logger) error {
}
}

// attempt to resolve with jujutsu
Copy link
Collaborator

Choose a reason for hiding this comment

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

If walk == auto, do we first attempt to resolve with git, and then attempt to resolve with jujutsu? That feels silly to me: we should not keep searching after we find a tree route. In other words, guard this with cfg.TreeRoot == "" (as we do below).

I suspect there's a flatter refactor of all this that looks less like the current case with a big default block and is instead:

  1. if no tree root, search with tree root file
  2. if (still) no tree root, search with tree root cmd
  3. if (still) no tree root (and walk is auto or git), search with git
  4. if (still) no tree root (and walk is auto or jujutsu), search with jujutsu
  5. if (still) no tree root, use the directory containing the config file

If you do opt to make this refactor, please split it into a separate initial commit that we could merge first.

cmd.Dir = path

err := cmd.Run()
if err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This must error out of jj is not installed, right? What happens? Is the user still able to use treefmt?

jjCmd = exec.Command("jj", "file", "track", "--config", "signing.backend=none", ".")
as.NoError(jjCmd.Run(), "failed to add everything to the index")

// update jujutsu's index (disable signing for testing)
Copy link
Collaborator

Choose a reason for hiding this comment

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

(disable signing for testing)

This is pretty repetitive. Can we instead create a config file for the test?

as.NoError(jjCmd.Run(), "failed to init jujutsu repository")

// run before adding anything to the index
// we shouldn't pick up untracked files, because here the jujutsu walker differs from the git walker
Copy link
Collaborator

Choose a reason for hiding this comment

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

I have no knowledge of jj. I can't tell if this comment is telling me something fundamentally different about jj, or if it's telling me something about treefmt's jj walker implementation. Could you rephrase this to make it clear?

}),
)

// try with a path not in the git index
Copy link
Collaborator

Choose a reason for hiding this comment

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

git index

Is this the right term with jj?

reader, err := walk.NewJujutsuReader(tempDir, "", &statz)
as.NoError(err)

files := make([]*walk.File, 33)
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: The number 33 looks pretty magical here. Is there some way to get rid of it? If not, could you add some explanation?

@@ -208,7 +209,10 @@ func NewReader(
// for now, we keep it simple and try git first, filesystem second
Copy link
Collaborator

Choose a reason for hiding this comment

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

This comment is no longer accurate.

nextLine := func() (string, error) {
line := j.scanner.Text()

if len(line) == 0 || line[0] != '"' {
Copy link
Collaborator

Choose a reason for hiding this comment

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

line[0] != '"'

This needs some explanation. What are we skipping? Is this really safe? Is there a more structured (json?) output we could consume instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants