The Use Case
Recently I was tasked with parsing some XML, returning non-conforming URL rewrite rules, and alerting on them within a GitHub Action. You see, in a project I was working on we had a URL rule that was a partial match for another route, and it caused some data issues in an API call. This was an edge case – but we wanted to strengthen our URL rewrite rules .. so we added ^ and $ to the existing rules, and the follow up task was to create something automated to make sure if we write anything loose .. that it gets reported on. Having never written my own GitHub Action, I dove down the rabbit hole of examples, documentation, and seeing what path I could take.
After digging through JavaScript, Docker, and composite runs .. I went with the simplest/easiest possible method: A bash script that returns results, formats them, and then outputs them to a PR comment. Why not fail the PR? Well – in some cases, you may have a legitimate reason for bypassing the warning.
The Bash Script
First step, creating the bash script, script.sh
. This will go into .github/workflows in your GitHub repository.
#!/bin/bash # Detect issues in URL Rewrite Rules set -euo pipefail output=""
for file in $(find /home/runner/work/UrlRewriteRuleCheckingGHAction/UrlRewriteRuleCheckingGHAction -name 'Web.config') do lineNumber=1 for line in $(xmlstarlet sel -T -t -m /configuration/system.webServer/rewrite/rules/rule/match/@url -v . -n "$file") do if [[ $line != \^* ]] || [[ $line != *\$ ]] then output+="Line Item: <br /><br /> $line <br /><br /> in $file on line $lineNumber;" fi ((lineNumber+=1)) done done echo "::set-output name=ERROR_LINES::${output::-1}"
So what’s going on here?
for file in $(find /home/runner/work/project/project -name 'Web.config')
Loop through ANY Web.config in our repository. This can be customized to target a specific file. We have multiple configs that could have rules to check.
for line in $(xmlstarlet sel -T -t -m /configuration/system.webServer/rewrite/rules/rule/match/@url -v . -n \"$file\")
xmlstarlet allows us to target specific XML nodes and get the value.
if [[ $line != \\^* ]] || [[ $line != *\\$ ]]
then
output+=\"Line Item: <br /><br /> $line <br /><br /> in $file on line $lineNumber;\"
fi
We’re checking to make sure every single line starts with ^ and ends with $. If either of these are false, we add the line and line number to the output.
And finally …
echo \"::set-output name=ERROR_LINES::${output::-1}\"
Set a variable, ERROR_LINES, for consumption outside of the subshell.
The GitHub Action File
The next file is validate_rewrite_rules.yml, which we will put in the same directory as the script.sh
file.
name: URLRewriteValidator on: pull_request: branches: - main jobs: url_rule_checker: runs-on: ubuntu-latest steps: - uses: actions/checkout@01aecccf739ca6ff86c0539fbc67a7a5007bbc81 - name: Install xmlstarlet run: sudo apt-get install xmlstarlet - name: Query against Web.config id: url_rule_checker run: | # Grant perms chmod +x "${GITHUB_WORKSPACE}/.github/workflows/script.sh" # Run Script "${GITHUB_WORKSPACE}/.github/workflows/script.sh" - name: Get Errors run: echo "Errors in \n ${{ steps.url_rule_checker.outputs.ERROR_LINES }}" - name: Format comment for PR id: format_comment if: steps.url_rule_checker.outputs.ERROR_LINES run: | COMMENT_BODY=`echo "${{ steps.url_rule_checker.outputs.ERROR_LINES }}" | sed 's/*/\\\*/g;s/;/<\/li><li>/g'` COMMENT_BODY="There are URL rewrite URLs that dont start/end with ^ and $. Verify that the URL rules are what you expect.<br /><ul><li>${COMMENT_BODY}</li></ul>" echo "::set-output name=formatted_comment::$COMMENT_BODY" echo "$COMMENT_BODY" | sed 's/*/\\\*/g;s/;/<\/li><li>/g' - uses: mshick/add-pr-comment@5cd99bf9c186219af43341076f1fe9c09e5a9934 # v1 if: steps.url_rule_checker.outputs.ERROR_LINES with: message: ${{ steps.format_comment.outputs.formatted_comment }} repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token-user-login: 'github-actions[bot]' allow-repeats: false
So let’s break it down..
name: URLRewriteValidator on: pull_request: branches: - main
We want to fire this action off on Pull Request.
- uses: actions/checkout@01aecccf739ca6ff86c0539fbc67a7a5007bbc81
To quote from the Action GitHub repo:
“This action checks-out your repository under $GITHUB_WORKSPACE , so your workflow can access it. Only a single commit is fetched by default, for the ref/SHA that triggered the workflow.”
- name: Install xmlstarlet run: sudo apt-get install xmlstarlet
This installs xmlstarlet within the shell.
- name: Query against Web.config id: url_rule_checker run: | # Grant perms chmod +x "${GITHUB_WORKSPACE}/.github/workflows/script.sh" # Run Script "${GITHUB_WORKSPACE}/.github/workflows/script.sh"
Here we execute our script that we created.
- name: Get Errors run: echo "Errors in \n ${{ steps.url_rule_checker.outputs.ERROR_LINES }}"
After the script runs, we now display/confirm our ERROR_LINES variable is set.
- name: Format comment for PR id: format_comment if: steps.url_rule_checker.outputs.ERROR_LINES run: | COMMENT_BODY=`echo "${{ steps.url_rule_checker.outputs.ERROR_LINES }}" | sed 's/*/\\\*/g;s/;/<\/li><li>/g'` COMMENT_BODY="There are URL rewrite URLs that dont start/end with ^ and $. Verify that the URL rules are what you expect.<br /><ul><li>${COMMENT_BODY}</li></ul>" echo "::set-output name=formatted_comment::$COMMENT_BODY" echo "$COMMENT_BODY" | sed 's/*/\\\*/g;s/;/<\/li><li>/g'
If we have ERROR_LINES, we want to parse/set the body of our comment. We are going to split on the semi-colon we insert in the script output, and insert it into List Item html tags.
- uses: mshick/add-pr-comment@5cd99bf9c186219af43341076f1fe9c09e5a9934 # v1 if: steps.url_rule_checker.outputs.ERROR_LINES with: message: ${{ steps.format_comment.outputs.formatted_comment }} repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token-user-login: 'github-actions[bot]' allow-repeats: false
And finally, we use a GitHub action called Add-Pr-Comment by mshick. We set the message to our formatted comment, pull the GITHUB_TOKEN from the secrets that are available via the GitHub Actions, and set the login.
Repository: https://github.com/MattTheDev/UrlRewriteRuleCheckingGHAction
Pull Request with Comments: https://github.com/MattTheDev/UrlRewriteRuleCheckingGHAction/pull/3
Leave a Comment