diff --git a/README.md b/README.md index 69428aaf..c222204e 100644 --- a/README.md +++ b/README.md @@ -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]()` | diff --git a/lib/add-channel.js b/lib/add-channel.js index 65703a7e..60698539 100644 --- a/lib/add-channel.js +++ b/lib/add-channel.js @@ -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, }), ); diff --git a/lib/fail.js b/lib/fail.js index 61109283..9439b87a 100644 --- a/lib/fail.js +++ b/lib/fail.js @@ -21,6 +21,7 @@ export default async function fail(pluginConfig, context, { Octokit }) { githubToken, githubUrl, githubApiPathPrefix, + githubApiUrl, proxy, failComment, failTitle, @@ -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( diff --git a/lib/octokit.js b/lib/octokit.js index 798b5756..d1d1baa9 100644 --- a/lib/octokit.js +++ b/lib/octokit.js @@ -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" diff --git a/lib/publish.js b/lib/publish.js index 6a5bdfc2..b91c39d1 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -26,6 +26,7 @@ export default async function publish(pluginConfig, context, { Octokit }) { githubToken, githubUrl, githubApiPathPrefix, + githubApiUrl, proxy, assets, draftRelease, @@ -39,6 +40,7 @@ export default async function publish(pluginConfig, context, { Octokit }) { githubToken, githubUrl, githubApiPathPrefix, + githubApiUrl, proxy, }), ); diff --git a/lib/resolve-config.js b/lib/resolve-config.js index 803f13a5..b8081c88 100644 --- a/lib/resolve-config.js +++ b/lib/resolve-config.js @@ -3,6 +3,7 @@ import { isNil, castArray } from "lodash-es"; export default function resolveConfig( { githubUrl, + githubApiUrl, githubApiPathPrefix, proxy, assets, @@ -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, diff --git a/lib/success.js b/lib/success.js index 75cca3a2..86729904 100644 --- a/lib/success.js +++ b/lib/success.js @@ -27,6 +27,7 @@ export default async function success(pluginConfig, context, { Octokit }) { githubToken, githubUrl, githubApiPathPrefix, + githubApiUrl, proxy, successComment, failComment, @@ -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 diff --git a/lib/verify.js b/lib/verify.js index 12a186ce..b951cee3 100644 --- a/lib/verify.js +++ b/lib/verify.js @@ -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]) => @@ -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), @@ -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 diff --git a/test/verify.test.js b/test/verify.test.js index 5d97ad91..9bac5d0b 100644 --- a/test/verify.test.js +++ b/test/verify.test.js @@ -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 = { @@ -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";