[clang] [llvm] [workflows] Split pr-code-format into two parts to make it more secure (PR #78216)

Tom Stellard via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 19 22:28:05 PST 2024


https://github.com/tstellar updated https://github.com/llvm/llvm-project/pull/78216

>From 035d4129ff02b776df53bfe149ce4af4af6072c4 Mon Sep 17 00:00:00 2001
From: Konrad Kleine <kkleine at redhat.com>
Date: Thu, 24 Mar 2022 09:44:21 +0100
Subject: [PATCH 01/10] Produce DWARF4 by default

Have a look at the following commit to see when the move from DWARF 4 to 5 first happened upstream:

https://github.com/llvm/llvm-project/commit/d3b26dea16108c427b19b5480c9edc76edf8f5b4?diff=unified
---
 clang/lib/Driver/ToolChain.cpp     | 4 +---
 clang/test/CodeGen/dwarf-version.c | 8 ++++----
 clang/test/Driver/as-options.s     | 4 ++--
 clang/test/Driver/cl-options.c     | 2 +-
 clang/test/Driver/clang-g-opts.c   | 2 +-
 clang/test/Driver/ve-toolchain.c   | 2 +-
 clang/test/Driver/ve-toolchain.cpp | 2 +-
 7 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 96a57927339a97..56c7d0e8db02c9 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -428,9 +428,7 @@ ToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
 }
 
 unsigned ToolChain::GetDefaultDwarfVersion() const {
-  // TODO: Remove the RISC-V special case when R_RISCV_SET_ULEB128 linker
-  // support becomes more widely available.
-  return getTriple().isRISCV() ? 4 : 5;
+  return 4;
 }
 
 Tool *ToolChain::getClang() const {
diff --git a/clang/test/CodeGen/dwarf-version.c b/clang/test/CodeGen/dwarf-version.c
index e63316ace69c87..3d68b06c58ff8b 100644
--- a/clang/test/CodeGen/dwarf-version.c
+++ b/clang/test/CodeGen/dwarf-version.c
@@ -2,10 +2,10 @@
 // RUN: %clang -target x86_64-linux-gnu -gdwarf-3 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER3
 // RUN: %clang -target x86_64-linux-gnu -gdwarf-4 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER4
 // RUN: %clang -target x86_64-linux-gnu -gdwarf-5 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER5
-// RUN: %clang -target x86_64-linux-gnu -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER5
-// RUN: %clang -target x86_64-linux-gnu -gdwarf -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER5
-// RUN: %clang --target=i386-pc-solaris -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER5
-// RUN: %clang --target=i386-pc-solaris -gdwarf -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER5
+// RUN: %clang -target x86_64-linux-gnu -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER4
+// RUN: %clang -target x86_64-linux-gnu -gdwarf -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER4
+// RUN: %clang --target=i386-pc-solaris -g -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER4
+// RUN: %clang --target=i386-pc-solaris -gdwarf -S -emit-llvm -o - %s | FileCheck %s --check-prefix=VER4
 
 // The -isysroot is used as a hack to avoid LIT messing with the SDKROOT
 // environment variable which indirecty overrides the version in the target
diff --git a/clang/test/Driver/as-options.s b/clang/test/Driver/as-options.s
index 73d002c7ef7ed3..71d55f7fd53761 100644
--- a/clang/test/Driver/as-options.s
+++ b/clang/test/Driver/as-options.s
@@ -122,7 +122,7 @@
 // RUN:   FileCheck --check-prefix=DEBUG %s
 // RUN: %clang --target=aarch64-linux-gnu -fno-integrated-as -g0 -g %s -### 2>&1 | \
 // RUN:   FileCheck --check-prefix=DEBUG %s
-// DEBUG: "-g" "-gdwarf-5"
+// DEBUG: "-g" "-gdwarf-4"
 // RUN: %clang --target=aarch64-linux-gnu -fno-integrated-as -g -g0 %s -### 2>&1 | \
 // RUN:   FileCheck --check-prefix=NODEBUG %s
 // RUN: %clang --target=aarch64-linux-gnu -fno-integrated-as -gdwarf-5 -g0 %s -### 2>&1 | \
@@ -141,7 +141,7 @@
 // RUN: %clang --target=aarch64-linux-gnu -fno-integrated-as -gdwarf-2 %s -### 2>&1 | \
 // RUN:   FileCheck --check-prefix=GDWARF2 %s
 // RUN: %clang --target=aarch64-linux-gnu -fno-integrated-as -gdwarf %s -### 2>&1 | \
-// RUN:   FileCheck --check-prefix=GDWARF5 %s
+// RUN:   FileCheck --check-prefix=GDWARF4 %s
 
 // RUN: %clang --target=aarch64-linux-gnu -fno-integrated-as -gdwarf-5 %s -### 2>&1 | \
 // RUN:   FileCheck --check-prefix=GDWARF5 %s
diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c
index 5b6dfe308a76ea..4da65272a1b0df 100644
--- a/clang/test/Driver/cl-options.c
+++ b/clang/test/Driver/cl-options.c
@@ -571,7 +571,7 @@
 // RUN: %clang_cl -gdwarf /Z7 /c -### -- %s 2>&1 | FileCheck -check-prefix=Z7_gdwarf %s
 // Z7_gdwarf-NOT: "-gcodeview"
 // Z7_gdwarf: "-debug-info-kind=constructor"
-// Z7_gdwarf: "-dwarf-version=
+// Z7_gdwarf: "-dwarf-version=4
 
 // RUN: %clang_cl /ZH:MD5 /c -### -- %s 2>&1 | FileCheck -check-prefix=ZH_MD5 %s
 // ZH_MD5: "-gsrc-hash=md5"
diff --git a/clang/test/Driver/clang-g-opts.c b/clang/test/Driver/clang-g-opts.c
index b73602a155b009..b0cf6467425340 100644
--- a/clang/test/Driver/clang-g-opts.c
+++ b/clang/test/Driver/clang-g-opts.c
@@ -36,7 +36,7 @@
 
 // CHECK-WITHOUT-G-NOT: -debug-info-kind
 // CHECK-WITH-G: "-debug-info-kind=constructor"
-// CHECK-WITH-G: "-dwarf-version=5"
+// CHECK-WITH-G: "-dwarf-version=4"
 // CHECK-WITH-G-DWARF4: "-dwarf-version=4"
 // CHECK-WITH-G-DWARF2: "-dwarf-version=2"
 
diff --git a/clang/test/Driver/ve-toolchain.c b/clang/test/Driver/ve-toolchain.c
index 078341eb1202d6..6ccbef6a0c36a2 100644
--- a/clang/test/Driver/ve-toolchain.c
+++ b/clang/test/Driver/ve-toolchain.c
@@ -6,7 +6,7 @@
 /// Checking dwarf-version
 
 // RUN: %clang -### -g --target=ve %s 2>&1 | FileCheck -check-prefix=DWARF_VER %s
-// DWARF_VER: "-dwarf-version=5"
+// DWARF_VER: "-dwarf-version=4"
 
 ///-----------------------------------------------------------------------------
 /// Checking include-path
diff --git a/clang/test/Driver/ve-toolchain.cpp b/clang/test/Driver/ve-toolchain.cpp
index cd48dd792f8582..f77781d4c6fa6d 100644
--- a/clang/test/Driver/ve-toolchain.cpp
+++ b/clang/test/Driver/ve-toolchain.cpp
@@ -7,7 +7,7 @@
 
 // RUN: %clangxx -### -g --target=ve-unknown-linux-gnu \
 // RUN:     %s 2>&1 | FileCheck -check-prefix=DWARF_VER %s
-// DWARF_VER: "-dwarf-version=5"
+// DWARF_VER: "-dwarf-version=4"
 
 ///-----------------------------------------------------------------------------
 /// Checking include-path

>From 014876fd665e4ccc7c5cbf211c662aa192973b32 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Sat, 13 Jan 2024 16:16:30 -0800
Subject: [PATCH 02/10] [workflows] Split pr-code-format into two parts to make
 it more secure

Actions triggered by pull_request_target events have access to all
repository secrets, so it is unsafe to use them when executing
untrusted code.  The pr-code-format workflow does not execute
any untrusted code, but it passes untrused input into clang-format.
An attacker could use this to exploit a flaw in clang-format and
potentially gain access to the repository secrets.

By splitting the workflow, we can use the pull_request target which
is more secure and isolate the issue write permissions in a separate
job.  The pull_request target also makes it easier to test changes
to the code-format-helepr.py script, because the version of the
script from the pull request will be used rather than the
version of the script from main.
---
 .github/workflows/issue-write.yml    | 72 ++++++++++++++++++++++++++++
 .github/workflows/pr-code-format.yml | 30 +++++-------
 llvm/utils/git/code-format-helper.py | 28 +++++++++++
 3 files changed, 112 insertions(+), 18 deletions(-)
 create mode 100644 .github/workflows/issue-write.yml

diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml
new file mode 100644
index 00000000000000..acc625a3e02a3d
--- /dev/null
+++ b/.github/workflows/issue-write.yml
@@ -0,0 +1,72 @@
+name: Comment on an issue
+
+on:
+  workflow_run:
+    workflows: ["Check code formatting"]
+    types:
+      - completed
+
+permissions:
+  contents: read
+
+jobs:
+  pr-comment:
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: write
+    if: >
+      github.event.workflow_run.event == 'pull_request'
+    steps:
+      - name: 'Download artifact'
+        # v7.0.1
+        uses: actions/github-script at 60a0d83039c74a4aee543508d2ffcb1c3799cdea
+        with:
+          script: |
+            let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
+               owner: context.repo.owner,
+               repo: context.repo.repo,
+               run_id: context.payload.workflow_run.id,
+            });
+            let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
+              return artifact.name == "workflow-args"
+            })[0];
+            let download = await github.rest.actions.downloadArtifact({
+               owner: context.repo.owner,
+               repo: context.repo.repo,
+               artifact_id: matchArtifact.id,
+               archive_format: 'zip',
+            });
+            let fs = require('fs');
+            fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/workflow-args.zip`, Buffer.from(download.data));
+
+      - run: unzip workflow-args.zip
+
+      - name: 'Comment on PR'
+        uses: actions/github-script at v3
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          script: |
+            var fs = require('fs');
+            const comments = JSON.parse(fs.readFileSync('./comments'));
+            if (!comments) {
+              return;
+            }
+            console.log(comments);
+            await comments.forEach(function (comment) {
+              if (comment.id) {
+                github.issues.updateComment({
+                  owner: context.repo.owner,
+                  repo: context.repo.repo,
+                  issue_number: comment.number,
+                  comment_id: comment.id,
+                  body: comment.body
+                });
+              } else {
+                github.issues.createComment({
+                  owner: context.repo.owner,
+                  repo: context.repo.repo,
+                  issue_number: comment.number,
+                  body: comment.body
+                });
+              }
+            });
diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml
index 5223089ee8a93d..1475d872498d49 100644
--- a/.github/workflows/pr-code-format.yml
+++ b/.github/workflows/pr-code-format.yml
@@ -1,7 +1,5 @@
 name: "Check code formatting"
-on: pull_request_target
-permissions:
-  pull-requests: write
+on: pull_request
 
 jobs:
   code_formatter:
@@ -27,18 +25,6 @@ jobs:
           separator: ","
           skip_initial_fetch: true
 
-      # We need to make sure that we aren't executing/using any code from the
-      # PR for security reasons as we're using pull_request_target. Checkout
-      # the target branch with the necessary files.
-      - name: Fetch code formatting utils
-        uses: actions/checkout at v4
-        with:
-          sparse-checkout: |
-            llvm/utils/git/requirements_formatting.txt
-            llvm/utils/git/code-format-helper.py
-          sparse-checkout-cone-mode: false
-          path: code-format-tools
-
       - name: "Listed files"
         env:
           CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
@@ -56,10 +42,10 @@ jobs:
         with:
           python-version: '3.11'
           cache: 'pip'
-          cache-dependency-path: 'code-format-tools/llvm/utils/git/requirements_formatting.txt'
+          cache-dependency-path: 'llvm/utils/git/requirements_formatting.txt'
 
       - name: Install python dependencies
-        run: pip install -r code-format-tools/llvm/utils/git/requirements_formatting.txt
+        run: pip install -r llvm/utils/git/requirements_formatting.txt
 
       - name: Run code formatter
         env:
@@ -72,9 +58,17 @@ jobs:
         # explicitly in code-format-helper.py and not have to diff starting at
         # the merge base.
         run: |
-          python ./code-format-tools/llvm/utils/git/code-format-helper.py \
+          python ./llvm/utils/git/code-format-helper.py \
+            --write-comment-to-file \
             --token ${{ secrets.GITHUB_TOKEN }} \
             --issue-number $GITHUB_PR_NUMBER \
             --start-rev $(git merge-base $START_REV $END_REV) \
             --end-rev $END_REV \
             --changed-files "$CHANGED_FILES"
+
+      - uses: actions/upload-artifact at v2
+        if: always()
+        with:
+          name: workflow-args
+          path: |
+            comments
diff --git a/llvm/utils/git/code-format-helper.py b/llvm/utils/git/code-format-helper.py
index 8a29a57d8d16bd..a96fae4953a863 100755
--- a/llvm/utils/git/code-format-helper.py
+++ b/llvm/utils/git/code-format-helper.py
@@ -44,6 +44,7 @@ class FormatArgs:
     token: str = None
     verbose: bool = True
     issue_number: int = 0
+    write_comment_to_file: bool = False
 
     def __init__(self, args: argparse.Namespace = None) -> None:
         if not args is None:
@@ -53,12 +54,14 @@ def __init__(self, args: argparse.Namespace = None) -> None:
             self.token = args.token
             self.changed_files = args.changed_files
             self.issue_number = args.issue_number
+            self.write_comment_to_file = args.write_comment_to_file
 
 
 class FormatHelper:
     COMMENT_TAG = "<!--LLVM CODE FORMAT COMMENT: {fmt}-->"
     name: str
     friendly_name: str
+    comment: dict = None
 
     @property
     def comment_tag(self) -> str:
@@ -110,6 +113,7 @@ def find_comment(self, pr: any) -> any:
         return None
 
     def update_pr(self, comment_text: str, args: FormatArgs, create_new: bool) -> None:
+
         import github
         from github import IssueComment, PullRequest
 
@@ -119,6 +123,16 @@ def update_pr(self, comment_text: str, args: FormatArgs, create_new: bool) -> No
         comment_text = self.comment_tag + "\n\n" + comment_text
 
         existing_comment = self.find_comment(pr)
+
+        if args.write_comment_to_file:
+            self.comment = {
+                'number' : pr.number,
+                'body' : comment_text
+            }
+            if existing_comment:
+                self.comment['id'] =  existing_comment.id
+            return
+
         if existing_comment:
             existing_comment.edit(comment_text)
         elif create_new:
@@ -309,6 +323,8 @@ def hook_main():
         if fmt.has_tool():
             if not fmt.run(args.changed_files, args):
                 failed_fmts.append(fmt.name)
+            if fmt.comment:
+              comments.append(fmt.comment)
         else:
             print(f"Couldn't find {fmt.name}, can't check " + fmt.friendly_name.lower())
 
@@ -349,6 +365,10 @@ def hook_main():
         type=str,
         help="Comma separated list of files that has been changed",
     )
+    parser.add_argument(
+        "--write-comment-to-file",
+        action='store_true',
+        help="Don't create a comments on the PR, instead write the comments and metadata a file called 'comment'"   )
 
     args = FormatArgs(parser.parse_args())
 
@@ -357,9 +377,17 @@ def hook_main():
         changed_files = args.changed_files.split(",")
 
     failed_formatters = []
+    comments = []
     for fmt in ALL_FORMATTERS:
         if not fmt.run(changed_files, args):
             failed_formatters.append(fmt.name)
+        if fmt.comment:
+            comments.append(fmt.comment)
+    
+    if len(comments):
+        with open('comments', 'w') as f:
+            import json
+            json.dump(comments, f)
 
     if len(failed_formatters) > 0:
         print(f"error: some formatters failed: {' '.join(failed_formatters)}")

>From 1ed78230a2cb6cc8b61448ad676cac3a5f239959 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Sat, 13 Jan 2024 16:19:59 -0800
Subject: [PATCH 03/10] XXX: Debug

---
 .github/workflows/pr-code-format.yml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml
index 1475d872498d49..9958ecb9c6f061 100644
--- a/.github/workflows/pr-code-format.yml
+++ b/.github/workflows/pr-code-format.yml
@@ -4,7 +4,6 @@ on: pull_request
 jobs:
   code_formatter:
     runs-on: ubuntu-latest
-    if: github.repository == 'llvm/llvm-project'
     steps:
       - name: Fetch LLVM sources
         uses: actions/checkout at v4

>From 59d4a17f76efa9055fed9ced2f0dfad85d4ccf1d Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Sat, 13 Jan 2024 16:16:30 -0800
Subject: [PATCH 04/10] [workflows] Split pr-code-format into two parts to make
 it more secure

Actions triggered by pull_request_target events have access to all
repository secrets, so it is unsafe to use them when executing
untrusted code.  The pr-code-format workflow does not execute
any untrusted code, but it passes untrused input into clang-format.
An attacker could use this to exploit a flaw in clang-format and
potentially gain access to the repository secrets.

By splitting the workflow, we can use the pull_request target which
is more secure and isolate the issue write permissions in a separate
job.  The pull_request target also makes it easier to test changes
to the code-format-helepr.py script, because the version of the
script from the pull request will be used rather than the
version of the script from main.

Fixes #77142
---
 .github/workflows/issue-write.yml    | 72 ++++++++++++++++++++++++++++
 .github/workflows/pr-code-format.yml | 30 +++++-------
 llvm/utils/git/code-format-helper.py | 27 +++++++++++
 3 files changed, 111 insertions(+), 18 deletions(-)
 create mode 100644 .github/workflows/issue-write.yml

diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml
new file mode 100644
index 00000000000000..acc625a3e02a3d
--- /dev/null
+++ b/.github/workflows/issue-write.yml
@@ -0,0 +1,72 @@
+name: Comment on an issue
+
+on:
+  workflow_run:
+    workflows: ["Check code formatting"]
+    types:
+      - completed
+
+permissions:
+  contents: read
+
+jobs:
+  pr-comment:
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: write
+    if: >
+      github.event.workflow_run.event == 'pull_request'
+    steps:
+      - name: 'Download artifact'
+        # v7.0.1
+        uses: actions/github-script at 60a0d83039c74a4aee543508d2ffcb1c3799cdea
+        with:
+          script: |
+            let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
+               owner: context.repo.owner,
+               repo: context.repo.repo,
+               run_id: context.payload.workflow_run.id,
+            });
+            let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
+              return artifact.name == "workflow-args"
+            })[0];
+            let download = await github.rest.actions.downloadArtifact({
+               owner: context.repo.owner,
+               repo: context.repo.repo,
+               artifact_id: matchArtifact.id,
+               archive_format: 'zip',
+            });
+            let fs = require('fs');
+            fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/workflow-args.zip`, Buffer.from(download.data));
+
+      - run: unzip workflow-args.zip
+
+      - name: 'Comment on PR'
+        uses: actions/github-script at v3
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          script: |
+            var fs = require('fs');
+            const comments = JSON.parse(fs.readFileSync('./comments'));
+            if (!comments) {
+              return;
+            }
+            console.log(comments);
+            await comments.forEach(function (comment) {
+              if (comment.id) {
+                github.issues.updateComment({
+                  owner: context.repo.owner,
+                  repo: context.repo.repo,
+                  issue_number: comment.number,
+                  comment_id: comment.id,
+                  body: comment.body
+                });
+              } else {
+                github.issues.createComment({
+                  owner: context.repo.owner,
+                  repo: context.repo.repo,
+                  issue_number: comment.number,
+                  body: comment.body
+                });
+              }
+            });
diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml
index 5223089ee8a93d..1475d872498d49 100644
--- a/.github/workflows/pr-code-format.yml
+++ b/.github/workflows/pr-code-format.yml
@@ -1,7 +1,5 @@
 name: "Check code formatting"
