Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 039ebde

Browse files
committedJul 13, 2022
chore(ci): make export PR reusable
Signed-off-by: heitorlessa <[email protected]>
1 parent 483c638 commit 039ebde

10 files changed

+234
-193
lines changed
 
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module.exports = async ({github, context, core}) => {
2+
const fs = require('fs');
3+
4+
const workflowRunId = process.env.WORKFLOW_ID;
5+
core.info(`Listing artifacts for workflow run ${workflowRunId}`);
6+
7+
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
8+
owner: context.repo.owner,
9+
repo: context.repo.repo,
10+
run_id: workflowRunId,
11+
});
12+
13+
const matchArtifact = artifacts.data.artifacts.filter(artifact => artifact.name == "pr")[0];
14+
15+
core.info(`Downloading artifacts for workflow run ${workflowRunId}`);
16+
const artifact = await github.rest.actions.downloadArtifact({
17+
owner: context.repo.owner,
18+
repo: context.repo.repo,
19+
artifact_id: matchArtifact.id,
20+
archive_format: 'zip',
21+
});
22+
23+
core.info("Saving artifact found", artifact);
24+
25+
fs.writeFileSync('pr.zip', Buffer.from(artifact.data));
26+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module.exports = async ({github, context, core}) => {
2+
const prBody = process.env.PR_BODY;
3+
const prNumber = process.env.PR_NUMBER;
4+
const blockLabel = process.env.BLOCK_LABEL;
5+
const blockReasonLabel = process.env.BLOCK_REASON_LABEL;
6+
7+
const RELATED_ISSUE_REGEX = /Issue number:[^\d\r\n]+(?<issue>\d+)/;
8+
9+
const isMatch = RELATED_ISSUE_REGEX.exec(prBody);
10+
if (isMatch == null) {
11+
core.info(`No related issue found, maybe the author didn't use the template but there is one.`)
12+
13+
let msg = "No related issues found. Please ensure there is an open issue related to this change to avoid significant delays or closure.";
14+
await github.rest.issues.createComment({
15+
owner: context.repo.owner,
16+
repo: context.repo.repo,
17+
body: msg,
18+
issue_number: prNumber,
19+
});
20+
21+
return await github.rest.issues.addLabels({
22+
issue_number: prNumber,
23+
owner: context.repo.owner,
24+
repo: context.repo.repo,
25+
labels: [blockLabel, blockReasonLabel]
26+
})
27+
}
28+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module.exports = async ({github, context, core}) => {
2+
const pr_number = process.env.PR_NUMBER
3+
const pr_title = process.env.PR_TITLE
4+
5+
console.log(pr_title)
6+
7+
const FEAT_REGEX = /feat(\((.+)\))?(\:.+)/
8+
const BUG_REGEX = /(fix|bug)(\((.+)\))?(\:.+)/
9+
const DOCS_REGEX = /(docs|doc)(\((.+)\))?(\:.+)/
10+
const CHORE_REGEX = /(chore)(\((.+)\))?(\:.+)/
11+
const DEPRECATED_REGEX = /(deprecated)(\((.+)\))?(\:.+)/
12+
const REFACTOR_REGEX = /(refactor)(\((.+)\))?(\:.+)/
13+
14+
const labels = {
15+
"feature": FEAT_REGEX,
16+
"bug": BUG_REGEX,
17+
"documentation": DOCS_REGEX,
18+
"internal": CHORE_REGEX,
19+
"enhancement": REFACTOR_REGEX,
20+
"deprecated": DEPRECATED_REGEX,
21+
}
22+
23+
for (const label in labels) {
24+
const matcher = new RegExp(labels[label])
25+
const isMatch = matcher.exec(pr_title)
26+
if (isMatch != null) {
27+
console.info(`Auto-labeling PR ${pr_number} with ${label}`)
28+
29+
await github.rest.issues.addLabels({
30+
issue_number: pr_number,
31+
owner: context.repo.owner,
32+
repo: context.repo.repo,
33+
labels: [label]
34+
})
35+
36+
break
37+
}
38+
}
39+
}

‎.github/scripts/label_related_issue.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
module.exports = async ({github, context, core}) => {
2-
const prBody = context.payload.body;
3-
const prNumber = context.payload.number;
2+
const prBody = process.env.PR_BODY;
3+
const prNumber = process.env.PR_NUMBER;
44
const releaseLabel = process.env.RELEASE_LABEL;
5-
const maintainersTeam = process.env.MAINTAINERS_TEAM
6-
5+
const maintainersTeam = process.env.MAINTAINERS_TEAM;
76
const RELATED_ISSUE_REGEX = /Issue number:[^\d\r\n]+(?<issue>\d+)/;
87

8+
core.info(prBody);
99
const isMatch = RELATED_ISSUE_REGEX.exec(prBody);
1010
if (!isMatch) {
1111
core.setFailed(`Unable to find related issue for PR number ${prNumber}.\n\n Body details: ${prBody}`);

‎.github/workflows/export_pr_details.yml

Lines changed: 0 additions & 75 deletions
This file was deleted.

‎.github/workflows/label_pr_on_title.yml

Lines changed: 19 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,86 +2,36 @@ name: Label PR based on title
22

33
on:
44
workflow_run:
5-
workflows: ["Record PR number"]
5+
workflows: ["Record PR details"]
66
types:
77
- completed
88

99
jobs:
10-
upload:
11-
runs-on: ubuntu-latest
10+
get_pr_details:
1211
# Guardrails to only ever run if PR recording workflow was indeed
1312
# run in a PR event and ran successfully
14-
if: >
15-
${{ github.event.workflow_run.event == 'pull_request' &&
16-
github.event.workflow_run.conclusion == 'success' }}
13+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
14+
uses: ./.github/workflows/reusable_export_pr_details.yml
15+
with:
16+
record_pr_workflow_id: ${{ github.event.workflow_run.id }}
17+
secrets:
18+
token: ${{ secrets.GITHUB_TOKEN }}
19+
label_pr:
20+
needs: get_pr_details
21+
runs-on: ubuntu-latest
1722
steps:
18-
- name: 'Download artifact'
19-
uses: actions/github-script@v6
20-
# For security, we only download artifacts tied to the successful PR recording workflow
21-
with:
22-
script: |
23-
const fs = require('fs');
24-
25-
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
26-
owner: context.repo.owner,
27-
repo: context.repo.repo,
28-
run_id: ${{github.event.workflow_run.id }},
29-
});
30-
31-
const matchArtifact = artifacts.data.artifacts.filter(artifact => artifact.name == "pr")[0];
32-
33-
const artifact = await github.rest.actions.downloadArtifact({
34-
owner: context.repo.owner,
35-
repo: context.repo.repo,
36-
artifact_id: matchArtifact.id,
37-
archive_format: 'zip',
38-
});
39-
40-
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(artifact.data));
41-
# NodeJS standard library doesn't provide ZIP capabilities; use system `unzip` command instead
42-
- run: unzip pr.zip
43-
44-
- name: 'Label PR based on title'
23+
- name: Checkout repository
24+
uses: actions/checkout@v3
25+
- name: "Label PR based on title"
4526
uses: actions/github-script@v6
27+
env:
28+
PR_NUMBER: ${{ needs.get_pr_details.outputs.prNumber }}
29+
PR_TITLE: ${{ needs.get_pr_details.outputs.prTitle }}
4630
with:
4731
github-token: ${{ secrets.GITHUB_TOKEN }}
4832
# This safely runs in our base repo, not on fork
4933
# thus allowing us to provide a write access token to label based on PR title
5034
# and label PR based on semantic title accordingly
5135
script: |
52-
const fs = require('fs');
53-
const pr_number = Number(fs.readFileSync('./number'));
54-
const pr_title = fs.readFileSync('./title', 'utf-8').trim();
55-
56-
const FEAT_REGEX = /feat(\((.+)\))?(\:.+)/
57-
const BUG_REGEX = /(fix|bug)(\((.+)\))?(\:.+)/
58-
const DOCS_REGEX = /(docs|doc)(\((.+)\))?(\:.+)/
59-
const CHORE_REGEX = /(chore)(\((.+)\))?(\:.+)/
60-
const DEPRECATED_REGEX = /(deprecated)(\((.+)\))?(\:.+)/
61-
const REFACTOR_REGEX = /(refactor)(\((.+)\))?(\:.+)/
62-
63-
const labels = {
64-
"feature": FEAT_REGEX,
65-
"bug": BUG_REGEX,
66-
"documentation": DOCS_REGEX,
67-
"internal": CHORE_REGEX,
68-
"enhancement": REFACTOR_REGEX,
69-
"deprecated": DEPRECATED_REGEX,
70-
}
71-
72-
for (const label in labels) {
73-
const matcher = new RegExp(labels[label])
74-
const isMatch = matcher.exec(pr_title)
75-
if (isMatch != null) {
76-
console.info(`Auto-labeling PR ${pr_number} with ${label}`)
77-
78-
await github.rest.issues.addLabels({
79-
issue_number: pr_number,
80-
owner: context.repo.owner,
81-
repo: context.repo.repo,
82-
labels: [label]
83-
})
84-
85-
break
86-
}
87-
}
36+
const script = require('.github/scripts/label_pr_based_on_title.js')
37+
await script({github, context, core})

