Skip to content

Commit 908ff83

Browse files
authoredMay 15, 2024··
fix: introduce dedicated option for GitHub API endpoint (#829)
Server and API endpoints can be different. Some code parts, e.g. issue parsing, need the server endpoint and we should make this explicit.
1 parent 9443145 commit 908ff83

9 files changed

+131
-23
lines changed
 

‎README.md

+9-7
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,20 @@ When using the _GITHUB_TOKEN_, the **minimum required permissions** are:
7171

7272
### Environment variables
7373

74-
| Variable | Description |
75-
| -------------------------------------------- | --------------------------------------------------------- |
76-
| `GH_TOKEN` or `GITHUB_TOKEN` | **Required.** The token used to authenticate with GitHub. |
77-
| `GITHUB_API_URL` or `GH_URL` or `GITHUB_URL` | The GitHub Enterprise endpoint. |
78-
| `GH_PREFIX` or `GITHUB_PREFIX` | The GitHub Enterprise API prefix. |
74+
| Variable | Description |
75+
| ------------------------------ | ------------------------------------------------------------------- |
76+
| `GITHUB_TOKEN` or `GH_TOKEN` | **Required.** The token used to authenticate with GitHub. |
77+
| `GITHUB_URL` or `GH_URL` | The GitHub server endpoint. |
78+
| `GITHUB_PREFIX` or `GH_PREFIX` | The GitHub API prefix, relative to `GITHUB_URL`. |
79+
| `GITHUB_API_URL` | The GitHub API endpoint. Note that this overwrites `GITHUB_PREFIX`. |
7980

8081
### Options
8182

8283
| Option | Description | Default |
8384
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
84-
| `githubUrl` | The GitHub Enterprise endpoint. | `GH_URL` or `GITHUB_URL` environment variable. |
85-
| `githubApiPathPrefix` | The GitHub Enterprise API prefix. | `GH_PREFIX` or `GITHUB_PREFIX` environment variable. |
85+
| `githubUrl` | The GitHub server endpoint. | `GH_URL` or `GITHUB_URL` environment variable. |
86+
| `githubApiPathPrefix` | The GitHub API prefix, relative to `githubUrl`. | `GH_PREFIX` or `GITHUB_PREFIX` environment variable. |
87+
| `githubApiUrl` | The GitHub API endpoint. Note that this overwrites `githubApiPathPrefix`. | `GITHUB_API_URL` environment variable. |
8688
| `proxy` | The proxy to use to access the GitHub API. Set to `false` to disable usage of proxy. See [proxy](#proxy). | `HTTP_PROXY` environment variable. |
8789
| `assets` | An array of files to upload to the release. See [assets](#assets). | - |
8890
| `successComment` | The comment to add to each issue and pull request resolved by the release. Set to `false` to disable commenting on issues and pull requests. See [successComment](#successcomment). | `:tada: This issue has been resolved in version ${nextRelease.version} :tada:\n\nThe release is available on [GitHub release](<github_release_url>)` |

‎lib/add-channel.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,15 @@ export default async function addChannel(pluginConfig, context, { Octokit }) {
1515
nextRelease: { name, gitTag, notes },
1616
logger,
1717
} = context;
18-
const { githubToken, githubUrl, githubApiPathPrefix, proxy } = resolveConfig(
19-
pluginConfig,
20-
context,
21-
);
18+
const { githubToken, githubUrl, githubApiPathPrefix, githubApiUrl, proxy } =
19+
resolveConfig(pluginConfig, context);
2220
const { owner, repo } = parseGithubUrl(repositoryUrl);
2321
const octokit = new Octokit(
2422
toOctokitOptions({
2523
githubToken,
2624
githubUrl,
2725
githubApiPathPrefix,
26+
githubApiUrl,
2827
proxy,
2928
}),
3029
);

‎lib/fail.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default async function fail(pluginConfig, context, { Octokit }) {
2121
githubToken,
2222
githubUrl,
2323
githubApiPathPrefix,
24+
githubApiUrl,
2425
proxy,
2526
failComment,
2627
failTitle,
@@ -32,7 +33,13 @@ export default async function fail(pluginConfig, context, { Octokit }) {
3233
logger.log("Skip issue creation.");
3334
} else {
3435
const octokit = new Octokit(
35-
toOctokitOptions({ githubToken, githubUrl, githubApiPathPrefix, proxy }),
36+
toOctokitOptions({
37+
githubToken,
38+
githubUrl,
39+
githubApiPathPrefix,
40+
githubApiUrl,
41+
proxy,
42+
}),
3643
);
3744
// In case the repo changed name, get the new `repo`/`owner` as the search API will not follow redirects
3845
const { data: repoData } = await octokit.request(

‎lib/octokit.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,16 @@ export const SemanticReleaseOctokit = Octokit.plugin(
4949
/* c8 ignore stop */
5050

5151
/**
52-
* @param {{githubToken: string, proxy: any} | {githubUrl: string, githubApiPathPrefix: string, githubToken: string, proxy: any}} options
52+
* @param {{githubToken: string, proxy: any} | {githubUrl: string, githubApiPathPrefix: string, githubApiUrl: string,githubToken: string, proxy: any}} options
5353
* @returns {{ auth: string, baseUrl?: string, request: { agent?: any } }}
5454
*/
5555
export function toOctokitOptions(options) {
5656
const baseUrl =
57-
"githubUrl" in options && options.githubUrl
58-
? urljoin(options.githubUrl, options.githubApiPathPrefix)
59-
: undefined;
57+
"githubApiUrl" in options && options.githubApiUrl
58+
? options.githubApiUrl
59+
: "githubUrl" in options && options.githubUrl
60+
? urljoin(options.githubUrl, options.githubApiPathPrefix)
61+
: undefined;
6062

6163
const agent = options.proxy
6264
? baseUrl && new URL(baseUrl).protocol.replace(":", "") === "http"

‎lib/publish.js

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export default async function publish(pluginConfig, context, { Octokit }) {
2626
githubToken,
2727
githubUrl,
2828
githubApiPathPrefix,
29+
githubApiUrl,
2930
proxy,
3031
assets,
3132
draftRelease,
@@ -39,6 +40,7 @@ export default async function publish(pluginConfig, context, { Octokit }) {
3940
githubToken,
4041
githubUrl,
4142
githubApiPathPrefix,
43+
githubApiUrl,
4244
proxy,
4345
}),
4446
);

‎lib/resolve-config.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { isNil, castArray } from "lodash-es";
33
export default function resolveConfig(
44
{
55
githubUrl,
6+
githubApiUrl,
67
githubApiPathPrefix,
78
proxy,
89
assets,
@@ -22,9 +23,10 @@ export default function resolveConfig(
2223
) {
2324
return {
2425
githubToken: env.GH_TOKEN || env.GITHUB_TOKEN,
25-
githubUrl: githubUrl || env.GITHUB_API_URL || env.GH_URL || env.GITHUB_URL,
26+
githubUrl: githubUrl || env.GH_URL || env.GITHUB_URL,
2627
githubApiPathPrefix:
2728
githubApiPathPrefix || env.GH_PREFIX || env.GITHUB_PREFIX || "",
29+
githubApiUrl: githubApiUrl || env.GITHUB_API_URL,
2830
proxy: isNil(proxy) ? env.http_proxy || env.HTTP_PROXY || false : proxy,
2931
assets: assets ? castArray(assets) : assets,
3032
successComment,

‎lib/success.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export default async function success(pluginConfig, context, { Octokit }) {
2727
githubToken,
2828
githubUrl,
2929
githubApiPathPrefix,
30+
githubApiUrl,
3031
proxy,
3132
successComment,
3233
failComment,
@@ -36,7 +37,13 @@ export default async function success(pluginConfig, context, { Octokit }) {
3637
} = resolveConfig(pluginConfig, context);
3738

3839
const octokit = new Octokit(
39-
toOctokitOptions({ githubToken, githubUrl, githubApiPathPrefix, proxy }),
40+
toOctokitOptions({
41+
githubToken,
42+
githubUrl,
43+
githubApiPathPrefix,
44+
githubApiUrl,
45+
proxy,
46+
}),
4047
);
4148

4249
// In case the repo changed name, get the new `repo`/`owner` as the search API will not follow redirects

‎lib/verify.js

+18-4
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,14 @@ export default async function verify(pluginConfig, context, { Octokit }) {
5656
options: { repositoryUrl },
5757
logger,
5858
} = context;
59-
const { githubToken, githubUrl, githubApiPathPrefix, proxy, ...options } =
60-
resolveConfig(pluginConfig, context);
59+
const {
60+
githubToken,
61+
githubUrl,
62+
githubApiPathPrefix,
63+
githubApiUrl,
64+
proxy,
65+
...options
66+
} = resolveConfig(pluginConfig, context);
6167

6268
const errors = Object.entries({ ...options, proxy }).reduce(
6369
(errors, [option, value]) =>
@@ -70,7 +76,9 @@ export default async function verify(pluginConfig, context, { Octokit }) {
7076
[],
7177
);
7278

73-
if (githubUrl) {
79+
if (githubApiUrl) {
80+
logger.log("Verify GitHub authentication (%s)", githubApiUrl);
81+
} else if (githubUrl) {
7482
logger.log(
7583
"Verify GitHub authentication (%s)",
7684
urlJoin(githubUrl, githubApiPathPrefix),
@@ -87,7 +95,13 @@ export default async function verify(pluginConfig, context, { Octokit }) {
8795
!errors.find(({ code }) => code === "EINVALIDPROXY")
8896
) {
8997
const octokit = new Octokit(
90-
toOctokitOptions({ githubToken, githubUrl, githubApiPathPrefix, proxy }),
98+
toOctokitOptions({
99+
githubToken,
100+
githubUrl,
101+
githubApiPathPrefix,
102+
githubApiUrl,
103+
proxy,
104+
}),
91105
);
92106

93107
// https://github.com/semantic-release/github/issues/182

‎test/verify.test.js

+74-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ test("Verify package, token and repository with environment variables", async (t
263263
]);
264264
});
265265

266-
test("Verify package, token and repository access with alternative environment varialbes", async (t) => {
266+
test("Verify package, token and repository access with alternative environment variables", async (t) => {
267267
const owner = "test_user";
268268
const repo = "test_repo";
269269
const env = {
@@ -299,6 +299,79 @@ test("Verify package, token and repository access with alternative environment v
299299
t.true(fetch.done());
300300
});
301301

302+
test("Verify package, token and repository access with custom API URL", async (t) => {
303+
const owner = "test_user";
304+
const repo = "test_repo";
305+
const env = { GH_TOKEN: "github_token" };
306+
const githubUrl = "https://othertesturl.com:9090";
307+
const githubApiUrl = "https://api.othertesturl.com:9090";
308+
309+
const fetch = fetchMock
310+
.sandbox()
311+
.getOnce(`https://api.othertesturl.com:9090/repos/${owner}/${repo}`, {
312+
permissions: { push: true },
313+
});
314+
315+
await t.notThrowsAsync(
316+
verify(
317+
{ githubUrl, githubApiUrl },
318+
{
319+
env,
320+
options: { repositoryUrl: `github:${owner}/${repo}` },
321+
logger: t.context.logger,
322+
},
323+
{
324+
Octokit: TestOctokit.defaults((options) => ({
325+
...options,
326+
request: { ...options.request, fetch },
327+
})),
328+
},
329+
),
330+
);
331+
332+
t.true(fetch.done());
333+
t.deepEqual(t.context.log.args[0], [
334+
"Verify GitHub authentication (%s)",
335+
"https://api.othertesturl.com:9090",
336+
]);
337+
});
338+
339+
test("Verify package, token and repository access with API URL in environment variable", async (t) => {
340+
const owner = "test_user";
341+
const repo = "test_repo";
342+
const env = {
343+
GITHUB_URL: "https://othertesturl.com:443",
344+
GITHUB_API_URL: "https://api.othertesturl.com:443",
345+
GITHUB_TOKEN: "github_token",
346+
};
347+
348+
const fetch = fetchMock
349+
.sandbox()
350+
.getOnce(`https://api.othertesturl.com:443/repos/${owner}/${repo}`, {
351+
permissions: { push: true },
352+
});
353+
354+
await t.notThrowsAsync(
355+
verify(
356+
{},
357+
{
358+
env,
359+
options: {
360+
repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`,
361+
},
362+
logger: t.context.logger,
363+
},
364+
{
365+
Octokit: TestOctokit.defaults((options) => ({
366+
...options,
367+
request: { ...options.request, fetch },
368+
})),
369+
},
370+
),
371+
);
372+
t.true(fetch.done());
373+
});
374+
302375
test('Verify "proxy" is a String', async (t) => {
303376
const owner = "test_user";
304377
const repo = "test_repo";

0 commit comments

Comments
 (0)
Please sign in to comment.