diff --git a/lib/definitions/constants.js b/lib/definitions/constants.js index 18f1ecd3..a052b8a9 100644 --- a/lib/definitions/constants.js +++ b/lib/definitions/constants.js @@ -1,3 +1,10 @@ export const HOME_URL = 'https://github.com/semantic-release/semantic-release'; export const RELEASE_NAME = 'GitLab release'; + +export const RETRY_CONFIGURATION = { + retry: { + limit: 3, + statusCodes: [429], + }, +}; diff --git a/lib/fail.js b/lib/fail.js index d2706236..608f7df9 100644 --- a/lib/fail.js +++ b/lib/fail.js @@ -6,6 +6,7 @@ const debug = _debug("semantic-release:gitlab"); import resolveConfig from "./resolve-config.js"; import getRepoId from "./get-repo-id.js"; import getFailComment from "./get-fail-comment.js"; +import { RETRY_CONFIGURATION } from "./definitions/constants.js"; export default async (pluginConfig, context) => { const { @@ -20,7 +21,12 @@ export default async (pluginConfig, context) => { ); const repoId = getRepoId(context, gitlabUrl, repositoryUrl); const encodedRepoId = encodeURIComponent(repoId); - const apiOptions = { headers: { "PRIVATE-TOKEN": gitlabToken } }; + const apiOptions = { + headers: { + "PRIVATE-TOKEN": gitlabToken, + }, + ...RETRY_CONFIGURATION, + }; if (failComment === false || failTitle === false) { logger.log("Skip issue creation."); diff --git a/lib/publish.js b/lib/publish.js index 97e75615..0f64baf6 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -11,7 +11,7 @@ const debug = _debug("semantic-release:gitlab"); import resolveConfig from "./resolve-config.js"; import getRepoId from "./get-repo-id.js"; import getAssets from "./glob-assets.js"; -import { RELEASE_NAME } from "./definitions/constants.js"; +import { RELEASE_NAME, RETRY_CONFIGURATION } from "./definitions/constants.js"; const isUrlScheme = (value) => /^(https|http|ftp):\/\//.test(value); @@ -46,6 +46,7 @@ export default async (pluginConfig, context) => { }, ], }, + ...RETRY_CONFIGURATION, }; debug("repoId: %o", repoId); diff --git a/lib/success.js b/lib/success.js index bc697b90..7db87e34 100644 --- a/lib/success.js +++ b/lib/success.js @@ -6,6 +6,7 @@ const debug = _debug("semantic-release:gitlab"); import resolveConfig from "./resolve-config.js"; import getRepoId from "./get-repo-id.js"; import getSuccessComment from "./get-success-comment.js"; +import { RETRY_CONFIGURATION } from "./definitions/constants.js"; export default async (pluginConfig, context) => { const { @@ -18,7 +19,12 @@ export default async (pluginConfig, context) => { const { gitlabToken, gitlabUrl, gitlabApiUrl, successComment, proxy } = resolveConfig(pluginConfig, context); const repoId = getRepoId(context, gitlabUrl, repositoryUrl); const encodedRepoId = encodeURIComponent(repoId); - const apiOptions = { headers: { "PRIVATE-TOKEN": gitlabToken } }; + const apiOptions = { + headers: { + "PRIVATE-TOKEN": gitlabToken, + }, + ...RETRY_CONFIGURATION, + }; if (successComment === false) { logger.log("Skip commenting on issues and pull requests."); diff --git a/lib/verify.js b/lib/verify.js index e7091ef1..5313528e 100644 --- a/lib/verify.js +++ b/lib/verify.js @@ -7,6 +7,7 @@ import AggregateError from "aggregate-error"; import resolveConfig from "./resolve-config.js"; import getRepoId from "./get-repo-id.js"; import getError from "./get-error.js"; +import { RETRY_CONFIGURATION } from "./definitions/constants.js"; const isNonEmptyString = (value) => isString(value) && value.trim(); const isStringOrStringArray = (value) => @@ -33,6 +34,12 @@ export default async (pluginConfig, context) => { } = context; const { gitlabToken, gitlabUrl, gitlabApiUrl, proxy, ...options } = resolveConfig(pluginConfig, context); const repoId = getRepoId(context, gitlabUrl, repositoryUrl); + const apiOptions = { + headers: { + "PRIVATE-TOKEN": gitlabToken, + }, + ...RETRY_CONFIGURATION, + }; debug("apiUrl: %o", gitlabApiUrl); debug("repoId: %o", repoId); @@ -65,7 +72,7 @@ export default async (pluginConfig, context) => { permissions: { project_access: projectAccess, group_access: groupAccess }, } = await got .get(urlJoin(gitlabApiUrl, `/projects/${encodeURIComponent(repoId)}`), { - headers: { "PRIVATE-TOKEN": gitlabToken }, + ...apiOptions, ...proxy, }) .json()); diff --git a/test/publish.test.js b/test/publish.test.js index 7c535c37..310b40a5 100644 --- a/test/publish.test.js +++ b/test/publish.test.js @@ -641,3 +641,27 @@ test.serial("Publish a release with error response", async (t) => { t.is(error.message, `Response code 499 (Something went wrong)`); t.true(gitlab.isDone()); }); + +test.serial("Publish a release with error response of 429 - too many requests - with persist", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = {}; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedRepoId = encodeURIComponent(`${owner}/${repo}`); + const gitlab = authenticate(env) + .post(`/projects/${encodedRepoId}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [], + }, + }) + .reply(429, { message: "Too many requests" }) + .persist(); + + const error = await t.throwsAsync(publish(pluginConfig, { env, options, nextRelease, logger: t.context.logger })); + t.is(error.message, `Response code 429 (Too many requests)`); + t.true(gitlab.isDone()); +}); diff --git a/test/verify.test.js b/test/verify.test.js index 48f3004f..1ee05791 100644 --- a/test/verify.test.js +++ b/test/verify.test.js @@ -567,7 +567,7 @@ test.serial("Throw error if GitLab API return any other errors", async (t) => { const owner = "test_user"; const repo = "test_repo"; const env = { GITLAB_TOKEN: "gitlab_token" }; - const gitlab = authenticate(env).get(`/projects/${owner}%2F${repo}`).times(3).reply(500); + const gitlab = authenticate(env).get(`/projects/${owner}%2F${repo}`).times(3).reply(500).persist(); const error = await t.throwsAsync( verify({}, { env, options: { repositoryUrl: `https://gitlab.com:${owner}/${repo}.git` }, logger: t.context.logger })