From e72243fb91f9fec2a16dd4e0b4175dc1e2337c6f Mon Sep 17 00:00:00 2001
From: alexanderkranga <acranga@extole.com>
Date: Tue, 6 Feb 2024 15:30:36 +0200
Subject: [PATCH] add our feature

---
 README.md                        |  5 ++++
 __test__/git-auth-helper.test.ts |  2 ++
 action.yml                       |  5 ++++
 dist/index.js                    | 32 ++++++++++++++++++--
 src/git-source-provider.ts       | 50 ++++++++++++++++++++++++++++----
 src/git-source-settings.ts       | 10 +++++++
 src/input-helper.ts              |  5 ++++
 7 files changed, 101 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index bfecf46..a47dab9 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,11 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
     # Otherwise, uses the default branch.
     ref: ''
 
+    # Whether to checkout the default repository branch if specified ref does not
+    # exist. If this is set to true, then fetch-depth should be 0
+    # Default: true
+    default-ref-on-error: ''
+
     # Personal access token (PAT) used to fetch the repository. The PAT is configured
     # with the local git config, which enables your scripts to run authenticated git
     # commands. The post-job step removes the PAT.
diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts
index 411faed..e8ea886 100644
--- a/__test__/git-auth-helper.test.ts
+++ b/__test__/git-auth-helper.test.ts
@@ -813,6 +813,8 @@ async function setup(testName: string): Promise<void> {
     nestedSubmodules: false,
     persistCredentials: true,
     ref: 'refs/heads/main',
+    defaultRefOnError: true,
+    defaultBranch: 'main',
     repositoryName: 'my-repo',
     repositoryOwner: 'my-org',
     repositoryPath: '',
diff --git a/action.yml b/action.yml
index 5aa90a7..ad48198 100644
--- a/action.yml
+++ b/action.yml
@@ -9,6 +9,11 @@ inputs:
       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, uses the default branch.
+  default-ref-on-error:
+    description: >
+      Whether to checkout the default repository branch if specified ref does not exist.
+      If this is set to true, then fetch-depth should be 0
+    default: true
   token:
     description: >
       Personal access token (PAT) used to fetch the repository. The PAT is configured
diff --git a/dist/index.js b/dist/index.js
index ddf2b3d..5b474f5 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -1226,6 +1226,17 @@ function getSource(settings) {
             core.startGroup('Setting up auth');
             yield authHelper.configureAuth();
             core.endGroup();
+            if (settings.defaultRefOnError && settings.defaultRefOnError === true) {
+                // Configure default branch
+                core.startGroup('Setting up default branch');
+                if (settings.sshKey) {
+                    settings.defaultBranch = yield git.getDefaultBranch(repositoryUrl);
+                }
+                else {
+                    settings.defaultBranch = yield githubApiHelper.getDefaultBranch(settings.authToken, settings.repositoryOwner, settings.repositoryName);
+                }
+                core.endGroup();
+            }
             // Determine the default branch
             if (!settings.ref && !settings.commit) {
                 core.startGroup('Determining the default branch');
@@ -1250,7 +1261,8 @@ function getSource(settings) {
             else if (settings.sparseCheckout) {
                 fetchOptions.filter = 'blob:none';
             }
-            if (settings.fetchDepth <= 0) {
+            if (settings.fetchDepth <= 0 ||
+                (settings.defaultRefOnError && settings.defaultRefOnError === true)) {
                 // Fetch all branches and tags
                 let refSpec = refHelper.getRefSpecForAllHistory(settings.ref, settings.commit);
                 yield git.fetch(refSpec, fetchOptions);
@@ -1270,7 +1282,19 @@ function getSource(settings) {
             core.endGroup();
             // Checkout info
             core.startGroup('Determining the checkout info');
-            const checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
+            let checkoutInfo;
+            if (settings.defaultRefOnError && settings.defaultRefOnError === true) {
+                try {
+                    checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
+                }
+                catch (error) {
+                    core.info('Could not determine the checkout info. Trying the default repo branch');
+                    checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.defaultBranch, settings.commit);
+                }
+            }
+            else {
+                checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
+            }
             core.endGroup();
             // LFS fetch
             // Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
@@ -1724,6 +1748,10 @@ function getInputs() {
         }
         core.debug(`ref = '${result.ref}'`);
         core.debug(`commit = '${result.commit}'`);
+        // Default ref on error
+        result.defaultRefOnError =
+            (core.getInput('default-ref-on-error') || 'true').toUpperCase() === 'TRUE';
+        core.debug(`default-ref-on-error = '${result.defaultRefOnError}'`);
         // Clean
         result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE';
         core.debug(`clean = ${result.clean}`);
diff --git a/src/git-source-provider.ts b/src/git-source-provider.ts
index 5c98e9f..a174802 100644
--- a/src/git-source-provider.ts
+++ b/src/git-source-provider.ts
@@ -130,6 +130,21 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
     await authHelper.configureAuth()
     core.endGroup()
 
+    if (settings.defaultRefOnError && settings.defaultRefOnError === true) {
+      // Configure default branch
+      core.startGroup('Setting up default branch')
+      if (settings.sshKey) {
+        settings.defaultBranch = await git.getDefaultBranch(repositoryUrl)
+      } else {
+        settings.defaultBranch = await githubApiHelper.getDefaultBranch(
+          settings.authToken,
+          settings.repositoryOwner,
+          settings.repositoryName
+        )
+      }
+      core.endGroup()
+    }
+
     // Determine the default branch
     if (!settings.ref && !settings.commit) {
       core.startGroup('Determining the default branch')
@@ -166,7 +181,10 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
       fetchOptions.filter = 'blob:none'
     }
 
-    if (settings.fetchDepth <= 0) {
+    if (
+      settings.fetchDepth <= 0 ||
+      (settings.defaultRefOnError && settings.defaultRefOnError === true)
+    ) {
       // Fetch all branches and tags
       let refSpec = refHelper.getRefSpecForAllHistory(
         settings.ref,
@@ -190,11 +208,31 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
 
     // Checkout info
     core.startGroup('Determining the checkout info')
-    const checkoutInfo = await refHelper.getCheckoutInfo(
-      git,
-      settings.ref,
-      settings.commit
-    )
+    let checkoutInfo: refHelper.ICheckoutInfo
+    if (settings.defaultRefOnError && settings.defaultRefOnError === true) {
+      try {
+        checkoutInfo = await refHelper.getCheckoutInfo(
+          git,
+          settings.ref,
+          settings.commit
+        )
+      } catch (error) {
+        core.info(
+          'Could not determine the checkout info. Trying the default repo branch'
+        )
+        checkoutInfo = await refHelper.getCheckoutInfo(
+          git,
+          settings.defaultBranch,
+          settings.commit
+        )
+      }
+    } else {
+      checkoutInfo = await refHelper.getCheckoutInfo(
+        git,
+        settings.ref,
+        settings.commit
+      )
+    }
     core.endGroup()
 
     // LFS fetch
diff --git a/src/git-source-settings.ts b/src/git-source-settings.ts
index 629350b..f94209b 100644
--- a/src/git-source-settings.ts
+++ b/src/git-source-settings.ts
@@ -19,6 +19,16 @@ export interface IGitSourceSettings {
    */
   ref: string
 
+  /**
+   * Whether to checkout the default repository branch if specified ref does not exist.
+   */
+  defaultRefOnError: boolean
+
+  /**
+   * The target ref to fetch if it exists
+   */
+  defaultBranch: string
+
   /**
    * The commit to checkout
    */
diff --git a/src/input-helper.ts b/src/input-helper.ts
index e546c19..cc854b0 100644
--- a/src/input-helper.ts
+++ b/src/input-helper.ts
@@ -78,6 +78,11 @@ export async function getInputs(): Promise<IGitSourceSettings> {
   core.debug(`ref = '${result.ref}'`)
   core.debug(`commit = '${result.commit}'`)
 
+  // Default ref on error
+  result.defaultRefOnError =
+    (core.getInput('default-ref-on-error') || 'true').toUpperCase() === 'TRUE'
+  core.debug(`default-ref-on-error = '${result.defaultRefOnError}'`)
+
   // Clean
   result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE'
   core.debug(`clean = ${result.clean}`)