Skip to content

Commit edec102

Browse files
committed
feat: Skip tag creation if it already exists
1 parent 21d811e commit edec102

File tree

3 files changed

+92
-24
lines changed

3 files changed

+92
-24
lines changed

Diff for: lib/publish.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,18 @@ module.exports = async (pluginConfig, {branch, repositoryUrl}, {version, gitHead
2323
debug('release branch: %o', branch);
2424
const ref = `refs/tags/${gitTag}`;
2525

26-
debug('Create git tag %o with commit %o', ref, gitHead);
27-
await github.gitdata.createReference({owner, repo, ref, sha: gitHead});
26+
try {
27+
// Test if the tag already exists
28+
await github.gitdata.getReference({owner, repo, ref: `tags/${gitTag}`});
29+
} catch (err) {
30+
// If the error is 404, the tag doesn't exist, otherwise it's an error
31+
if (err.code !== 404) {
32+
throw err;
33+
}
34+
debug('Create git tag %o with commit %o', ref, gitHead);
35+
await github.gitdata.createReference({owner, repo, ref, sha: gitHead});
36+
}
37+
2838
const {data: {id, html_url}} = await github.repos.createRelease(release); // eslint-disable-line camelcase
2939
logger.log('Published Github release: %s', html_url);
3040

Diff for: test/integration.test.js

+10-6
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,17 @@ test.serial('Publish a release with an array of assets', async t => {
117117
const github = authenticate({githubToken})
118118
.get(`/repos/${owner}/${repo}`)
119119
.reply(200, {permissions: {push: true}})
120+
.get(`/repos/${owner}/${repo}/git/refs/tags/${nextRelease.gitTag}`)
121+
.reply(404)
122+
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
123+
.reply({})
120124
.post(`/repos/${owner}/${repo}/releases`, {
121125
tag_name: nextRelease.gitTag,
122126
target_commitish: options.branch,
123127
name: nextRelease.gitTag,
124128
body: nextRelease.notes,
125129
})
126-
.reply(200, {html_url: releaseUrl, id: releaseId})
127-
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
128-
.reply({});
130+
.reply(200, {html_url: releaseUrl, id: releaseId});
129131

130132
const githubUpload = upload({githubToken})
131133
.post(`/repos/${owner}/${repo}/releases/${releaseId}/assets?name=${escape('upload.txt')}`)
@@ -168,15 +170,17 @@ test.serial('Verify Github auth and release', async t => {
168170
const github = authenticate({githubToken: process.env.GH_TOKEN})
169171
.get(`/repos/${owner}/${repo}`)
170172
.reply(200, {permissions: {push: true}})
173+
.get(`/repos/${owner}/${repo}/git/refs/tags/${nextRelease.gitTag}`)
174+
.reply(404)
175+
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
176+
.reply({})
171177
.post(`/repos/${owner}/${repo}/releases`, {
172178
tag_name: nextRelease.gitTag,
173179
target_commitish: options.branch,
174180
name: nextRelease.gitTag,
175181
body: nextRelease.notes,
176182
})
177-
.reply(200, {html_url: releaseUrl, id: releaseId})
178-
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
179-
.reply({});
183+
.reply(200, {html_url: releaseUrl, id: releaseId});
180184

181185
const githubUpload = upload({githubToken: process.env.GH_TOKEN})
182186
.post(`/repos/${owner}/${repo}/releases/${releaseId}/assets?name=${escape('upload.txt')}`)

Diff for: test/publish.test.js

+70-16
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,43 @@ test.serial('Publish a release', async t => {
4040
const releaseUrl = `https://github.com/${owner}/${repo}/releases/${nextRelease.version}`;
4141

4242
const github = authenticate({githubToken})
43+
.get(`/repos/${owner}/${repo}/git/refs/tags/${nextRelease.gitTag}`)
44+
.reply(404)
45+
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
46+
.reply({})
4347
.post(`/repos/${owner}/${repo}/releases`, {
4448
tag_name: nextRelease.gitTag,
4549
target_commitish: options.branch,
4650
name: nextRelease.gitTag,
4751
body: nextRelease.notes,
4852
})
49-
.reply(200, {html_url: releaseUrl})
50-
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
51-
.reply({});
53+
.reply(200, {html_url: releaseUrl});
54+
55+
await publish(pluginConfig, options, nextRelease, t.context.logger);
56+
57+
t.true(t.context.log.calledWith(match.string, releaseUrl));
58+
t.true(github.isDone());
59+
});
60+
61+
test.serial('Publish a release with an existing tag', async t => {
62+
const owner = 'test_user';
63+
const repo = 'test_repo';
64+
const githubToken = 'github_token';
65+
const pluginConfig = {githubToken};
66+
const nextRelease = {version: '1.0.0', gitHead: '123', gitTag: 'v1.0.0', notes: 'Test release note body'};
67+
const options = {branch: 'master', repositoryUrl: `https://github.com/${owner}/${repo}.git`};
68+
const releaseUrl = `https://github.com/${owner}/${repo}/releases/${nextRelease.version}`;
69+
70+
const github = authenticate({githubToken})
71+
.get(`/repos/${owner}/${repo}/git/refs/tags/${nextRelease.gitTag}`)
72+
.reply({ref: `refs/tags/${nextRelease.gitTag}`, object: {sha: 'e23a1bd8d7240c1eb3287374956042ffbcadca84'}})
73+
.post(`/repos/${owner}/${repo}/releases`, {
74+
tag_name: nextRelease.gitTag,
75+
target_commitish: options.branch,
76+
name: nextRelease.gitTag,
77+
body: nextRelease.notes,
78+
})
79+
.reply(200, {html_url: releaseUrl});
5280

5381
await publish(pluginConfig, options, nextRelease, t.context.logger);
5482

@@ -74,15 +102,17 @@ test.serial('Publish a release with one asset', async t => {
74102
githubToken: process.env.GH_TOKEN,
75103
githubApiPathPrefix: process.env.GH_PREFIX,
76104
})
105+
.get(`/repos/${owner}/${repo}/git/refs/tags/${nextRelease.gitTag}`)
106+
.reply(404)
107+
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
108+
.reply({})
77109
.post(`/repos/${owner}/${repo}/releases`, {
78110
tag_name: nextRelease.gitTag,
79111
target_commitish: options.branch,
80112
name: nextRelease.gitTag,
81113
body: nextRelease.notes,
82114
})
83-
.reply(200, {html_url: releaseUrl, id: releaseId})
84-
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
85-
.reply({});
115+
.reply(200, {html_url: releaseUrl, id: releaseId});
86116

87117
const githubUpload = upload({githubUrl: process.env.GH_URL, githubToken: process.env.GH_TOKEN})
88118
.post(`/repos/${owner}/${repo}/releases/${releaseId}/assets?name=${escape('upload.txt')}`)
@@ -115,15 +145,17 @@ test.serial('Publish a release with one asset and custom github url', async t =>
115145
githubUrl: process.env.GITHUB_URL,
116146
githubApiPathPrefix: process.env.GITHUB_PREFIX,
117147
})
148+
.get(`/repos/${owner}/${repo}/git/refs/tags/${nextRelease.gitTag}`)
149+
.reply(404)
150+
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
151+
.reply({})
118152
.post(`/repos/${owner}/${repo}/releases`, {
119153
tag_name: nextRelease.gitTag,
120154
target_commitish: options.branch,
121155
name: nextRelease.gitTag,
122156
body: nextRelease.notes,
123157
})
124-
.reply(200, {html_url: releaseUrl, id: releaseId})
125-
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
126-
.reply({});
158+
.reply(200, {html_url: releaseUrl, id: releaseId});
127159

128160
const githubUpload = upload({githubToken: process.env.GITHUB_TOKEN, githubUrl: process.env.GITHUB_URL})
129161
.post(`/repos/${owner}/${repo}/releases/${releaseId}/assets?name=${escape('upload.txt')}`)
@@ -156,15 +188,17 @@ test.serial('Publish a release with an array of assets', async t => {
156188
const releaseId = 1;
157189

158190
const github = authenticate({githubToken})
191+
.get(`/repos/${owner}/${repo}/git/refs/tags/${nextRelease.gitTag}`)
192+
.reply(404)
193+
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
194+
.reply({})
159195
.post(`/repos/${owner}/${repo}/releases`, {
160196
tag_name: nextRelease.gitTag,
161197
target_commitish: options.branch,
162198
name: nextRelease.gitTag,
163199
body: nextRelease.notes,
164200
})
165-
.reply(200, {html_url: releaseUrl, id: releaseId})
166-
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
167-
.reply({});
201+
.reply(200, {html_url: releaseUrl, id: releaseId});
168202

169203
const githubUpload = upload({githubToken})
170204
.post(`/repos/${owner}/${repo}/releases/${releaseId}/assets?name=${escape('upload.txt')}`)
@@ -185,7 +219,7 @@ test.serial('Publish a release with an array of assets', async t => {
185219
t.true(githubUpload.isDone());
186220
});
187221

188-
test.serial('Publish a release with an array of misconfigured assets', async t => {
222+
test.serial('Publish a release with an array of missing assets', async t => {
189223
const owner = 'test_user';
190224
const repo = 'test_repo';
191225
const githubToken = 'github_token';
@@ -199,15 +233,17 @@ test.serial('Publish a release with an array of misconfigured assets', async t =
199233
const releaseId = 1;
200234

201235
const github = authenticate({githubToken})
236+
.get(`/repos/${owner}/${repo}/git/refs/tags/${nextRelease.gitTag}`)
237+
.reply(404)
238+
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
239+
.reply({})
202240
.post(`/repos/${owner}/${repo}/releases`, {
203241
tag_name: nextRelease.gitTag,
204242
target_commitish: options.branch,
205243
name: nextRelease.gitTag,
206244
body: nextRelease.notes,
207245
})
208-
.reply(200, {html_url: releaseUrl, id: releaseId})
209-
.post(`/repos/${owner}/${repo}/git/refs`, {ref: `refs/tags/${nextRelease.gitTag}`, sha: nextRelease.gitHead})
210-
.reply({});
246+
.reply(200, {html_url: releaseUrl, id: releaseId});
211247

212248
await publish(pluginConfig, options, nextRelease, t.context.logger);
213249

@@ -216,3 +252,21 @@ test.serial('Publish a release with an array of misconfigured assets', async t =
216252
t.true(t.context.error.calledWith(match.string, 'test/fixtures'));
217253
t.true(github.isDone());
218254
});
255+
256+
test.serial('Throw Error if get tag call return an error other than 404', async t => {
257+
const owner = 'test_user';
258+
const repo = 'test_repo';
259+
const githubToken = 'github_token';
260+
const pluginConfig = {githubToken};
261+
const nextRelease = {version: '1.0.0', gitHead: '123', gitTag: 'v1.0.0', notes: 'Test release note body'};
262+
const options = {branch: 'master', repositoryUrl: `https://github.com/${owner}/${repo}.git`};
263+
264+
const github = authenticate({githubToken})
265+
.get(`/repos/${owner}/${repo}/git/refs/tags/${nextRelease.gitTag}`)
266+
.reply(500);
267+
268+
const error = await t.throws(publish(pluginConfig, options, nextRelease, t.context.logger), Error);
269+
270+
t.is(error.code, 500);
271+
t.true(github.isDone());
272+
});

0 commit comments

Comments
 (0)