-on: pull_request_target
-permissions:
-  pull-requests: write
+on: pull_request
 
 jobs:
   code_formatter:
@@ -27,18 +25,6 @@ jobs:
           separator: ","
           skip_initial_fetch: true
 
-      # We need to make sure that we aren't executing/using any code from the
-      # PR for security reasons as we're using pull_request_target. Checkout
-      # the target branch with the necessary files.
-      - name: Fetch code formatting utils
-        uses: actions/checkout at v4
-        with:
-          sparse-checkout: |
-            llvm/utils/git/requirements_formatting.txt
-            llvm/utils/git/code-format-helper.py
-          sparse-checkout-cone-mode: false
-          path: code-format-tools
-
       - name: "Listed files"
         env:
           CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
@@ -56,10 +42,10 @@ jobs:
         with:
           python-version: '3.11'
           cache: 'pip'
-          cache-dependency-path: 'code-format-tools/llvm/utils/git/requirements_formatting.txt'
+          cache-dependency-path: 'llvm/utils/git/requirements_formatting.txt'
 
       - name: Install python dependencies
-        run: pip install -r code-format-tools/llvm/utils/git/requirements_formatting.txt
+        run: pip install -r llvm/utils/git/requirements_formatting.txt
 
       - name: Run code formatter
         env:
