Improve backport command (#51306)
authorAlexander Köplinger <alex.koeplinger@outlook.com>
Thu, 15 Apr 2021 18:06:02 +0000 (20:06 +0200)
committerGitHub <noreply@github.com>
Thu, 15 Apr 2021 18:06:02 +0000 (20:06 +0200)
GitHub Actions started doing shallow checkouts so we often ran into the case where applying the patch would fail with an error due to the commit blobs not being available:

```
error: sha1 information is lacking or useless (eng/pipelines/common/xplat-setup.yml).
error: could not build fake ancestor
```

Fix this by always checking out the whole history. Since this makes checkout quite slow (~2mins), refactor the action so we post the "Started backporting" comment before doing the checkout so the user isn't confused why nothing happens.

.github/workflows/backport.yml
eng/actions/backport/action.yml
eng/actions/backport/index.js

index 79cde1d..9699f4d 100644 (file)
@@ -8,11 +8,39 @@ jobs:
     if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/backport to')
     runs-on: ubuntu-20.04
     steps:
+    - name: Extract backport target branch
+      uses: actions/github-script@v3
+      id: target-branch-extractor
+      with:
+        result-encoding: string
+        script: |
+          if (context.eventName !== "issue_comment") throw "Error: This action only works on issue_comment events.";
+
+          // extract the target branch name from the trigger phrase containing these characters: a-z, A-Z, digits, forward slash, dot, hyphen, underscore
+          const regex = /\/backport to ([a-zA-Z\d\/\.\-\_]+)/;
+          target_branch = regex.exec(context.payload.comment.body);
+          if (target_branch == null) throw "Error: No backport branch found in the trigger phrase.";
+
+          return target_branch[1];
+    - name: Post backport started comment to pull request
+      uses: actions/github-script@v3
+      with:
+        script: |
+          const backport_start_body = `Started backporting to ${{ steps.target-branch-extractor.outputs.result }}: https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${process.env.GITHUB_RUN_ID}`;
+          await github.issues.createComment({
+            issue_number: context.issue.number,
+            owner: context.repo.owner,
+            repo: context.repo.repo,
+            body: backport_start_body
+          });
     - name: Checkout repo
       uses: actions/checkout@v2
+      with:
+        fetch-depth: 0
     - name: Run backport
       uses: ./eng/actions/backport
       with:
+        target_branch: ${{ steps.target-branch-extractor.outputs.result }}
         auth_token: ${{ secrets.GITHUB_TOKEN }}
         pr_description_template: |
           Backport of #%source_pr_number% to %target_branch%
index c136dd5..e596f1d 100644 (file)
@@ -1,6 +1,8 @@
 name: 'PR Backporter'
 description: 'Backports a pull request to a branch using the "/backport to <branch>" comment'
 inputs:
+  target_branch:
+    description: 'Backport target branch.'
   auth_token:
     description: 'The token used to authenticate to GitHub.'
   pr_title_template:
index 0761961..a1201ac 100644 (file)
@@ -20,17 +20,13 @@ async function run() {
   const github = require("@actions/github");
   const exec = require("@actions/exec");
 
-  if (github.context.eventName !== "issue_comment") throw "Error: This action only works on issue_comment events.";
-
-  const run_id = process.env.GITHUB_RUN_ID;
   const repo_owner = github.context.payload.repository.owner.login;
   const repo_name = github.context.payload.repository.name;
   const pr_number = github.context.payload.issue.number;
-  const pr_source_ref = process.env.GITHUB_REF;
   const comment_user = github.context.payload.comment.user.login;
 
-  let octokit = github.getOctokit(core.getInput("auth_token"));
-  let target_branch = "";
+  let octokit = github.getOctokit(core.getInput("auth_token", { required: true }));
+  let target_branch = core.getInput("target_branch", { required: true });
 
   try {
     // verify the comment user is a repo collaborator
@@ -45,26 +41,11 @@ async function run() {
       throw new BackportException(`Error: @${comment_user} is not a repo collaborator, backporting is not allowed.`);
     }
 
-    // extract the target branch name from the trigger phrase containing these characters: a-z, A-Z, digits, forward slash, dot, hyphen, underscore
-    console.log(`Extracting target branch`);
-    const regex = /\/backport to ([a-zA-Z\d\/\.\-\_]+)/;
-    target_branch = regex.exec(github.context.payload.comment.body)[1];
-    if (target_branch == null) throw new BackportException("Error: No backport branch found in the trigger phrase.");
     try { await exec.exec(`git ls-remote --exit-code --heads origin ${target_branch}`) } catch { throw new BackportException(`Error: The specified backport target branch ${target_branch} wasn't found in the repo.`); }
     console.log(`Backport target branch: ${target_branch}`);
 
-    // Post backport started comment to pull request
-    const backport_start_body = `Started backporting to ${target_branch}: https://github.com/${repo_owner}/${repo_name}/actions/runs/${run_id}`;
-    await octokit.issues.createComment({
-      owner: repo_owner,
-      repo: repo_name,
-      issue_number: pr_number,
-      body: backport_start_body
-    });
-
     console.log("Applying backport patch");
 
-    await exec.exec(`git -c protocol.version=2 fetch --no-tags --progress --no-recurse-submodules origin ${target_branch} ${pr_source_ref}`);
     await exec.exec(`git checkout ${target_branch}`);
     await exec.exec(`git clean -xdff`);