Repository navigation
build(deps): bump oauthlib from 4.0.0 to 4.0.1 in /03-Azure/01-04-AI/08_Predictive_Maintenance/src/agent-workflow/app #519
Workflow file for this run
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: PR Compliance Check | |
| # Runs with a read-only token so it also works for pull requests from forks. | |
| # The PR comment is posted by pr-compliance-comment.yml (workflow_run), which | |
| # downloads the artifact produced here and never executes code from the PR. | |
| on: | |
| pull_request: | |
| paths: | |
| - '01-Identity and Access Management/**' | |
| - '02-Security/**' | |
| - '03-Azure/**' | |
| - '04-Microsoft-365/**' | |
| - '.github/workflows/pr-compliance-check.yml' | |
| - '.github/scripts/check_file_structure.py' | |
| - '.github/scripts/requirements-compliance.txt' | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: pr-compliance-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| compliance-check: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| # The PR merge commit plus its first parent (the base) is enough to diff. | |
| fetch-depth: 2 | |
| persist-credentials: false | |
| - name: Get changed files | |
| run: | | |
| git -c core.quotepath=off diff --name-only --diff-filter=ACMRT HEAD^1 HEAD -- \ | |
| '01-Identity and Access Management/' \ | |
| '02-Security/' \ | |
| '03-Azure/' \ | |
| '04-Microsoft-365/' \ | |
| > changed-files.txt | |
| echo "Changed files:" | |
| cat changed-files.txt | |
| - name: Setup Python | |
| uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 | |
| with: | |
| python-version: '3.13' | |
| cache: pip | |
| cache-dependency-path: .github/scripts/requirements-compliance.txt | |
| - name: Install brokelink | |
| run: pip install -r .github/scripts/requirements-compliance.txt | |
| - name: Check markdown links and images | |
| id: brokelink-check | |
| continue-on-error: true | |
| env: | |
| PYTHONIOENCODING: utf-8 | |
| run: | | |
| # Escape values for GitHub workflow commands (::error ...). | |
| esc_data() { local v=${1//%/%25}; v=${v//$'\r'/%0D}; printf '%s' "${v//$'\n'/%0A}"; } | |
| esc_prop() { local v; v=$(esc_data "$1"); v=${v//:/%3A}; printf '%s' "${v//,/%2C}"; } | |
| # Full report for the job summary, compact table rows for the PR comment. | |
| printf '## 🔗 Brokelink Check Results\n\n' > brokelink-results.md | |
| : > brokelink-rows.md | |
| EXIT_CODE=0 | |
| CHECKED=0 | |
| FAILED=0 | |
| BROKEN_TOTAL=0 | |
| MAX_ROWS=20 | |
| while IFS= read -r file; do | |
| [ -z "$file" ] && continue | |
| [[ "$file" == *.md ]] || continue | |
| CHECKED=$((CHECKED + 1)) | |
| echo "Checking: $file" | |
| FILE_EXIT=0 | |
| OUTPUT=$(brokelink "$file" --include="*.md" --check-images 2>&1) || FILE_EXIT=$? | |
| if [ "$FILE_EXIT" -ne 0 ]; then | |
| EXIT_CODE=1 | |
| FAILED=$((FAILED + 1)) | |
| COUNT=$(printf '%s\n' "$OUTPUT" | grep -oP 'Found \K[0-9]+(?= broken)' | head -n 1 || true) | |
| [ -z "$COUNT" ] && COUNT=$(printf '%s\n' "$OUTPUT" | grep -cE '^\s*Line [0-9]+:' || true) | |
| BROKEN_TOTAL=$((BROKEN_TOTAL + ${COUNT:-0})) | |
| # e.g. "Missing files (3), Missing images (1)" | |
| KINDS=$(printf '%s\n' "$OUTPUT" | grep -oP '^\s*\S+\s+\K[A-Za-z][A-Za-z ]+ \([0-9]+\)(?=:)' | paste -sd ',' - | sed 's/,/, /g' || true) | |
| { | |
| echo "❌ **$file** - Issues found" | |
| echo '```' | |
| echo "$OUTPUT" | |
| echo '```' | |
| echo "" | |
| } >> brokelink-results.md | |
| if [ "$FAILED" -le "$MAX_ROWS" ]; then | |
| echo "| \`$file\` | ${COUNT:-?} | ${KINDS:-see run details} |" >> brokelink-rows.md | |
| fi | |
| # One annotation per broken line so it shows inline in "Files changed". | |
| ANNOTATED=0 | |
| while IFS= read -r hit; do | |
| [ -z "$hit" ] && continue | |
| echo "::error file=$(esc_prop "$file"),line=${hit%%:*},title=Broken link or image::$(esc_data "${hit#*: }")" | |
| ANNOTATED=1 | |
| done < <(printf '%s\n' "$OUTPUT" | grep -oP '^\s*Line \K[0-9]+: .*' | sort -u || true) | |
| if [ "$ANNOTATED" -eq 0 ]; then | |
| echo "::error file=$(esc_prop "$file"),title=Broken links or images::brokelink found broken links or images in this file. See the job summary for details." | |
| fi | |
| else | |
| printf '✅ **%s** - OK\n\n' "$file" >> brokelink-results.md | |
| fi | |
| done < changed-files.txt | |
| if [ "$CHECKED" -eq 0 ]; then | |
| echo "*No changed markdown files to check.*" >> brokelink-results.md | |
| fi | |
| { | |
| echo '### 🔗 Links & Images' | |
| echo '' | |
| if [ "$CHECKED" -eq 0 ]; then | |
| echo '*No changed markdown files to check.*' | |
| else | |
| echo "$((CHECKED - FAILED)) of $CHECKED markdown file(s) OK · $BROKEN_TOTAL broken link(s)/image(s)" | |
| if [ "$FAILED" -gt 0 ]; then | |
| echo '' | |
| echo '| File | Broken | What |' | |
| echo '|---|---|---|' | |
| cat brokelink-rows.md | |
| if [ "$FAILED" -gt "$MAX_ROWS" ]; then | |
| echo "| *…and $((FAILED - MAX_ROWS)) more file(s)* | | |" | |
| fi | |
| fi | |
| fi | |
| echo '' | |
| } > brokelink-comment.md | |
| { | |
| echo "BROKELINK_EXIT_CODE=$EXIT_CODE" | |
| echo "checked=$CHECKED" | |
| echo "failed=$FAILED" | |
| echo "broken=$BROKEN_TOTAL" | |
| } >> "$GITHUB_OUTPUT" | |
| cat brokelink-results.md | |
| - name: Run file structure compliance check | |
| id: structure-check | |
| continue-on-error: true | |
| run: python .github/scripts/check_file_structure.py < changed-files.txt | |
| - name: Upload compliance summary | |
| if: always() | |
| run: | | |
| if [ -f structure-check-results.md ]; then | |
| cat structure-check-results.md >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| if [ -f brokelink-results.md ]; then | |
| cat brokelink-results.md >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| - name: Check final compliance status | |
| id: final-status | |
| env: | |
| BROKELINK_STATUS: ${{ steps.brokelink-check.outputs.BROKELINK_EXIT_CODE }} | |
| BROKELINK_OUTCOME: ${{ steps.brokelink-check.outcome }} | |
| STRUCTURE_OUTCOME: ${{ steps.structure-check.outcome }} | |
| run: | | |
| if [ "$BROKELINK_STATUS" != "0" ] || [ "$BROKELINK_OUTCOME" == "failure" ] || [ "$STRUCTURE_OUTCOME" == "failure" ]; then | |
| echo "COMPLIANCE_FAILED=true" >> "$GITHUB_OUTPUT" | |
| echo "❌ Compliance check failed" | |
| else | |
| echo "COMPLIANCE_FAILED=false" >> "$GITHUB_OUTPUT" | |
| echo "✅ All compliance checks passed" | |
| fi | |
| - name: Build PR comment body | |
| env: | |
| COMPLIANCE_FAILED: ${{ steps.final-status.outputs.COMPLIANCE_FAILED }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| STRUCTURE_OUTCOME: ${{ steps.structure-check.outcome }} | |
| STRUCTURE_ISSUES: ${{ steps.structure-check.outputs.issues }} | |
| STRUCTURE_WARNINGS: ${{ steps.structure-check.outputs.warnings }} | |
| PROJECTS_TOTAL: ${{ steps.structure-check.outputs.projects_total }} | |
| PROJECTS_FAILED: ${{ steps.structure-check.outputs.projects_failed }} | |
| LINKS_CHECKED: ${{ steps.brokelink-check.outputs.checked }} | |
| LINKS_FAILED: ${{ steps.brokelink-check.outputs.failed }} | |
| LINKS_BROKEN: ${{ steps.brokelink-check.outputs.broken }} | |
| run: | | |
| if [ "$STRUCTURE_OUTCOME" == "failure" ]; then | |
| if [ -n "$STRUCTURE_ISSUES" ]; then | |
| STRUCTURE_LINE="❌ ${STRUCTURE_ISSUES} issue(s) in ${PROJECTS_FAILED} of ${PROJECTS_TOTAL} project(s)" | |
| else | |
| STRUCTURE_LINE="❌ Check errored, see run details" | |
| fi | |
| else | |
| STRUCTURE_LINE="✅ OK" | |
| [ "${STRUCTURE_WARNINGS:-0}" -gt 0 ] && STRUCTURE_LINE="✅ OK (${STRUCTURE_WARNINGS} warning(s))" | |
| fi | |
| if [ -z "$LINKS_CHECKED" ]; then | |
| LINKS_LINE="❌ Check errored, see run details" | |
| elif [ "${LINKS_FAILED:-0}" -gt 0 ]; then | |
| LINKS_LINE="❌ ${LINKS_BROKEN} broken in ${LINKS_FAILED} of ${LINKS_CHECKED} file(s)" | |
| elif [ "$LINKS_CHECKED" -eq 0 ]; then | |
| LINKS_LINE="➖ No markdown files changed" | |
| else | |
| LINKS_LINE="✅ OK (${LINKS_CHECKED} file(s))" | |
| fi | |
| mkdir -p pr-comment | |
| { | |
| if [ "$COMPLIANCE_FAILED" == "true" ]; then | |
| echo '## ❌ PR Compliance Check Failed' | |
| echo '' | |
| echo 'Please fix the issues below before merging.' | |
| else | |
| echo '## ✅ PR Compliance Check Passed' | |
| echo '' | |
| echo 'All compliance checks passed for the latest commit.' | |
| fi | |
| echo '' | |
| echo '| Check | Result |' | |
| echo '|---|---|' | |
| echo "| 📋 Challenges & Walkthrough structure | $STRUCTURE_LINE |" | |
| echo "| 🔗 Links & images | $LINKS_LINE |" | |
| echo '' | |
| if [ "$COMPLIANCE_FAILED" == "true" ]; then | |
| if [ "$STRUCTURE_OUTCOME" == "failure" ] && [ -f structure-check-comment.md ]; then | |
| cat structure-check-comment.md | |
| echo '' | |
| fi | |
| if [ "${LINKS_FAILED:-0}" -gt 0 ] && [ -f brokelink-comment.md ]; then | |
| cat brokelink-comment.md | |
| echo 'Broken links are also annotated inline in the **Files changed** tab.' | |
| echo '' | |
| fi | |
| fi | |
| echo "📄 **[Full report in the workflow run summary]($RUN_URL)**" | |
| echo '' | |
| echo '---' | |
| echo '*This comment was automatically generated by the PR Compliance Check workflow.*' | |
| } > pr-comment/pr-comment.md | |
| echo "$PR_NUMBER" > pr-comment/pr-number.txt | |
| cat pr-comment/pr-comment.md | |
| - name: Upload PR comment artifact | |
| uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 | |
| with: | |
| name: pr-compliance-comment | |
| path: pr-comment/ | |
| retention-days: 3 | |
| if-no-files-found: error | |
| - name: Fail workflow if compliance failed | |
| if: steps.final-status.outputs.COMPLIANCE_FAILED == 'true' | |
| run: exit 1 |