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: add optional annotated or signed tags #1871

Open
wants to merge 25 commits into
base: master
Choose a base branch
from

Conversation

DiogoAbu
Copy link

@DiogoAbu DiogoAbu commented Apr 6, 2021

This adds the option to annotate or sign the tag.
This is opt-in, the default values will result in the current implementation.

To make an unsigned, annotated tag:

{
  "tagAnnotate": true
}

To make an signed tag:

{
  "tagSign": true
}

Or by setting the git config tag.gpgsign to true.

To customize the tag message:

{
  "tagMessage": "release ${nextRelease.version}"
}

The message will be applied to the tag only if one of the following is true: tagAnnotate, tagSign or git config tag.gpgsign. Otherwise the tag is considered lightweight, which is the current implementation.

Also, tagSign takes precedence over tagAnnotate. The git config tag.gpgsign takes precedence over both.

@DiogoAbu
Copy link
Author

DiogoAbu commented Apr 6, 2021

#1871 #1589 #1266 #1192 #214

@t1m0thyj
Copy link

Hi, may I ask what's the status of this PR? We are also missing this feature, and adding it will be highly appreciated 🙏

@gr2m
Copy link
Member

gr2m commented May 21, 2021

sorry for not getting back to it. Both @travi and I are too occupied right now, but we are discussing how to make more time for @semantic-release. Please give us some more time

@stuart-warren
Copy link

stuart-warren commented Jul 1, 2021

tools like miniver currently require annotated tags

https://github.com/jbweston/miniver

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.
https://git-scm.com/docs/git-tag

@DanySK
Copy link

DanySK commented Nov 26, 2021

I need annotated tags as well

@DanySK
Copy link

DanySK commented Nov 26, 2021

Meanwhile, I concocted a terrible workaround to be able to get annotated tags:

tagFormat: "${version}"
plugins:
  - "@semantic-release/commit-analyzer"
  - "@semantic-release/release-notes-generator"
  - "@semantic-release/changelog"
  -
    - "@semantic-release/exec"
    - publishCmd: |
        git tag -a -f ${nextRelease.version} ${nextRelease.version} -F CHANGELOG.md
        git push --force origin ${nextRelease.version}
        # commands that need an annotated tag to work
  - "@semantic-release/github"
  - "@semantic-release/git"

@DiogoAbu
Copy link
Author

As a alternative to @DanySK...
I use patch-package with this file passing -s to make it signed and -m to add the required message:

semantic-release+18.0.0.patch