@@ -72,9 +58,17 @@ jobs:
         # explicitly in code-format-helper.py and not have to diff starting at
         # the merge base.
         run: |
-          python ./code-format-tools/llvm/utils/git/code-format-helper.py \
+          python ./llvm/utils/git/code-format-helper.py \
+            --write-comment-to-file \
             --token ${{ secrets.GITHUB_TOKEN }} \
             --issue-number $GITHUB_PR_NUMBER \
             --start-rev $(git merge-base $START_REV $END_REV) \
             --end-rev $END_REV \
             --changed-files "$CHANGED_FILES"
+
+      - uses: actions/upload-artifact at v2
+        if: always()
+        with:
+          name: workflow-args
+          path: |
+            comments
diff --git a/llvm/utils/git/code-format-helper.py b/llvm/utils/git/code-format-helper.py
index 8a29a57d8d16bd..f96c9da586dfcc 100755
--- a/llvm/utils/git/code-format-helper.py
+++ b/llvm/utils/git/code-format-helper.py
@@ -44,6 +44,7 @@ class FormatArgs:
     token: str = None
     verbose: bool = True
     issue_number: int = 0
+    write_comment_to_file: bool = False
 
     def __init__(self, args: argparse.Namespace = None) -> None:
         if not args is None:
@@ -53,12 +54,14 @@ def __init__(self, args: argparse.Namespace = None) -> None:
             self.token = args.token
             self.changed_files = args.changed_files
             self.issue_number = args.issue_number
