xref: /llvm-project/.github/workflows/issue-write.yml (revision 56ffbd97fda16008d02180a460211829354f1094)
1name: Comment on an issue
2
3on:
4  workflow_run:
5    workflows:
6      - "Check code formatting"
7      - "Check for private emails used in PRs"
8      - "PR Request Release Note"
9    types:
10      - completed
11
12permissions:
13  contents: read
14
15jobs:
16  pr-comment:
17    runs-on: ubuntu-latest
18    permissions:
19      pull-requests: write
20    if: >
21      github.event.workflow_run.event == 'pull_request' &&
22      (
23        github.event.workflow_run.conclusion == 'success' ||
24        github.event.workflow_run.conclusion == 'failure'
25      )
26    steps:
27      - name: Fetch Sources
28        uses: actions/checkout@v4
29        with:
30          sparse-checkout: |
31            .github/workflows/unprivileged-download-artifact/action.yml
32          sparse-checkout-cone-mode: false
33      - name: 'Download artifact'
34        uses: ./.github/workflows/unprivileged-download-artifact
35        id: download-artifact
36        with:
37          run-id: ${{ github.event.workflow_run.id }}
38          artifact-name: workflow-args
39
40      - name: 'Comment on PR'
41        if: steps.download-artifact.outputs.artifact-id != ''
42        uses: actions/github-script@v3
43        with:
44          github-token: ${{ secrets.GITHUB_TOKEN }}
45          script: |
46            var fs = require('fs');
47            const comments = JSON.parse(fs.readFileSync('./comments'));
48            if (!comments || comments.length == 0) {
49              return;
50            }
51
52            let runInfo = await github.actions.getWorkflowRun({
53              owner: context.repo.owner,
54              repo: context.repo.repo,
55              run_id: context.payload.workflow_run.id
56            });
57
58            console.log(runInfo);
59
60
61            // Query to find the number of the pull request that triggered this job.
62            // The associated pull requests are based off of the branch name, so if
63            // you create a pull request for a branch, close it, and then create
64            // another pull request with the same branch, then this query will return
65            // two associated pull requests.  This is why we have to fetch all the
66            // associated pull requests and then iterate through them to find the
67            // one that is open.
68            const gql_query = `
69              query($repo_owner : String!, $repo_name : String!, $branch: String!) {
70                repository(owner: $repo_owner, name: $repo_name) {
71                  ref (qualifiedName: $branch) {
72                    associatedPullRequests(first: 100) {
73                      nodes {
74                        baseRepository {
75                          owner {
76                            login
77                          }
78                        }
79                        number
80                        state
81                      }
82                    }
83                  }
84                }
85              }
86            `
87            const gql_variables = {
88              repo_owner: runInfo.data.head_repository.owner.login,
89              repo_name: runInfo.data.head_repository.name,
90              branch: runInfo.data.head_branch
91            }
92            const gql_result = await github.graphql(gql_query, gql_variables);
93            console.log(gql_result);
94            // If the branch for the PR was deleted before this job has a chance
95            // to run, then the ref will be null.  This can happen if someone:
96            // 1. Rebase the PR, which triggers some workflow.
97            // 2. Immediately merges the PR and deletes the branch.
98            // 3. The workflow finishes and triggers this job.
99            if (!gql_result.repository.ref) {
100              console.log("Ref has been deleted");
101              return;
102            }
103            console.log(gql_result.repository.ref.associatedPullRequests.nodes);
104
105            var pr_number = 0;
106            gql_result.repository.ref.associatedPullRequests.nodes.forEach((pr) => {
107
108              // The largest PR number is the one we care about.  The only way
109              // to have more than one associated pull requests is if all the
110              // old pull requests are in the closed state.
111              if (pr.baseRepository.owner.login = context.repo.owner && pr.number > pr_number) {
112                pr_number = pr.number;
113              }
114            });
115            if (pr_number == 0) {
116              console.log("Error retrieving pull request number");
117              return;
118            }
119
120            await comments.forEach(function (comment) {
121              if (comment.id) {
122                // Security check: Ensure that this comment was created by
123                // the github-actions bot, so a malicious input won't overwrite
124                // a user's comment.
125                github.issues.getComment({
126                  owner: context.repo.owner,
127                  repo: context.repo.repo,
128                  comment_id: comment.id
129                }).then((old_comment) => {
130                  console.log(old_comment);
131                  if (old_comment.data.user.login != "github-actions[bot]") {
132                    console.log("Invalid comment id: " + comment.id);
133                    return;
134                  }
135                  github.issues.updateComment({
136                    owner: context.repo.owner,
137                    repo: context.repo.repo,
138                    issue_number: pr_number,
139                    comment_id: comment.id,
140                    body: comment.body
141                  });
142                });
143              } else {
144                github.issues.createComment({
145                  owner: context.repo.owner,
146                  repo: context.repo.repo,
147                  issue_number: pr_number,
148                  body: comment.body
149                });
150              }
151            });
152
153      - name: Dump comments file
154        if: >-
155          always() &&
156          steps.download-artifact.outputs.artifact-id != ''
157        run: cat comments
158