Skip to content

Commit b89a939

Browse files
yairm210Yair Morgenstern
andauthored
Solve the race-condition when matrix builds try to create the same release (#147)
* Solve the race-condition when matrix builds try to create the same release * Separate get_release into another function --------- Co-authored-by: Yair Morgenstern <[email protected]>
1 parent 5e35e58 commit b89a939

File tree

2 files changed

+92
-47
lines changed

2 files changed

+92
-47
lines changed

dist/index.js

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,13 @@ function get_or_create_release(tag_1, draft_1, prerelease_1, make_latest_1, rele
6767
return __awaiter(this, arguments, void 0, function* (tag, draft, prerelease, make_latest, release_name, body, octokit, overwrite, promote, target_commit, release_id = 0) {
6868
let release;
6969
try {
70-
if (release_id !== 0) {
71-
// Draft releases can only be found by ID, not by tag.
72-
core.info(`Getting release by id ${release_id}`);
73-
release = yield octokit.request(releaseByID, Object.assign(Object.assign({}, repo()), { release_id: release_id }));
74-
core.debug(`The release has the following ID: ${release.data.id}`);
75-
}
76-
else {
77-
core.info(`Getting release by tag ${tag}.`);
78-
// @ts-ignore
79-
release = yield octokit.request(releaseByTag, Object.assign(Object.assign({}, repo()), { tag: tag }));
80-
}
70+
release = yield get_release(octokit, tag, release_id);
8171
}
8272
catch (error) {
8373
// If this returns 404, we need to create the release first.
8474
if (error.status !== 404)
8575
throw error;
86-
core.info(`Release for tag ${tag} doesn't exist yet so we'll create it now.`);
76+
core.info(`Release for tag ${tag} doesn't exist - creating it`);
8777
if (target_commit) {
8878
try {
8979
yield octokit.request(getRef, Object.assign(Object.assign({}, repo()), { ref: `tags/${tag}` }));
@@ -94,13 +84,43 @@ function get_or_create_release(tag_1, draft_1, prerelease_1, make_latest_1, rele
9484
throw tagError;
9585
}
9686
}
97-
// @ts-ignore
98-
const _release = yield octokit.request(createRelease, Object.assign(Object.assign({}, repo()), { tag_name: tag, draft: draft, prerelease: prerelease, make_latest: make_latest ? 'true' : 'false', name: release_name, body: body, target_commitish: target_commit }));
99-
return _release;
87+
try {
88+
// @ts-ignore
89+
const _release = yield octokit.request(createRelease, Object.assign(Object.assign({}, repo()), { tag_name: tag, draft: draft, prerelease: prerelease, make_latest: make_latest ? 'true' : 'false', name: release_name, body: body, target_commitish: target_commit }));
90+
return _release;
91+
}
92+
catch (create_release_error) {
93+
if (create_release_error.status == 422 &&
94+
create_release_error.response.data.errors[0].code == 'already_exists') {
95+
core.info(`Tried to create a release for tag ${tag}, but it already exists - probably due to race condition between matrix jobs.`);
96+
release = yield get_release(octokit, tag, release_id);
97+
// In this case, we do not throw the error, and we don't return since possibly we want to update it
98+
}
99+
else {
100+
core.setFailed(`Failed to create release for tag ${tag}: ${error.message}`);
101+
throw error;
102+
}
103+
}
100104
}
101105
return yield update_release(promote, release, tag, overwrite, release_name, body, octokit);
102106
});
103107
}
108+
/** May throw octokit exceptions */
109+
function get_release(octokit, tag, release_id) {
110+
return __awaiter(this, void 0, void 0, function* () {
111+
if (release_id !== 0) {
112+
// Draft releases can only be found by ID, not by tag.
113+
core.info(`Getting release by id ${release_id}`);
114+
// @ts-ignore
115+
return yield octokit.request(releaseByID, Object.assign(Object.assign({}, repo()), { release_id: release_id }));
116+
}
117+
else {
118+
core.info(`Getting release by tag ${tag}.`);
119+
// @ts-ignore
120+
return yield octokit.request(releaseByTag, Object.assign(Object.assign({}, repo()), { tag: tag }));
121+
}
122+
});
123+
}
104124
function update_release(promote, release, tag, overwrite, release_name, body, octokit) {
105125
return __awaiter(this, void 0, void 0, function* () {
106126
let updateObject;

src/main.ts

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,12 @@ async function get_or_create_release(
4242
> {
4343
let release: ReleaseByTagResp | ReleaseByIDResp
4444
try {
45-
if (release_id !== 0) {
46-
// Draft releases can only be found by ID, not by tag.
47-
core.info(`Getting release by id ${release_id}`)
48-
release = await octokit.request(releaseByID, {
49-
...repo(),
50-
release_id: release_id
51-
})
52-
53-
core.debug(`The release has the following ID: ${release.data.id}`)
54-
} else {
55-
core.info(`Getting release by tag ${tag}.`)
56-
// @ts-ignore
57-
release = await octokit.request(releaseByTag, {
58-
...repo(),
59-
tag: tag
60-
})
61-
}
45+
release = await get_release(octokit, tag, release_id)
6246
} catch (error: any) {
6347
// If this returns 404, we need to create the release first.
6448
if (error.status !== 404) throw error
6549

66-
core.info(
67-
`Release for tag ${tag} doesn't exist yet so we'll create it now.`
68-
)
50+
core.info(`Release for tag ${tag} doesn't exist - creating it`)
6951
if (target_commit) {
7052
try {
7153
await octokit.request(getRef, {
@@ -77,18 +59,37 @@ async function get_or_create_release(
7759
if (tagError.status !== 404) throw tagError
7860
}
7961
}
80-
// @ts-ignore
81-
const _release = await octokit.request(createRelease, {
82-
...repo(),
83-
tag_name: tag,
84-
draft: draft,
85-
prerelease: prerelease,
86-
make_latest: make_latest ? 'true' : 'false',
87-
name: release_name,
88-
body: body,
89-
target_commitish: target_commit
90-
})
91-
return _release
62+
63+
try {
64+
// @ts-ignore
65+
const _release = await octokit.request(createRelease, {
66+
...repo(),
67+
tag_name: tag,
68+
draft: draft,
69+
prerelease: prerelease,
70+
make_latest: make_latest ? 'true' : 'false',
71+
name: release_name,
72+
body: body,
73+
target_commitish: target_commit
74+
})
75+
return _release
76+
} catch (create_release_error: any) {
77+
if (
78+
create_release_error.status == 422 &&
79+
create_release_error.response.data.errors[0].code == 'already_exists'
80+
) {
81+
core.info(
82+
`Tried to create a release for tag ${tag}, but it already exists - probably due to race condition between matrix jobs.`
83+
)
84+
release = await get_release(octokit, tag, release_id)
85+
// In this case, we do not throw the error, and we don't return since possibly we want to update it
86+
} else {
87+
core.setFailed(
88+
`Failed to create release for tag ${tag}: ${error.message}`
89+
)
90+
throw error
91+
}
92+
}
9293
}
9394

9495
return await update_release(
@@ -102,6 +103,30 @@ async function get_or_create_release(
102103
)
103104
}
104105

106+
/** May throw octokit exceptions */
107+
async function get_release(
108+
octokit: Octokit,
109+
tag: string,
110+
release_id: number
111+
): Promise<ReleaseByTagResp | ReleaseByIDResp> {
112+
if (release_id !== 0) {
113+
// Draft releases can only be found by ID, not by tag.
114+
core.info(`Getting release by id ${release_id}`)
115+
// @ts-ignore
116+
return await octokit.request(releaseByID, {
117+
...repo(),
118+
release_id: release_id
119+
})
120+
} else {
121+
core.info(`Getting release by tag ${tag}.`)
122+
// @ts-ignore
123+
return await octokit.request(releaseByTag, {
124+
...repo(),
125+
tag: tag
126+
})
127+
}
128+
}
129+
105130
async function update_release(
106131
promote: boolean,
107132
release: ReleaseByTagResp | ReleaseByIDResp,

0 commit comments

Comments
 (0)