‎.github/workflows/on_merged_pr.yml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,37 @@
1-
# Maintenance: Verify why we're having permissions issues even with write scope, then re-enable it.
2-
# logs: https://github.com/awslabs/aws-lambda-powertools-python/runs/7030238348?check_suite_focus=true
1+
name: On PR merge
32

43
on:
5-
pull_request:
4+
workflow_run:
5+
workflows: ["Record PR details"]
66
types:
7-
- closed
7+
- completed
88

99
env:
1010
RELEASE_LABEL: "pending-release"
1111
MAINTAINERS_TEAM: "@awslabs/aws-lambda-powertools-python"
1212

1313
jobs:
14+
get_pr_details:
15+
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
16+
uses: ./.github/workflows/reusable_export_pr_details.yml
17+
with:
18+
record_pr_workflow_id: ${{ github.event.workflow_run.id }}
19+
secrets:
20+
token: ${{ secrets.GITHUB_TOKEN }}
1421
release_label_on_merge:
15-
if: github.event.pull_request.merged == true && github.event.pull_request.user.login != 'dependabot[bot]'
22+
needs: get_pr_details
23+
# Maintenance: Conditional isn't working as expected
24+
if: |
25+
needs.get_pr_details.outputs.prAuthor != 'dependabot[bot]'
26+
&& needs.get_pr_details.outputs.prIsMerged == true
1627
runs-on: ubuntu-latest
17-
permissions:
18-
issues: write # required for new scoped token
19-
pull-requests: write # required for new scoped token
2028
steps:
2129
- uses: actions/checkout@v3
2230
- name: "Label PR related issue for release"
2331
uses: actions/github-script@v6
32+
env:
33+
PR_NUMBER: ${{ needs.get_pr_details.outputs.prNumber }}
34+
PR_BODY: ${{ needs.get_pr_details.outputs.prBody }}
2435
with:
2536
github-token: ${{ secrets.GITHUB_TOKEN }}
2637
script: |

