From 731eba56b459b3e8a56c9c67c6d179634a7d1672 Mon Sep 17 00:00:00 2001 From: janssen-tiobe <118828444+janssen-tiobe@users.noreply.github.com> Date: Mon, 23 Oct 2023 16:36:55 +0200 Subject: [PATCH] #33012: Reimplemented octokit again, tests for no_proxy --- dist/index.js | 178 +++--------------- jest.config.js | 2 +- package-lock.json | 29 --- package.json | 1 - src/configuration.ts | 33 +++- .../{proxy => integration}/httpclient.test.ts | 26 ++- test/{proxy => integration}/octokit.test.ts | 48 ++--- 7 files changed, 96 insertions(+), 221 deletions(-) rename test/{proxy => integration}/httpclient.test.ts (81%) rename test/{proxy => integration}/octokit.test.ts (73%) diff --git a/dist/index.js b/dist/index.js index 90ee7ddd..c8e0abfb 100644 --- a/dist/index.js +++ b/dist/index.js @@ -7,15 +7,19 @@ "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.viewerUrl = exports.baseUrl = exports.httpClient = exports.octokit = exports.retryConfig = exports.ticsConfig = exports.githubConfig = void 0; +exports.viewerUrl = exports.baseUrl = exports.octokit = exports.httpClient = exports.retryConfig = exports.ticsConfig = exports.githubConfig = void 0; const core_1 = __nccwpck_require__(2186); const github_1 = __nccwpck_require__(5438); -const action_1 = __nccwpck_require__(1231); +const core_2 = __nccwpck_require__(6762); +const plugin_paginate_rest_1 = __nccwpck_require__(4193); +const plugin_rest_endpoint_methods_1 = __nccwpck_require__(3044); const plugin_retry_1 = __nccwpck_require__(6298); const http_client_1 = __nccwpck_require__(6255); const api_helper_1 = __nccwpck_require__(3823); +const undici_1 = __nccwpck_require__(1773); const os_1 = __nccwpck_require__(2037); exports.githubConfig = { + baseUrl: process.env.GITHUB_API_URL ? process.env.GITHUB_API_URL : 'https://api.github.com', repo: process.env.GITHUB_REPOSITORY ? process.env.GITHUB_REPOSITORY : '', owner: process.env.GITHUB_REPOSITORY ? process.env.GITHUB_REPOSITORY.split('/')[0] : '', reponame: process.env.GITHUB_REPOSITORY ? process.env.GITHUB_REPOSITORY.split('/')[1] : '', @@ -83,20 +87,27 @@ const ignoreSslError = exports.ticsConfig.hostnameVerification === '0' || exports.ticsConfig.hostnameVerification === 'false' || exports.ticsConfig.trustStrategy === 'self-signed' || exports.ticsConfig.trustStrategy === 'all'; -// octokit/action uses the environment variable GITHUB_TOKEN -process.env.GITHUB_TOKEN = exports.ticsConfig.githubToken; -exports.octokit = new (action_1.Octokit.plugin(plugin_retry_1.retry))({ - request: { - fetch: action_1.customFetch, - retries: exports.retryConfig.maxRetries, - retryAfter: 5 - } -}); exports.httpClient = new http_client_1.HttpClient('tics-github-action', undefined, { allowRetries: true, maxRetries: exports.retryConfig.maxRetries, ignoreSslError: ignoreSslError }); +const octokitOptions = { + auth: exports.ticsConfig.githubToken, + baseUrl: exports.githubConfig.baseUrl, + request: { + agent: exports.httpClient.getAgent(exports.githubConfig.baseUrl), + fetch: async (url, opts) => { + return (0, undici_1.fetch)(url, { + ...opts, + dispatcher: exports.httpClient.getAgentDispatcher(exports.githubConfig.baseUrl) + }); + }, + retries: exports.retryConfig.maxRetries, + retryAfter: 5 + } +}; +exports.octokit = new (core_2.Octokit.plugin(plugin_paginate_rest_1.paginateRest, plugin_rest_endpoint_methods_1.restEndpointMethods, plugin_retry_1.retry).defaults(octokitOptions))(); exports.baseUrl = (0, api_helper_1.getTicsWebBaseUrlFromUrl)(exports.ticsConfig.ticsConfiguration); exports.viewerUrl = exports.ticsConfig.viewerUrl ? exports.ticsConfig.viewerUrl.replace(/\/+$/, '') : exports.baseUrl; @@ -8571,151 +8582,6 @@ function parseParams (str) { module.exports = parseParams -/***/ }), - -/***/ 1231: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// pkg/dist-src/index.js -var dist_src_exports = {}; -__export(dist_src_exports, { - Octokit: () => Octokit, - customFetch: () => customFetch, - getProxyAgent: () => getProxyAgent -}); -module.exports = __toCommonJS(dist_src_exports); -var import_core = __nccwpck_require__(6762); -var import_auth_action = __nccwpck_require__(20); -var import_plugin_paginate_rest = __nccwpck_require__(4193); -var import_plugin_rest_endpoint_methods = __nccwpck_require__(3044); - -// pkg/dist-src/version.js -var VERSION = "6.0.6"; - -// pkg/dist-src/index.js -var import_undici = __nccwpck_require__(1773); -var DEFAULTS = { - authStrategy: import_auth_action.createActionAuth, - baseUrl: getApiBaseUrl(), - userAgent: `octokit-action.js/${VERSION}` -}; -function getProxyAgent() { - const httpProxy = process.env["HTTP_PROXY"] || process.env["http_proxy"]; - if (httpProxy) { - return new import_undici.ProxyAgent(httpProxy); - } - const httpsProxy = process.env["HTTPS_PROXY"] || process.env["https_proxy"]; - if (httpsProxy) { - return new import_undici.ProxyAgent(httpsProxy); - } - return void 0; -} -var customFetch = async function(url, opts) { - return await (0, import_undici.fetch)(url, { - dispatcher: getProxyAgent(), - ...opts - }); -}; -var Octokit = import_core.Octokit.plugin( - import_plugin_paginate_rest.paginateRest, - import_plugin_rest_endpoint_methods.legacyRestEndpointMethods -).defaults(function buildDefaults(options) { - return { - ...DEFAULTS, - ...options, - request: { - fetch: customFetch, - ...options.request - } - }; -}); -function getApiBaseUrl() { - return process.env["GITHUB_API_URL"] || "https://api.github.com"; -} -// Annotate the CommonJS export names for ESM import in node: -0 && (0); - - -/***/ }), - -/***/ 20: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// pkg/dist-src/index.js -var dist_src_exports = {}; -__export(dist_src_exports, { - createActionAuth: () => createActionAuth -}); -module.exports = __toCommonJS(dist_src_exports); -var import_auth_token = __nccwpck_require__(334); -var createActionAuth = function createActionAuth2() { - if (!process.env.GITHUB_ACTION) { - throw new Error( - "[@octokit/auth-action] `GITHUB_ACTION` environment variable is not set. @octokit/auth-action is meant to be used in GitHub Actions only." - ); - } - const definitions = [ - process.env.GITHUB_TOKEN, - process.env.INPUT_GITHUB_TOKEN, - process.env.INPUT_TOKEN - ].filter(Boolean); - if (definitions.length === 0) { - throw new Error( - "[@octokit/auth-action] `GITHUB_TOKEN` variable is not set. It must be set on either `env:` or `with:`. See https://github.com/octokit/auth-action.js#createactionauth" - ); - } - if (definitions.length > 1) { - throw new Error( - "[@octokit/auth-action] The token variable is specified more than once. Use either `with.token`, `with.GITHUB_TOKEN`, or `env.GITHUB_TOKEN`. See https://github.com/octokit/auth-action.js#createactionauth" - ); - } - const token = definitions.pop(); - return (0, import_auth_token.createTokenAuth)(token); -}; -// Annotate the CommonJS export names for ESM import in node: -0 && (0); - - /***/ }), /***/ 334: diff --git a/jest.config.js b/jest.config.js index 0bcca101..36655445 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,7 +6,7 @@ module.exports = { clearMocks: true, moduleFileExtensions: ['js', 'ts'], - testMatch: ['**/proxy/**/*.test.ts'], + testMatch: ['**/integration/**/*.test.ts'], transform: { '^.+\\.ts$': 'ts-jest' } diff --git a/package-lock.json b/package-lock.json index 4d253371..05d3b8a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "@actions/exec": "^1.1.1", "@actions/github": "^6.0.0", "@actions/http-client": "^2.2.0", - "@octokit/action": "^6.0.6", "@octokit/plugin-retry": "^6.0.1", "@octokit/request-error": "^5.0.1", "canonical-path": "^1.0.0", @@ -1371,34 +1370,6 @@ "node": ">= 8" } }, - "node_modules/@octokit/action": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@octokit/action/-/action-6.0.6.tgz", - "integrity": "sha512-glsTZrjXgAHpyDKQah53hQUkb79mSrGSSqLeyiri9wDs3Ds3aaR7D9H3r5kLW6RAY606to9cjwVEClbEkoGoow==", - "dependencies": { - "@octokit/auth-action": "^4.0.0", - "@octokit/core": "^5.0.0", - "@octokit/plugin-paginate-rest": "^9.0.0", - "@octokit/plugin-rest-endpoint-methods": "^10.0.0", - "@octokit/types": "^12.0.0", - "undici": "^5.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/auth-action": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@octokit/auth-action/-/auth-action-4.0.1.tgz", - "integrity": "sha512-mJLOcFFafIivLZ7BEkGDCTFoHPJv7BeL5Zwy7j5qMDU0b/DKshhi6GCU9tw3vmKhOxTNquYfvwqsEfPpemaaxg==", - "dependencies": { - "@octokit/auth-token": "^4.0.0", - "@octokit/types": "^12.0.0" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/@octokit/auth-token": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", diff --git a/package.json b/package.json index 2e8d9d0e..fb0a9f26 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "@actions/exec": "^1.1.1", "@actions/github": "^6.0.0", "@actions/http-client": "^2.2.0", - "@octokit/action": "^6.0.6", "@octokit/plugin-retry": "^6.0.1", "@octokit/request-error": "^5.0.1", "canonical-path": "^1.0.0", diff --git a/src/configuration.ts b/src/configuration.ts index 65b7ef01..3bb96518 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -1,12 +1,17 @@ import { getBooleanInput, getInput, isDebug } from '@actions/core'; import { context } from '@actions/github'; -import { Octokit, customFetch } from '@octokit/action'; +import { Octokit } from '@octokit/core'; +import { paginateRest } from '@octokit/plugin-paginate-rest'; +import { restEndpointMethods } from '@octokit/plugin-rest-endpoint-methods'; import { retry } from '@octokit/plugin-retry'; +import { OctokitOptions } from '@octokit/core/dist-types/types'; import { HttpClient, HttpCodes } from '@actions/http-client'; import { getTicsWebBaseUrlFromUrl } from './tics/api_helper'; +import { RequestInfo, RequestInit, fetch } from 'undici'; import { EOL } from 'os'; export const githubConfig = { + baseUrl: process.env.GITHUB_API_URL ? process.env.GITHUB_API_URL : 'https://api.github.com', repo: process.env.GITHUB_REPOSITORY ? process.env.GITHUB_REPOSITORY : '', owner: process.env.GITHUB_REPOSITORY ? process.env.GITHUB_REPOSITORY.split('/')[0] : '', reponame: process.env.GITHUB_REPOSITORY ? process.env.GITHUB_REPOSITORY.split('/')[1] : '', @@ -80,20 +85,28 @@ const ignoreSslError: boolean = ticsConfig.trustStrategy === 'self-signed' || ticsConfig.trustStrategy === 'all'; -// octokit/action uses the environment variable GITHUB_TOKEN -process.env.GITHUB_TOKEN = ticsConfig.githubToken; -export const octokit = new (Octokit.plugin(retry))({ - request: { - fetch: customFetch, - retries: retryConfig.maxRetries, - retryAfter: 5 - } -}); export const httpClient = new HttpClient('tics-github-action', undefined, { allowRetries: true, maxRetries: retryConfig.maxRetries, ignoreSslError: ignoreSslError }); +const octokitOptions: OctokitOptions = { + auth: ticsConfig.githubToken, + baseUrl: githubConfig.baseUrl, + request: { + agent: httpClient.getAgent(githubConfig.baseUrl), + fetch: async (url: RequestInfo, opts: RequestInit | undefined) => { + return fetch(url, { + ...opts, + dispatcher: httpClient.getAgentDispatcher(githubConfig.baseUrl) + }); + }, + retries: retryConfig.maxRetries, + retryAfter: 5 + } +}; + +export const octokit = new (Octokit.plugin(paginateRest, restEndpointMethods, retry).defaults(octokitOptions))(); export const baseUrl = getTicsWebBaseUrlFromUrl(ticsConfig.ticsConfiguration); export const viewerUrl = ticsConfig.viewerUrl ? ticsConfig.viewerUrl.replace(/\/+$/, '') : baseUrl; diff --git a/test/proxy/httpclient.test.ts b/test/integration/httpclient.test.ts similarity index 81% rename from test/proxy/httpclient.test.ts rename to test/integration/httpclient.test.ts index d97ae835..bd57de8c 100644 --- a/test/proxy/httpclient.test.ts +++ b/test/integration/httpclient.test.ts @@ -8,6 +8,7 @@ const originalProxyUrl = process.env['http_proxy']; process.env['http_proxy'] = proxyUrl; // set required inputs +process.env.INPUT_GITHUBTOKEN = 'token'; process.env.INPUT_PROJECTNAME = 'tics-github-action'; process.env.INPUT_TICSCONFIGURATION = 'http://localhost/tiobeweb/TICS/api/cfg?name=default'; process.env.INPUT_EXCLUDEMOVEDFILES = 'false'; @@ -15,7 +16,6 @@ process.env.INPUT_INSTALLTICS = 'false'; process.env.INPUT_POSTANNOTATIONS = 'false'; process.env.INPUT_POSTTOCONVERSATION = 'false'; process.env.INPUT_PULLREQUESTAPPROVAL = 'false'; -process.env.GITHUB_ACTION = 'true'; // eslint-disable-next-line import/first import { httpClient } from '../../src/configuration'; @@ -37,6 +37,7 @@ describe('@actions/http-client (using http_proxy)', () => { // setup proxy server proxyServer = createProxy( http.createServer((req, res) => { + requestCount++; if (req.url == '/200') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end('{"data": "pass"}'); @@ -50,7 +51,6 @@ describe('@actions/http-client (using http_proxy)', () => { proxyServer.listen(port); proxyServer.on('connect', req => { - requestCount++; proxyConnects.push(req.url ?? ''); }); }); @@ -105,4 +105,26 @@ describe('@actions/http-client (using http_proxy)', () => { expect(proxyConnects).toContain('0.0.0.0:8082'); expect(requestCount).toEqual(9); }, 10000); + + test('Should retry on basic REST request, but not through the proxy', async () => { + // setting no_proxy + const originalNoProxy = process.env['no_proxy']; + process.env['no_proxy'] = '0.0.0.0'; + + const httpClient = new HttpClient('tics-github-action', undefined, { + allowRetries: true, + maxRetries: 8 + }); + + const time = Date.now(); + const response = await httpClient.get('http://0.0.0.0:8082/502'); + + // resetting no_proxy + process.env['no_proxy'] = originalNoProxy; + + expect((Date.now() - time) / 1000).toBeGreaterThanOrEqual(2); + expect(response.message.statusCode).toEqual(502); + expect(proxyConnects.length).toEqual(0); + expect(requestCount).toEqual(9); + }, 10000); }); diff --git a/test/proxy/octokit.test.ts b/test/integration/octokit.test.ts similarity index 73% rename from test/proxy/octokit.test.ts rename to test/integration/octokit.test.ts index b618314e..2c05a8ef 100644 --- a/test/proxy/octokit.test.ts +++ b/test/integration/octokit.test.ts @@ -17,36 +17,28 @@ process.env.INPUT_INSTALLTICS = 'false'; process.env.INPUT_POSTANNOTATIONS = 'false'; process.env.INPUT_POSTTOCONVERSATION = 'false'; process.env.INPUT_PULLREQUESTAPPROVAL = 'false'; -process.env.GITHUB_ACTION = 'true'; // eslint-disable-next-line import/first import { octokit } from '../../src/configuration'; import { RequestError } from '@octokit/request-error'; -import { Octokit, customFetch } from '@octokit/action'; -import { retry } from '@octokit/plugin-retry'; describe('@octokit/action (using https_proxy)', () => { let proxyServer: http.Server; - let requestCount = 0; let proxyConnects: string[]; beforeAll(async () => { // setup proxy server proxyServer = createProxy(); - await new Promise(resolve => { - const port = Number(proxyUrl.split(':')[2]); - proxyServer.listen(port, () => resolve()); - }); + const port = Number(proxyUrl.split(':')[2]); + proxyServer.listen(port); proxyServer.on('connect', req => { - requestCount++; proxyConnects.push(req.url ?? ''); }); }); beforeEach(() => { proxyConnects = []; - requestCount = 0; }); afterAll(async () => { @@ -64,7 +56,25 @@ describe('@octokit/action (using https_proxy)', () => { } }); - test('Should return basic REST request with proxy', async () => { + test('Should return basic REST request, but not through the proxy', async () => { + // setting no_proxy + const originalNoProxy = process.env['no_proxy']; + process.env['no_proxy'] = 'api.github.com:443'; + + const branch = await octokit.rest.repos.getBranch({ + owner: 'tiobe', + repo: 'tics-github-action', + branch: 'main' + }); + + // resetting no_proxy + process.env['no_proxy'] = originalNoProxy; + + expect(branch.data.name).toEqual('main'); + expect(proxyConnects.length).toEqual(0); + }); + + test('Should return basic REST request through the proxy', async () => { const branch = await octokit.rest.repos.getBranch({ owner: 'tiobe', repo: 'tics-github-action', @@ -72,10 +82,9 @@ describe('@octokit/action (using https_proxy)', () => { }); expect(branch.data.name).toEqual('main'); expect(proxyConnects).toEqual(['api.github.com:443']); - expect(requestCount).toEqual(1); }); - test('Should return basic pagination request with proxy', async () => { + test('Should return basic pagination request through the proxy', async () => { const branch = await octokit.paginate(octokit.rest.repos.listBranches, { owner: 'tiobe', repo: 'tics-github-action', @@ -83,37 +92,32 @@ describe('@octokit/action (using https_proxy)', () => { }); expect(branch.find(b => b.name === 'main')).not.toBeUndefined(); expect(proxyConnects).toEqual(['api.github.com:443']); - expect(requestCount).toEqual(1); }); - test('Should return basic GraphQL request with proxy', async () => { + test('Should return basic GraphQL request through the proxy', async () => { const repository = await octokit.graphql('{repository(owner:"tiobe", name:"tics-github-action"){name}}'); expect(repository).toEqual({ repository: { name: 'tics-github-action' } }); expect(proxyConnects).toEqual(['api.github.com:443']); - expect(requestCount).toEqual(1); }); - test('Should retry when request url is unavailable', async () => { + test('Should retry 3 times on request through the proxy', async () => { const time = Date.now(); let retryCount = 0; try { - const octokit = new (Octokit.plugin(retry))({ + await octokit.request('/', { baseUrl: 'http://0.0.0.0:8081', request: { - fetch: customFetch, retries: 3, // for the purpose of testing, set a lower number of retries retryAfter: 1 // for the purpose of testing, set a lower timeout } }); - - await octokit.request('/'); } catch (error: unknown) { retryCount = (error as RequestError).request.request?.retryCount; } expect((Date.now() - time) / 1000).toBeGreaterThanOrEqual(3); expect(proxyConnects).toContain('0.0.0.0:8081'); + expect(proxyConnects.length).toEqual(4); expect(retryCount).toEqual(3); - expect(requestCount).toEqual(4); }, 10000); });