Skip to content

Commit 92085c3

Browse files
committed
Add pr-comment-on-release functionality.
1 parent fb2ba2a commit 92085c3

File tree

2 files changed

+158
-38
lines changed

2 files changed

+158
-38
lines changed

README.yaml

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66

77
# Name of this project
8-
name: example-github-action-composite
8+
name: pr-comment-on-release
99

1010
# Tags of this project
1111
tags:
@@ -18,7 +18,7 @@ tags:
1818
license: "APACHE2"
1919

2020
# Canonical GitHub repo
21-
github_repo: cloudposse/example-github-action-composite
21+
github_repo: cloudposse-github-actions/pr-comment-on-release
2222

2323
# Badges to display
2424
badges:
@@ -32,47 +32,49 @@ badges:
3232
related: []
3333

3434
# Short description of this project
35-
description: Template repository of composite GitHub Action
35+
description: Comments on a (merged) PR when it is included in a GitHub release.
3636

3737
introduction: |-
38-
This is template repository to create composite GitHub Actions.
39-
Feel free to use it as reference and starting point.
38+
This composite action comments on a (merged) Pull Request when it is included in a GitHub release.
4039
4140
references:
42-
- name: "github-actions-workflows"
41+
- name: "cloudposse-github-actions"
4342
description: "Reusable workflows for different types of projects"
44-
url: "https://github.com/cloudposse/github-actions-workflows"
45-
- name: "example-github-action-release-workflow"
43+
url: "https://github.com/cloudposse-github-actions"
44+
- name: "pr-comment-on-release"
4645
description: "Example application with complicated release workflow"
47-
url: "https://github.com/cloudposse/example-github-action-release-workflow"
46+
url: "https://github.com/cloudposse-github-actions/pr-comment-on-release"
4847

4948
# How to use this project
5049
usage: |-
5150
```yaml
52-
name: Pull Request
51+
name: PR Comment on Release
52+
5353
on:
54-
pull_request:
55-
branches: [ 'main' ]
56-
types: [opened, synchronize, reopened, closed, labeled, unlabeled]
54+
release:
55+
types: [published]
56+
57+
permissions:
58+
deployments: write
59+
id-token: write
60+
contents: write
61+
pull-requests: write
5762
5863
jobs:
5964
context:
6065
runs-on: ubuntu-latest
6166
steps:
62-
- name: Example action
63-
uses: cloudposse/example-github-action-composite@main
64-
id: example
67+
- name: Comment on Release
68+
uses: cloudposse-github-actions/pr-comment-on-release
69+
id: pr-comment-on-release
6570
with:
66-
param1: true
67-
68-
outputs:
69-
result: ${{ steps.example.outputs.result1 }}
71+
retries: 5 # Override number of retries
7072
```
7173
7274
include:
7375
- "docs/github-action.md"
7476

7577
# Contributors to this project
7678
contributors:
77-
- name: "Igor Rodionov"
78-
github: "goruha"
79+
- name: "Yoni Koren"
80+
github: "korenyoni"

action.yml