‎.github/workflows/on_opened_pr.yml

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,40 @@
1+
name: On PR open
2+
13
on:
24
workflow_run:
3-
workflows: ["Record PR number"]
5+
workflows: ["Record PR details"]
46
types:
57
- completed
68

79
env:
810
BLOCK_LABEL: "do-not-merge"
911
BLOCK_REASON_LABEL: "need-issue"
12+
IGNORE_AUTHORS: '["dependabot[bot]", "markdownify[bot]"]'
1013

1114
jobs:
1215
get_pr_details:
13-
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
14-
uses: ./.github/workflows/export_pr_details.yml
16+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
17+
uses: ./.github/workflows/reusable_export_pr_details.yml
1518
with:
1619
record_pr_workflow_id: ${{ github.event.workflow_run.id }}
1720
secrets:
1821
token: ${{ secrets.GITHUB_TOKEN }}
1922
check_related_issue:
2023
needs: get_pr_details
21-
if: >
22-
${{ needs.get_pr_details.outputs.prAuthor != 'dependabot[bot]' &&
23-
needs.get_pr_details.outputs.prAction == 'opened'
24-
}}
24+
# Maintenance: Refactor condition to the correct env syntax later
25+
if: |
26+
needs.get_pr_details.outputs.prAction == 'opened'
27+
&& contains(fromJson('["dependabot[bot]", "markdownify[bot]"]'), needs.get_pr_details.outputs.prAuthor) != true
2528
runs-on: ubuntu-latest
2629
steps:
30+
- uses: actions/checkout@v3
2731
- name: "Ensure related issue is present"
2832
uses: actions/github-script@v6
33+
env:
34+
PR_BODY: ${{ needs.get_pr_details.outputs.prBody }}
35+
PR_NUMBER: ${{ needs.get_pr_details.outputs.prNumber }}
2936
with:
3037
github-token: ${{ secrets.GITHUB_TOKEN }}
31-
# Maintenance: convert into a standalone JS like post_release.js
3238
script: |
33-
const prBody = "${{ needs.get_pr_details.outputs.prBody }}";
34-
const prNumber = ${{ needs.get_pr_details.outputs.prNumber }};
35-
const blockLabel = process.env.BLOCK_LABEL;
36-
const blockReasonLabel = process.env.BLOCK_REASON_LABEL;
37-
38-
const RELATED_ISSUE_REGEX = /Issue number:.+(\d)/
39-
40-
const matcher = new RegExp(RELATED_ISSUE_REGEX)
41-
const isMatch = matcher.exec(prBody)
42-
if (isMatch == null) {
43-
console.info(`No related issue found, maybe the author didn't use the template but there is one.`)
44-
45-
let msg = "No related issues found. Please ensure there is an open issue related to this change to avoid significant delays or closure.";
46-
await github.rest.issues.createComment({
47-
owner: context.repo.owner,
48-
repo: context.repo.repo,
49-
body: msg,
50-
issue_number: prNumber,
51-
});
52-
53-
await github.rest.issues.addLabels({
54-
issue_number: prNumber,
55-
owner: context.repo.owner,
56-
repo: context.repo.repo,
57-
labels: [blockLabel, blockReasonLabel]
58-
})
59-
}
39+
const script = require('.github/scripts/label_missing_related_issue.js')
40+
await script({github, context, core})

