[REQUEST]More detailed example code in Pattern.cs #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Issue Created Handler | |
on: | |
issues: | |
types: [opened] | |
jobs: | |
handle-new-issue: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v3 | |
- name: Install Python Markdown | |
run: pip install markdown | |
- name: Determine Work Item Type | |
id: determine-work-item-type | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
const labels = context.payload.issue.labels.map(label => label.name.toLowerCase()); | |
let workItemType = ""; | |
if (labels.includes("bug")) { | |
workItemType = "Bug"; | |
} else if (labels.includes("enhancement")) { | |
workItemType = "User Story"; | |
} else { | |
workItemType = "Customer Escalation"; | |
} | |
// URL-encode the work item type (e.g., "User Story" becomes "User%20Story") | |
const encodedType = encodeURIComponent(workItemType); | |
return encodedType; | |
result-encoding: string | |
- name: Create work item in Azure DevOps | |
id: create-work-item | |
env: | |
AZDO_ORG: ${{ secrets.AZDO_ORG }} | |
AZDO_PROJECT: ${{ secrets.AZDO_PROJECT }} | |
AZURE_DEVOPS_TOKEN: ${{ secrets.AZURE_DEVOPS_TOKEN }} | |
AZDO_AREA_PATH: ${{ secrets.AZDO_AREA_PATH }} | |
ISSUE_TITLE: ${{ github.event.issue.title }} | |
ISSUE_NUMBER: ${{ github.event.issue.number }} | |
ISSUE_URL: ${{ github.event.issue.html_url }} | |
ISSUE_BODY: ${{ github.event.issue.body }} | |
WORK_ITEM_TYPE: ${{ steps.determine-work-item-type.outputs.result }} | |
run: | | |
echo "Creating Azure DevOps work item for GitHub Issue: $ISSUE_TITLE" | |
# Build the base work item payload | |
FORMATTED_ISSUE_BODY=$(python -c "import sys, markdown, re; html = markdown.markdown(sys.stdin.read()); print(re.sub(r'<img[^>]*>', '', html))" <<< "$ISSUE_BODY") | |
PATCH_DOC=$(jq -n \ | |
--arg title "GitHub Issue #$ISSUE_NUMBER: $ISSUE_TITLE" \ | |
--arg description "<div> | |
<p><strong>ISSUE DETAILS:</strong></p> | |
<p>Issue Number: $ISSUE_NUMBER</p> | |
<p><a href=\"$ISSUE_URL\">View Issue on GitHub</a></p> | |
<p>$FORMATTED_ISSUE_BODY</p> | |
<p style=\"color:red;\"><strong>NOTE:</strong> Please ensure to remove the \"CommentOnGitHub\" tag <u>if no action is required</u> for the work item.</p> | |
</div>" \ | |
--arg areaPath "$AZDO_AREA_PATH" \ | |
'[{"op": "add", "path": "/fields/System.Title", "value": $title}, | |
{"op": "add", "path": "/fields/System.Description", "value": $description}, | |
{"op": "add", "path": "/fields/System.AreaPath", "value": $areaPath}, | |
{"op": "add", "path": "/fields/System.Tags", "value": "CommentOnGitHub"}]') | |
# Adding additional custom fields if the work item type is "Customer Escalation" | |
if [[ "$WORK_ITEM_TYPE" == "Customer%20Escalation" ]]; then | |
PATCH_DOC=$(echo "$PATCH_DOC" | jq '. + | |
[{"op": "add", "path": "/fields/Custom.EscalationPriority", "value": "Priority 3 - Medium"}, | |
{"op": "add", "path": "/fields/Custom.Requestor", "value": "Semi BU"}, | |
{"op": "add", "path": "/fields/Custom.BUAffinity", "value": "Semi/Elec"}]') | |
fi | |
# Adding additional custom fields if the work item type is "Bug" | |
if [[ "$WORK_ITEM_TYPE" == "Bug" ]]; then | |
STS_VERSION=$(echo "$ISSUE_BODY" | sed -n '/System Setup/,$p' | grep -oP '(?<=STS Software Version )\d+\.\d+(\.\w+)?' | head -n 1 | tr -d '\r') | |
# Check if STS_VERSION matches expected format | |
if [[ -n "$STS_VERSION" ]]; then | |
REPORTED_IN="STS Software Bundle $STS_VERSION" | |
else | |
REPORTED_IN="STS Software Bundle" | |
fi | |
echo "Extracted STS Software Version: $STS_VERSION" | |
echo "Final ReportedIn value: $REPORTED_IN" | |
PATCH_DOC=$(echo "$PATCH_DOC" | jq --arg reportedIn "$REPORTED_IN" '. + | |
[{"op": "add", "path": "/fields/Custom.ReportedIn", "value": $reportedIn}]') | |
fi | |
echo "$PATCH_DOC" > patch.json | |
WORK_ITEM_API_URL="https://dev.azure.com/$AZDO_ORG/$AZDO_PROJECT/_apis/wit/workitems/\$${WORK_ITEM_TYPE}?api-version=6.0" | |
echo "Work Item API URL: $WORK_ITEM_API_URL" | |
RESPONSE=$(curl -s -u :$AZURE_DEVOPS_TOKEN \ | |
-X POST \ | |
-H "Content-Type: application/json-patch+json" \ | |
--data @patch.json \ | |
"$WORK_ITEM_API_URL") | |
WORK_ITEM_ID=$(echo "$RESPONSE" | jq -r '.id') | |
if [ "$WORK_ITEM_ID" = "null" ]; then | |
echo "Error: Work item creation failed." | |
exit 1 | |
fi | |
WORK_ITEM_URL="https://dev.azure.com/$AZDO_ORG/$AZDO_PROJECT/_workitems/edit/$WORK_ITEM_ID" | |
echo "::set-output name=work_item_id::$WORK_ITEM_ID" | |
echo "::set-output name=work_item_url::$WORK_ITEM_URL" | |
- name: Link GitHub Issue to Azure DevOps Work Item | |
env: | |
AZDO_ORG: ${{ secrets.AZDO_ORG }} | |
AZDO_PROJECT: ${{ secrets.AZDO_PROJECT }} | |
AZURE_DEVOPS_TOKEN: ${{ secrets.AZURE_DEVOPS_TOKEN }} | |
WORK_ITEM_ID: ${{ steps.create-work-item.outputs.work_item_id }} | |
ISSUE_NUMBER: ${{ github.event.issue.number }} | |
GH_REPO_GUID: ${{ secrets.GH_REPO_GUID }} | |
run: | | |
echo "Linking GitHub Issue to the Azure DevOps Work Item" | |
PATCH_RELATION=$(jq -n \ | |
--arg issueNumber "$ISSUE_NUMBER" \ | |
--arg repoGuid "$GH_REPO_GUID" \ | |
'[{ | |
"op": "add", | |
"path": "/relations/-", | |
"value": { | |
"rel": "ArtifactLink", | |
"url": "vstfs:///GitHub/Issue/\($repoGuid)%2F\($issueNumber)", | |
"attributes": { | |
"name": "GitHub Issue" | |
} | |
} | |
}]') | |
echo "$PATCH_RELATION" > patch-relation.json | |
WORK_ITEM_API_URL="https://dev.azure.com/$AZDO_ORG/$AZDO_PROJECT/_apis/wit/workitems/$WORK_ITEM_ID?api-version=6.0" | |
RESPONSE=$(curl -s -u :$AZURE_DEVOPS_TOKEN \ | |
-X PATCH \ | |
-H "Content-Type: application/json-patch+json" \ | |
--data @patch-relation.json \ | |
"$WORK_ITEM_API_URL") | |
- name: Notify NI Developers on Teams | |
env: | |
TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_WEBHOOK_URL }} | |
ISSUE_TITLE: ${{ github.event.issue.title }} | |
ISSUE_BODY: ${{ github.event.issue.body }} | |
ISSUE_URL: ${{ github.event.issue.html_url }} | |
ISSUE_NUMBER: ${{ github.event.issue.number }} | |
WORK_ITEM_ID: ${{ steps.create-work-item.outputs.work_item_id }} | |
WORK_ITEM_URL: ${{ steps.create-work-item.outputs.work_item_url }} | |
WORK_ITEM_TYPE_ENCODED: ${{ steps.determine-work-item-type.outputs.result }} | |
run: | | |
echo "Decoding work item type..." | |
WORK_ITEM_TYPE=$(python -c "import urllib.parse; print(urllib.parse.unquote('''$WORK_ITEM_TYPE_ENCODED'''))") | |
echo "Formatting issue body for Teams..." | |
FORMATTED_ISSUE_BODY=$(echo "$ISSUE_BODY" \ | |
| sed -E 's/\*\*([^*]+)\*\*/<strong>\1<\/strong>/g' \ | |
| sed ':a;N;$!ba;s/\n/<br>/g') | |
echo "Generating JSON payload with jq" | |
jq -n \ | |
--arg issueTitle "$ISSUE_TITLE" \ | |
--arg issueBody "$FORMATTED_ISSUE_BODY" \ | |
--arg issueUrl "$ISSUE_URL" \ | |
--arg issueNumber "$ISSUE_NUMBER" \ | |
--arg workItemId "$WORK_ITEM_ID" \ | |
--arg workItemType "$WORK_ITEM_TYPE" \ | |
--arg workItemUrl "$WORK_ITEM_URL" \ | |
'{ | |
"@type": "MessageCard", | |
"@context": "https://schema.org/extensions", | |
"themeColor": "0076D7", | |
"summary": "New GitHub Issue and Work Item Created", | |
"sections": [ | |
{ | |
"text": ("<strong>New GitHub Issue (#" + $issueNumber + "): " + $issueTitle + "</strong><br><br>" | |
+ "<strong>**Title:**</strong> " + $issueTitle + "<br>" | |
+ "<strong>**Issue URL:**</strong> [View Issue](" + $issueUrl + ")<br>" | |
+ "<strong>**Work Item ID:**</strong> " + $workItemId + "<br>" | |
+ "<strong>**Work Item Type:**</strong> " + $workItemType + "<br>" | |
+ "<strong>**Work Item URL:**</strong> [View Work Item](" + $workItemUrl + ")<br><br>" | |
+ "<strong>**Description:**</strong> " + $issueBody), | |
"markdown": true | |
} | |
] | |
}' > teams_payload.json | |
echo "Previewing JSON payload:" | |
cat teams_payload.json | |
echo "Sending notication to Teams Channel." | |
if ! curl -s -f -H "Content-Type: application/json" -d @teams_payload.json "$TEAMS_WEBHOOK_URL"; then | |
echo "Teams notification failed. Attempting to send error alert." | |
jq -n \ | |
--arg workItemId "$WORK_ITEM_ID" \ | |
--arg workItemType "$WORK_ITEM_TYPE" \ | |
--arg workItemUrl "$WORK_ITEM_URL" \ | |
--arg issueUrl "$ISSUE_URL" \ | |
--arg errorText "Unable to fetch the details for issue #$ISSUE_NUMBER" \ | |
'{ | |
"@type": "MessageCard", | |
"@context": "https://schema.org/extensions", | |
"themeColor": "FF0000", | |
"summary": "Unable to fetch Issue Details", | |
"sections": [ | |
{ | |
"text": ("<strong>Unable to fetch Issue Title</strong><br><br>" | |
+ "<strong>**Issue URL:**</strong> [View Issue](" + $issueUrl + ")<br>" | |
+ "<strong>**Work Item ID:**</strong> " + $workItemId + "<br>" | |
+ "<strong>**Work Item Type:**</strong> " + $workItemType + "<br>" | |
+ "<strong>**Work Item URL:**</strong> [View Work Item](" + $workItemUrl + ")<br><br>" | |
+ "<strong>**Error Details:**</strong> " + $errorText), | |
"markdown": true | |
} | |
] | |
}' > teams_error_payload.json | |
echo "Sending fallback error card..." | |
curl -s -H "Content-Type: application/json" -d @teams_error_payload.json "$TEAMS_WEBHOOK_URL" | |
exit 1 | |
fi | |
- name: Add comment on GitHub Issue | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
const issueNumber = context.payload.issue.number; | |
const commentBody = `Thank you for posting, the NI development team has been notified and a corresponding work item has been created internally. The team will review and reply back if any further clarification is required.`; | |
await github.rest.issues.createComment({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: issueNumber, | |
body: commentBody, | |
}); |