Skip to content

Commit

Permalink
fix: introduce dedicated option for GitHub API endpoint
Browse files Browse the repository at this point in the history
Server and API endpoints can be different. Some code parts, e.g. issue parsing, need the server endpoint and we should make this explicit.
  • Loading branch information
fgreinacher committed May 10, 2024
1 parent aaede2a commit 0bb4285
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 23 deletions.
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,20 @@ When using the _GITHUB_TOKEN_, the **minimum required permissions** are:

### Environment variables

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

### Options

| Option | Description | Default |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `githubUrl` | The GitHub Enterprise endpoint. | `GH_URL` or `GITHUB_URL` environment variable. |
| `githubApiPathPrefix` | The GitHub Enterprise API prefix. | `GH_PREFIX` or `GITHUB_PREFIX` environment variable. |
| `githubUrl` | The GitHub server endpoint. | `GH_URL` or `GITHUB_URL` environment variable. |
| `githubApiPathPrefix` | The GitHub API prefix, relative to `githubUrl`. | `GH_PREFIX` or `GITHUB_PREFIX` environment variable. |
| `githubApiUrl` | The GitHub API endpoint. Note that this overwrites `githubApiPathPrefix`. | `GITHUB_API_URL` environment variable. |
| `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. |
| `assets` | An array of files to upload to the release. See [assets](#assets). | - |
| `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>)` |
Expand Down
7 changes: 3 additions & 4 deletions lib/add-channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,15 @@ export default async function addChannel(pluginConfig, context, { Octokit }) {
nextRelease: { name, gitTag, notes },
logger,
} = context;
const { githubToken, githubUrl, githubApiPathPrefix, proxy } = resolveConfig(
pluginConfig,
context,
);
const { githubToken, githubUrl, githubApiPathPrefix, githubApiUrl, proxy } =
resolveConfig(pluginConfig, context);
const { owner, repo } = parseGithubUrl(repositoryUrl);
const octokit = new Octokit(
toOctokitOptions({
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
}),
);
Expand Down
9 changes: 8 additions & 1 deletion lib/fail.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default async function fail(pluginConfig, context, { Octokit }) {
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
failComment,
failTitle,
Expand All @@ -32,7 +33,13 @@ export default async function fail(pluginConfig, context, { Octokit }) {
logger.log("Skip issue creation.");
} else {
const octokit = new Octokit(
toOctokitOptions({ githubToken, githubUrl, githubApiPathPrefix, proxy }),
toOctokitOptions({
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
}),
);
// In case the repo changed name, get the new `repo`/`owner` as the search API will not follow redirects
const { data: repoData } = await octokit.request(
Expand Down
10 changes: 6 additions & 4 deletions lib/octokit.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@ export const SemanticReleaseOctokit = Octokit.plugin(
/* c8 ignore stop */

/**
* @param {{githubToken: string, proxy: any} | {githubUrl: string, githubApiPathPrefix: string, githubToken: string, proxy: any}} options
* @param {{githubToken: string, proxy: any} | {githubUrl: string, githubApiPathPrefix: string, githubApiUrl: string,githubToken: string, proxy: any}} options
* @returns {{ auth: string, baseUrl?: string, request: { agent?: any } }}
*/
export function toOctokitOptions(options) {
const baseUrl =
"githubUrl" in options && options.githubUrl
? urljoin(options.githubUrl, options.githubApiPathPrefix)
: undefined;
"githubApiUrl" in options && options.githubApiUrl
? options.githubApiUrl
: "githubUrl" in options && options.githubUrl
? urljoin(options.githubUrl, options.githubApiPathPrefix)
: undefined;

const agent = options.proxy
? baseUrl && new URL(baseUrl).protocol.replace(":", "") === "http"
Expand Down
2 changes: 2 additions & 0 deletions lib/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default async function publish(pluginConfig, context, { Octokit }) {
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
assets,
draftRelease,
Expand All @@ -39,6 +40,7 @@ export default async function publish(pluginConfig, context, { Octokit }) {
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
}),
);
Expand Down
4 changes: 3 additions & 1 deletion lib/resolve-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { isNil, castArray } from "lodash-es";
export default function resolveConfig(
{
githubUrl,
githubApiUrl,
githubApiPathPrefix,
proxy,
assets,
Expand All @@ -22,9 +23,10 @@ export default function resolveConfig(
) {
return {
githubToken: env.GH_TOKEN || env.GITHUB_TOKEN,
githubUrl: githubUrl || env.GITHUB_API_URL || env.GH_URL || env.GITHUB_URL,
githubUrl: githubUrl || env.GH_URL || env.GITHUB_URL,
githubApiPathPrefix:
githubApiPathPrefix || env.GH_PREFIX || env.GITHUB_PREFIX || "",
githubApiUrl: githubApiUrl || env.GITHUB_API_URL,
proxy: isNil(proxy) ? env.http_proxy || env.HTTP_PROXY || false : proxy,
assets: assets ? castArray(assets) : assets,
successComment,
Expand Down
9 changes: 8 additions & 1 deletion lib/success.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default async function success(pluginConfig, context, { Octokit }) {
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
successComment,
failComment,
Expand All @@ -36,7 +37,13 @@ export default async function success(pluginConfig, context, { Octokit }) {
} = resolveConfig(pluginConfig, context);

const octokit = new Octokit(
toOctokitOptions({ githubToken, githubUrl, githubApiPathPrefix, proxy }),
toOctokitOptions({
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
}),
);

// In case the repo changed name, get the new `repo`/`owner` as the search API will not follow redirects
Expand Down
22 changes: 18 additions & 4 deletions lib/verify.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,14 @@ export default async function verify(pluginConfig, context, { Octokit }) {
options: { repositoryUrl },
logger,
} = context;
const { githubToken, githubUrl, githubApiPathPrefix, proxy, ...options } =
resolveConfig(pluginConfig, context);
const {
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
...options
} = resolveConfig(pluginConfig, context);

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

if (githubUrl) {
if (githubApiUrl) {
logger.log("Verify GitHub authentication (%s)", githubApiUrl);
} else if (githubUrl) {
logger.log(
"Verify GitHub authentication (%s)",
urlJoin(githubUrl, githubApiPathPrefix),
Expand All @@ -87,7 +95,13 @@ export default async function verify(pluginConfig, context, { Octokit }) {
!errors.find(({ code }) => code === "EINVALIDPROXY")
) {
const octokit = new Octokit(
toOctokitOptions({ githubToken, githubUrl, githubApiPathPrefix, proxy }),
toOctokitOptions({
githubToken,
githubUrl,
githubApiPathPrefix,
githubApiUrl,
proxy,
}),
);

// https://github.com/semantic-release/github/issues/182
Expand Down
75 changes: 74 additions & 1 deletion test/verify.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ test("Verify package, token and repository with environment variables", async (t
]);
});

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

test("Verify package, token and repository access with custom API URL", async (t) => {
const owner = "test_user";
const repo = "test_repo";
const env = { GH_TOKEN: "github_token" };
const githubUrl = "https://othertesturl.com:9090";
const githubApiUrl = "https://api.othertesturl.com:9090";

const fetch = fetchMock
.sandbox()
.getOnce(`https://api.othertesturl.com:9090/repos/${owner}/${repo}`, {
permissions: { push: true },
});

