isamert / scli

a simple terminal user interface for signal messenger (using signal-cli)
GNU General Public License v3.0
439 stars 40 forks source link

Version string in release archives changes, which makes packaging harder #151

Closed grembo closed 2 years ago

grembo commented 2 years ago

(tagging @0mp, who is maintaining the FreeBSD port)

VERSION contains a version string that changes based on the state of the archive.

https://github.com/isamert/scli/blob/d9b38cf874aa6466f503a0b1df447d47ffad8326/VERSION#L1

This means, right after v0.6.5 was released, the file contained:

d2f437a (HEAD -> master, tag: v0.6.5, develop)

later this changed to

d2f437a (tag: v0.6.5).

This results in hashes of artifacts changing, which means package builders relying on those being correct end up not being able to fetch the package - one would think that official artifacts stay the same, but it appears that this might actually not be the case (comparing contents of v0.6.6 and v0.6.5 sources on the release page lead to this assumption).

There a discussion about this here: https://github.com/python-versioneer/python-versioneer/issues/217

exquo commented 2 years ago

Thanks for reporting, and for pointing to the same problem in the python-versioneer repo! I can see how this is an issue for the packagers. We definitely want to make life easier for you guys!

Here is what's happening:

We want scli --version to print a meaningful output whether scli has been obtained with git clone or downloaded from GitHub as a zip / tar.gz archive. But I don't want to have to update the version string somewhere in the source code, and then make a 'bump version' commit before every release. Instead, getting the version number is taken care of by get_version() coupled with the VERSION file. If scli finds a .git dir, then scli --version runs git describe. If, on the other hand, scli has been downloaded as an archive from GitHub, then GitHub runs git archive to create that file; thanks to a hook in .gitattributes, during this process the contents of VERSION file are replaced with the actual version info, similar to that printed by git describe (see comments in the VERSION file). Unfortunately, it's not exactly the same as git describe: we are limited to what git log's --pretty=format:'...' provides. The closest thing to what we want - the latest tag name - is the %d placeholder, which comes burdened with this extranous information about git branches pointing to the current commit. And those can change, of course, e.g. when a new commit is added to a branch that initally pointed to the tag. python-versioneer apparently uses the same technique. Our version is a minimal implementation of the same idea.

Now, the problem arises because the archive files that GitHub provides for downloading, like the 'source code' files on the releases page, are generated dynamically at download time. This implies that there is no guarantee that the hashes of zip / tar.gz files downloaded at different times will stay the same. It's the same thing that causes #143.

Potential solutions

I am leaning towards the first option as the "least worst". It will also solve #143 and the potential future issues arising from relying on dynamically generated archive files. But none of the above seem ideal. Suggestions welcome!

@0mp has this come up in the past? Is this commit relevant? (The message "Fix scli --version")

@alexeyre can this be a problem for nixpkgs too?

grembo commented 2 years ago

@exquo What about using the %(describe) placeholder instead? It's available since git 2.32.

Example:

$Format:%h %(describe:match=v*)$

The above matches all annotated tags which start with a "v". So the one caveat is that tagging has to happen using git tag -a <tagname> (which seems like good practice for releases anyway).

The results look like this:

0bb2874 v0.0.1
aa12f3e v0.0.1-1-gaa12f3e
c41b211 v0.0.3

Which relate to:

  1. Build/export of version v0.0.1
  2. Build/export of first commit after version v0.0.1 (with hash)
  3. Build/export of version v0.0.3

I created a test repo to verify that this is actually supported by github: grembo/gitformattest

Testing shows that version strings stay stable this way.

grembo commented 2 years ago

The next release of git should contain this change, which will allow to do:

$Format:%h %(describe:match=v*:tags=true)$

to get rid of the annotation requirement on tags (even though, I kind of like using them anyway).

exquo commented 2 years ago

What about using the %(describe) placeholder instead? It's available since git 2.32.

That's exactly what we need here, thanks so much!

I'm on an older git version, so was not aware of this addition. Ironically, it's right there next to %d in the git formatter documentation linked to above 🤦.

one caveat is that tagging has to happen using git tag -a <tagname>

Yes, we're using git's annotated tags. I agree it's a good practice regardless.

If you want to make a PR with this change to the VERSION file, I'd be happy to merge.

That should take care of this particular problem, but other issues caused by changing hashes of dynamically generated files might come up in the future. So, (note-to-self), we might still want to start uploading our own archive files to the releases.