Lines changed: 134 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,141 @@
1-
name: 'Example composite GitHub action'
2-
description: 'Example composite GitHub action'
1+
name: "PR Comment on Release"
2+
description: "Comments on a (merged) PR when it is included in a GitHub release."
33
author: hello@cloudposse.com
44
branding:
5-
icon: 'file'
6-
color: 'white'
5+
icon: "file"
6+
color: "white"
77
inputs:
8-
param1:
9-
required: true
10-
description: "Input parameter placeholder"
11-
default: "true"
12-
outputs:
13-
result1:
14-
description: "Output result placeholder"
15-
value: "${{ steps.context.outputs.action-result }}"
8+
retries:
9+
required: false
10+
description: "Number of retries"
11+
default: "3"
1612
runs:
1713
using: "composite"
1814
steps:
19-
- id: context
20-
shell: bash
21-
run: |
22-
echo "action-result=${{ inputs.param1 }}" >> $GITHUB_OUTPUT
15+
- uses: actions/github-script@v7
16+
with:
17+
result-encoding: string
18+
retries: 3
19+
script: |
20+
// Function to check if a value is unique in an array
21+
function onlyUnique(value, index, array) {
22+
return array.indexOf(value) === index;
23+
}
2324
25+
// Function to create or update a comment for a pull request (PR) associated with a release
26+
async function createCommentForPR(pr_id, release) {
27+
// Parameters for fetching comments related to the PR
28+
const parameters = {
29+
owner: context.repo.owner,
30+
repo: context.repo.repo,
31+
issue_number: pr_id,
32+
per_page: 100,
33+
}
34+
35+
// Constructing the message to be posted or updated as a comment
36+
const messageId = `<!-- release-pr-comment:${release.id} -->`;
37+
const message = `
38+
${messageId}
39+
These changes were released in [${release.name}](${release.html_url}).
40+
`;
41+
42+
// Сreate a new comment
43+
await github.rest.issues.createComment({
44+
owner: context.repo.owner,
45+
repo: context.repo.repo,
46+
issue_number: pr_id,
47+
body: message
48+
});
49+
}
50+
51+
// Retrieving the ID of the current release
52+
release_id = context.payload.release.id;
53+
54+
// Fetching details of the current release
55+
currentReleaseResponse = await github.rest.repos.getRelease({
56+
owner: context.repo.owner,
57+
repo: context.repo.repo,
58+
release_id,
59+
});
60+
61+
currentRelease = currentReleaseResponse.data;
62+
63+
// Extracting tag name and target branch from the current release
64+
currentTag = currentRelease.tag_name;
65+
currentBranch = currentRelease.target_commitish;
66+
67+
// Listing all releases of the repository
68+
releases = await github.rest.repos.listReleases({
69+
owner: context.repo.owner,
70+
repo: context.repo.repo,
71+
});
72+
73+
// Initializing variables for storing information about the previous release
74+
previousRelease = null;
75+
currentReleaseFound = false;
76+
77+
// Iterating through releases to find the previous release relative to the current one
78+
for (release of releases.data) {
79+
if (currentReleaseFound) {
80+
previousRelease = release;
81+
break;
82+
} else if (release.tag_name == currentTag) {
83+
currentReleaseFound = true;
84+
}
85+
}
86+
87+
// If no previous release is found, log a message and return
88+
if (previousRelease == null) {
89+
console.log(`No previous release found for ${currentTag}`);
90+
return;
91+
}
92+
93+
// Comparing commits between the current and previous releases
94+
commitsResponse = await github.rest.repos.compareCommits({
95+
owner: context.repo.owner,
96+
repo: context.repo.repo,
97+
base: previousRelease.tag_name,
98+
head: currentRelease.tag_name,
99+
});
100+
101+
commits = commitsResponse.data;
102+
103+
// Initializing an array to store pull request numbers associated with the commits
104+
pull_requests = [];
105+
106+
// Iterating through commits to find associated pull requests and extracting their numbers
107+
for (commit of commits.commits) {
108+
responseCommit = await github.rest.git.getCommit({
109+
owner: context.repo.owner,
110+
repo: context.repo.repo,
111+
commit_sha: commit.sha,
112+
});
113+
114+
// GraphQL query to fetch details about the commit, including associated pull requests
115+
const query = `
116+
{
117+
resource(url: "${context.payload.repository.html_url}/commit/${commit.sha}") {
118+
... on Commit {
119+
messageHeadlineHTML
120+
messageBodyHTML
121+
associatedPullRequests(first: 10) {
122+
pageInfo { hasNextPage }
123+
edges { node { number } }
124+
}
125+
}
126+
}
127+
}
128+
`;
129+
130+
response = await github.graphql(query);
131+
132+
// Extracting pull request numbers from the GraphQL response
133+
for (edge of response.resource.associatedPullRequests.edges) {
134+
pull_requests.push(edge.node.number);
135+
}
136+
}
137+
138+
// Iterating through unique pull request numbers and creating or updating comments for them
139+
for (id of pull_requests.filter(onlyUnique)) {
140+
await createCommentForPR(id, currentRelease);
141+
}

0 commit comments

Comments
 (0)