+            self.write_comment_to_file = args.write_comment_to_file
 
 
 class FormatHelper:
     COMMENT_TAG = "<!--LLVM CODE FORMAT COMMENT: {fmt}-->"
     name: str
     friendly_name: str
+    comment: dict = None
 
     @property
     def comment_tag(self) -> str:
@@ -119,6 +122,16 @@ def update_pr(self, comment_text: str, args: FormatArgs, create_new: bool) -> No
         comment_text = self.comment_tag + "\n\n" + comment_text
 
         existing_comment = self.find_comment(pr)
+
+        if args.write_comment_to_file:
+            self.comment = {
+                'number' : pr.number,
+                'body' : comment_text
+            }
+            if existing_comment:
+                self.comment['id'] =  existing_comment.id
+            return
+
         if existing_comment:
             existing_comment.edit(comment_text)
         elif create_new:
@@ -309,6 +322,8 @@ def hook_main():
         if fmt.has_tool():
             if not fmt.run(args.changed_files, args):
                 failed_fmts.append(fmt.name)
+            if fmt.comment:
+              comments.append(fmt.comment)
         else:
             print(f"Couldn't find {fmt.name}, can't check " + fmt.friendly_name.lower())
 
@@ -349,6 +364,10 @@ def hook_main():
         type=str,
         help="Comma separated list of files that has been changed",
     )
