From 385d3aa94f91957b010a631eae136cac51807fd6 Mon Sep 17 00:00:00 2001 From: Peter Murray <681306+peter-murray@users.noreply.github.com> Date: Fri, 9 Sep 2022 13:05:37 +0000 Subject: [PATCH 1/3] Adding ability to specify the GitHub Server URL and allowing for it to differ from the Actions workflow host --- .gitignore | 3 +- README.md | 5 ++ __test__/git-auth-helper.test.ts | 3 +- action.yml | 3 + dist/index.js | 114 +++++++++++++++++++++++-------- src/git-auth-helper.ts | 2 +- src/git-source-provider.ts | 9 ++- src/git-source-settings.ts | 5 ++ src/github-api-helper.ts | 20 +++--- src/input-helper.ts | 5 ++ src/octokit-helper.ts | 23 +++++++ src/ref-helper.ts | 18 ++--- src/url-helper.ts | 34 ++++++--- 13 files changed, 182 insertions(+), 62 deletions(-) create mode 100644 src/octokit-helper.ts diff --git a/.gitignore b/.gitignore index 8baa767ff..cd1f03c78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ __test__/_temp _temp/ lib/ -node_modules/ \ No newline at end of file +node_modules/ +.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index 7619c06a7..22e9a4994 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,11 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl # config --global --add safe.directory ` # Default: true set-safe-directory: '' + + # The base URL for the GitHub instance that you are trying to clone from, will use + # environment defaults to fetch from the same instance that the workflow is + # running from unless specified. + github-server-url: '' ``` diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts index a6731c2b4..64d49cc83 100644 --- a/__test__/git-auth-helper.test.ts +++ b/__test__/git-auth-helper.test.ts @@ -778,7 +778,8 @@ async function setup(testName: string): Promise { sshKnownHosts: '', sshStrict: true, workflowOrganizationId: 123456, - setSafeDirectory: true + setSafeDirectory: true, + githubServerUrl: undefined } } diff --git a/action.yml b/action.yml index 96c535ef7..12c5f4c48 100644 --- a/action.yml +++ b/action.yml @@ -71,6 +71,9 @@ inputs: set-safe-directory: description: Add repository path as safe.directory for Git global config by running `git config --global --add safe.directory ` default: true + github-server-url: + description: The base URL for the GitHub instance that you are trying to clone from, will use environment defaults to fetch from the same instance that the workflow is running from unless specified. + required: false runs: using: node16 main: dist/index.js diff --git a/dist/index.js b/dist/index.js index c7bc6957b..edde37e02 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1295,6 +1295,51 @@ module.exports._parse = parse; module.exports._enoent = enoent; +/***/ }), + +/***/ 24: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getOctokit = exports.Octokit = void 0; +const github = __importStar(__webpack_require__(469)); +const url_helper_1 = __webpack_require__(81); +// Centralize all Octokit references by re-exporting +var rest_1 = __webpack_require__(0); +Object.defineProperty(exports, "Octokit", { enumerable: true, get: function () { return rest_1.Octokit; } }); +function getOctokit(authToken, opts) { + const options = { + baseUrl: (0, url_helper_1.getServerApiUrl)(opts.baseUrl) + }; + if (opts.userAgent) { + options.userAgent = opts.userAgent; + } + return new github.GitHub(authToken, options); +} +exports.getOctokit = getOctokit; + + /***/ }), /***/ 26: @@ -1935,13 +1980,13 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getServerUrl = exports.getFetchUrl = void 0; +exports.isGhes = exports.getServerApiUrl = exports.getServerUrl = exports.getFetchUrl = void 0; const assert = __importStar(__webpack_require__(357)); const url_1 = __webpack_require__(835); function getFetchUrl(settings) { assert.ok(settings.repositoryOwner, 'settings.repositoryOwner must be defined'); assert.ok(settings.repositoryName, 'settings.repositoryName must be defined'); - const serviceUrl = getServerUrl(); + const serviceUrl = getServerUrl(settings.githubServerUrl); const encodedOwner = encodeURIComponent(settings.repositoryOwner); const encodedName = encodeURIComponent(settings.repositoryName); if (settings.sshKey) { @@ -1951,13 +1996,27 @@ function getFetchUrl(settings) { return `${serviceUrl.origin}/${encodedOwner}/${encodedName}`; } exports.getFetchUrl = getFetchUrl; -function getServerUrl() { - // todo: remove GITHUB_URL after support for GHES Alpha is no longer needed - return new url_1.URL(process.env['GITHUB_SERVER_URL'] || - process.env['GITHUB_URL'] || - 'https://github.com'); +function getServerUrl(url) { + let urlValue = url && url.trim().length > 0 + ? url + : process.env['GITHUB_SERVER_URL'] || 'https://github.com'; + return new url_1.URL(urlValue); } exports.getServerUrl = getServerUrl; +function getServerApiUrl(url) { + let apiUrl = 'https://api.github.com'; + if (isGhes(url)) { + const serverUrl = getServerUrl(url); + apiUrl = new url_1.URL(`${serverUrl.origin}/api/v3`).toString(); + } + return apiUrl; +} +exports.getServerApiUrl = getServerApiUrl; +function isGhes(url) { + const ghUrl = getServerUrl(url); + return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; +} +exports.isGhes = isGhes; /***/ }), @@ -4279,9 +4338,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkCommitInfo = exports.testRef = exports.getRefSpec = exports.getRefSpecForAllHistory = exports.getCheckoutInfo = exports.tagsRefSpec = void 0; -const url_1 = __webpack_require__(835); const core = __importStar(__webpack_require__(470)); const github = __importStar(__webpack_require__(469)); +const octokit_helper_1 = __webpack_require__(24); +const url_helper_1 = __webpack_require__(81); exports.tagsRefSpec = '+refs/tags/*:refs/tags/*'; function getCheckoutInfo(git, ref, commit) { return __awaiter(this, void 0, void 0, function* () { @@ -4431,12 +4491,12 @@ function testRef(git, ref, commit) { }); } exports.testRef = testRef; -function checkCommitInfo(token, commitInfo, repositoryOwner, repositoryName, ref, commit) { +function checkCommitInfo(token, commitInfo, repositoryOwner, repositoryName, ref, commit, baseUrl) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { try { // GHES? - if (isGhes()) { + if ((0, url_helper_1.isGhes)(baseUrl)) { return; } // Auth token? @@ -4481,7 +4541,8 @@ function checkCommitInfo(token, commitInfo, repositoryOwner, repositoryName, ref const actualHeadSha = match[1]; if (actualHeadSha !== expectedHeadSha) { core.debug(`Expected head sha ${expectedHeadSha}; actual head sha ${actualHeadSha}`); - const octokit = new github.GitHub(token, { + const octokit = (0, octokit_helper_1.getOctokit)(token, { + baseUrl: baseUrl, userAgent: `actions-checkout-tracepoint/1.0 (code=STALE_MERGE;owner=${repositoryOwner};repo=${repositoryName};pr=${fromPayload('number')};run_id=${process.env['GITHUB_RUN_ID']};expected_head_sha=${expectedHeadSha};actual_head_sha=${actualHeadSha})` }); yield octokit.repos.get({ owner: repositoryOwner, repo: repositoryName }); @@ -4507,10 +4568,6 @@ function select(obj, path) { const key = path.substr(0, i); return select(obj[key], path.substr(i + 1)); } -function isGhes() { - const ghUrl = new url_1.URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com'); - return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; -} /***/ }), @@ -6561,7 +6618,7 @@ class GitAuthHelper { this.git = gitCommandManager; this.settings = gitSourceSettings || {}; // Token auth header - const serverUrl = urlHelper.getServerUrl(); + const serverUrl = urlHelper.getServerUrl(this.settings.githubServerUrl); this.tokenConfigKey = `http.${serverUrl.origin}/.extraheader`; // "origin" is SCHEME://HOSTNAME[:PORT] const basicCredential = Buffer.from(`x-access-token:${this.settings.authToken}`, 'utf8').toString('base64'); core.setSecret(basicCredential); @@ -7382,7 +7439,7 @@ function getSource(settings) { else if (settings.sshKey) { throw new Error(`Input 'ssh-key' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH.`); } - yield githubApiHelper.downloadRepository(settings.authToken, settings.repositoryOwner, settings.repositoryName, settings.ref, settings.commit, settings.repositoryPath); + yield githubApiHelper.downloadRepository(settings.authToken, settings.repositoryOwner, settings.repositoryName, settings.ref, settings.commit, settings.repositoryPath, settings.githubServerUrl); return; } // Save state for POST action @@ -7415,7 +7472,7 @@ function getSource(settings) { settings.ref = yield git.getDefaultBranch(repositoryUrl); } else { - settings.ref = yield githubApiHelper.getDefaultBranch(settings.authToken, settings.repositoryOwner, settings.repositoryName); + settings.ref = yield githubApiHelper.getDefaultBranch(settings.authToken, settings.repositoryOwner, settings.repositoryName, settings.githubServerUrl); } core.endGroup(); } @@ -7481,7 +7538,7 @@ function getSource(settings) { // Log commit sha yield git.log1("--format='%H'"); // Check for incorrect pull request merge commit - yield refHelper.checkCommitInfo(settings.authToken, commitInfo, settings.repositoryOwner, settings.repositoryName, settings.ref, settings.commit); + yield refHelper.checkCommitInfo(settings.authToken, commitInfo, settings.repositoryOwner, settings.repositoryName, settings.ref, settings.commit, settings.githubServerUrl); } finally { // Remove auth @@ -10966,24 +11023,24 @@ exports.getDefaultBranch = exports.downloadRepository = void 0; const assert = __importStar(__webpack_require__(357)); const core = __importStar(__webpack_require__(470)); const fs = __importStar(__webpack_require__(747)); -const github = __importStar(__webpack_require__(469)); const io = __importStar(__webpack_require__(1)); const path = __importStar(__webpack_require__(622)); const retryHelper = __importStar(__webpack_require__(587)); const toolCache = __importStar(__webpack_require__(533)); const v4_1 = __importDefault(__webpack_require__(826)); +const octokit_helper_1 = __webpack_require__(24); const IS_WINDOWS = process.platform === 'win32'; -function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath) { +function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath, baseUrl) { return __awaiter(this, void 0, void 0, function* () { // Determine the default branch if (!ref && !commit) { core.info('Determining the default branch'); - ref = yield getDefaultBranch(authToken, owner, repo); + ref = yield getDefaultBranch(authToken, owner, repo, baseUrl); } // Download the archive let archiveData = yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () { core.info('Downloading the archive'); - return yield downloadArchive(authToken, owner, repo, ref, commit); + return yield downloadArchive(authToken, owner, repo, ref, commit, baseUrl); })); // Write archive to disk core.info('Writing archive to disk'); @@ -11027,12 +11084,12 @@ exports.downloadRepository = downloadRepository; /** * Looks up the default branch name */ -function getDefaultBranch(authToken, owner, repo) { +function getDefaultBranch(authToken, owner, repo, baseUrl) { return __awaiter(this, void 0, void 0, function* () { return yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () { var _a; core.info('Retrieving the default branch name'); - const octokit = new github.GitHub(authToken); + const octokit = (0, octokit_helper_1.getOctokit)(authToken, { baseUrl: baseUrl }); let result; try { // Get the default branch from the repo info @@ -11062,9 +11119,9 @@ function getDefaultBranch(authToken, owner, repo) { }); } exports.getDefaultBranch = getDefaultBranch; -function downloadArchive(authToken, owner, repo, ref, commit) { +function downloadArchive(authToken, owner, repo, ref, commit, baseUrl) { return __awaiter(this, void 0, void 0, function* () { - const octokit = new github.GitHub(authToken); + const octokit = (0, octokit_helper_1.getOctokit)(authToken, { baseUrl: baseUrl }); const params = { owner: owner, repo: repo, @@ -17330,6 +17387,9 @@ function getInputs() { // Set safe.directory in git global config. result.setSafeDirectory = (core.getInput('set-safe-directory') || 'true').toUpperCase() === 'TRUE'; + // Determine the GitHub URL that the repository is being hosted from + result.githubServerUrl = core.getInput('github-server-url'); + core.debug(`GitHub Host URL = ${result.githubServerUrl}`); return result; }); } diff --git a/src/git-auth-helper.ts b/src/git-auth-helper.ts index 8a1c7c379..3c6db8e77 100644 --- a/src/git-auth-helper.ts +++ b/src/git-auth-helper.ts @@ -52,7 +52,7 @@ class GitAuthHelper { this.settings = gitSourceSettings || (({} as unknown) as IGitSourceSettings) // Token auth header - const serverUrl = urlHelper.getServerUrl() + const serverUrl = urlHelper.getServerUrl(this.settings.githubServerUrl) this.tokenConfigKey = `http.${serverUrl.origin}/.extraheader` // "origin" is SCHEME://HOSTNAME[:PORT] const basicCredential = Buffer.from( `x-access-token:${this.settings.authToken}`, diff --git a/src/git-source-provider.ts b/src/git-source-provider.ts index 545a7a3bd..48f20da28 100644 --- a/src/git-source-provider.ts +++ b/src/git-source-provider.ts @@ -93,7 +93,8 @@ export async function getSource(settings: IGitSourceSettings): Promise { settings.repositoryName, settings.ref, settings.commit, - settings.repositoryPath + settings.repositoryPath, + settings.githubServerUrl ) return } @@ -138,7 +139,8 @@ export async function getSource(settings: IGitSourceSettings): Promise { settings.ref = await githubApiHelper.getDefaultBranch( settings.authToken, settings.repositoryOwner, - settings.repositoryName + settings.repositoryName, + settings.githubServerUrl ) } core.endGroup() @@ -232,7 +234,8 @@ export async function getSource(settings: IGitSourceSettings): Promise { settings.repositoryOwner, settings.repositoryName, settings.ref, - settings.commit + settings.commit, + settings.githubServerUrl ) } finally { // Remove auth diff --git a/src/git-source-settings.ts b/src/git-source-settings.ts index 6fa3960fd..2da562266 100644 --- a/src/git-source-settings.ts +++ b/src/git-source-settings.ts @@ -83,4 +83,9 @@ export interface IGitSourceSettings { * Indicates whether to add repositoryPath as safe.directory in git global config */ setSafeDirectory: boolean + + /** + * User override on the GitHub Server/Host URL that hosts the repository to be cloned + */ + githubServerUrl: string | undefined } diff --git a/src/github-api-helper.ts b/src/github-api-helper.ts index 45b979a16..5c0ee1e03 100644 --- a/src/github-api-helper.ts +++ b/src/github-api-helper.ts @@ -1,13 +1,12 @@ import * as assert from 'assert' import * as core from '@actions/core' import * as fs from 'fs' -import * as github from '@actions/github' import * as io from '@actions/io' import * as path from 'path' import * as retryHelper from './retry-helper' import * as toolCache from '@actions/tool-cache' import {default as uuid} from 'uuid/v4' -import {Octokit} from '@octokit/rest' +import {getOctokit, Octokit} from './octokit-helper' const IS_WINDOWS = process.platform === 'win32' @@ -17,18 +16,19 @@ export async function downloadRepository( repo: string, ref: string, commit: string, - repositoryPath: string + repositoryPath: string, + baseUrl?: string ): Promise { // Determine the default branch if (!ref && !commit) { core.info('Determining the default branch') - ref = await getDefaultBranch(authToken, owner, repo) + ref = await getDefaultBranch(authToken, owner, repo, baseUrl) } // Download the archive let archiveData = await retryHelper.execute(async () => { core.info('Downloading the archive') - return await downloadArchive(authToken, owner, repo, ref, commit) + return await downloadArchive(authToken, owner, repo, ref, commit, baseUrl) }) // Write archive to disk @@ -79,11 +79,12 @@ export async function downloadRepository( export async function getDefaultBranch( authToken: string, owner: string, - repo: string + repo: string, + baseUrl?: string ): Promise { return await retryHelper.execute(async () => { core.info('Retrieving the default branch name') - const octokit = new github.GitHub(authToken) + const octokit = getOctokit(authToken, {baseUrl: baseUrl}) let result: string try { // Get the default branch from the repo info @@ -121,9 +122,10 @@ async function downloadArchive( owner: string, repo: string, ref: string, - commit: string + commit: string, + baseUrl?: string ): Promise { - const octokit = new github.GitHub(authToken) + const octokit = getOctokit(authToken, {baseUrl: baseUrl}) const params: Octokit.ReposGetArchiveLinkParams = { owner: owner, repo: repo, diff --git a/src/input-helper.ts b/src/input-helper.ts index 8c2f90157..237b06aff 100644 --- a/src/input-helper.ts +++ b/src/input-helper.ts @@ -125,5 +125,10 @@ export async function getInputs(): Promise { // Set safe.directory in git global config. result.setSafeDirectory = (core.getInput('set-safe-directory') || 'true').toUpperCase() === 'TRUE' + + // Determine the GitHub URL that the repository is being hosted from + result.githubServerUrl = core.getInput('github-server-url') + core.debug(`GitHub Host URL = ${result.githubServerUrl}`) + return result } diff --git a/src/octokit-helper.ts b/src/octokit-helper.ts new file mode 100644 index 000000000..4fb128574 --- /dev/null +++ b/src/octokit-helper.ts @@ -0,0 +1,23 @@ +import * as github from '@actions/github' +import {Octokit} from '@octokit/rest' +import {getServerApiUrl} from './url-helper' + +// Centralize all Octokit references by re-exporting +export {Octokit} from '@octokit/rest' + +export type OctokitOptions = { + baseUrl?: string + userAgent?: string +} + +export function getOctokit(authToken: string, opts: OctokitOptions) { + const options: Octokit.Options = { + baseUrl: getServerApiUrl(opts.baseUrl) + } + + if (opts.userAgent) { + options.userAgent = opts.userAgent + } + + return new github.GitHub(authToken, options) +} diff --git a/src/ref-helper.ts b/src/ref-helper.ts index 209f49d70..823f929e5 100644 --- a/src/ref-helper.ts +++ b/src/ref-helper.ts @@ -1,7 +1,8 @@ -import {URL} from 'url' import {IGitCommandManager} from './git-command-manager' import * as core from '@actions/core' import * as github from '@actions/github' +import {getOctokit} from './octokit-helper' +import {isGhes} from './url-helper' export const tagsRefSpec = '+refs/tags/*:refs/tags/*' @@ -183,11 +184,12 @@ export async function checkCommitInfo( repositoryOwner: string, repositoryName: string, ref: string, - commit: string + commit: string, + baseUrl?: string ): Promise { try { // GHES? - if (isGhes()) { + if (isGhes(baseUrl)) { return } @@ -243,7 +245,8 @@ export async function checkCommitInfo( core.debug( `Expected head sha ${expectedHeadSha}; actual head sha ${actualHeadSha}` ) - const octokit = new github.GitHub(token, { + const octokit = getOctokit(token, { + baseUrl: baseUrl, userAgent: `actions-checkout-tracepoint/1.0 (code=STALE_MERGE;owner=${repositoryOwner};repo=${repositoryName};pr=${fromPayload( 'number' )};run_id=${ @@ -276,10 +279,3 @@ function select(obj: any, path: string): any { const key = path.substr(0, i) return select(obj[key], path.substr(i + 1)) } - -function isGhes(): boolean { - const ghUrl = new URL( - process.env['GITHUB_SERVER_URL'] || 'https://github.com' - ) - return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM' -} diff --git a/src/url-helper.ts b/src/url-helper.ts index 05f1cbd67..6807b7f8e 100644 --- a/src/url-helper.ts +++ b/src/url-helper.ts @@ -1,6 +1,6 @@ import * as assert from 'assert' -import {IGitSourceSettings} from './git-source-settings' import {URL} from 'url' +import {IGitSourceSettings} from './git-source-settings' export function getFetchUrl(settings: IGitSourceSettings): string { assert.ok( @@ -8,7 +8,7 @@ export function getFetchUrl(settings: IGitSourceSettings): string { 'settings.repositoryOwner must be defined' ) assert.ok(settings.repositoryName, 'settings.repositoryName must be defined') - const serviceUrl = getServerUrl() + const serviceUrl = getServerUrl(settings.githubServerUrl) const encodedOwner = encodeURIComponent(settings.repositoryOwner) const encodedName = encodeURIComponent(settings.repositoryName) if (settings.sshKey) { @@ -19,11 +19,27 @@ export function getFetchUrl(settings: IGitSourceSettings): string { return `${serviceUrl.origin}/${encodedOwner}/${encodedName}` } -export function getServerUrl(): URL { - // todo: remove GITHUB_URL after support for GHES Alpha is no longer needed - return new URL( - process.env['GITHUB_SERVER_URL'] || - process.env['GITHUB_URL'] || - 'https://github.com' - ) +export function getServerUrl(url?: string): URL { + let urlValue = + url && url.trim().length > 0 + ? url + : process.env['GITHUB_SERVER_URL'] || 'https://github.com' + return new URL(urlValue) +} + +export function getServerApiUrl(url?: string): string { + let apiUrl = 'https://api.github.com' + + if (isGhes(url)) { + const serverUrl = getServerUrl(url) + apiUrl = new URL(`${serverUrl.origin}/api/v3`).toString() + } + + return apiUrl +} + +export function isGhes(url?: string): boolean { + const ghUrl = getServerUrl(url) + + return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM' } From 092f9bd6139b52c308e494ee0745a22ef4f0e527 Mon Sep 17 00:00:00 2001 From: Peter Murray <681306+peter-murray@users.noreply.github.com> Date: Thu, 15 Sep 2022 14:17:18 +0000 Subject: [PATCH 2/3] Adding tests for injecting the GitHub URL --- __test__/git-auth-helper.test.ts | 49 +++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts index 64d49cc83..adadd8b2c 100644 --- a/__test__/git-auth-helper.test.ts +++ b/__test__/git-auth-helper.test.ts @@ -5,8 +5,8 @@ import * as io from '@actions/io' import * as os from 'os' import * as path from 'path' import * as stateHelper from '../lib/state-helper' -import {IGitCommandManager} from '../lib/git-command-manager' -import {IGitSourceSettings} from '../lib/git-source-settings' +import { IGitCommandManager } from '../lib/git-command-manager' +import { IGitSourceSettings } from '../lib/git-source-settings' const isWindows = process.platform === 'win32' const testWorkspace = path.join(__dirname, '_temp', 'git-auth-helper') @@ -17,9 +17,10 @@ let localGitConfigPath: string let globalGitConfigPath: string let runnerTemp: string let tempHomedir: string -let git: IGitCommandManager & {env: {[key: string]: string}} +let git: IGitCommandManager & { env: { [key: string]: string } } let settings: IGitSourceSettings let sshPath: string +let githubServerUrl: string describe('git-auth-helper tests', () => { beforeAll(async () => { @@ -32,7 +33,7 @@ describe('git-auth-helper tests', () => { beforeEach(() => { // Mock setSecret - jest.spyOn(core, 'setSecret').mockImplementation((secret: string) => {}) + jest.spyOn(core, 'setSecret').mockImplementation((secret: string) => { }) // Mock error/warning/info/debug jest.spyOn(core, 'error').mockImplementation(jest.fn()) @@ -67,11 +68,15 @@ describe('git-auth-helper tests', () => { } }) - const configureAuth_configuresAuthHeader = - 'configureAuth configures auth header' - it(configureAuth_configuresAuthHeader, async () => { + async function testAuthHeader(testName: string, serverUrl: string | undefined = undefined) { // Arrange - await setup(configureAuth_configuresAuthHeader) + let expectedServerUrl = 'https://github.com' + if (serverUrl) { + githubServerUrl = serverUrl + expectedServerUrl = githubServerUrl + } + + await setup(testName) expect(settings.authToken).toBeTruthy() // sanity check const authHelper = gitAuthHelper.createAuthHelper(git, settings) @@ -88,9 +93,25 @@ describe('git-auth-helper tests', () => { ).toString('base64') expect( configContent.indexOf( - `http.https://github.com/.extraheader AUTHORIZATION: basic ${basicCredential}` + `http.${expectedServerUrl}/.extraheader AUTHORIZATION: basic ${basicCredential}` ) ).toBeGreaterThanOrEqual(0) + } + + const configureAuth_configuresAuthHeader = + 'configureAuth configures auth header' + it(configureAuth_configuresAuthHeader, async () => { + await testAuthHeader(configureAuth_configuresAuthHeader); + }) + + const configureAuth_AcceptsGitHubServerUrl = 'inject https://my-ghes-server.com as github server url' + it(configureAuth_AcceptsGitHubServerUrl, async () => { + await testAuthHeader(configureAuth_AcceptsGitHubServerUrl, 'https://my-ghes-server.com'); + }) + + const configureAuth_AcceptsGitHubServerUrlSetToGHEC = 'inject https://github.com as github server url' + it(configureAuth_AcceptsGitHubServerUrlSetToGHEC, async () => { + await testAuthHeader(configureAuth_AcceptsGitHubServerUrl, 'https://github.com'); }) const configureAuth_configuresAuthHeaderEvenWhenPersistCredentialsFalse = @@ -678,9 +699,9 @@ async function setup(testName: string): Promise { workspace = path.join(testWorkspace, testName, 'workspace') runnerTemp = path.join(testWorkspace, testName, 'runner-temp') tempHomedir = path.join(testWorkspace, testName, 'home-dir') - await fs.promises.mkdir(workspace, {recursive: true}) - await fs.promises.mkdir(runnerTemp, {recursive: true}) - await fs.promises.mkdir(tempHomedir, {recursive: true}) + await fs.promises.mkdir(workspace, { recursive: true }) + await fs.promises.mkdir(runnerTemp, { recursive: true }) + await fs.promises.mkdir(tempHomedir, { recursive: true }) process.env['RUNNER_TEMP'] = runnerTemp process.env['HOME'] = tempHomedir @@ -688,7 +709,7 @@ async function setup(testName: string): Promise { globalGitConfigPath = path.join(tempHomedir, '.gitconfig') await fs.promises.writeFile(globalGitConfigPath, '') localGitConfigPath = path.join(workspace, '.git', 'config') - await fs.promises.mkdir(path.dirname(localGitConfigPath), {recursive: true}) + await fs.promises.mkdir(path.dirname(localGitConfigPath), { recursive: true }) await fs.promises.writeFile(localGitConfigPath, '') git = { @@ -779,7 +800,7 @@ async function setup(testName: string): Promise { sshStrict: true, workflowOrganizationId: 123456, setSafeDirectory: true, - githubServerUrl: undefined + githubServerUrl: githubServerUrl } } From 0ff8af69447c1b738662d9e595207d6c3669b6d1 Mon Sep 17 00:00:00 2001 From: Peter Murray <681306+peter-murray@users.noreply.github.com> Date: Tue, 20 Sep 2022 07:41:19 +0000 Subject: [PATCH 3/3] Addressing code review comments for PR #922 --- README.md | 3 +- __test__/git-auth-helper.test.ts | 39 ++++--- action.yml | 2 +- dist/index.js | 100 +++++++++--------- src/github-api-helper.ts | 2 +- ...{octokit-helper.ts => octokit-provider.ts} | 0 src/ref-helper.ts | 2 +- 7 files changed, 80 insertions(+), 68 deletions(-) rename src/{octokit-helper.ts => octokit-provider.ts} (100%) diff --git a/README.md b/README.md index 22e9a4994..b85967d31 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,8 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl # The base URL for the GitHub instance that you are trying to clone from, will use # environment defaults to fetch from the same instance that the workflow is - # running from unless specified. + # running from unless specified. Example URLs are https://github.com or + # https://my-ghes-server.example.com github-server-url: '' ``` diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts index adadd8b2c..2acec38f8 100644 --- a/__test__/git-auth-helper.test.ts +++ b/__test__/git-auth-helper.test.ts @@ -5,8 +5,8 @@ import * as io from '@actions/io' import * as os from 'os' import * as path from 'path' import * as stateHelper from '../lib/state-helper' -import { IGitCommandManager } from '../lib/git-command-manager' -import { IGitSourceSettings } from '../lib/git-source-settings' +import {IGitCommandManager} from '../lib/git-command-manager' +import {IGitSourceSettings} from '../lib/git-source-settings' const isWindows = process.platform === 'win32' const testWorkspace = path.join(__dirname, '_temp', 'git-auth-helper') @@ -17,7 +17,7 @@ let localGitConfigPath: string let globalGitConfigPath: string let runnerTemp: string let tempHomedir: string -let git: IGitCommandManager & { env: { [key: string]: string } } +let git: IGitCommandManager & {env: {[key: string]: string}} let settings: IGitSourceSettings let sshPath: string let githubServerUrl: string @@ -33,7 +33,7 @@ describe('git-auth-helper tests', () => { beforeEach(() => { // Mock setSecret - jest.spyOn(core, 'setSecret').mockImplementation((secret: string) => { }) + jest.spyOn(core, 'setSecret').mockImplementation((secret: string) => {}) // Mock error/warning/info/debug jest.spyOn(core, 'error').mockImplementation(jest.fn()) @@ -68,7 +68,10 @@ describe('git-auth-helper tests', () => { } }) - async function testAuthHeader(testName: string, serverUrl: string | undefined = undefined) { + async function testAuthHeader( + testName: string, + serverUrl: string | undefined = undefined + ) { // Arrange let expectedServerUrl = 'https://github.com' if (serverUrl) { @@ -101,17 +104,25 @@ describe('git-auth-helper tests', () => { const configureAuth_configuresAuthHeader = 'configureAuth configures auth header' it(configureAuth_configuresAuthHeader, async () => { - await testAuthHeader(configureAuth_configuresAuthHeader); + await testAuthHeader(configureAuth_configuresAuthHeader) }) - const configureAuth_AcceptsGitHubServerUrl = 'inject https://my-ghes-server.com as github server url' + const configureAuth_AcceptsGitHubServerUrl = + 'inject https://my-ghes-server.com as github server url' it(configureAuth_AcceptsGitHubServerUrl, async () => { - await testAuthHeader(configureAuth_AcceptsGitHubServerUrl, 'https://my-ghes-server.com'); + await testAuthHeader( + configureAuth_AcceptsGitHubServerUrl, + 'https://my-ghes-server.com' + ) }) - const configureAuth_AcceptsGitHubServerUrlSetToGHEC = 'inject https://github.com as github server url' + const configureAuth_AcceptsGitHubServerUrlSetToGHEC = + 'inject https://github.com as github server url' it(configureAuth_AcceptsGitHubServerUrlSetToGHEC, async () => { - await testAuthHeader(configureAuth_AcceptsGitHubServerUrl, 'https://github.com'); + await testAuthHeader( + configureAuth_AcceptsGitHubServerUrl, + 'https://github.com' + ) }) const configureAuth_configuresAuthHeaderEvenWhenPersistCredentialsFalse = @@ -699,9 +710,9 @@ async function setup(testName: string): Promise { workspace = path.join(testWorkspace, testName, 'workspace') runnerTemp = path.join(testWorkspace, testName, 'runner-temp') tempHomedir = path.join(testWorkspace, testName, 'home-dir') - await fs.promises.mkdir(workspace, { recursive: true }) - await fs.promises.mkdir(runnerTemp, { recursive: true }) - await fs.promises.mkdir(tempHomedir, { recursive: true }) + await fs.promises.mkdir(workspace, {recursive: true}) + await fs.promises.mkdir(runnerTemp, {recursive: true}) + await fs.promises.mkdir(tempHomedir, {recursive: true}) process.env['RUNNER_TEMP'] = runnerTemp process.env['HOME'] = tempHomedir @@ -709,7 +720,7 @@ async function setup(testName: string): Promise { globalGitConfigPath = path.join(tempHomedir, '.gitconfig') await fs.promises.writeFile(globalGitConfigPath, '') localGitConfigPath = path.join(workspace, '.git', 'config') - await fs.promises.mkdir(path.dirname(localGitConfigPath), { recursive: true }) + await fs.promises.mkdir(path.dirname(localGitConfigPath), {recursive: true}) await fs.promises.writeFile(localGitConfigPath, '') git = { diff --git a/action.yml b/action.yml index 12c5f4c48..cab09ebd3 100644 --- a/action.yml +++ b/action.yml @@ -72,7 +72,7 @@ inputs: description: Add repository path as safe.directory for Git global config by running `git config --global --add safe.directory ` default: true github-server-url: - description: The base URL for the GitHub instance that you are trying to clone from, will use environment defaults to fetch from the same instance that the workflow is running from unless specified. + description: The base URL for the GitHub instance that you are trying to clone from, will use environment defaults to fetch from the same instance that the workflow is running from unless specified. Example URLs are https://github.com or https://my-ghes-server.example.com required: false runs: using: node16 diff --git a/dist/index.js b/dist/index.js index edde37e02..d1ed5f972 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1295,51 +1295,6 @@ module.exports._parse = parse; module.exports._enoent = enoent; -/***/ }), - -/***/ 24: -/***/ (function(__unusedmodule, exports, __webpack_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getOctokit = exports.Octokit = void 0; -const github = __importStar(__webpack_require__(469)); -const url_helper_1 = __webpack_require__(81); -// Centralize all Octokit references by re-exporting -var rest_1 = __webpack_require__(0); -Object.defineProperty(exports, "Octokit", { enumerable: true, get: function () { return rest_1.Octokit; } }); -function getOctokit(authToken, opts) { - const options = { - baseUrl: (0, url_helper_1.getServerApiUrl)(opts.baseUrl) - }; - if (opts.userAgent) { - options.userAgent = opts.userAgent; - } - return new github.GitHub(authToken, options); -} -exports.getOctokit = getOctokit; - - /***/ }), /***/ 26: @@ -4125,6 +4080,51 @@ function authenticationPlugin(octokit, options) { } +/***/ }), + +/***/ 195: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getOctokit = exports.Octokit = void 0; +const github = __importStar(__webpack_require__(469)); +const url_helper_1 = __webpack_require__(81); +// Centralize all Octokit references by re-exporting +var rest_1 = __webpack_require__(0); +Object.defineProperty(exports, "Octokit", { enumerable: true, get: function () { return rest_1.Octokit; } }); +function getOctokit(authToken, opts) { + const options = { + baseUrl: (0, url_helper_1.getServerApiUrl)(opts.baseUrl) + }; + if (opts.userAgent) { + options.userAgent = opts.userAgent; + } + return new github.GitHub(authToken, options); +} +exports.getOctokit = getOctokit; + + /***/ }), /***/ 197: @@ -4340,7 +4340,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.checkCommitInfo = exports.testRef = exports.getRefSpec = exports.getRefSpecForAllHistory = exports.getCheckoutInfo = exports.tagsRefSpec = void 0; const core = __importStar(__webpack_require__(470)); const github = __importStar(__webpack_require__(469)); -const octokit_helper_1 = __webpack_require__(24); +const octokit_provider_1 = __webpack_require__(195); const url_helper_1 = __webpack_require__(81); exports.tagsRefSpec = '+refs/tags/*:refs/tags/*'; function getCheckoutInfo(git, ref, commit) { @@ -4541,7 +4541,7 @@ function checkCommitInfo(token, commitInfo, repositoryOwner, repositoryName, ref const actualHeadSha = match[1]; if (actualHeadSha !== expectedHeadSha) { core.debug(`Expected head sha ${expectedHeadSha}; actual head sha ${actualHeadSha}`); - const octokit = (0, octokit_helper_1.getOctokit)(token, { + const octokit = (0, octokit_provider_1.getOctokit)(token, { baseUrl: baseUrl, userAgent: `actions-checkout-tracepoint/1.0 (code=STALE_MERGE;owner=${repositoryOwner};repo=${repositoryName};pr=${fromPayload('number')};run_id=${process.env['GITHUB_RUN_ID']};expected_head_sha=${expectedHeadSha};actual_head_sha=${actualHeadSha})` }); @@ -11028,7 +11028,7 @@ const path = __importStar(__webpack_require__(622)); const retryHelper = __importStar(__webpack_require__(587)); const toolCache = __importStar(__webpack_require__(533)); const v4_1 = __importDefault(__webpack_require__(826)); -const octokit_helper_1 = __webpack_require__(24); +const octokit_provider_1 = __webpack_require__(195); const IS_WINDOWS = process.platform === 'win32'; function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath, baseUrl) { return __awaiter(this, void 0, void 0, function* () { @@ -11089,7 +11089,7 @@ function getDefaultBranch(authToken, owner, repo, baseUrl) { return yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () { var _a; core.info('Retrieving the default branch name'); - const octokit = (0, octokit_helper_1.getOctokit)(authToken, { baseUrl: baseUrl }); + const octokit = (0, octokit_provider_1.getOctokit)(authToken, { baseUrl: baseUrl }); let result; try { // Get the default branch from the repo info @@ -11121,7 +11121,7 @@ function getDefaultBranch(authToken, owner, repo, baseUrl) { exports.getDefaultBranch = getDefaultBranch; function downloadArchive(authToken, owner, repo, ref, commit, baseUrl) { return __awaiter(this, void 0, void 0, function* () { - const octokit = (0, octokit_helper_1.getOctokit)(authToken, { baseUrl: baseUrl }); + const octokit = (0, octokit_provider_1.getOctokit)(authToken, { baseUrl: baseUrl }); const params = { owner: owner, repo: repo, diff --git a/src/github-api-helper.ts b/src/github-api-helper.ts index 5c0ee1e03..2124a869b 100644 --- a/src/github-api-helper.ts +++ b/src/github-api-helper.ts @@ -6,7 +6,7 @@ import * as path from 'path' import * as retryHelper from './retry-helper' import * as toolCache from '@actions/tool-cache' import {default as uuid} from 'uuid/v4' -import {getOctokit, Octokit} from './octokit-helper' +import {getOctokit, Octokit} from './octokit-provider' const IS_WINDOWS = process.platform === 'win32' diff --git a/src/octokit-helper.ts b/src/octokit-provider.ts similarity index 100% rename from src/octokit-helper.ts rename to src/octokit-provider.ts diff --git a/src/ref-helper.ts b/src/ref-helper.ts index 823f929e5..ce875fc09 100644 --- a/src/ref-helper.ts +++ b/src/ref-helper.ts @@ -1,7 +1,7 @@ import {IGitCommandManager} from './git-command-manager' import * as core from '@actions/core' import * as github from '@actions/github' -import {getOctokit} from './octokit-helper' +import {getOctokit} from './octokit-provider' import {isGhes} from './url-helper' export const tagsRefSpec = '+refs/tags/*:refs/tags/*'