From 9119c527bef2cf5bae4423e8251a22c0b0e8cdf4 Mon Sep 17 00:00:00 2001 From: James Ives Date: Thu, 4 Mar 2021 08:47:44 -0500 Subject: [PATCH] Enables Support for Self-Hosted GitHub Instances (GitHub Enterprise) (#622) * Adds Changes * Update main.test.ts * Format * Update README.md * Formatting --- README.md | 2 +- __tests__/git.test.ts | 16 ++++++++++++++++ __tests__/main.test.ts | 3 +++ __tests__/ssh.test.ts | 4 ++++ __tests__/util.test.ts | 29 +++++++++++++++++++++++++++-- __tests__/worktree.error.test.ts | 1 + __tests__/worktree.test.ts | 4 ++++ src/constants.ts | 13 +++++++++++-- src/git.ts | 2 +- src/ssh.ts | 6 ++---- src/util.ts | 8 ++++++-- 11 files changed, 76 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 4d984c58..ca75ec09 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@

- This GitHub Action will automatically deploy your project to GitHub Pages. It can be configured to push your production-ready code into any branch you'd like, including gh-pages and docs. It can also handle cross repository deployments too. + This GitHub Action will automatically deploy your project to GitHub Pages. It can be configured to push your production-ready code into any branch you'd like, including gh-pages and docs. It can also handle cross repository deployments and works with GitHub Enterprise too.

diff --git a/__tests__/git.test.ts b/__tests__/git.test.ts index 5331158b..5f704c7c 100644 --- a/__tests__/git.test.ts +++ b/__tests__/git.test.ts @@ -42,6 +42,7 @@ describe('git', () => { describe('init', () => { it('should execute commands', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, repositoryPath: 'JamesIves/github-pages-deploy-action', token: '123', @@ -64,6 +65,7 @@ describe('git', () => { }) Object.assign(action, { + hostname: 'github.com', silent: false, repositoryPath: 'JamesIves/github-pages-deploy-action', token: '123', @@ -87,6 +89,7 @@ describe('git', () => { it('should correctly continue when it cannot unset a git config value', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, repositoryPath: 'JamesIves/github-pages-deploy-action', token: '123', @@ -108,6 +111,7 @@ describe('git', () => { process.env.CI = 'true' Object.assign(action, { + hostname: 'github.com', silent: false, repositoryPath: 'JamesIves/github-pages-deploy-action', sshKey: true, @@ -128,6 +132,7 @@ describe('git', () => { it('should correctly continue when it cannot remove origin', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, repositoryPath: 'JamesIves/github-pages-deploy-action', token: '123', @@ -148,6 +153,7 @@ describe('git', () => { describe('deploy', () => { it('should execute commands', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'assets', branch: 'branch', @@ -170,6 +176,7 @@ describe('git', () => { it('should not push when asked to dryRun', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, dryRun: true, folder: 'assets', @@ -192,6 +199,7 @@ describe('git', () => { it('should execute commands with single commit toggled', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'other', folderPath: 'other', @@ -215,6 +223,7 @@ describe('git', () => { it('should execute commands with single commit toggled and existing branch', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'other', folderPath: 'other', @@ -238,6 +247,7 @@ describe('git', () => { it('should execute commands with single commit and dryRun toggled', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'other', folderPath: 'other', @@ -270,6 +280,7 @@ describe('git', () => { }) Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'assets', folderPath: 'assets', @@ -300,6 +311,7 @@ describe('git', () => { it('should execute commands with clean options', async () => { process.env.GITHUB_SHA = '' Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'other', folderPath: 'other', @@ -324,6 +336,7 @@ describe('git', () => { it('should execute commands with clean options stored as an array', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'assets', folderPath: 'assets', @@ -347,6 +360,7 @@ describe('git', () => { it('should gracefully handle target folder', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, folder: '.', branch: 'branch', @@ -367,6 +381,7 @@ describe('git', () => { it('should stop early if there is nothing to commit', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'assets', branch: 'branch', @@ -390,6 +405,7 @@ describe('git', () => { }) Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'assets', branch: 'branch', diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index e7d85d22..a1708ecb 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -41,6 +41,7 @@ describe('main', () => { folder: 'assets', branch: 'branch', token: '123', + hostname: 'github.com', pusher: { name: 'asd', email: 'as@cat' @@ -56,6 +57,7 @@ describe('main', () => { it('should run through the commands and succeed', async () => { Object.assign(action, { + hostname: 'github.com', repositoryPath: 'JamesIves/github-pages-deploy-action', folder: 'assets', branch: 'branch', @@ -75,6 +77,7 @@ describe('main', () => { it('should throw if an error is encountered', async () => { Object.assign(action, { + hostname: 'github.com', folder: 'assets', branch: 'branch', token: null, diff --git a/__tests__/ssh.test.ts b/__tests__/ssh.test.ts index 17cc90f4..b9dc73cd 100644 --- a/__tests__/ssh.test.ts +++ b/__tests__/ssh.test.ts @@ -43,6 +43,7 @@ describe('configureSSH', () => { it('should skip client configuration if sshKey is set to true', async () => { Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'assets', branch: 'branch', @@ -67,6 +68,7 @@ describe('configureSSH', () => { }) Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'assets', branch: 'branch', @@ -91,6 +93,7 @@ describe('configureSSH', () => { }) Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'assets', branch: 'branch', @@ -115,6 +118,7 @@ describe('configureSSH', () => { }) Object.assign(action, { + hostname: 'github.com', silent: false, folder: 'assets', branch: 'branch', diff --git a/__tests__/util.test.ts b/__tests__/util.test.ts index c0679849..a7ade4a3 100644 --- a/__tests__/util.test.ts +++ b/__tests__/util.test.ts @@ -5,7 +5,8 @@ import { generateRepositoryPath, generateFolderPath, suppressSensitiveInformation, - checkParameters + checkParameters, + stripProtocolFromUrl } from '../src/util' describe('util', () => { @@ -79,11 +80,13 @@ describe('util', () => { branch: '123', workspace: 'src/', folder: 'build', + hostname: 'github.com', token: null, sshKey: 'real_token', silent: false, isTest: TestFlag.NONE } + expect(generateRepositoryPath(action)).toEqual( 'git@github.com:JamesIves/github-pages-deploy-action' ) @@ -95,13 +98,15 @@ describe('util', () => { branch: '123', workspace: 'src/', folder: 'build', + hostname: 'enterprise.github.com', token: '123', sshKey: null, silent: false, isTest: TestFlag.NONE } + expect(generateRepositoryPath(action)).toEqual( - 'https://x-access-token:123@github.com/JamesIves/github-pages-deploy-action.git' + 'https://x-access-token:123@enterprise.github.com/JamesIves/github-pages-deploy-action.git' ) }) @@ -302,4 +307,24 @@ describe('util', () => { } }) }) + + describe('stripProtocolFromUrl', () => { + it('removes https', () => { + expect(stripProtocolFromUrl('https://github.com')).toBe('github.com') + }) + + it('removes http', () => { + expect(stripProtocolFromUrl('http://github.com')).toBe('github.com') + }) + + it('removes https|http and www.', () => { + expect(stripProtocolFromUrl('http://www.github.com')).toBe('github.com') + }) + + it('works with a url that is not github.com', () => { + expect(stripProtocolFromUrl('http://github.enterprise.jamesiv.es')).toBe( + 'github.enterprise.jamesiv.es' + ) + }) + }) }) diff --git a/__tests__/worktree.error.test.ts b/__tests__/worktree.error.test.ts index 57676ebd..0bbf7df6 100644 --- a/__tests__/worktree.error.test.ts +++ b/__tests__/worktree.error.test.ts @@ -16,6 +16,7 @@ describe('generateWorktree', () => { try { await generateWorktree( { + hostname: 'github.com', workspace: 'somewhere', singleCommit: false, branch: 'gh-pages', diff --git a/__tests__/worktree.test.ts b/__tests__/worktree.test.ts index 91626f7c..4d5e1e96 100644 --- a/__tests__/worktree.test.ts +++ b/__tests__/worktree.test.ts @@ -81,6 +81,7 @@ describe('generateWorktree', () => { const workspace = clonedir as string await generateWorktree( { + hostname: 'github.com', workspace, singleCommit: false, branch: 'gh-pages', @@ -111,6 +112,7 @@ describe('generateWorktree', () => { const workspace = clonedir as string await generateWorktree( { + hostname: 'github.com', workspace, singleCommit: false, branch: 'no-pages', @@ -138,6 +140,7 @@ describe('generateWorktree', () => { const workspace = clonedir as string await generateWorktree( { + hostname: 'github.com', workspace, singleCommit: true, branch: 'gh-pages', @@ -169,6 +172,7 @@ describe('generateWorktree', () => { const workspace = clonedir as string await generateWorktree( { + hostname: 'github.com', workspace, singleCommit: true, branch: 'no-pages', diff --git a/src/constants.ts b/src/constants.ts index cfcefbb8..a2f682af 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,6 +1,6 @@ import {getInput} from '@actions/core' import * as github from '@actions/github' -import {isNullOrUndefined} from './util' +import {isNullOrUndefined, stripProtocolFromUrl} from './util' const {pusher, repository} = github.context.payload @@ -25,6 +25,8 @@ export interface ActionInterface { cleanExclude?: string[] /** If you need to customize the commit message for an integration you can do so. */ commitMessage?: string + /** The hostname of which the GitHub Workflow is being run on, ie: github.com */ + hostname?: string /** The git config email. */ email?: string /** The folder to deploy. */ @@ -89,6 +91,9 @@ export const action: ActionInterface = { cleanExclude: (getInput('clean-exclude') || '') .split('\n') .filter(l => l !== ''), + hostname: process.env.GITHUB_SERVER_URL + ? stripProtocolFromUrl(process.env.GITHUB_SERVER_URL) + : 'github.com', isTest: TestFlag.NONE, email: !isNullOrUndefined(getInput('git-config-email')) ? getInput('git-config-email') @@ -96,7 +101,11 @@ export const action: ActionInterface = { ? pusher.email : `${ process.env.GITHUB_ACTOR || 'github-pages-deploy-action' - }@users.noreply.github.com`, + }@users.noreply.${ + process.env.GITHUB_SERVER_URL + ? stripProtocolFromUrl(process.env.GITHUB_SERVER_URL) + : 'github.com' + }`, name: !isNullOrUndefined(getInput('git-config-name')) ? getInput('git-config-name') : pusher && pusher.name diff --git a/src/git.ts b/src/git.ts index 7760c8f9..4313a9d4 100644 --- a/src/git.ts +++ b/src/git.ts @@ -29,7 +29,7 @@ export async function init(action: ActionInterface): Promise { Only runs in the GitHub Actions CI environment if a user is not using an SSH key. */ await execute( - `git config --local --unset-all http.https://github.com/.extraheader`, + `git config --local --unset-all http.https://${action.hostname}/.extraheader`, action.workspace, action.silent ) diff --git a/src/ssh.ts b/src/ssh.ts index 1a05e4d7..846c124f 100644 --- a/src/ssh.ts +++ b/src/ssh.ts @@ -12,10 +12,8 @@ export async function configureSSH(action: ActionInterface): Promise { const sshKnownHostsDirectory = `${sshDirectory}/known_hosts` // SSH fingerprints provided by GitHub: https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/githubs-ssh-key-fingerprints - const sshGitHubKnownHostRsa = - '\ngithub.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==\n' - const sshGitHubKnownHostDss = - '\ngithub.com ssh-dss AAAAB3NzaC1kc3MAAACBANGFW2P9xlGU3zWrymJgI/lKo//ZW2WfVtmbsUZJ5uyKArtlQOT2+WRhcg4979aFxgKdcsqAYW3/LS1T2km3jYW/vr4Uzn+dXWODVk5VlUiZ1HFOHf6s6ITcZvjvdbp6ZbpM+DuJT7Bw+h5Fx8Qt8I16oCZYmAPJRtu46o9C2zk1AAAAFQC4gdFGcSbp5Gr0Wd5Ay/jtcldMewAAAIATTgn4sY4Nem/FQE+XJlyUQptPWMem5fwOcWtSXiTKaaN0lkk2p2snz+EJvAGXGq9dTSWHyLJSM2W6ZdQDqWJ1k+cL8CARAqL+UMwF84CR0m3hj+wtVGD/J4G5kW2DBAf4/bqzP4469lT+dF2FRQ2L9JKXrCWcnhMtJUvua8dvnwAAAIB6C4nQfAA7x8oLta6tT+oCk2WQcydNsyugE8vLrHlogoWEicla6cWPk7oXSspbzUcfkjN3Qa6e74PhRkc7JdSdAlFzU3m7LMkXo1MHgkqNX8glxWNVqBSc0YRdbFdTkL0C6gtpklilhvuHQCdbgB3LBAikcRkDp+FCVkUgPC/7Rw==\n' + const sshGitHubKnownHostRsa = `\n${action.hostname} ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==\n` + const sshGitHubKnownHostDss = `\n${action.hostname} ssh-dss AAAAB3NzaC1kc3MAAACBANGFW2P9xlGU3zWrymJgI/lKo//ZW2WfVtmbsUZJ5uyKArtlQOT2+WRhcg4979aFxgKdcsqAYW3/LS1T2km3jYW/vr4Uzn+dXWODVk5VlUiZ1HFOHf6s6ITcZvjvdbp6ZbpM+DuJT7Bw+h5Fx8Qt8I16oCZYmAPJRtu46o9C2zk1AAAAFQC4gdFGcSbp5Gr0Wd5Ay/jtcldMewAAAIATTgn4sY4Nem/FQE+XJlyUQptPWMem5fwOcWtSXiTKaaN0lkk2p2snz+EJvAGXGq9dTSWHyLJSM2W6ZdQDqWJ1k+cL8CARAqL+UMwF84CR0m3hj+wtVGD/J4G5kW2DBAf4/bqzP4469lT+dF2FRQ2L9JKXrCWcnhMtJUvua8dvnwAAAIB6C4nQfAA7x8oLta6tT+oCk2WQcydNsyugE8vLrHlogoWEicla6cWPk7oXSspbzUcfkjN3Qa6e74PhRkc7JdSdAlFzU3m7LMkXo1MHgkqNX8glxWNVqBSc0YRdbFdTkL0C6gtpklilhvuHQCdbgB3LBAikcRkDp+FCVkUgPC/7Rw==\n` info(`Configuring SSH client… 🔑`) diff --git a/src/util.ts b/src/util.ts index 8db99d65..8c052e19 100644 --- a/src/util.ts +++ b/src/util.ts @@ -18,8 +18,8 @@ export const generateTokenType = (action: ActionInterface): string => /* Generates a the repository path used to make the commits. */ export const generateRepositoryPath = (action: ActionInterface): string => action.sshKey - ? `git@github.com:${action.repositoryName}` - : `https://${`x-access-token:${action.token}`}@github.com/${ + ? `git@${action.hostname}:${action.repositoryName}` + : `https://${`x-access-token:${action.token}`}@${action.hostname}/${ action.repositoryName }.git` @@ -89,3 +89,7 @@ export const suppressSensitiveInformation = ( return value } + +/** Strips the protocol from a provided URL. */ +export const stripProtocolFromUrl = (url: string): string => + url.replace(/^(?:https?:\/\/)?(?:www\.)?/i, '').split('/')[0]