+    parser.add_argument(
+        "--write-comment-to-file",
+        action='store_true',
+        help="Don't create a comments on the PR, instead write the comments and metadata a file called 'comment'"   )
 
     args = FormatArgs(parser.parse_args())
 
@@ -357,9 +376,17 @@ def hook_main():
         changed_files = args.changed_files.split(",")
 
     failed_formatters = []
+    comments = []
     for fmt in ALL_FORMATTERS:
         if not fmt.run(changed_files, args):
             failed_formatters.append(fmt.name)
+        if fmt.comment:
+            comments.append(fmt.comment)
+    
+    if len(comments):
+        with open('comments', 'w') as f:
+            import json
+            json.dump(comments, f)
 
     if len(failed_formatters) > 0:
         print(f"error: some formatters failed: {' '.join(failed_formatters)}")

>From 24256f6fd0441212fb849e8694e3cae1c36bb620 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Thu, 18 Jan 2024 17:05:34 -0800
Subject: [PATCH 05/10] Update issue templates

---
 .github/ISSUE_TEMPLATE/custom.md | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100644 .github/ISSUE_TEMPLATE/custom.md

diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md
new file mode 100644
index 00000000000000..b0ea96e64e4984
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/custom.md
@@ -0,0 +1,10 @@
+---
+name: Custom issue template
+about: Describe this issue template's purpose here.
+title: ''
+labels: bug
+assignees: tstellar
+
+---
+
+

