From b90728ad51bd3113cbaa28627a15bfaca873b311 Mon Sep 17 00:00:00 2001 From: Sua Yoo Date: Sun, 24 Jan 2021 06:26:56 -0800 Subject: [PATCH] Account for custom tag name when retrieving latest tag (#722) * parse `tagName` when determining latest tag * update tests * pass context * add test * fix ambiguous argument on ubuntu * remove quotes from match arg Co-authored-by: Lars Kappert --- lib/plugin/GitBase.js | 16 ++++++++++------ test/git.init.js | 20 ++++++++++++++++++++ test/github.js | 16 ++++++++-------- test/tasks.js | 14 +++++++------- 4 files changed, 45 insertions(+), 21 deletions(-) diff --git a/lib/plugin/GitBase.js b/lib/plugin/GitBase.js index dcf35ed4..6e5c4f42 100644 --- a/lib/plugin/GitBase.js +++ b/lib/plugin/GitBase.js @@ -13,8 +13,8 @@ class GitBase extends Plugin { this.remoteUrl = await this.getRemoteUrl(); await this.fetch(); const repo = parseGitUrl(this.remoteUrl); - const latestTagName = await this.getLatestTagName(); - const secondLatestTagName = this.options.isUpdate ? await this.getSecondLatestTagName() : null; + const latestTagName = await this.getLatestTagName(repo); + const secondLatestTagName = this.options.isUpdate ? await this.getSecondLatestTagName(latestTagName) : null; const tagTemplate = this.options.tagName || ((latestTagName || '').match(/^v/) ? 'v${version}' : '${version}'); this.setContext({ repo, tagTemplate, latestTagName, secondLatestTagName }); this.config.setContext({ latestTag: latestTagName }); @@ -88,15 +88,19 @@ class GitBase extends Plugin { }); } - getLatestTagName() { - return this.exec('git describe --tags --abbrev=0', { options }).then( + getLatestTagName(repo) { + const context = Object.assign({ repo }, this.getContext(), { version: '*' }); + const match = format(this.options.tagName || '${version}', context); + return this.exec(`git describe --tags --match=${match} --abbrev=0`, { options }).then( stdout => stdout || null, () => null ); } - async getSecondLatestTagName() { - const sha = await this.exec('git rev-list --tags --skip=1 --max-count=1', { options }); + async getSecondLatestTagName(latestTag) { + const sha = await this.exec(`git rev-list ${latestTag || '--skip=1'} --tags --max-count=1`, { + options + }); return this.exec(`git describe --tags --abbrev=0 ${sha}`, { options }).catch(() => null); } } diff --git a/test/git.init.js b/test/git.init.js index dbf1bcb2..513af7a4 100644 --- a/test/git.init.js +++ b/test/git.init.js @@ -118,6 +118,26 @@ test.serial('should get the latest tag after fetch', async t => { t.is(gitClient.getContext('latestTagName'), '1.0.0'); }); +test.serial('should get the latest custom tag after fetch when tagName is configured', async t => { + const shell = factory(Shell); + const gitClient = factory(Git, { + options: { git: { tagName: 'TAGNAME-v${version}' } }, + container: { shell } + }); + const { bare, target } = t.context; + const other = mkTmpDir(); + sh.exec('git push'); + sh.exec(`git clone ${bare} ${other}`); + sh.pushd('-q', other); + sh.exec('git tag TAGNAME-OTHER-v2.0.0'); + sh.exec('git tag TAGNAME-v1.0.0'); + sh.exec('git tag TAGNAME-OTHER-v2.0.2'); + sh.exec('git push --tags'); + sh.pushd('-q', target); + await gitClient.init(); + t.is(gitClient.getContext('latestTagName'), 'TAGNAME-v1.0.0'); +}); + test.serial('should generate correct changelog', async t => { const gitClient = factory(Git, { options: { git } }); sh.exec('git tag 1.0.0'); diff --git a/test/github.js b/test/github.js index 8bb438da..2fe65839 100644 --- a/test/github.js +++ b/test/github.js @@ -48,7 +48,7 @@ test('should release and upload assets', async t => { }; const github = factory(GitHub, { options }); const exec = sinon.stub(github.shell, 'exec').callThrough(); - exec.withArgs('git describe --tags --abbrev=0').resolves('2.0.1'); + exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('2.0.1'); interceptAuthentication(); interceptCollaborator(); @@ -77,7 +77,7 @@ test('should create a pre-release and draft release notes', async t => { }; const github = factory(GitHub, { options }); const exec = sinon.stub(github.shell, 'exec').callThrough(); - exec.withArgs('git describe --tags --abbrev=0').resolves('2.0.1'); + exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('2.0.1'); interceptAuthentication(); interceptCollaborator(); @@ -108,9 +108,9 @@ test('should update release and upload assets', async t => { }; const github = factory(GitHub, { options }); const exec = sinon.stub(github.shell, 'exec').callThrough(); - exec.withArgs('git describe --tags --abbrev=0').resolves('2.0.1'); + exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('2.0.1'); exec.withArgs('git rev-list 2.0.1 --tags --max-count=1').resolves('71f1812'); - exec.withArgs('git describe --tags --abbrev=0 71f1812').resolves('2.0.1'); + exec.withArgs('git describe --tags --match=* --abbrev=0 71f1812').resolves('2.0.1'); interceptAuthentication(); interceptCollaborator(); @@ -131,7 +131,7 @@ test('should release to enterprise host', async t => { const exec = sinon.stub(github.shell, 'exec').callThrough(); exec.withArgs('git remote get-url origin').resolves(`https://github.example.org/user/repo`); exec.withArgs('git config --get remote.origin.url').resolves(`https://github.example.org/user/repo`); - exec.withArgs('git describe --tags --abbrev=0').resolves(`1.0.0`); + exec.withArgs('git describe --tags --match=* --abbrev=0').resolves(`1.0.0`); const remote = { api: 'https://github.example.org/api/v3', host: 'github.example.org' }; interceptAuthentication(remote); @@ -162,7 +162,7 @@ test('should release to alternative host and proxy', async t => { }; const github = factory(GitHub, { options }); const exec = sinon.stub(github.shell, 'exec').callThrough(); - exec.withArgs('git describe --tags --abbrev=0').resolves('1.0.0'); + exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('1.0.0'); await runTasks(github); @@ -178,7 +178,7 @@ test('should release to git.pushRepo', async t => { const options = { git: { pushRepo: 'upstream', changelog: null }, github: { tokenRef, skipChecks: true } }; const github = factory(GitHub, { options }); const exec = sinon.stub(github.shell, 'exec').callThrough(); - exec.withArgs('git describe --tags --abbrev=0').resolves('1.0.0'); + exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('1.0.0'); exec.withArgs('git remote get-url upstream').resolves('https://my-custom-host.org/user/repo'); await runTasks(github); @@ -268,7 +268,7 @@ test('should not call octokit client in dry run', async t => { const github = factory(GitHub, { options }); const spy = sinon.spy(github, 'client', ['get']); const exec = sinon.stub(github.shell, 'exec').callThrough(); - exec.withArgs('git describe --tags --abbrev=0').resolves('v1.0.0'); + exec.withArgs('git describe --tags --match=* --abbrev=0').resolves('v1.0.0'); await runTasks(github); diff --git a/test/tasks.js b/test/tasks.js index 61d3c11e..9f9effb2 100644 --- a/test/tasks.js +++ b/test/tasks.js @@ -79,7 +79,7 @@ test.serial('should run tasks without package.json', async t => { t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/); t.is(log.warn.callCount, 0); { - const { stdout } = sh.exec('git describe --tags --abbrev=0'); + const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0'); t.is(stdout.trim(), '2.0.0'); } }); @@ -102,7 +102,7 @@ test.serial('should run tasks with minimal config and without any warnings/error await runTasks({}, getContainer({ increment: 'patch' })); t.true(log.obtrusive.firstCall.args[0].includes('release my-package (1.2.3...1.2.4)')); t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/); - const { stdout } = sh.exec('git describe --tags --abbrev=0'); + const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0'); t.is(stdout.trim(), '1.2.4'); }); @@ -111,7 +111,7 @@ test.serial('should use pkg.version', async t => { await runTasks({}, getContainer({ increment: 'minor' })); t.true(log.obtrusive.firstCall.args[0].includes('release my-package (1.2.3...1.3.0)')); t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/); - const { stdout } = sh.exec('git describe --tags --abbrev=0'); + const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0'); t.is(stdout.trim(), '1.3.0'); }); @@ -126,7 +126,7 @@ test.serial('should use pkg.version (in sub dir) w/o tagging repo', async t => { await runTasks({}, container); t.true(log.obtrusive.firstCall.args[0].endsWith('release my-package (1.2.3...1.3.0)')); t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/); - const { stdout } = sh.exec('git describe --tags --abbrev=0'); + const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0'); t.is(stdout.trim(), '1.0.0'); const npmArgs = getArgs(exec.args, 'npm'); t.is(npmArgs[4], 'npm version 1.3.0 --no-git-tag-version'); @@ -140,7 +140,7 @@ test.serial('should ignore version in pkg.version and use git tag instead', asyn await runTasks({}, getContainer({ increment: 'minor', npm: { ignoreVersion: true } })); t.true(log.obtrusive.firstCall.args[0].includes('release my-package (1.1.1...1.2.0)')); t.regex(log.log.lastCall.args[0], /Done \(in [0-9]+s\.\)/); - const { stdout } = sh.exec('git describe --tags --abbrev=0'); + const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0'); t.is(stdout.trim(), '1.2.0'); }); @@ -273,7 +273,7 @@ test.serial('should release all the things (pre-release, github, gitlab)', async const { stdout: commitMessage } = sh.exec('git log --oneline --format=%B -n 1 HEAD'); t.is(commitMessage.trim(), `Release 1.1.0-alpha.0 for ${pkgName} (from 1.0.0)`); - const { stdout: tagName } = sh.exec('git describe --tags --abbrev=0'); + const { stdout: tagName } = sh.exec('git describe --tags --match=* --abbrev=0'); t.is(tagName.trim(), 'v1.1.0-alpha.0'); const { stdout: tagAnnotation } = sh.exec('git for-each-ref refs/tags/v1.1.0-alpha.0 --format="%(contents)"'); @@ -309,7 +309,7 @@ test.serial('should publish pre-release without pre-id with different npm.tag', 'npm publish . --tag next' ]); - const { stdout } = sh.exec('git describe --tags --abbrev=0'); + const { stdout } = sh.exec('git describe --tags --match=* --abbrev=0'); t.is(stdout.trim(), 'v2.0.0-0'); t.true(log.obtrusive.firstCall.args[0].endsWith(`release ${pkgName} (1.0.0...2.0.0-0)`)); t.true(log.log.firstCall.args[0].endsWith(`https://www.npmjs.com/package/${pkgName}`));