Skip to content

fix(version): create correct independent tags when using --sign-git-tag#3917

Merged
JamesHenry merged 5 commits intolerna:mainfrom
ivml:fix/version-sign-git-tag
Dec 15, 2023
Merged

fix(version): create correct independent tags when using --sign-git-tag#3917
JamesHenry merged 5 commits intolerna:mainfrom
ivml:fix/version-sign-git-tag

Conversation

@ivml
Copy link
Copy Markdown
Contributor

@ivml ivml commented Dec 8, 2023

Since lerna@7.3.0, running lerna version with independent versioning and the --sign-git-tag flag would always create 0, 1, ... N as tags instead of the actual version.

Description

A recent fix done in #3832 introduced a new issue. In TypeScript, for (const tag in tags) would iterate through the array of tags. However, for...in returns a list of keys on the tags object, meaning that it iterates through the indices of the array, rather than the values. This means that regardless of what version number we are creating a tag for, that value will never be used - its index in the tags array will be used instead.

The issue is a bit niche, as it only happens when the repo is configured to use independent versioning and the --sign-git-tag flag is used.

Motivation and Context

This is an issue because your project might have a specific version (e.g. 1.0.0), but lerna version will create the tag 0 for it. This is especially crucial when using --conventional-commits, as that flag uses the latest tag in order to evaluate the next version bump.

The issue is described in more detail in #3916.

How Has This Been Tested?

For this fix, I wrote some E2E tests in e2e/version/src/sign-git-tag.spec.ts that bump the version and use the --sign-git-tag flag. You can see the tests failing when using for...in, but pass when using for...of.

Things get a bit interesting - since the E2E tests run actual git commands, the tests need a GPG key, otherwise they will fail. For this reason, I have changed the ci.yml workflow to generate a GPG key, store its ID and revocation file, configure git to use the key, and finally, revoke and delete the key after the tests pass.

I have a feeling this might be overkill, and it probably makes testing locally harder, as it implies the user has setup a key themselves.

Therefore, I would love some feedback on the tests - whether it was a good idea, whether the implementation was overkill (especially for a one-word change), and whether there are alternatives (e.g. mocking git signing somehow).

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Chore (change that has absolutely no effect on users)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

Copy link
Copy Markdown
Member

@JamesHenry JamesHenry left a comment

Choose a reason for hiding this comment

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

Thanks a lot for this @ivml!

Out of curiosity was this GPG key gen approach copied from/inspired by another open source repo?

NX_AGENT_NAME: ${{ matrix.agent }}

- name: Revoke and delete GPG key
run: |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We would want this to always run, even in error cases, right? So we need to add the if always syntax to this step

- name: Revoke and delete GPG key
run: |
# As instructed in the revocation file, the colon needs to first be removed
sed -i "s/:-----BEGIN PGP PUBLIC KEY BLOCK-----/-----BEGIN PGP PUBLIC KEY BLOCK-----/" $REVOCATION_FILE
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
sed -i "s/:-----BEGIN PGP PUBLIC KEY BLOCK-----/-----BEGIN PGP PUBLIC KEY BLOCK-----/" $REVOCATION_FILE
sed -i "s/:-----BEGIN GPG PUBLIC KEY BLOCK-----/-----BEGIN GPG PUBLIC KEY BLOCK-----/" $REVOCATION_FILE

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This one is not a typo. If you were to open a revocation file in a text editor, it would look something like this:

This is a revocation certificate for the OpenPGP key:

pub   rsa2048 2023-12-11 [SC]
      81CFAE4BD0034D6D1AD443408F11F369BDA6B541
uid          Tester McPerson <test@example.com>

A revocation certificate is a kind of "kill switch" to publicly
declare that a key shall not anymore be used.  It is not possible
to retract such a revocation certificate once it has been published.

Use it to revoke this key in case of a compromise or loss of
the secret key.  However, if the secret key is still accessible,
it is better to generate a new revocation certificate and give
a reason for the revocation.  For details see the description of
of the gpg command "--generate-revocation" in the GnuPG manual.

To avoid an accidental use of this file, a colon has been inserted
before the 5 dashes below.  Remove this colon with a text editor
before importing and publishing this revocation certificate.

:-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: This is a revocation certificate

iQE2BCABCAAgFiEEgd+uS9ADTW0a1ENAjxHzab2msUEFAmV2yBoCHQAACgkQjxHz
...

-----END PGP PUBLIC KEY BLOCK-----

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah sorry that was me just not being familiar enough with these specs/standards

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

To be honest it's an easy thing to miss - your other suggestions were indeed typos, so it made sense for this to also be a typo :) It's good to double-check in these situations, so your feedback was spot on!

@JamesHenry
Copy link
Copy Markdown
Member

Sorry just read your note about the potential difficulty for local test runs, I agree.

Maybe we could exclude this spec if process.env.CI !== 'true'?

@ivml
Copy link
Copy Markdown
Contributor Author

ivml commented Dec 11, 2023

Maybe we could exclude this spec if process.env.CI !== 'true'?

Thanks, that is a good suggestion. I attempted to do that in ab6c403 but I am unsure if there are no better alternatives for the syntax.

Out of curiosity was this GPG key gen approach copied from/inspired by another open source repo?

There is not a particular example that I am aware of.

Signing a commit in a workflow is something that can be done relatively easy if you have generated a key, uploaded it to your account and made some secrets. I have stumbled on and used this gist as an example in the past - https://gist.github.com/vansergen/88eb7e71fea2e3bdaf6aa3e752371eb7

Generating the key inside the workflow, storing it, and revoking it was way less intuitive. I had a bunch of failed attempts in my fork that took small incremental changes to get to here (that I have cleaned up). I mostly had an idea, and took it to Copilot for validation and error deciphering. For example, it was that back-and-forth that told me that the revocation file path is written to stderr instead of stdout after successfully generating a key.

@ivml ivml force-pushed the fix/version-sign-git-tag branch from 2cc1ddc to 5956ed9 Compare December 11, 2023 09:24
@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Dec 15, 2023

@JamesHenry JamesHenry merged commit 8f7a32b into lerna:main Dec 15, 2023
@JamesHenry
Copy link
Copy Markdown
Member

Thanks a lot @ivml!

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