‎.github/workflows/record_pr.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
name: Record PR number
1+
name: Record PR details
22

33
on:
44
pull_request:
55
types: [opened, edited, closed]
66

77
jobs:
8-
build:
8+
record_pr:
99
runs-on: ubuntu-latest
1010

1111
steps:
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: Export previously recorded PR
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
record_pr_workflow_id:
7+
required: true
8+
type: number
9+
secrets:
10+
token:
11+
required: true
12+
# Map the workflow outputs to job outputs
13+
outputs:
14+
prNumber:
15+
description: "PR Number"
16+
value: ${{ jobs.export_pr_details.outputs.prNumber }}
17+
prTitle:
18+
description: "PR Title"
19+
value: ${{ jobs.export_pr_details.outputs.prTitle }}
20+
prBody:
21+
description: "PR Body as string"
22+
value: ${{ jobs.export_pr_details.outputs.prBody }}
23+
prAuthor:
24+
description: "PR author username"
25+
value: ${{ jobs.export_pr_details.outputs.prAuthor }}
26+
prAction:
27+
description: "PR event action"
28+
value: ${{ jobs.export_pr_details.outputs.prAction }}
29+
prIsMerged:
30+
description: "Whether PR is merged"
31+
value: ${{ jobs.export_pr_details.outputs.prIsMerged }}
32+
33+
jobs:
34+
export_pr_details:
35+
runs-on: ubuntu-latest
36+
env:
37+
FILENAME: pr.txt
38+
# Map the job outputs to step outputs
39+
outputs:
40+
prNumber: ${{ steps.prNumber.outputs.prNumber }}
41+
prTitle: ${{ steps.prTitle.outputs.prTitle }}
42+
prBody: ${{ steps.prBody.outputs.prBody }}
43+
prAuthor: ${{ steps.prAuthor.outputs.prAuthor }}
44+
prAction: ${{ steps.prAction.outputs.prAction }}
45+
prIsMerged: ${{ steps.prIsMerged.outputs.prIsMerged }}
46+
steps:
47+
- name: Checkout repository # in case caller workflow doesn't checkout thus failing with file not found
48+
uses: actions/checkout@v3
49+
- name: "Download previously saved PR"
50+
uses: actions/github-script@v6
51+
env:
52+
WORKFLOW_ID: ${{ inputs.record_pr_workflow_id }}
53+
# For security, we only download artifacts tied to the successful PR recording workflow
54+
with:
55+
github-token: ${{ secrets.token }}
56+
script: |
57+
const script = require('.github/scripts/download_pr_artifact.js')
58+
await script({github, context, core})
59+
# NodeJS standard library doesn't provide ZIP capabilities; use system `unzip` command instead
60+
- name: "Unzip PR artifact"
61+
run: unzip pr.zip
62+
# NOTE: We need separate steps for each mapped output and respective IDs
63+
# otherwise the parent caller won't see them regardless on how outputs are set.
64+
- name: "Export Pull Request Number"
65+
id: prNumber
66+
run: echo ::set-output name=prNumber::$(jq -c '.number' ${FILENAME})
67+
- name: "Export Pull Request Title"
68+
id: prTitle
69+
run: echo ::set-output name=prTitle::$(jq -c '.pull_request.title' ${FILENAME})
70+
- name: "Export Pull Request Body"
71+
id: prBody
72+
run: echo ::set-output name=prBody::$(jq -c '.pull_request.body' ${FILENAME})
73+
- name: "Export Pull Request Author"
74+
id: prAuthor
75+
run: echo ::set-output name=prAuthor::$(jq -c '.pull_request.user.login' ${FILENAME})
76+
- name: "Export Pull Request Action"
77+
id: prAction
78+
run: echo ::set-output name=prAction::$(jq -c '.action' ${FILENAME})
79+
- name: "Export Pull Request Merged status"
80+
id: prIsMerged
81+
run: echo ::set-output name=prIsMerged::$(jq -c '.pull_request.merged' ${FILENAME})

0 commit comments

Comments
 (0)
Please sign in to comment.