await t.notThrowsAsync(
verify(
{ githubUrl, githubApiUrl },
{
env,
options: { repositoryUrl: `github:${owner}/${repo}` },
logger: t.context.logger,
},
{
Octokit: TestOctokit.defaults((options) => ({
...options,
request: { ...options.request, fetch },
})),
},
),
);

t.true(fetch.done());
t.deepEqual(t.context.log.args[0], [
"Verify GitHub authentication (%s)",
"https://api.othertesturl.com:9090",
]);
});

test("Verify package, token and repository access with API URL in environment variable", async (t) => {
const owner = "test_user";
const repo = "test_repo";
const env = {
GITHUB_URL: "https://othertesturl.com:443",
GITHUB_API_URL: "https://api.othertesturl.com:443",
GITHUB_TOKEN: "github_token",
};

const fetch = fetchMock
.sandbox()
.getOnce(`https://api.othertesturl.com:443/repos/${owner}/${repo}`, {
permissions: { push: true },
});

await t.notThrowsAsync(
verify(
{},
{
env,
options: {
repositoryUrl: `git@othertesturl.com:${owner}/${repo}.git`,
},
logger: t.context.logger,
},
{
Octokit: TestOctokit.defaults((options) => ({
...options,
request: { ...options.request, fetch },
})),
},
),
);
t.true(fetch.done());
});

test('Verify "proxy" is a String', async (t) => {
const owner = "test_user";
const repo = "test_repo";
Expand Down

0 comments on commit 0bb4285

Please sign in to comment.