-
Notifications
You must be signed in to change notification settings - Fork 2
/
action.yml
154 lines (140 loc) · 7.5 KB
/
action.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
name: 'Azure DevOps Commit Validator and Pull Request Linker'
description: 'Enforce that each commit in a pull request has AB# in the commit message and link all of the work items to the pull request'
branding:
icon: "user-check"
color: "purple"
inputs:
check-pull-request:
description: "Check the pull request body and title for AB#xxx"
required: true
default: false
check-commits:
description: "Check each commit in the pull request for AB#xxx"
required: true
default: true
fail-if-missing-workitem-commit-link:
description: "Only if check-commits=true, fail the action if a commit in the pull request is missing AB# in every commit message"
required: false
default: true
link-commits-to-pull-request:
description: "Only if check-commits=true, link the work items found in commits to the pull request"
required: false
default: true
azure-devops-token:
description: "Only required if link-commits-to-pull-request=true, Azure DevOps Personal Access Token to link work item to PR (needs to be a full PAT)"
required: false
azure-devops-organization:
description: "Only required if link-commits-to-pull-request=true, the name of the Azure DevOps organization"
required: false
github-token:
description: "The GitHub token that has contents-read and pull_request-write access"
required: true
default: ${{ github.token }}
comment-on-failure:
description: "Comment on the pull request if the action fails"
required: true
default: true
runs:
using: "composite"
steps:
- name: pr-workitems-validator
shell: bash
env:
GH_TOKEN: ${{ inputs.github-token }}
run: |
# run azdo_commit_message_validator
# prerequisite check
for cmd in gh jq cut grep; do
if ! command -v $cmd &> /dev/null; then
echo "::error title=${cmd} not installed::Could not find \`${cmd}\` on the runner"
exit 1
fi
done
# have to do some hocus pocus since this isn't a full javascript action
main=$(find ../../_actions/joshjohanning/azdo_commit_message_validator -name "main.js" | grep -v "node_modules")
echo "::debug::main.js script location: $main"
PULL_NUMBER=$(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH")
# install npm modules if they are not found
if ${{ inputs.check-commits }}; then
if ${{ inputs.link-commits-to-pull-request }}; then
DIRECTORY=$(dirname "${main}")
if [ ! -d "${DIRECTORY}/node_modules" ]; then
CURRENT_DIRECTORY=$(pwd)
cd $DIRECTORY
npm install
echo "" && echo ""
cd $CURRENT_DIRECTORY
fi
fi
COMMITS=$(gh api --paginate ${{ github.event.pull_request.commits_url }})
echo $COMMITS | jq -c '.[]' | while read commit; do
COMMIT_SHA=$(echo $commit | jq '.sha')
SHORT_COMMIT_SHA=$(echo $COMMIT_SHA | cut -c 1-7)
COMMIT_MESSAGE=$(echo $commit | jq '.commit.message')
echo "Validating new commit: ${COMMIT_SHA} - ${COMMIT_MESSAGE}"
if ! echo "$COMMIT_MESSAGE" | grep -i -E -q "AB#[0-9]+"; then
# only fail the action if the input is true
if ${{ inputs.fail-if-missing-workitem-commit-link }}; then
echo ""
echo ""
echo "Pull request contains invalid commit: ${COMMIT_SHA}. This commit lacks an AB#xxx in the message, in the expected format: AB#xxx -- failing operation."
echo "::error title=Commit(s) not linked to work items::There is at least one commit (${SHORT_COMMIT_SHA}) in pull request #${PULL_NUMBER} that is not linked to a work item"
# TODO: add comment to pr
exit 1
fi
else
echo "valid commit"
# set WORKITEM equal to the number after the # in the commit message
WORKITEM=$(echo "$COMMIT_MESSAGE" | grep -i -o -E "AB#[0-9]+" | cut -c 4-)
echo "Workitem = $WORKITEM"
if ${{ inputs.link-commits-to-pull-request }}; then
# make the call to main.js to do the linking
# TODO: check to see if org/pat are set
echo "Attempting to link work item ${WORKITEM} to pull request ${PULL_NUMBER}..."
REPO_TOKEN=${{ inputs.github-token }} AZURE_DEVOPS_ORG=${{ inputs.azure-devops-organization }} AZURE_DEVOPS_PAT=${{ inputs.azure-devops-token }} WORKITEMID=$WORKITEM PULLREQUESTID=${{ github.event.number }} REPO=${{ github.repository }} node $main
echo "...PR linked to work item"
fi
fi
done
fi
if ${{ inputs.check-pull-request }}; then
PULL_REQUEST=$(gh api ${{ github.event.pull_request.url }})
PULL_BODY=$(echo $PULL_REQUEST | jq --raw-output .body)
PULL_TITLE=$(echo $PULL_REQUEST | jq --raw-output .title)
if ! echo "$PULL_TITLE $PULL_BODY" | grep -i -E -q "AB#[0-9]+"; then
echo "PR not linked to a work item"
echo "::error title=Pull Request not linked to work item(s)::The pull request #${PULL_NUMBER} is not linked to any work item(s)"
COMMENT=":x: This pull request is not linked to a work item. Please update the title or body to include a work item and re-run the failed job to continue. Any new commits to the pull request will also re-run the job."
CURRENT_DATE_TIME=$(date +"%Y-%m-%d %T")
COMMENT_EXTRA=$'\n\n[View workflow run for details](${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt}}) _(last ran\: '${CURRENT_DATE_TIME}')_'
COMMENT_COMBINED="${COMMENT}${COMMENT_EXTRA}"
COMMENTS_CLEAN=$(gh api --paginate ${{ github.event.pull_request.comments_url }} | tr -d '\000-\031')
COMMENT_ID=$(echo "$COMMENTS_CLEAN" | jq -r --arg comment "$COMMENT" '.[] | select(.body | contains($comment)) | .id')
echo "Comment ID(s): $COMMENT_ID"
# Check if the comment already exists
if [ -n "$COMMENT_ID" ]; then
echo "Comment already exists: $COMMENT_ID"
# Edit the comment
echo "... attempting to update the PR comment"
gh api ${{ github.event.repository.url }}/issues/comments/${COMMENT_ID} --method PATCH --field body="${COMMENT_COMBINED}" > /dev/null
echo "... PR comment updated"
else
echo "Comment does not exist. Posting a new comment."
gh pr comment $PULL_NUMBER --body "${COMMENT_COMBINED}"
fi
exit 1
else
echo "PR linked to work item"
# TODO: do we want to update or delete the PR comment if it exists b/c previously failed?
# Extract work items from PR body and title
WORKITEMS=$(echo "$PULL_BODY $PULL_TITLE" | grep -i -o -E "AB#[0-9]+" | sort | uniq)
# Loop through each work item
for WORKITEM in $WORKITEMS; do
# Remove the "AB#" or "ab#" prefix and keep only the number
WORKITEM_NUMBER=${WORKITEM:3}
echo "Pull request linked to work item number: $WORKITEM_NUMBER"
# TODO: validate work item?
# TODO: add this as an ::info or to the job summary?
done
fi
fi