Skip to content

Commit 9d34d25

Browse files
chore(project): merge pull request #809 from semantic-release/fix/project-id
Use project ID for API calls if available
2 parents 630e27e + 01957e7 commit 9d34d25

13 files changed

+304
-210
lines changed

lib/definitions/errors.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,20 @@ Your configuration for the \`labels\` option is \`${stringify(labels)}\`.`,
4141
}),
4242
EINVALIDGITLABURL: () => ({
4343
message: 'The git repository URL is not a valid GitLab URL.',
44-
details: `The **semantic-release** \`repositoryUrl\` option must a valid GitLab URL with the format \`<GitLab_URL>/<repoId>.git\`.
44+
details: `The **semantic-release** \`repositoryUrl\` option must a valid GitLab URL with the format \`<GitLab_URL>/<projectPath>.git\`.
4545
4646
By default the \`repositoryUrl\` option is retrieved from the \`repository\` property of your \`package.json\` or the [git origin url](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) of the repository cloned by your CI environment.`,
4747
}),
48-
EINVALIDGLTOKEN: ({repoId}) => ({
48+
EINVALIDGLTOKEN: ({projectPath}) => ({
4949
message: 'Invalid GitLab token.',
5050
details: `The [GitLab token](${linkify(
5151
'README.md#gitlab-authentication'
52-
)}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must be a valid [personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) allowing to push to the repository ${repoId}.
52+
)}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must be a valid [personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) allowing to push to the repository ${projectPath}.
5353
5454
Please make sure to set the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable in your CI with the exact value of the GitLab personal token.`,
5555
}),
56-
EMISSINGREPO: ({repoId}) => ({
57-
message: `The repository ${repoId} doesn't exist.`,
56+
EMISSINGREPO: ({projectPath}) => ({
57+
message: `The repository ${projectPath} doesn't exist.`,
5858
details: `The **semantic-release** \`repositoryUrl\` option must refer to your GitLab repository. The repository must be accessible with the [GitLab API](https://docs.gitlab.com/ce/api/README.html).
5959
6060
By default the \`repositoryUrl\` option is retrieved from the \`repository\` property of your \`package.json\` or the [git origin url](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) of the repository cloned by your CI environment.
@@ -63,21 +63,21 @@ If you are using [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee)
6363
'README.md#options'
6464
)}).`,
6565
}),
66-
EGLNOPUSHPERMISSION: ({repoId}) => ({
67-
message: `The GitLab token doesn't allow to push on the repository ${repoId}.`,
66+
EGLNOPUSHPERMISSION: ({projectPath}) => ({
67+
message: `The GitLab token doesn't allow to push on the repository ${projectPath}.`,
6868
details: `The user associated with the [GitLab token](${linkify(
6969
'README.md#gitlab-authentication'
70-
)}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must allows to push to the repository ${repoId}.
70+
)}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must allows to push to the repository ${projectPath}.
7171
72-
Please make sure the GitLab user associated with the token has the [permission to push](https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions) to the repository ${repoId}.`,
72+
Please make sure the GitLab user associated with the token has the [permission to push](https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions) to the repository ${projectPath}.`,
7373
}),
74-
EGLNOPULLPERMISSION: ({repoId}) => ({
75-
message: `The GitLab token doesn't allow to pull from the repository ${repoId}.`,
74+
EGLNOPULLPERMISSION: ({projectPath}) => ({
75+
message: `The GitLab token doesn't allow to pull from the repository ${projectPath}.`,
7676
details: `The user associated with the [GitLab token](${linkify(
7777
'README.md#gitlab-authentication'
78-
)}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must allow pull from the repository ${repoId}.
78+
)}) configured in the \`GL_TOKEN\` or \`GITLAB_TOKEN\` environment variable must allow pull from the repository ${projectPath}.
7979
80-
Please make sure the GitLab user associated with the token has the [permission to push](https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions) to the repository ${repoId}.`,
80+
Please make sure the GitLab user associated with the token has the [permission to push](https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions) to the repository ${projectPath}.`,
8181
}),
8282
ENOGLTOKEN: ({repositoryUrl}) => ({
8383
message: 'No GitLab token specified.',

lib/fail.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import got from "got";
44
import _debug from "debug";
55
const debug = _debug("semantic-release:gitlab");
66
import resolveConfig from "./resolve-config.js";
7-
import getRepoId from "./get-repo-id.js";
87
import getFailComment from "./get-fail-comment.js";
8+
import getProjectContext from "./get-project-context.js";
99

1010
export default async (pluginConfig, context) => {
1111
const {
@@ -25,8 +25,8 @@ export default async (pluginConfig, context) => {
2525
assignee,
2626
retryLimit,
2727
} = resolveConfig(pluginConfig, context);
28-
const repoId = getRepoId(context, gitlabUrl, repositoryUrl);
29-
const encodedRepoId = encodeURIComponent(repoId);
28+
const { encodedProjectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl);
29+
3030
const apiOptions = {
3131
headers: { "PRIVATE-TOKEN": gitlabToken },
3232
retry: { limit: retryLimit },
@@ -42,7 +42,7 @@ Using 'false' for 'failComment' or 'failTitle' is deprecated and will be removed
4242
const encodedFailTitle = encodeURIComponent(failTitle);
4343
const description = failComment ? template(failComment)({ branch, errors }) : getFailComment(branch, errors);
4444

45-
const issuesEndpoint = urlJoin(gitlabApiUrl, `/projects/${encodedRepoId}/issues`);
45+
const issuesEndpoint = urlJoin(projectApiUrl, `issues`);
4646
const openFailTitleIssueEndpoint = urlJoin(issuesEndpoint, `?state=opened&search=${encodedFailTitle}`);
4747

4848
const openFailTitleIssues = await got(openFailTitleIssueEndpoint, { ...apiOptions }).json();
@@ -67,7 +67,7 @@ Using 'false' for 'failComment' or 'failTitle' is deprecated and will be removed
6767
const { id, web_url } = existingIssue;
6868
logger.log("Commented on issue #%d: %s.", id, web_url);
6969
} else {
70-
const newIssue = { id: encodedRepoId, description, labels, title: failTitle, assignee_id: assignee };
70+
const newIssue = { id: encodedProjectPath, description, labels, title: failTitle, assignee_id: assignee };
7171
debug("create issue: %O", newIssue);
7272

7373
/* eslint camelcase: off */

lib/get-project-context.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import escapeStringRegexp from "escape-string-regexp";
2+
import parseUrl from "parse-url";
3+
import urlJoin from "url-join";
4+
5+
export default (
6+
{ envCi: { service } = {}, env: { CI_PROJECT_ID, CI_PROJECT_PATH } },
7+
gitlabUrl,
8+
gitlabApiUrl,
9+
repositoryUrl
10+
) => {
11+
const projectId = service === "gitlab" && CI_PROJECT_ID ? CI_PROJECT_ID : null;
12+
const projectPath =
13+
service === "gitlab" && CI_PROJECT_PATH
14+
? CI_PROJECT_PATH
15+
: parseUrl(repositoryUrl)
16+
.pathname.replace(new RegExp(`^${escapeStringRegexp(parseUrl(gitlabUrl).pathname)}`), "")
17+
.replace(/^\//, "")
18+
.replace(/\/$/, "")
19+
.replace(/\.git$/, "");
20+
const encodedProjectPath = encodeURIComponent(projectPath);
21+
const projectApiUrl = urlJoin(gitlabApiUrl, `/projects/${projectId ?? encodedProjectPath}`);
22+
return {
23+
projectPath,
24+
encodedProjectPath,
25+
projectApiUrl,
26+
};
27+
};

lib/get-repo-id.js

-11
This file was deleted.

lib/publish.js

+11-14
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import got from "got";
99
import _debug from "debug";
1010
const debug = _debug("semantic-release:gitlab");
1111
import resolveConfig from "./resolve-config.js";
12-
import getRepoId from "./get-repo-id.js";
1312
import getAssets from "./glob-assets.js";
1413
import { RELEASE_NAME } from "./definitions/constants.js";
14+
import getProjectContext from "./get-project-context.js";
1515

1616
const isUrlScheme = (value) => /^(https|http|ftp):\/\//.test(value);
1717

@@ -27,8 +27,8 @@ export default async (pluginConfig, context) => {
2727
context
2828
);
2929
const assetsList = [];
30-
const repoId = getRepoId(context, gitlabUrl, repositoryUrl);
31-
const encodedRepoId = encodeURIComponent(repoId);
30+
const { projectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl);
31+
3232
const encodedGitTag = encodeURIComponent(gitTag);
3333
const encodedVersion = encodeURIComponent(version);
3434
const apiOptions = {
@@ -52,7 +52,7 @@ export default async (pluginConfig, context) => {
5252
retry: { limit: retryLimit },
5353
};
5454

55-
debug("repoId: %o", repoId);
55+
debug("projectPath: %o", projectPath);
5656
debug("release name: %o", gitTag);
5757
debug("release ref: %o", gitHead);
5858
debug("milestones: %o", milestones);
@@ -114,8 +114,8 @@ export default async (pluginConfig, context) => {
114114
const encodedLabel = encodeURIComponent(label);
115115
// https://docs.gitlab.com/ee/user/packages/generic_packages/#publish-a-package-file
116116
uploadEndpoint = urlJoin(
117-
gitlabApiUrl,
118-
`/projects/${encodedRepoId}/packages/generic/release/${encodedVersion}/${encodedLabel}?${
117+
projectApiUrl,
118+
`packages/generic/release/${encodedVersion}/${encodedLabel}?${
119119
status ? `status=${status}&` : ""
120120
}select=package_file`
121121
);
@@ -130,17 +130,14 @@ export default async (pluginConfig, context) => {
130130
}
131131

132132
// https://docs.gitlab.com/ee/user/packages/generic_packages/#download-package-file
133-
const url = urlJoin(
134-
gitlabApiUrl,
135-
`/projects/${encodedRepoId}/packages/generic/release/${encodedVersion}/${encodedLabel}`
136-
);
133+
const url = urlJoin(projectApiUrl, `packages/generic/release/${encodedVersion}/${encodedLabel}`);
137134

138135
assetsList.push({ label, alt: "release", url, type: "package", filepath });
139136

140137
logger.log("Uploaded file: %s (%s)", url, response.file.url);
141138
} else {
142139
// Handle normal assets
143-
uploadEndpoint = urlJoin(gitlabApiUrl, `/projects/${encodedRepoId}/uploads`);
140+
uploadEndpoint = urlJoin(projectApiUrl, "uploads");
144141

145142
debug("POST-ing the file %s to %s", file, uploadEndpoint);
146143

@@ -167,7 +164,7 @@ export default async (pluginConfig, context) => {
167164

168165
debug("Create a release for git tag %o with commit %o", gitTag, gitHead);
169166

170-
const createReleaseEndpoint = urlJoin(gitlabApiUrl, `/projects/${encodedRepoId}/releases`);
167+
const createReleaseEndpoint = urlJoin(projectApiUrl, "releases");
171168

172169
const json = {
173170
/* eslint-disable camelcase */
@@ -178,7 +175,7 @@ export default async (pluginConfig, context) => {
178175
links: assetsList.map(({ label, alt, url, type, filepath, rawUrl }) => {
179176
return {
180177
name: label || alt,
181-
url: rawUrl || (isUrlScheme(url) ? url : urlJoin(gitlabUrl, repoId, url)),
178+
url: rawUrl || (isUrlScheme(url) ? url : urlJoin(gitlabUrl, projectPath, url)),
182179
link_type: type,
183180
filepath,
184181
};
@@ -202,7 +199,7 @@ export default async (pluginConfig, context) => {
202199

203200
logger.log("Published GitLab release: %s", gitTag);
204201

205-
const releaseUrl = urlJoin(gitlabUrl, repoId, `/-/releases/${encodedGitTag}`);
202+
const releaseUrl = urlJoin(gitlabUrl, projectPath, `/-/releases/${encodedGitTag}`);
206203

207204
return { name: RELEASE_NAME, url: releaseUrl };
208205
};

lib/success.js

+3-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import got from "got";
44
import _debug from "debug";
55
const debug = _debug("semantic-release:gitlab");
66
import resolveConfig from "./resolve-config.js";
7-
import getRepoId from "./get-repo-id.js";
7+
import getProjectContext from "./get-project-context.js";
88
import getSuccessComment from "./get-success-comment.js";
99

1010
export default async (pluginConfig, context) => {
@@ -17,8 +17,7 @@ export default async (pluginConfig, context) => {
1717
} = context;
1818
const { gitlabToken, gitlabUrl, gitlabApiUrl, successComment, successCommentCondition, proxy, retryLimit } =
1919
resolveConfig(pluginConfig, context);
20-
const repoId = getRepoId(context, gitlabUrl, repositoryUrl);
21-
const encodedRepoId = encodeURIComponent(repoId);
20+
const { projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl);
2221
const apiOptions = {
2322
headers: { "PRIVATE-TOKEN": gitlabToken },
2423
retry: { limit: retryLimit },
@@ -77,10 +76,7 @@ Using 'false' for 'successComment' is deprecated and will be removed in a future
7776
};
7877

7978
const getRelatedMergeRequests = async (commitHash) => {
80-
const relatedMergeRequestsEndpoint = urlJoin(
81-
gitlabApiUrl,
82-
`/projects/${encodedRepoId}/repository/commits/${commitHash}/merge_requests`
83-
);
79+
const relatedMergeRequestsEndpoint = urlJoin(projectApiUrl, `repository/commits/${commitHash}/merge_requests`);
8480
debug("Getting MRs from %s", relatedMergeRequestsEndpoint);
8581
const relatedMergeRequests = await got
8682
.get(relatedMergeRequestsEndpoint, {

lib/verify.js

+10-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { isString, isPlainObject, isNil, isArray } from "lodash-es";
2-
import urlJoin from "url-join";
32
import got from "got";
43
import _debug from "debug";
54
const debug = _debug("semantic-release:gitlab");
65
import AggregateError from "aggregate-error";
76
import resolveConfig from "./resolve-config.js";
8-
import getRepoId from "./get-repo-id.js";
7+
import getProjectContext from "./get-project-context.js";
98
import getError from "./get-error.js";
109

1110
const isNonEmptyString = (value) => isString(value) && value.trim();
@@ -32,10 +31,10 @@ export default async (pluginConfig, context) => {
3231
logger,
3332
} = context;
3433
const { gitlabToken, gitlabUrl, gitlabApiUrl, proxy, ...options } = resolveConfig(pluginConfig, context);
35-
const repoId = getRepoId(context, gitlabUrl, repositoryUrl);
34+
const { projectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl);
3635

3736
debug("apiUrl: %o", gitlabApiUrl);
38-
debug("repoId: %o", repoId);
37+
debug("projectPath: %o", projectPath);
3938

4039
const isValid = (option, value) => {
4140
const validator = VALIDATORS[option];
@@ -46,15 +45,15 @@ export default async (pluginConfig, context) => {
4645
.filter(([option, value]) => !isValid(option, value))
4746
.map(([option, value]) => getError(`EINVALID${option.toUpperCase()}`, { [option]: value }));
4847

49-
if (!repoId) {
48+
if (!projectPath) {
5049
errors.push(getError("EINVALIDGITLABURL"));
5150
}
5251

5352
if (!gitlabToken) {
5453
errors.push(getError("ENOGLTOKEN", { repositoryUrl }));
5554
}
5655

57-
if (gitlabToken && repoId) {
56+
if (gitlabToken && projectPath) {
5857
let projectAccess;
5958
let groupAccess;
6059

@@ -64,7 +63,7 @@ export default async (pluginConfig, context) => {
6463
({
6564
permissions: { project_access: projectAccess, group_access: groupAccess },
6665
} = await got
67-
.get(urlJoin(gitlabApiUrl, `/projects/${encodeURIComponent(repoId)}`), {
66+
.get(projectApiUrl, {
6867
headers: { "PRIVATE-TOKEN": gitlabToken },
6968
...proxy,
7069
})
@@ -73,17 +72,17 @@ export default async (pluginConfig, context) => {
7372
context.options.dryRun &&
7473
!((projectAccess && projectAccess.access_level >= 10) || (groupAccess && groupAccess.access_level >= 10))
7574
) {
76-
errors.push(getError("EGLNOPULLPERMISSION", { repoId }));
75+
errors.push(getError("EGLNOPULLPERMISSION", { projectPath }));
7776
} else if (
7877
!((projectAccess && projectAccess.access_level >= 30) || (groupAccess && groupAccess.access_level >= 30))
7978
) {
80-
errors.push(getError("EGLNOPUSHPERMISSION", { repoId }));
79+
errors.push(getError("EGLNOPUSHPERMISSION", { projectPath }));
8180
}
8281
} catch (error) {
8382
if (error.response && error.response.statusCode === 401) {
84-
errors.push(getError("EINVALIDGLTOKEN", { repoId }));
83+
errors.push(getError("EINVALIDGLTOKEN", { projectPath }));
8584
} else if (error.response && error.response.statusCode === 404) {
86-
errors.push(getError("EMISSINGREPO", { repoId }));
85+
errors.push(getError("EMISSINGREPO", { projectPath }));
8786
} else {
8887
throw error;
8988
}

0 commit comments

Comments
 (0)