diff --git a/lib/resolve-config.js b/lib/resolve-config.js index 91b85a84..eed1928c 100644 --- a/lib/resolve-config.js +++ b/lib/resolve-config.js @@ -1,4 +1,5 @@ const {isNil, castArray} = require('lodash'); +const resolveProxy = require('./resolve-proxy'); module.exports = ( { @@ -15,21 +16,25 @@ module.exports = ( addReleases, }, {env} -) => ({ - githubToken: env.GH_TOKEN || env.GITHUB_TOKEN, - githubUrl: githubUrl || env.GITHUB_API_URL || env.GH_URL || env.GITHUB_URL, - githubApiPathPrefix: githubApiPathPrefix || env.GH_PREFIX || env.GITHUB_PREFIX || '', - proxy: isNil(proxy) ? env.http_proxy || env.HTTP_PROXY || false : proxy, - assets: assets ? castArray(assets) : assets, - successComment, - failTitle: isNil(failTitle) ? 'The automated release is failing 🚨' : failTitle, - failComment, - labels: isNil(labels) ? ['semantic-release'] : labels === false ? false : castArray(labels), - assignees: assignees ? castArray(assignees) : assignees, - releasedLabels: isNil(releasedLabels) - ? [`released<%= nextRelease.channel ? \` on @\${nextRelease.channel}\` : "" %>`] - : releasedLabels === false - ? false - : castArray(releasedLabels), - addReleases: isNil(addReleases) ? false : addReleases, -}); +) => { + githubUrl ||= env.GITHUB_API_URL || env.GH_URL || env.GITHUB_URL; + + return { + githubToken: env.GH_TOKEN || env.GITHUB_TOKEN, + githubUrl, + githubApiPathPrefix: githubApiPathPrefix || env.GH_PREFIX || env.GITHUB_PREFIX || '', + proxy: isNil(proxy) ? resolveProxy(githubUrl, env) : proxy, + assets: assets ? castArray(assets) : assets, + successComment, + failTitle: isNil(failTitle) ? 'The automated release is failing 🚨' : failTitle, + failComment, + labels: isNil(labels) ? ['semantic-release'] : labels === false ? false : castArray(labels), + assignees: assignees ? castArray(assignees) : assignees, + releasedLabels: isNil(releasedLabels) + ? [`released<%= nextRelease.channel ? \` on @\${nextRelease.channel}\` : "" %>`] + : releasedLabels === false + ? false + : castArray(releasedLabels), + addReleases: isNil(addReleases) ? false : addReleases, + }; +}; diff --git a/lib/resolve-proxy.js b/lib/resolve-proxy.js new file mode 100644 index 00000000..25c05ab3 --- /dev/null +++ b/lib/resolve-proxy.js @@ -0,0 +1,24 @@ +module.exports = (githubUrl, env) => { + githubUrl ||= 'https://api.github.com'; + const proxy = env.http_proxy || env.HTTP_PROXY || false; + const noProxy = env.no_proxy || env.NO_PROXY; + + if (proxy && noProxy) { + const {hostname} = new URL(githubUrl); + for (let noProxyHost of noProxy.split(',')) { + if (noProxyHost === '*') { + return false; + } + + if (noProxyHost.startsWith('.')) { + noProxyHost = noProxyHost.slice(1); + } + + if (hostname === noProxyHost || hostname.endsWith('.' + noProxyHost)) { + return false; + } + } + } + + return proxy; +}; diff --git a/test/resolve-proxy.test.js b/test/resolve-proxy.test.js new file mode 100644 index 00000000..bc6aacf8 --- /dev/null +++ b/test/resolve-proxy.test.js @@ -0,0 +1,47 @@ +const test = require('ava'); +const resolveProxy = require('../lib/resolve-proxy'); + +test('Resolve proxy with no proxy configuration', (t) => { + t.is(resolveProxy(undefined, {}), false); +}); + +test('Resolve proxy with no exclusions', (t) => { + t.is(resolveProxy(undefined, {http_proxy: 'proxy.example.com'}), 'proxy.example.com'); +}); + +test('Resolve proxy with no matching exclusion', (t) => { + t.is( + resolveProxy(undefined, { + http_proxy: 'proxy.example.com', + no_proxy: 'notapi.github.com,.example.org,example.net', + }), + 'proxy.example.com' + ); +}); + +test('Resolve proxy with matching exclusion', (t) => { + t.is(resolveProxy(undefined, {http_proxy: 'proxy.example.com', no_proxy: 'github.com'}), false); +}); + +test('Resolve proxy with matching exclusion (leading .)', (t) => { + t.is(resolveProxy(undefined, {http_proxy: 'proxy.example.com', no_proxy: '.github.com'}), false); +}); + +test('Resolve proxy with global exclusion', (t) => { + t.is(resolveProxy(undefined, {http_proxy: 'proxy.example.com', no_proxy: '*'}), false); +}); + +test('Resolve proxy with matching GitHub Enterprise exclusion', (t) => { + t.is( + resolveProxy('https://github.example.com/api/v3', {http_proxy: 'proxy.example.com', no_proxy: 'example.com'}), + false + ); +}); + +test('Resolve proxy with uppercase environment variables', (t) => { + t.is(resolveProxy(undefined, {HTTP_PROXY: 'proxy.example.com', NO_PROXY: 'github.com'}), false); + t.is( + resolveProxy(undefined, {HTTP_PROXY: 'proxy.example.com', NO_PROXY: 'subdomain.github.com'}), + 'proxy.example.com' + ); +});