1
+ #! /bin/bash
2
+ # This runs Vale on updated files in last commit, checks if the Vale alerts are on new/modified lines, and if so, builds curl request
3
+ # for GitHub review comment API. Also checks if a commment already exists before posting.
4
+ # To test locally, create a Github personal access token and export a $GITHUB_AUTH_TOKEN environmental variable to use the token
5
+
6
+ # Check if jq is installed
7
+ hash jq 2> /dev/null || { echo >&2 " Error: jq is not installed" ; exit 1; }
8
+
9
+ # Set $PULL_NUMBER and $COMMIT_ID for local testing. Otherwise use variables passed by Prow
10
+ if [ $# -eq 0 ]; then
11
+ COMMIT_ID=$( git log -n 1 --pretty=format:" %H" )
12
+ PULL_NUMBER=$( curl -s " https://api.github.com/search/issues?q=$COMMIT_ID " | jq ' .items[0].number' )
13
+ else
14
+ PULL_NUMBER=$1
15
+ COMMIT_ID=$2
16
+ fi
17
+
18
+ FILES=$( git diff --name-only HEAD~1 HEAD --diff-filter=d " *.adoc" ' :(exclude)_unused_topics/*' )
19
+
20
+ function post_review_comment {
21
+
22
+ LINE_NUMBER=$3
23
+ BODY=$1
24
+ FILENAME=$2
25
+ echo " Sending review comment curl request..."
26
+ curl -L -X POST -H " Accept: application/vnd.github+json" -H " Authorization: Bearer $GITHUB_AUTH_TOKEN " -H " X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/openshift/openshift-docs/pulls/$PULL_NUMBER /comments -d ' {"body":"' " $BODY " ' ","commit_id":"' " $COMMIT_ID " ' ","path":"' " $FILENAME " ' ","line":' " $LINE_NUMBER " ' ,"side":"RIGHT"}'
27
+
28
+ }
29
+
30
+ function get_vale_errors {
31
+ echo " Getting the Vale errors and PR comments and filtering out existing comments..."
32
+ local vale_json=" $1 "
33
+ local pull_comments_json=" $2 "
34
+
35
+ # jq map and filter to retain only Vale alerts that don't already have a corresponding review comment on the PR
36
+ updated_vale_json=$( jq -n --argjson vale " $vale_json " --argjson comments " $pull_comments_json " ' $vale | map(select(. as $v | $comments | any(.path == $v.path and .line == $v.line and .body == $v.body) | not))' | jq)
37
+
38
+ export updated_vale_json
39
+
40
+ }
41
+
42
+ # Run vale with the custom template on updated files and determine if a review comment should be posted
43
+ for FILE in ${FILES} ;
44
+ do
45
+ # Clean out conditional markup in place and parse for vale errors
46
+ sed -i ' s/ifdef::.*\|ifndef::.*\|ifeval::.*\|endif::.*/ /' " $FILE "
47
+ vale_json=$( vale --minAlertLevel=error --output=.vale/templates/bot-comment-output.tmpl " $FILE " | jq)
48
+
49
+ # Check if there are Vale errors before processing the file further.
50
+ if [[ " $vale_json " != " []" ]]; then
51
+ echo " Vale errors found in the file..."
52
+
53
+ # Check if Vale review comments already exist in the PR
54
+ pull_comments_json=$( curl -L -H " Accept: application/vnd.github+json" -H " Authorization: Bearer $GITHUB_AUTH_TOKEN " -H " X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/openshift/openshift-docs/pulls/$PULL_NUMBER /comments | jq)
55
+
56
+ # If there are existing comments in the response, compare with Vale errors, otherwise proceed with existing Vale errors
57
+ if [[ " $pull_comments_json " != " []" ]]; then
58
+ get_vale_errors " $vale_json " " $pull_comments_json "
59
+ else
60
+ echo " No existing comments found..."
61
+ updated_vale_json=" $vale_json "
62
+ fi
63
+ else
64
+ echo " No Vale errors found in the file, moving to next file..."
65
+ continue # move to next file
66
+ fi
67
+
68
+ # Following logic checks if the line number is a part of the git diff. If it's not part of the diff it will be discarded.
69
+ # We only want to check new/modified content, plus the GitHub API only accepts comments within the diff for the review comments endpoint.
70
+ if [[ " $updated_vale_json " == " []" ]]; then
71
+ echo " All Vale alerts already have existing comments, moving to next file..."
72
+ continue # move to next file
73
+ else
74
+ echo " Checking if Vale alerts without existing comments are part of added or modified content..."
75
+ fi
76
+
77
+ # Iterate through $updated_vale_json and post a comment if required
78
+ jq -c ' .[]' <<< " $updated_vale_json" | while IFS= read -r object; do
79
+ BODY=$( echo " $object " | jq -r ' .body' )
80
+ FILENAME=$( echo " $object " | jq -r ' .path' )
81
+ LINE_NUMBER=$( echo " $object " | jq -r ' .line' )
82
+
83
+ # Check the unified file diff for the alert and file
84
+ file_diff=$( git diff --unified=0 --stat --diff-filter=AM HEAD~1 HEAD " ${FILENAME} " ' :(exclude)_unused_topics/*' )
85
+
86
+ # Iterate through each line to find the line diff info and check if the alert is in the diff
87
+ while read -r line; do
88
+ # Check if the line contains the hunk beginning with @@
89
+ if [[ $line =~ @@ ]]; then
90
+
91
+ # Valid:
92
+ # @@ -35 +31 @@
93
+ # @@ -35 +31,5 @@
94
+
95
+ # Check if there is a comma in the number pairing before @@
96
+ if [[ $line =~ \+ .* \, .* \ @@ ]]; then
97
+ # There are comma separated numbers before closing @@. Grab the number before the comma as the diff_start_line, after the comma is the added_lines.
98
+ added_lines=$( echo " $line " | grep -oP ' \d+\s+@@' | grep -oP ' \d+' )
99
+ diff_start_line=$( echo " $line " | awk -F' +' ' {print $2}' | awk -F' ,' ' {print $1}' )
100
+ else
101
+ # There are no comma seperated numbers. Consider the number after the plus as diff_start_line with no added lines - this means there's a modification on a single line
102
+ added_lines=0
103
+ diff_start_line=$( echo " $line " | grep -oP ' \+\d+\s+@@' | grep -oP ' \d+' )
104
+ fi
105
+
106
+ # If the last_number is 0, disregard the hunk and move to the next hunk as zero lines were modified (deletions only)
107
+ if [ " $diff_start_line " -eq 0 ]; then
108
+ continue
109
+ fi
110
+
111
+ # Check if the LINE_NUMBER falls within the range (diff_start_line) to (diff_start_line + added_lines)
112
+ if (( LINE_NUMBER >= diff_start_line && LINE_NUMBER <= diff_start_line + added_lines )) ; then
113
+
114
+ post_review_comment " $BODY " " $FILENAME " " $LINE_NUMBER "
115
+
116
+ break # Exit the loop since the alert is within the diff, move on to the next JSON object
117
+ else
118
+ echo " Vale error alert not part of the file's added/modified content..."
119
+ fi
120
+ fi
121
+
122
+ done <<< " $file_diff"
123
+
124
+ done
125
+
126
+ done
0 commit comments