>From 54ff65dcac32bbd51d472e881f2baabce2297be3 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Thu, 18 Jan 2024 17:17:44 -0800
Subject: [PATCH 06/10] Create config.yml

---
 .github/ISSUE_TEMPLATE/config.yml | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 .github/ISSUE_TEMPLATE/config.yml

diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000000000..0086358db1eb97
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1 @@
+blank_issues_enabled: true

>From dc39cb9e40c98fbe9746d29cb10921833ace5f24 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Thu, 18 Jan 2024 17:27:00 -0800
Subject: [PATCH 07/10] Create custom.md

---
 .github/custom.md | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 .github/custom.md

diff --git a/.github/custom.md b/.github/custom.md
new file mode 100644
index 00000000000000..757028b89fa0a2
--- /dev/null
+++ b/.github/custom.md
@@ -0,0 +1,8 @@
+---
+name: Custom issue template
+about: Describe this issue template's purpose here.
+title: ''
+labels: bug
+assignees: tstellar
+
+---

>From b74d29524cea2be4608080b48610a6726dee087e Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Thu, 18 Jan 2024 17:27:30 -0800
Subject: [PATCH 08/10] Create main.md

---
 .github/ISSUE_TEMPLATE/hidden/main.md | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 .github/ISSUE_TEMPLATE/hidden/main.md

