From 020ea7d7d5aa6c123fe4c97754b6b1b36c0a8e2c Mon Sep 17 00:00:00 2001 From: Killian Hamayada Date: Fri, 5 Jan 2024 21:51:59 +0100 Subject: [PATCH] fix: use one note reference per tag to prevent conflicts (#2085) Co-authored-by: Matt Travi <126441+travi@users.noreply.github.com> --- index.js | 11 +++++---- lib/git.js | 49 +++++++++++++++++++++++++++++++-------- test/helpers/git-utils.js | 4 ++-- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/index.js b/index.js index 67877fb4b3..19c9f7057e 100644 --- a/index.js +++ b/index.js @@ -123,12 +123,15 @@ async function run(context, plugins) { if (options.dryRun) { logger.warn(`Skip ${nextRelease.gitTag} tag creation in dry-run mode`); } else { - await addNote({ channels: [...currentRelease.channels, nextRelease.channel] }, nextRelease.gitHead, { + await addNote({ channels: [...currentRelease.channels, nextRelease.channel] }, nextRelease.gitTag, { cwd, env, }); await push(options.repositoryUrl, { cwd, env }); - await pushNotes(options.repositoryUrl, { cwd, env }); + await pushNotes(options.repositoryUrl, nextRelease.gitTag, { + cwd, + env, + }); logger.success( `Add ${nextRelease.channel ? `channel ${nextRelease.channel}` : "default channel"} to tag ${ nextRelease.gitTag @@ -203,9 +206,9 @@ async function run(context, plugins) { } else { // Create the tag before calling the publish plugins as some require the tag to exists await tag(nextRelease.gitTag, nextRelease.gitHead, { cwd, env }); - await addNote({ channels: [nextRelease.channel] }, nextRelease.gitHead, { cwd, env }); + await addNote({ channels: [nextRelease.channel] }, nextRelease.gitTag, { cwd, env }); await push(options.repositoryUrl, { cwd, env }); - await pushNotes(options.repositoryUrl, { cwd, env }); + await pushNotes(options.repositoryUrl, nextRelease.gitTag, { cwd, env }); logger.success(`Created tag ${nextRelease.gitTag}`); } diff --git a/lib/git.js b/lib/git.js index fa25173573..979256cf37 100644 --- a/lib/git.js +++ b/lib/git.js @@ -2,6 +2,7 @@ import gitLogParser from "git-log-parser"; import getStream from "get-stream"; import { execa } from "execa"; import debugGit from "debug"; +import { merge } from "lodash-es"; import { GIT_NOTE_REF } from "./definitions/constants.js"; const debug = debugGit("semantic-release:git"); @@ -141,13 +142,9 @@ export async function fetch(repositoryUrl, branch, ciBranch, execaOptions) { */ export async function fetchNotes(repositoryUrl, execaOptions) { try { - await execa( - "git", - ["fetch", "--unshallow", repositoryUrl, `+refs/notes/${GIT_NOTE_REF}:refs/notes/${GIT_NOTE_REF}`], - execaOptions - ); + await execa("git", ["fetch", "--unshallow", repositoryUrl, `+refs/notes/*:refs/notes/*`], execaOptions); } catch { - await execa("git", ["fetch", repositoryUrl, `+refs/notes/${GIT_NOTE_REF}:refs/notes/${GIT_NOTE_REF}`], { + await execa("git", ["fetch", repositoryUrl, `+refs/notes/*:refs/notes/*`], { ...execaOptions, reject: false, }); @@ -246,8 +243,8 @@ export async function push(repositoryUrl, execaOptions) { * * @throws {Error} if the push failed. */ -export async function pushNotes(repositoryUrl, execaOptions) { - await execa("git", ["push", repositoryUrl, `refs/notes/${GIT_NOTE_REF}`], execaOptions); +export async function pushNotes(repositoryUrl, ref, execaOptions) { + await execa("git", ["push", repositoryUrl, `refs/notes/${GIT_NOTE_REF}-${ref}`], execaOptions); } /** @@ -307,8 +304,26 @@ export async function isBranchUpToDate(repositoryUrl, branch, execaOptions) { * @return {Object} the parsed JSON note if there is one, an empty object otherwise. */ export async function getNote(ref, execaOptions) { + const handleError = (error) => { + if (error.exitCode === 1) { + return { stdout: "{}" }; + } + + debug(error); + throw error; + }; + try { - return JSON.parse((await execa("git", ["notes", "--ref", GIT_NOTE_REF, "show", ref], execaOptions)).stdout); + return merge( + JSON.parse( + // Used for retro-compatibility + (await execa("git", ["notes", "--ref", GIT_NOTE_REF, "show", ref], execaOptions).catch(handleError)).stdout + ), + JSON.parse( + (await execa("git", ["notes", "--ref", `${GIT_NOTE_REF}-${ref}`, "show", ref], execaOptions).catch(handleError)) + .stdout + ) + ); } catch (error) { if (error.exitCode === 1) { return {}; @@ -327,5 +342,19 @@ export async function getNote(ref, execaOptions) { * @param {Object} [execaOpts] Options to pass to `execa`. */ export async function addNote(note, ref, execaOptions) { - await execa("git", ["notes", "--ref", GIT_NOTE_REF, "add", "-f", "-m", JSON.stringify(note), ref], execaOptions); + await execa( + "git", + ["notes", "--ref", `${GIT_NOTE_REF}-${ref}`, "add", "-f", "-m", JSON.stringify(note), ref], + execaOptions + ); +} + +/** + * Get the reference of a tag + * + * @param {String} tag The tag name to get the reference of. + * @param {Object} [execaOpts] Options to pass to `execa`. + **/ +export async function getTagRef(tag, execaOptions) { + return (await execa("git", ["show-ref", tag, "--hash"], execaOptions)).stdout; } diff --git a/test/helpers/git-utils.js b/test/helpers/git-utils.js index db70cdb8e0..5cb14770e8 100644 --- a/test/helpers/git-utils.js +++ b/test/helpers/git-utils.js @@ -315,7 +315,7 @@ export async function rebase(ref, execaOptions) { * @param {Object} [execaOpts] Options to pass to `execa`. */ export async function gitAddNote(note, ref, execaOptions) { - await execa("git", ["notes", "--ref", GIT_NOTE_REF, "add", "-m", note, ref], execaOptions); + await execa("git", ["notes", "--ref", `${GIT_NOTE_REF}-${ref}`, "add", "-m", note, ref], execaOptions); } /** @@ -325,5 +325,5 @@ export async function gitAddNote(note, ref, execaOptions) { * @param {Object} [execaOpts] Options to pass to `execa`. */ export async function gitGetNote(ref, execaOptions) { - return (await execa("git", ["notes", "--ref", GIT_NOTE_REF, "show", ref], execaOptions)).stdout; + return (await execa("git", ["notes", "--ref", `${GIT_NOTE_REF}-${ref}`, "show", ref], execaOptions)).stdout; }