From 61d93be5e5c82c8aa66c05db8ad1a8dea3f022e2 Mon Sep 17 00:00:00 2001 From: CHANX Date: Thu, 27 Apr 2023 23:17:17 +0800 Subject: [PATCH 1/3] fix: support pathname except ssh --- README.md | 5 +++-- action.yml | 2 +- dist/index.js | 17 ++++++++++++----- src/git-auth-helper.ts | 5 +++-- src/url-helper.ts | 10 ++++++++-- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index bfecf46..4677bde 100644 --- a/README.md +++ b/README.md @@ -118,8 +118,9 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/ # 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 + # running from unless specified. Also support URL pathname except SSH (`ssh-key` + # not specified). Example URLs are https://github.com or + # https://my-ghes-server.example.com or https://my-ghes-server.example.com/git/ github-server-url: '' ``` diff --git a/action.yml b/action.yml index 5aa90a7..013e903 100644 --- a/action.yml +++ b/action.yml @@ -92,7 +92,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. Example URLs are https://github.com or https://my-ghes-server.example.com + 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. Also support URL pathname except SSH (`ssh-key` not specified). Example URLs are https://github.com or https://my-ghes-server.example.com or https://my-ghes-server.example.com/git/ required: false runs: using: node20 diff --git a/dist/index.js b/dist/index.js index ddf2b3d..ebfb5c6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -163,13 +163,14 @@ class GitAuthHelper { this.settings = gitSourceSettings || {}; // Token auth header const serverUrl = urlHelper.getServerUrl(this.settings.githubServerUrl); - this.tokenConfigKey = `http.${serverUrl.origin}/.extraheader`; // "origin" is SCHEME://HOSTNAME[:PORT] + const baseURL = urlHelper.getBaseUrl(serverUrl.href); + this.tokenConfigKey = `http.${baseURL}/.extraheader`; // "origin" is SCHEME://HOSTNAME[:PORT] const basicCredential = Buffer.from(`x-access-token:${this.settings.authToken}`, 'utf8').toString('base64'); core.setSecret(basicCredential); this.tokenPlaceholderConfigValue = `AUTHORIZATION: basic ***`; this.tokenConfigValue = `AUTHORIZATION: basic ${basicCredential}`; // Instead of SSH URL - this.insteadOfKey = `url.${serverUrl.origin}/.insteadOf`; // "origin" is SCHEME://HOSTNAME[:PORT] + this.insteadOfKey = `url.${baseURL}/.insteadOf`; // "origin" is SCHEME://HOSTNAME[:PORT] this.insteadOfValues.push(`git@${serverUrl.hostname}:`); if (this.settings.workflowOrganizationId) { this.insteadOfValues.push(`org-${this.settings.workflowOrganizationId}@github.com:`); @@ -2371,7 +2372,7 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.isGhes = exports.getServerApiUrl = exports.getServerUrl = exports.getFetchUrl = void 0; +exports.isGhes = exports.getServerApiUrl = exports.getBaseUrl = exports.getServerUrl = exports.getFetchUrl = void 0; const assert = __importStar(__nccwpck_require__(9491)); const url_1 = __nccwpck_require__(7310); function getFetchUrl(settings) { @@ -2384,16 +2385,22 @@ function getFetchUrl(settings) { return `git@${serviceUrl.hostname}:${encodedOwner}/${encodedName}.git`; } // "origin" is SCHEME://HOSTNAME[:PORT] - return `${serviceUrl.origin}/${encodedOwner}/${encodedName}`; + const baseURL = getBaseUrl(serviceUrl.href); + return `${baseURL}/${encodedOwner}/${encodedName}`; } exports.getFetchUrl = getFetchUrl; function getServerUrl(url) { - let urlValue = url && url.trim().length > 0 + const 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 getBaseUrl(url) { + const matcher = url.match(/^[^?]+/); + return (matcher && matcher[0].replace(/\/+$/g, '')) || ''; +} +exports.getBaseUrl = getBaseUrl; function getServerApiUrl(url) { let apiUrl = 'https://api.github.com'; if (isGhes(url)) { diff --git a/src/git-auth-helper.ts b/src/git-auth-helper.ts index 364a04e..b5a6cf0 100644 --- a/src/git-auth-helper.ts +++ b/src/git-auth-helper.ts @@ -53,7 +53,8 @@ class GitAuthHelper { // Token auth header const serverUrl = urlHelper.getServerUrl(this.settings.githubServerUrl) - this.tokenConfigKey = `http.${serverUrl.origin}/.extraheader` // "origin" is SCHEME://HOSTNAME[:PORT] + const baseURL = urlHelper.getBaseUrl(serverUrl.href) + this.tokenConfigKey = `http.${baseURL}/.extraheader` // "origin" is SCHEME://HOSTNAME[:PORT] const basicCredential = Buffer.from( `x-access-token:${this.settings.authToken}`, 'utf8' @@ -63,7 +64,7 @@ class GitAuthHelper { this.tokenConfigValue = `AUTHORIZATION: basic ${basicCredential}` // Instead of SSH URL - this.insteadOfKey = `url.${serverUrl.origin}/.insteadOf` // "origin" is SCHEME://HOSTNAME[:PORT] + this.insteadOfKey = `url.${baseURL}/.insteadOf` // "origin" is SCHEME://HOSTNAME[:PORT] this.insteadOfValues.push(`git@${serverUrl.hostname}:`) if (this.settings.workflowOrganizationId) { this.insteadOfValues.push( diff --git a/src/url-helper.ts b/src/url-helper.ts index 6807b7f..d12a82a 100644 --- a/src/url-helper.ts +++ b/src/url-helper.ts @@ -16,17 +16,23 @@ export function getFetchUrl(settings: IGitSourceSettings): string { } // "origin" is SCHEME://HOSTNAME[:PORT] - return `${serviceUrl.origin}/${encodedOwner}/${encodedName}` + const baseURL = getBaseUrl(serviceUrl.href) + return `${baseURL}/${encodedOwner}/${encodedName}` } export function getServerUrl(url?: string): URL { - let urlValue = + const urlValue = url && url.trim().length > 0 ? url : process.env['GITHUB_SERVER_URL'] || 'https://github.com' return new URL(urlValue) } +export function getBaseUrl(url: string): string { + const matcher = url.match(/^[^?]+/) + return (matcher && matcher[0].replace(/\/+$/g, '')) || '' +} + export function getServerApiUrl(url?: string): string { let apiUrl = 'https://api.github.com' From efa69110c5233567b7627625874e90ad0c7e8043 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 20 Oct 2023 15:46:57 +0800 Subject: [PATCH 2/3] alter getBaseUrl --- src/url-helper.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/url-helper.ts b/src/url-helper.ts index d12a82a..a5d4f80 100644 --- a/src/url-helper.ts +++ b/src/url-helper.ts @@ -16,7 +16,7 @@ export function getFetchUrl(settings: IGitSourceSettings): string { } // "origin" is SCHEME://HOSTNAME[:PORT] - const baseURL = getBaseUrl(serviceUrl.href) + const baseURL = getBaseUrl(serviceUrl) return `${baseURL}/${encodedOwner}/${encodedName}` } @@ -28,9 +28,8 @@ export function getServerUrl(url?: string): URL { return new URL(urlValue) } -export function getBaseUrl(url: string): string { - const matcher = url.match(/^[^?]+/) - return (matcher && matcher[0].replace(/\/+$/g, '')) || '' +function getBaseUrl(u: URL) { + return u.protocol + "//" + u.host + u.pathname.replace(/\/+$/g, ''); } export function getServerApiUrl(url?: string): string { From 5b61398e30af089f8a69c2fcc9ee075e46f5289f Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 20 Oct 2023 15:47:00 +0800 Subject: [PATCH 3/3] add tests --- __test__/url-helper.test.ts | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 __test__/url-helper.test.ts diff --git a/__test__/url-helper.test.ts b/__test__/url-helper.test.ts new file mode 100644 index 0000000..4c7e59c --- /dev/null +++ b/__test__/url-helper.test.ts @@ -0,0 +1,46 @@ +import * as urlHelper from '../lib/url-helper' + +import { IGitSourceSettings } from '../lib/git-source-settings'; + +function getSettings(u: string): IGitSourceSettings { + return { + githubServerUrl: u, + repositoryPath: '', + repositoryOwner: 'some-owner', + repositoryName: 'some-name', + ref: '', commit: '', clean: false, filter: undefined, + sparseCheckout: [], sparseCheckoutConeMode: false, + fetchDepth: 0, fetchTags: false, showProgress: false, + lfs: false, submodules: false, nestedSubmodules: false, + authToken: '', sshKey: '', sshKnownHosts: '', sshStrict: false, + persistCredentials: false, workflowOrganizationId: undefined, + setSafeDirectory: false + } +} +describe('url-helper tests', () => { + it('getFetchUrl works on GitHub repos', async () => { + expect(urlHelper.getFetchUrl(getSettings('https://github.com'))).toBe( + "https://github.com/some-owner/some-name" + ) + }) + + it('getFetchUrl works on 3rd party repos with sub-path', async () => { + expect(urlHelper.getFetchUrl(getSettings('https://other.com/subpath'))).toBe( + 'https://other.com/subpath/some-owner/some-name' + ) + }) + + it('getFetchUrl works on 3rd party repos with ssh keys', async () => { + expect(urlHelper.getFetchUrl(getSettings('https://other.com/subpath'))).toBe( + 'https://other.com/subpath/some-owner/some-name' + ) + }) + + it('getFetchUrl works with ssh credentials', async () => { + let settings = getSettings('https://other.com/subpath'); + settings.sshKey = 'not-empty' + expect(urlHelper.getFetchUrl(settings)).toBe( + 'git@other.com:some-owner/some-name.git' + ) + }) +})