pypa / setuptools-scm

the blessed package to manage your versions by scm tags
https://setuptools-scm.readthedocs.io/en/latest/
MIT License
849 stars 213 forks source link

Support jujutsu (jj) VCS #1070

Open dbarnett opened 3 weeks ago

dbarnett commented 3 weeks ago

Would it be possible to support https://github.com/martinvonz/jj so that if I clone a repo of a python project using that, I'm still able to build its python package contents normally?

At least in the case of their git backend that could be as simple as detecting if the repo dir contains a .jj/repo/store/git/ and running the existing git detection against that $GIT_DIR (example: https://martinvonz.github.io/jj/latest/github/#using-github-cli).

RonnyPfannschmidt commented 3 weeks ago

That needs some research, at first glance its probably possible

But there's a need to verify all plumbing command's are available and we need automated tests for it

It's not something I can currently send time on

RonnyPfannschmidt commented 3 weeks ago

A colocated repo may be the easiest start

Anything more needs research

dbarnett commented 3 weeks ago

Yeah, actually colocated repos already work (they're just a normal git repo with an extra .jj/ subdir). The others should be as trivial as adding an alternate gitdir path to check.

RonnyPfannschmidt commented 3 weeks ago

as far as im aware, jj will know the correct metadata, so id strongly prefer using jj commands over pretending a jj repo is a drunk git repo

dbarnett commented 3 weeks ago

Fair 😄

I'm involved with the jj project, so LMK if I can help here too with the research / coding.

RonnyPfannschmidt commented 2 weeks ago

the key part is whether there are commands to give us some extra details on the worktree

a backend should be fairly straightforward, but a key part wil lbe testign how we get what version when in the testsuite

RonnyPfannschmidt commented 2 weeks ago

so if jj had a way to get the metadata for "infer development version from scm metadata" in a easy way, it might be as simple as a single command

dbarnett commented 2 weeks ago

Some relevant jj commands for reference...

One gotcha: the @ part should probably be something like git_head(), but ideally not git-specific... I'll do some more digging on that part...

RonnyPfannschmidt commented 2 weeks ago

lovely starting point

dbarnett commented 2 weeks ago

K, this one-liner should spit out one or two lines of input to determine the necessary tag/commit metadata:

$ jj log --no-graph \
    -r 'latest(::@ ~ (empty() ~ tags()))' \
    -r 'latest(::@ & tags())' \
    --template 'tags++" "++change_id++"\n"'
 rqpqstnkkssmnpxtrotnoomxnrvnuvwo
v0.14.0 vktsrykqlynwupyvuupoxqsqnqswzkqo

If there's no tagged ancestor it'll be missing the 2nd line of output (triggering the fallback_version or error case):

 rqpqstnkkssmnpxtrotnoomxnrvnuvwo

If the "current commit" IS the last tagged commit it'll resolve both revisions as the same and spit out a single line with a tagged commit (meaning it's a clean tagged version and doesn't need a hash suffix):

v0.14.0 vktsrykqlynwupyvuupoxqsqnqswzkqo

Details on the revset mini-language at https://martinvonz.github.io/jj/latest/revsets/. For a quick explanation of the mechanics here, the latest(::@ ~ (empty() ~ tags())) means "last commit that's part of the current working copy that's not empty OR is tagged". The latest(::@ & tags()) means "last commit that's part of the current working copy that's tagged".

Filtering out empty commits is important because jj paradigms usually have an empty commit on top of the "real" commit (akin to git's staging area).

RonnyPfannschmidt commented 2 weeks ago

so how to add the distanceto the listing

we need current commit id, last reachable tag, distance in commits to the tag to match what we do with the others

dbarnett commented 2 weeks ago

One way would be to run 2 separate commands, one to figure out the tag and another to find all newer commits:

  1. jj log -r 'latest(heads(::@ & tags()))' --no-graph -T 'tags++" "++change_id++"\n"' -> v0.14.0 vktsrykqlynwupyvuupoxqsqnqswzkqo
  2. jj log -r 'v0.14.0::@ ~ empty()' --no-graph -T 'change_id++"\n"' -> (D lines of commit IDs for distance D>=0)

That might act funny when there are branched/merged commits, depending on what you mean by "distance", but in the case of multiple commit paths from tag to head I'm not sure there's a simple way to flatten to "longest distance" or "shortest distance" using the revset language, without separate processing.

dbarnett commented 2 weeks ago

That might act funny when there are branched/merged commits, depending on what you mean by "distance"...

Nice, I verified those commands seem correct and it gets the same count git describe does in the case of merge commits (just the total unioned count of all commits between between TAG and HEAD).