diff --git a/.github/ISSUE_TEMPLATE/hidden/main.md b/.github/ISSUE_TEMPLATE/hidden/main.md
new file mode 100644
index 00000000000000..757028b89fa0a2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/hidden/main.md
@@ -0,0 +1,8 @@
+---
+name: Custom issue template
+about: Describe this issue template's purpose here.
+title: ''
+labels: bug
+assignees: tstellar
+
+---

>From f0986cb226bcc602970c9be9a378529c0d597aaf Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Thu, 18 Jan 2024 17:28:23 -0800
Subject: [PATCH 09/10] Update custom.md

---
 .github/ISSUE_TEMPLATE/custom.md | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md
index b0ea96e64e4984..8b137891791fe9 100644
--- a/.github/ISSUE_TEMPLATE/custom.md
+++ b/.github/ISSUE_TEMPLATE/custom.md
@@ -1,10 +1 @@
----
-name: Custom issue template
-about: Describe this issue template's purpose here.
-title: ''
-labels: bug
-assignees: tstellar
-
----
-
 

>From 9a0012c21ff02ec826f25e13583843eb404f13b4 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Fri, 19 Jan 2024 22:26:05 -0800
Subject: [PATCH 10/10] Dump comments file to make debugging easier

---
 .github/workflows/issue-write.yml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml
index acc625a3e02a3d..b3bfd12058d529 100644
--- a/.github/workflows/issue-write.yml
+++ b/.github/workflows/issue-write.yml
@@ -70,3 +70,7 @@ jobs:
                 });
               }
             });
+
+      - name: Dump comments file
+        if: always()
+        run: cat comments



More information about the cfe-commits mailing list