Open Xunnamius opened 4 years ago
Is it possible that some of the changes you made between versions rewrote history. It is important for the commit of the previous release to be found in the history of the branch.
I haven't dug into the details of your proposed change, but I use pre-releases regularly without seeing the issues you are describing. I've also manually added notes following the documented steps in a few cases where semantic-release was added to an existing project and had success in those cases as well.
Is it possible that something is simply not in the state that is expected in your scenario?
@travi Thanks for the response!
In the case of rewriting history, all permutations of git notes --ref semantic-release show commit-hash-tag-is-pointing-at
should fail too if the commit was rewritten (should say something like "no notes object found"), no? I'm no git expert yet :) But git does find the notes... if you don't use the tag name as the ref but the commit hash the tag is pointing to. Why are just tag refs causing a problem here? I even tried switching shells (and switching machines, and switching git versions) and it still happens.
Moreover, git tag --merged canary
shows all tags visible in the history of canary
, and that includes v3.0.0-canary.1
:
And looking at the git log
and git notes --ref semantic-release list
outputs above and comparing the hashes, all of the notes are added to all the correct commit hashes.
Also, running git log --notes='*'
shows commits and their notes side-by-side, and all release commits in repository history are printing their proper notes as expected, e.g.:
So all the notes exist, they have the proper contents, they point to commits that exist, those commits are properly tagged, those tags are all visible from the tip of canary
...
My proposed change is the addition of line 309 in lib/git.js
which runs git log -1 --pretty=format:%H ref
(ref
is a tag like v2.1.0
) and passes that result to git notes
instead of passing ref
directly. Strange that replacing a tag ref like v3.0.0-canary.1
or v2.1.0
with the commits they point to seems to fix it.
Anything's possible, so I'll whip up a MRE and see if I can replicate the behavior :)
Update:
So I attempted to create a MRE here on my local machine, but I couldn't initially reproduce the issue. Even when deploying directly from my development environment, it still worked. Issuing the raw command that failed in the other repo succeeded in the MRE repo:
$ git notes --ref semantic-release show v2.0.0-canary.1 | cat
{"channels":["canary"]}
Huh. In the old repo, I kept getting errors like:
git notes --ref=semantic-release show v3.0.0-canary.1
error: no note found for object 4dbe4cb6c81c408cf34869aa295c52d91eb37940
Which was very strange to me because git log show 4dbe4cb6c81c408cf34869aa295c52d91eb37940
just output commit d13f38f6aedd05840e438f62ff2092218a806984 (tag: v3.0.0-canary.1)
. Turns out that 4dbe4
object is the actual v3.0.0-canary.1
annotated tag object (and I learned something new about git ๐). semantic-release
is using annotated tags in the first repo and lightweight tags in the new MRE repo. So a command like git notes --ref=semantic-release show v3.0.0-canary.1
, where v3.0.0-canary.1
is an annotated tag, tries to get notes added to the tag object itself (4dbe4
) and not the release commit that semantic-release
actually added the notes to (and that tag 4dbe4
is pointing to), which is why using the actual commit hash instead of the tag name fixed it in #1709 ๐ฅณ
Unlike my local environment where I set up the MRE, I have my GitHub Actions pipeline setup so that all tags must be signed via tag.gpgsign=true
, which apparently forces tags to be annotated rather than lightweight. Early on, when I was first playing with semantic-release
, I was getting strange behavior where semantic-release
would fail after trying to open the default editor in the middle of the publication pipeline. I "fixed" it by adding EDITOR='echo semantic-release-bot > $1'
to the CI environment variables and thought nothing more of it, but now it makes sense why that was happening.
To evidence the two repos using different tags types, I ran git for-each-ref refs/tags
on both:
Original repo (workflow-playground):
Tag v1.0.15
was created on my local machine (to simulate there already being releases in the repo), which is why it's lightweight. Tag v2.0.0
was the first tag created by semantic-release and before I configured default tag signing, which is why it's also lightweight. After v2.0.0
, all tags are managed by semantic-release
and signed (and annotated).
Attempted MRE:
All tags in this repo are lightweight (they point directly to commits).
And for the cherry on top: forcing semantic-release
to sign release v2.0.0-canary.2
(complete with EDITOR
patch) and then pushing another release-triggering commit makes semantic-release attempt to re-release v2.0.0-canary.2
instead of v2.0.0-canary.3
, which is the buggy behavior described in the OP:
If I'm understanding this right, as a consequence of this bug, it appears all notes are functionally ignored by semantic-release
for repositories using annotated tags. The only reason semantic-release
appears to work at all with annotated tags is because of this line where note-related errors cause {"channels":[null]}
(default release branch) to be returned by default.
I also saw #1192 which makes me think semantic-release
should already be creating annotated tags by default (but I could easily be wrong, as I've stumbled upon #1266). Could this be a regression? Or is the existence of tag signing/annotated tags not supported by semantic-release
? If they are supported, a more holistic fix might be to move the notes off the commits and onto annotated tags, which semantic-release
would create instead by default (making my EDITOR
hack unnecessary), but that sounds like a massively breaking change. Instead, #1709, plus providing a message when execa
-ing the git tag
command if semantic-release
detects its about to create an annotated tag (or just populate the EDITOR
environment variable in via execa
options) would be a similarly holistic fix but without it being a breaking change. If annotated tags aren't supported, #1709 + the above would allow them to be supported out of the box, I think.
Arguments for supporting annotated tags too, from git-scm and stackoverflow:
Annotated tags are meant for release while lightweight tags are meant for private or temporary object labels. For this reason, some git commands for naming objects (like git describe) will ignore lightweight tags by default.
i'll look deeper into your details later, but would like to at least point out that annotated tag support was reverted, as mentioned in https://github.com/semantic-release/semantic-release/issues/1262.
thanks a lot for investigating so thoroughly.
As a final addition to the above, I implemented the EDITOR
behavior described here:
1709, plus providing a message when execa-ing the git tag command if semantic-release detects its about to create an annotated tag (or just populate the EDITOR environment variable in via execa options) would be a similarly holistic fix but without it being a breaking change.
So now my semantic-release
fork supports my repos of signed tags no hassles. Proof of concept is #1710.
Thanks for this awesome package!
Just want to second the appreciation for your thorough investigation here Bernard ๐๐ผ
same is happening with me too any solutions on this ?
I have a fork that rebases my PR fix onto semantic-release master every now and then. Once I get around to addressing gr2m's concerns (it keeps falling off my todo list sadly), I believe the maintainers might give my PR a second look and I can do away with the fork.
Is rebasing prerelease branches essentially not supported? I've now dug into how the notes stuff worked to be able to salvage prerelease branches that have been rebased and end up in this broken state... (I missed the troubleshooting entry) but I'd love to be able to rebase the branches without having to worry about this.
@Xunnamius does your change address this? I guess I'm a little fuzzy on exactly what it's fixing โ I guess it ensures that the notes point to commits orphaned from rebasing so that they still show up when calculating the next prerelease version?
I've got this issue on some of my repos.
Push something from a dev branch into beta
:
That will create a release v1.0.0-beta.1
so everything is Ok
~> git fetch origin +refs/notes/semantic-release:refs/notes/semantic-release
~> git notes --ref semantic-release show v1.0.0-beta.1
{"channels":["beta"]}
Merge beta
into rc
That will create a release v1.0.0-rc.1
on the exact same commit of the beta
release. So the notes will be shared.
~> git fetch origin +refs/notes/semantic-release:refs/notes/semantic-release
~> git notes --ref semantic-release show v1.0.0-rc.1
{"channels":["rc"]}
Push something new on beta
.
That will try to make a v1.0.0-beta.1
tag instead of v1.0.0-beta.2
and CI will fail because of tag already exist.
~> git fetch origin +refs/notes/semantic-release:refs/notes/semantic-release
~> git notes --ref semantic-release show v1.0.0-beta.1
{"channels":["rc"]}
I think the tag note must be :
{"channels":["rc", "beta"]}
But even in editing the note like this didn't unlock the CI and semantic-release
still fail because of tag already exist.
~> # that didn't work
~> git fetch origin +refs/notes/semantic-release:refs/notes/semantic-release
~> git notes --ref semantic-release show v1.0.0-beta.1
{"channels":["rc", "beta"]}
~> git notes --ref semantic-release add -f -m '{"channels":["rc", "beta"]}' v1.0.0-beta.1
~> git push origin refs/notes/semantic-release
If someone got a workaround to unlock CI when we got this case, it can help me a lot.
Also, I've some trouble to understand why semantic-release
use notes. I think it can parse tags to get the info contained in notes.
Maybe it's just to know the order of the release on the same tags ?
Can someone explain to me ?
As a workaround, I create a script that replace Semantic-Release
I use it in a GitHub action
It probably need some more work. I also add some info in the README.md
@jrolfs If you're experiencing the same problem I was, then at its root is that all notes are functionally ignored by semantic-release for repositories using annotated tags as explained in my very first posts above. My first PR makes semantic-release pay attention to annotated tags by using the commit hash instead of the tag ref when semantic-release executes the git notes
command:
Turns out that
4dbe4
object is the actualv3.0.0-canary.1
annotated tag object ... semantic-release is using annotated tags in the first repo and lightweight tags in the new MRE repo. So a command likegit notes --ref=semantic-release show v3.0.0-canary.1
, wherev3.0.0-canary.1
is an annotated tag, tries to get notes added to the tag object itself (4dbe4
) and not the release commit that semantic-release actually added the notes to (and that tag4dbe4
is pointing to), which is why using the actual commit hash instead of the tag name fixed it in #1709
My second PR stops semantic-release from asking for an additional message when creating an annotated tag to mark the new release, which screwed up my CD pipelines.
I merge my pre-release branches using git merge
and/or GitHub PRs rather than rebase since it's easier to keep the history straight. I'm not sure semantic-release supports rebasing since it effectively rewrites history and destroys the association between notes and commits.
@shiipou This issue will happen on repos that are using annotated tags (e.g. if you use gpg to sign your commits/tags). This is because, at least at the time I opened this issue, notes are ignored by semantic-release for repositories using annotated tags. semantic-release uses notes to enable complex configurations like when releases on multiple channels are associated with a single commit.
@Xunnamius ah, no this was a red herring/I was totally mistaken. My issue is with Git tags as of course rebasing clobbers the previous tags. I guess I had just gotten used to being able to rebase prerelease branches with Changesets since it uses files instead of tags.
Pls to ignore โ ๐ฌ โ sorry y'all
Hello, any update ?
I'm using GitHub Flow/Trunk Based Development thanks to
semantic-release
, and it's great! I'm going to move all my packages over to asemantic-release
CI/CD trunk-based flow, but most of them already have manually published releases. So, to create a uniform repo configuration for my packages, I've been playing with a dummy GitHub Actions/semantic-release repo. I tagged and manually released some initial commits tomain
to simulate switching a project with preexisting tags and releases over tosemantic-release
. I made several more commits tomain
and several successful semantic releases. Next, I configured a prerelease branchcanary
(channel is alsocanary
) offmain
and pushed a breaking change.semantic-release
published the prerelease no problem:v3.0.0-canary.1
.Current behavior
However, I made some more changes, I pushed them, I expected release
v3.0.0-canary.2
, but instead I got an error:So... it's trying to re-publish the same prerelease version,
v3.0.0-canary.1
? A quick scan of the issues shows problems similar to mine, perhaps related. The troubleshooting docs also talk about force pushing and git notes.Some facts about my issue:
v3.0.0-canary.1
is in the git history ofcanary
:{"channels":[null]}
while 6cae4d5 is the note with{"channels":['canary']}
:semantic-release
doesn't "see" thev3.0.0-canary.1
release it just made, instead finding the oldv2.3.4
release:And the 2d branch graph:
This same problem happens with GitHub Actions runners as well as my local machine when running
npx semantic-release -d
. I ended up spelunking down into the code similar to #1685 to see what was going on. It turns out that the problem may be git itself, or (perhaps more likely) the assumptions about howgit notes show
handles references. Specifically this line. It seems commands likegit notes --ref semantic-release show v2.1.0
do not work (or at least don't seem to). However, when using the commit hash instead of the tag name, i.e.git notes --ref semantic-release show 1eeba8e
, everything works:After forking
semantic-release
, adding a line that replaces the tag ref with the hash of the commit its pointing to, and replacingsemantic-release
withXunnamius/semantic-release
in my package.json, pushes to my prerelease branch are now released properly.Expected behavior
v3.0.0-canary.1
is found as the previous release tag with branchcanary
and channelcanary
. The next release should then bev3.0.0-canary.2
.Environment
@semantic-release/commit-analyzer
@semantic-release/release-notes-generator
@semantic-release/exec
@semantic-release/changelog
@semantic-release/npm
@semantic-release/git
@semantic-release/github