diff --git a/node_modules/semantic-release/lib/git.js b/node_modules/semantic-release/lib/git.js
index 8aaf884..53a610f 100644
--- a/node_modules/semantic-release/lib/git.js
+++ b/node_modules/semantic-release/lib/git.js
@@ -221,7 +221,7 @@ async function verifyAuth(repositoryUrl, branch, execaOptions) {
  * @throws {Error} if the tag creation failed.
  */
 async function tag(tagName, ref, execaOptions) {
-  await execa('git', ['tag', tagName, ref], execaOptions);
+  await execa('git', ['tag', tagName, ref, '-s', '-m', `release ${tagName}`], execaOptions);
 }
 
 /**

@DanySK
Copy link

DanySK commented Nov 26, 2021

Still, it would be nice to see your PR merged

@eladchen
Copy link

@DanySK - While you wait, I recommend you check out https://github.com/abstracter-io/atomic-release

You can create a custom command that creates an annotated tag instead of a lightweight

@lsagetlethias
Copy link

Hello, what is the status of this PR?

@DanySK
Copy link

DanySK commented Jan 3, 2022

I'm also interested to understand what is holding this back, it's a major hassle for me at the moment

@Langstra
Copy link

Langstra commented Jan 5, 2022

We ran into an issue that looked like this, but in the end turned out to be something slightly different. Semantic-release creates notes and Gitlab treats those the same as commits. Thus when requiring signed commits, they also require you to sign notes, which is not possible.
https://gitlab.com/gitlab-org/gitlab/-/issues/209901

@maaheeb
Copy link

maaheeb commented Nov 16, 2022

Would like to see this as well!

@sharkymcdongles
Copy link

+1 for asking for a merge pretty please <3

@travi @gr2m maybe pretty please

@SchoolGuy
Copy link

@travi Is there anything one can do to help with the progress of this PR? I would like to enable signed commits and tags for my repository but cannot do that due to the fact that this feature is missing with this project. My GPG key for the project would be available as a secret in GitHub Actions and Git would obviously be configured to use the mentioned key.

@fastman
Copy link

fastman commented Oct 25, 2023

Looking forward to having this merged.

Copy link
Member

@sheerlox sheerlox left a comment

Choose a reason for hiding this comment

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

I've added a few comments. The main doubt I have with this change is the git config precedence over the semantic-release one.

I also notice you haven't added test cases covering your changes.

P.S. Sorry for the late response, I do realize this PR is over 2 years old, and I hope you're still willing to push it through after all that time.

await execa("git", ["tag", tagName, ref], execaOptions);
async function tag(tagName, ref, {tagAnnotate, tagSign, tagMessage}, execaOptions) {
const args = ["tag", tagName, ref];
const gitTagSign = await shouldSignTag(execaOptions);
Copy link
Member

Choose a reason for hiding this comment

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

What is the reasoning behind accounting for & giving precedence to the git configuration?

I see a few problems with that:

  • if I set tagSign to false in my config, it might still sign the tag based on my system configuration
  • it makes the changes breaking, as it will start unsolicitedly signing tags

Because of that, I don't think the git configuration should be accounted for. If overriding the release configuration behavior is needed in a specific setup, overriding it with the CLI flag is enough.

Copy link
Author

@DiogoAbu DiogoAbu Nov 24, 2023

Choose a reason for hiding this comment

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

If I remember correctly...
I check for the git config first because signed tags must have a message, otherwise it fails. Currently if I set tag.gpgsign to true it will fail when creating a tag.
So if you set tagSign to false and tag.gpgsign is true it will still sign a tag to prevent the release from failing.
That said I don't think it is unsolicitedly if I previously set tag.gpgsign.
Does this make sense?

If one of -a, -s, or -u is passed, the command creates a tag object, and requires a tag message.

@@ -296,7 +320,9 @@ test.serial('Read configuration from file path in "extends"', async (t) => {
branches: ["test_branch"],
repositoryUrl: "https://host.null/owner/module.git",
tagFormat: `v\${version}`,
plugins: ["plugin-1", ["plugin-2", { plugin2Opt: "value" }]],
Copy link
Member

Choose a reason for hiding this comment

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

This should probably not be removed.

Default: `release ${nextRelease.version}`<br>
CLI arguments: `-tm`, `--tag-message`

The message for the tag. The tag message is generated with [Lodash template](https://lodash.com/docs#template) and will be compiled with the `nextRelease` variable.
Copy link
Member

Choose a reason for hiding this comment

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

nextRelease being an internal variable, there should be a link to its documentation.

@@ -23,6 +23,14 @@ Usage:
.option("b", { alias: "branches", describe: "Git branches to release from", ...stringList, group: "Options" })
.option("r", { alias: "repository-url", describe: "Git repository URL", type: "string", group: "Options" })
.option("t", { alias: "tag-format", describe: "Git tag format", type: "string", group: "Options" })
.option("ta", {
alias: "tag-annotate",
describe: "Whether to make an unsigned, annotated tag",
Copy link
Member

Choose a reason for hiding this comment

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

Streamline to "Toggle tag annotation".

type: "boolean",
group: "Options",
})
.option("ts", {alias: "tag-sign", describe: "Whether to make GPG-signed tag", type: "boolean", group: "Options"})
Copy link
Member

Choose a reason for hiding this comment

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

Streamline to "Toggle tag signing".

{
tagAnnotate: options.tagAnnotate,
tagSign: options.tagSign,
tagMessage: template(options.tagMessage)({ nextRelease }),
Copy link
Member

Choose a reason for hiding this comment

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

I would make the tagMessage optional, and default to the nextRelease.gitTag.

Example use case: I want my release tags to be signed, but I don't care about the annotation message.

Copy link
Author

Choose a reason for hiding this comment

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

I tought it already was optional, and the default, set on get-config.js, is release \${nextRelease.version}.

@AliSajid
Copy link

Looking forward to this getting merged.

@Korben11
Copy link

In the meantime, my workaround doesn't require a force push for using Gitlab API.

#!/usr/bin/env bash
# release.sh

# TODO: remove when merged, this is workaround for annotated tags
# https://github.com/semantic-release/semantic-release/pull/1871

if [ -z "$1" ]; then
	echo "Please provide a tag."
	echo "Usage: ./release.sh v[X.Y.Z]"
	exit
fi

GIT_TAG=$1

JSON_STRING=$( jq -n \
                  --arg tag_name "${GIT_TAG}" \
                  --arg ref "main" \
                  '{tag_name: $tag_name, ref: $ref}' )

if [ -n "$2" ]; then
  NOTES=$2
  JSON_STRING=$(echo $JSON_STRING | jq -r --arg message "${NOTES}" '.message = $message')
fi

echo "Recreating annotated tag ${GIT_TAG}..."

URL="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/repository/tags"

curl -X DELETE "${URL}/${GIT_TAG}" -H "PRIVATE-TOKEN: ${GITLAB_TOKEN}"
curl -X POST "${URL}" -H "Content-Type: application/json" -H "PRIVATE-TOKEN: ${GITLAB_TOKEN}" -d "${JSON_STRING}"
{
  ...
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/git",
    [
      "@semantic-release/exec",
      {
        "publishCmd": "./release.sh ${nextRelease.gitTag} \"${nextRelease.notes}\""
      }
    ],
    "@semantic-release/gitlab"
  ],
  ...
}

@candrews
Copy link

I'm eagerly awaiting the merge of this improvement 🤞

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.

None yet