-
Notifications
You must be signed in to change notification settings - Fork 69
108 lines (103 loc) · 4.69 KB
/
contextual-advice.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
name: Contextual Advice
on:
- pull_request_target
permissions:
pull-requests: write
jobs:
# Provide context-specific advice to reviewers based on the files touched.
contextual_advice:
name: Contextual Advice
runs-on: ubuntu-latest
steps:
# The following checks out the code from the pull request.
#
# This is not normally secure or recommended. It is safe in this context,
# however, because we are not executing any code located within the PR
# branch or its commits, regardless of provenance.
#
# Do not execute any code located within the repository!
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
# To create advice for a file or directory, determine the filename by:
# $ echo "$filename" | sed -E 's/[^[:alnum:]]+/_/g'
#
# (Leave off trailing '/' for directories.)
#
# Then add `.md` to the end of the resulting string and stick it in
# the advice folder.
#
# E.g.:
#
# .gitignore -> _gitignore.md
# .github/actions/post-checkout/action.yml -> _github_actions_post_checkout_action_yml.md
# config/sync/core.extension.yml -> config_sync_core_extension_yml.md
# docroot/sites/default -> docroot_sites_default.md
#
- name: Find available advice for each modified file.
id: find_advice
continue-on-error: true
run: |
mkdir -p ./.pr_advice;
advice_path=".github/workflows/config/advice/";
while read filename; do
echo "::debug::Looking for relevant advice for ${filename}...";
IFS='/' read -r -a path_components <<< "${filename}";
advice_file_path="${advice_path}";
advice_filename="";
# We'll separate path components by underscore, but we don't want
# a leading underscore in the filename. So we'll set the delimiter
# to an underscore after the first path component is processed.
delimiter="";
for path_component in "${path_components[@]}"; do
sanitized="$(echo "${path_component}" | sed -E 's/[^[:alnum:]]+/_/g')";
advice_file_path="${advice_file_path}${delimiter}${sanitized}";
echo "::debug::Looking in ${advice_file_path}.md ...";
if [ -f "${advice_file_path}.md" ]; then
if [ ! -z "${advice_filename}" ]; then
echo "::debug::Discarding advice in ${advice_filename} for (presumably) more relevant advice...";
fi;
advice_filename="${advice_file_path}.md";
echo "::debug::Found relevant advice for ${filename} at ${advice_filename}.";
fi;
# Join second and subsequent path components with an underscore.
delimiter="_";
done;
if [ ! -z "${advice_filename}" ]; then
cp "${advice_filename}" ./.pr_advice/;
echo "provide_advice=true" >> $GITHUB_OUTPUT;
else
echo "::debug::... none found.";
fi;
done < <(git diff --name-only "${GITHUB_BASE_SHA}" "${GITHUB_PR_SHA}");
env:
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }}
GITHUB_PR_SHA: ${{ github.event.pull_request.head.sha }}
- name: Provide advice in a PR comment.
if: steps.find_advice.outputs.provide_advice == 'true'
continue-on-error: true
run: |
# Find comments containing token, if any, and delete them.
gh api \
-H "Accept: application/vnd.github+json" \
/repos/${GITHUB_REPOSITORY}/issues/${GITHUB_PR}/comments \
| jq '.[] | select(.body | contains("<!-- PR Advice -->")).id' \
| while read -r pr_comment; do \
gh api \
--method DELETE \
-H "Accept: application/vnd.github+json" \
"/repos/${GITHUB_REPOSITORY}/issues/comments/${pr_comment}"; \
done;
body="$(awk 'FNR==1 && NR!=1 {print "\n<hr/>\n"}{print}' ./.pr_advice/*.md)";
# Create a new comment containing the compiled advice.
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
/repos/${GITHUB_REPOSITORY}/issues/${GITHUB_PR}/comments \
-f body="<!-- PR Advice -->
${body}";
env:
GITHUB_PR: "${{ github.event.pull_request.number }}"
GITHUB_PR_SHA: ${{ github.event.pull_request.head.sha }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}