From ec00d65c65bf19020f5b6b1a359605d5ebe9f61f Mon Sep 17 00:00:00 2001
From: Daniel Hwang <danielleehwang@gmail.com>
Date: Fri, 29 May 2020 15:57:30 -0700
Subject: [PATCH] add support for gist.github.com

---
 README.md                        |  3 +++
 __test__/git-auth-helper.test.ts |  1 +
 __test__/input-helper.test.ts    |  7 +++++++
 action.yml                       |  2 ++
 dist/index.js                    | 32 ++++++++++++++++++++++++--------
 src/git-auth-helper.ts           |  2 +-
 src/git-source-settings.ts       |  5 +++++
 src/input-helper.ts              | 12 ++++++++++--
 src/url-helper.ts                | 21 ++++++++++++++++-----
 9 files changed, 69 insertions(+), 16 deletions(-)

diff --git a/README.md b/README.md
index 9104f8b..8982c3f 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,9 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous
     # Default: ${{ github.repository }}
     repository: ''
 
+    # Gist name with owner. For example, schacon/1
+    gist: ''
+
     # The branch, tag or SHA to checkout. When checking out the repository that
     # triggered a workflow, this defaults to the reference or SHA for that event.
     # Otherwise, defaults to `master`.
diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts
index 92a462a..ce7b914 100644
--- a/__test__/git-auth-helper.test.ts
+++ b/__test__/git-auth-helper.test.ts
@@ -767,6 +767,7 @@ async function setup(testName: string): Promise<void> {
     repositoryName: 'my-repo',
     repositoryOwner: 'my-org',
     repositoryPath: '',
+    isGist: false,
     sshKey: sshPath ? 'some ssh private key' : '',
     sshKnownHosts: '',
     sshStrict: true
diff --git a/__test__/input-helper.test.ts b/__test__/input-helper.test.ts
index 00732ef..0a59969 100644
--- a/__test__/input-helper.test.ts
+++ b/__test__/input-helper.test.ts
@@ -117,6 +117,13 @@ describe('input-helper tests', () => {
     expect(settings.commit).toBeFalsy()
   })
 
+  it('sets correct default ref/sha for gist', () => {
+    inputs.gist = 'some-owner/some-gist'
+    const settings: IGitSourceSettings = inputHelper.getInputs()
+    expect(settings.ref).toBe('refs/heads/master')
+    expect(settings.commit).toBeFalsy()
+  })
+
   it('sets ref to empty when explicit sha', () => {
     inputs.ref = '1111111111222222222233333333334444444444'
     const settings: IGitSourceSettings = inputHelper.getInputs()
diff --git a/action.yml b/action.yml
index 58e11b7..c066833 100644
--- a/action.yml
+++ b/action.yml
@@ -4,6 +4,8 @@ inputs:
   repository:
     description: 'Repository name with owner. For example, actions/checkout'
     default: ${{ github.repository }}
+  gist:
+    description: 'Gist name with owner. For example, schacon/1'
   ref:
     description: >
       The branch, tag or SHA to checkout. When checking out the repository that
diff --git a/dist/index.js b/dist/index.js
index 0c78d25..3312562 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -1389,21 +1389,30 @@ 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.isGist);
     const encodedOwner = encodeURIComponent(settings.repositoryOwner);
     const encodedName = encodeURIComponent(settings.repositoryName);
+    let encodedNwo = `${encodedOwner}/${encodedName}`;
+    if (settings.isGist) {
+        encodedNwo = encodedName;
+    }
     if (settings.sshKey) {
-        return `git@${serviceUrl.hostname}:${encodedOwner}/${encodedName}.git`;
+        return `git@${serviceUrl.hostname}:${encodedNwo}.git`;
     }
     // "origin" is SCHEME://HOSTNAME[:PORT]
-    return `${serviceUrl.origin}/${encodedOwner}/${encodedName}`;
+    return `${serviceUrl.origin}/${encodedNwo}`;
 }
 exports.getFetchUrl = getFetchUrl;
-function getServerUrl() {
+function getServerUrl(isGist) {
     // todo: remove GITHUB_URL after support for GHES Alpha is no longer needed
-    return new url_1.URL(process.env['GITHUB_SERVER_URL'] ||
+    let serverUrl = new url_1.URL(process.env['GITHUB_SERVER_URL'] ||
         process.env['GITHUB_URL'] ||
         'https://github.com');
+    // todo: don't assume subdomain isolation
+    if (isGist) {
+        serverUrl.hostname = `gist.${serverUrl.hostname}`;
+    }
+    return serverUrl;
 }
 exports.getServerUrl = getServerUrl;
 
@@ -5418,7 +5427,7 @@ class GitAuthHelper {
         this.git = gitCommandManager;
         this.settings = gitSourceSettings || {};
         // Token auth header
-        const serverUrl = urlHelper.getServerUrl();
+        const serverUrl = urlHelper.getServerUrl(this.settings.isGist);
         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);
@@ -14438,15 +14447,22 @@ function getInputs() {
     githubWorkspacePath = path.resolve(githubWorkspacePath);
     core.debug(`GITHUB_WORKSPACE = '${githubWorkspacePath}'`);
     fsHelper.directoryExistsSync(githubWorkspacePath, true);
+    // Gist repository?
+    result.isGist = !!core.getInput('gist') || false;
+    core.debug(`isGist = '${result.isGist}'`);
     // Qualified repository
-    const qualifiedRepository = core.getInput('repository') ||
+    let qualifiedRepository = core.getInput('repository') ||
         `${github.context.repo.owner}/${github.context.repo.repo}`;
+    if (result.isGist) {
+        qualifiedRepository = core.getInput('gist');
+    }
     core.debug(`qualified repository = '${qualifiedRepository}'`);
     const splitRepository = qualifiedRepository.split('/');
     if (splitRepository.length !== 2 ||
         !splitRepository[0] ||
         !splitRepository[1]) {
-        throw new Error(`Invalid repository '${qualifiedRepository}'. Expected format {owner}/{repo}.`);
+        const model = result.isGist ? 'gist' : 'repository';
+        throw new Error(`Invalid ${model} '${qualifiedRepository}'. Expected format {owner}/{repo}.`);
     }
     result.repositoryOwner = splitRepository[0];
     result.repositoryName = splitRepository[1];
diff --git a/src/git-auth-helper.ts b/src/git-auth-helper.ts
index fc1404c..46330fe 100644
--- a/src/git-auth-helper.ts
+++ b/src/git-auth-helper.ts
@@ -51,7 +51,7 @@ class GitAuthHelper {
     this.settings = gitSourceSettings || (({} as unknown) as IGitSourceSettings)
 
     // Token auth header
-    const serverUrl = urlHelper.getServerUrl()
+    const serverUrl = urlHelper.getServerUrl(this.settings.isGist)
     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-settings.ts b/src/git-source-settings.ts
index 2786222..2d26ba2 100644
--- a/src/git-source-settings.ts
+++ b/src/git-source-settings.ts
@@ -73,4 +73,9 @@ export interface IGitSourceSettings {
    * Indicates whether to persist the credentials on disk to enable scripting authenticated git commands
    */
   persistCredentials: boolean
+
+  /**
+   * Indicates whether this repository is a gist
+   */
+  isGist: boolean
 }
diff --git a/src/input-helper.ts b/src/input-helper.ts
index 11a1ab6..a692cf3 100644
--- a/src/input-helper.ts
+++ b/src/input-helper.ts
@@ -16,10 +16,17 @@ export function getInputs(): IGitSourceSettings {
   core.debug(`GITHUB_WORKSPACE = '${githubWorkspacePath}'`)
   fsHelper.directoryExistsSync(githubWorkspacePath, true)
 
+  // Gist repository?
+  result.isGist = !!core.getInput('gist') || false
+  core.debug(`isGist = '${result.isGist}'`)
+
   // Qualified repository
-  const qualifiedRepository =
+  let qualifiedRepository =
     core.getInput('repository') ||
     `${github.context.repo.owner}/${github.context.repo.repo}`
+  if (result.isGist) {
+    qualifiedRepository = core.getInput('gist')
+  }
   core.debug(`qualified repository = '${qualifiedRepository}'`)
   const splitRepository = qualifiedRepository.split('/')
   if (
@@ -27,8 +34,9 @@ export function getInputs(): IGitSourceSettings {
     !splitRepository[0] ||
     !splitRepository[1]
   ) {
+    const model = result.isGist ? 'gist' : 'repository'
     throw new Error(
-      `Invalid repository '${qualifiedRepository}'. Expected format {owner}/{repo}.`
+      `Invalid ${model} '${qualifiedRepository}'. Expected format {owner}/{repo}.`
     )
   }
   result.repositoryOwner = splitRepository[0]
diff --git a/src/url-helper.ts b/src/url-helper.ts
index 05f1cbd..6c2a6de 100644
--- a/src/url-helper.ts
+++ b/src/url-helper.ts
@@ -8,22 +8,33 @@ 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.isGist)
   const encodedOwner = encodeURIComponent(settings.repositoryOwner)
   const encodedName = encodeURIComponent(settings.repositoryName)
+  let encodedNwo = `${encodedOwner}/${encodedName}`
+  if (settings.isGist) {
+    encodedNwo = encodedName
+  }
   if (settings.sshKey) {
-    return `git@${serviceUrl.hostname}:${encodedOwner}/${encodedName}.git`
+    return `git@${serviceUrl.hostname}:${encodedNwo}.git`
   }
 
   // "origin" is SCHEME://HOSTNAME[:PORT]
-  return `${serviceUrl.origin}/${encodedOwner}/${encodedName}`
+  return `${serviceUrl.origin}/${encodedNwo}`
 }
 
-export function getServerUrl(): URL {
+export function getServerUrl(isGist: boolean): URL {
   // todo: remove GITHUB_URL after support for GHES Alpha is no longer needed
-  return new URL(
+  let serverUrl = new URL(
     process.env['GITHUB_SERVER_URL'] ||
       process.env['GITHUB_URL'] ||
       'https://github.com'
   )
+
+  // todo: don't assume subdomain isolation
+  if (isGist) {
+    serverUrl.hostname = `gist.${serverUrl.hostname}`
+  }
+
+  return serverUrl
 }