Update databasecustompathwindows.md #808
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: Vale Auto-Fix | |
| on: | |
| pull_request: | |
| types: [opened, synchronize] | |
| branches: | |
| - dev | |
| paths: | |
| - 'docs/**/*.md' | |
| - '!docs/**/CLAUDE.md' | |
| - '!docs/**/SKILL.md' | |
| - '!docs/kb/**' | |
| concurrency: | |
| group: vale-autofix-${{ github.event.pull_request.number }} | |
| jobs: | |
| vale-autofix: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Check if triggered by bot commit | |
| id: bot-check | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Get the latest commit on the PR head | |
| COMMIT=$(gh api repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }} --jq '{author: .commit.author.name, message: .commit.message}') | |
| AUTHOR=$(echo "$COMMIT" | jq -r '.author') | |
| MESSAGE=$(echo "$COMMIT" | jq -r '.message') | |
| echo "Latest commit author: $AUTHOR" | |
| echo "Latest commit message: $MESSAGE" | |
| # Skip if this is a commit from the vale-autofix workflow itself | |
| # (prevents re-trigger loops) but allow other bot commits through | |
| # so they still get linted | |
| if echo "$MESSAGE" | grep -qE '^fix\((vale|dale)\):'; then | |
| echo "Skipping: commit is from vale-autofix workflow" | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Checkout PR branch | |
| if: steps.bot-check.outputs.skip != 'true' | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| ref: ${{ github.event.pull_request.head.ref }} | |
| token: ${{ secrets.VALE_TOKEN }} | |
| fetch-depth: 0 | |
| - name: Configure git identity | |
| if: steps.bot-check.outputs.skip != 'true' | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Get changed markdown files | |
| id: changed-files | |
| if: steps.bot-check.outputs.skip != 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PR_NUMBER=${{ github.event.pull_request.number }} | |
| CHANGED_MD_FILES=$(gh pr diff "$PR_NUMBER" --name-only | grep -E '^docs/.*\.md$' | grep -v '/CLAUDE\.md$' | grep -v '/SKILL\.md$' | grep -v '^docs/kb/' || true) | |
| if [ -z "$CHANGED_MD_FILES" ]; then | |
| echo "No docs markdown files changed" | |
| echo "count=0" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "Changed markdown files:" | |
| echo "$CHANGED_MD_FILES" | |
| echo "count=$(echo "$CHANGED_MD_FILES" | wc -l | tr -d ' ')" >> "$GITHUB_OUTPUT" | |
| echo "$CHANGED_MD_FILES" > /tmp/changed-files.txt | |
| fi | |
| - name: Install Vale | |
| if: steps.changed-files.outputs.count > 0 | |
| run: | | |
| wget -q https://github.com/errata-ai/vale/releases/download/v3.9.5/vale_3.9.5_Linux_64-bit.tar.gz -O /tmp/vale.tar.gz | |
| tar -xzf /tmp/vale.tar.gz -C /tmp | |
| chmod +x /tmp/vale | |
| /tmp/vale --version | |
| - name: Run Vale on changed files | |
| id: vale-initial | |
| if: steps.changed-files.outputs.count > 0 | |
| run: | | |
| jq -n '[]' > /tmp/violations.json | |
| while IFS= read -r file; do | |
| if [ -f "$file" ]; then | |
| RESULT=$(/tmp/vale --output JSON "$file" 2>>/tmp/vale-stderr.log || true) | |
| if [ -n "$RESULT" ] && [ "$RESULT" != "{}" ]; then | |
| echo "$RESULT" | jq --arg f "$file" ' | |
| [to_entries[] | .value[] | {path: $f, line: .Line, check: .Check, message: .Message}] | |
| ' > /tmp/vale-file.json | |
| jq -s '.[0] + .[1]' /tmp/violations.json /tmp/vale-file.json > /tmp/vale-tmp.json | |
| mv /tmp/vale-tmp.json /tmp/violations.json | |
| fi | |
| fi | |
| done < /tmp/changed-files.txt | |
| TOTAL=$(jq 'length' /tmp/violations.json) | |
| echo "total=$TOTAL" >> "$GITHUB_OUTPUT" | |
| echo "Vale found $TOTAL issue(s)" | |
| - name: Phase 1 — Script fixes | |
| id: phase1 | |
| if: steps.vale-initial.outputs.total > 0 | |
| run: | | |
| chmod +x scripts/vale-autofix.sh | |
| SUMMARY=$(./scripts/vale-autofix.sh /tmp/violations.json) | |
| echo "$SUMMARY" > /tmp/phase1-summary.json | |
| PHASE1_TOTAL=$(echo "$SUMMARY" | jq '.total') | |
| echo "fixed=$PHASE1_TOTAL" >> "$GITHUB_OUTPUT" | |
| echo "Phase 1 fixed $PHASE1_TOTAL issue(s)" | |
| - name: Re-run Vale for remaining violations | |
| id: vale-remaining | |
| if: steps.vale-initial.outputs.total > 0 | |
| run: | | |
| jq -n '[]' > /tmp/remaining-violations.json | |
| while IFS= read -r file; do | |
| if [ -f "$file" ]; then | |
| RESULT=$(/tmp/vale --output JSON "$file" 2>>/tmp/vale-stderr.log || true) | |
| if [ -n "$RESULT" ] && [ "$RESULT" != "{}" ]; then | |
| echo "$RESULT" | jq --arg f "$file" ' | |
| [to_entries[] | .value[] | {path: $f, line: .Line, check: .Check, message: .Message}] | |
| ' > /tmp/vale-file.json | |
| jq -s '.[0] + .[1]' /tmp/remaining-violations.json /tmp/vale-file.json > /tmp/vale-tmp.json | |
| mv /tmp/vale-tmp.json /tmp/remaining-violations.json | |
| fi | |
| fi | |
| done < /tmp/changed-files.txt | |
| REMAINING=$(jq 'length' /tmp/remaining-violations.json) | |
| echo "remaining=$REMAINING" >> "$GITHUB_OUTPUT" | |
| echo "$REMAINING remaining violation(s) for Phase 2" | |
| - name: Phase 2 — Claude fixes | |
| id: phase2 | |
| if: steps.vale-remaining.outputs.remaining > 0 | |
| continue-on-error: true | |
| uses: anthropics/claude-code-action@51705da45eecce209d4700538bf8377d5b5fc695 # v1 | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| show_full_output: true | |
| prompt: | | |
| You are a documentation fixer. Your job is to fix Vale linting violations in markdown files. | |
| Read docs/CLAUDE.md for Netwrix writing standards before making any changes. | |
| Here are the remaining Vale violations after mechanical fixes were applied: | |
| ```json | |
| $(cat /tmp/remaining-violations.json) | |
| ``` | |
| For each violation: | |
| 1. Read the file and understand the context around the flagged line | |
| 2. Apply a fix that resolves the Vale rule while preserving the author's meaning | |
| 3. If you are NOT confident in a fix (ambiguous context, multiple valid interpretations, fix would change meaning) SKIP it | |
| Note: if your fixes change any heading text, do not update anchor links — the workflow repairs all anchor links automatically after all fixes are complete. | |
| After fixing, write a JSON summary to /tmp/phase2-summary.json with this structure: | |
| ```json | |
| { | |
| "fixed": [ | |
| {"path": "file.md", "line": 1, "check": "Netwrix.RuleName", "action": "brief description of fix"} | |
| ], | |
| "skipped": [ | |
| {"path": "file.md", "line": 1, "check": "Netwrix.RuleName", "reason": "why it was skipped"} | |
| ] | |
| } | |
| ``` | |
| IMPORTANT: Write the summary JSON file, then stop. Do NOT run any git commands — the workflow handles staging, committing, and pushing. Do not post any PR comments. | |
| claude_args: '--allowedTools "Bash(git:*),Read,Write,Edit,Glob,Grep"' | |
| - name: Phase 3 — Dale fixes | |
| id: phase3 | |
| if: steps.bot-check.outputs.skip != 'true' && steps.changed-files.outputs.count > 0 | |
| continue-on-error: true | |
| uses: anthropics/claude-code-action@51705da45eecce209d4700538bf8377d5b5fc695 # v1 | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| show_full_output: true | |
| prompt: | | |
| You are Dale, a documentation fixer. Your job is to find and fix documentation style issues using Dale rules. | |
| Read docs/CLAUDE.md for Netwrix writing standards before making any changes. | |
| INSTRUCTIONS: | |
| Step 1: Read every .yml rule file in .claude/skills/dale/rules/ | |
| Step 2: Read the list of changed files from /tmp/changed-files.txt (one file path per line). | |
| Step 3: Read each changed file. For each file, check every line against each rule's "reason" field. | |
| Step 4: Fix each violation in-place, preserving the author's meaning. If you are NOT confident in a fix (ambiguous context, multiple valid interpretations, fix would change meaning), SKIP it. | |
| Note: if your fixes change any heading text, do not update anchor links — the workflow repairs all anchor links automatically after all fixes are complete. | |
| Step 5: Write a JSON summary to /tmp/dale-summary.json with this structure: | |
| ```json | |
| { | |
| "fixed": [ | |
| {"path": "file.md", "line": 1, "rule": "passive-voice", "action": "brief description of fix"} | |
| ], | |
| "skipped": [ | |
| {"path": "file.md", "line": 1, "rule": "idioms", "reason": "why it was skipped"} | |
| ] | |
| } | |
| ``` | |
| If no issues found, write: {"fixed": [], "skipped": []} | |
| Step 6: Write the summary JSON file (see Step 5 format above), then stop. | |
| IMPORTANT: Do NOT run any git commands — the workflow handles staging, committing, and pushing. Do not post any PR comments. | |
| claude_args: '--allowedTools "Bash(git:*),Read,Write,Edit,Glob,Grep"' | |
| - name: Fix heading anchors | |
| if: steps.bot-check.outputs.skip != 'true' && steps.changed-files.outputs.count > 0 | |
| run: | | |
| bash scripts/vale-autofix.sh --anchors-only origin/dev /tmp/changed-files.txt | |
| - name: Check anchor links | |
| id: anchor-check | |
| if: steps.bot-check.outputs.skip != 'true' && steps.changed-files.outputs.count > 0 | |
| continue-on-error: true | |
| run: | | |
| chmod +x scripts/check-anchors.sh | |
| touch /tmp/anchor-errors.txt | |
| BROKEN=0 | |
| mapfile -t FILES < /tmp/changed-files.txt | |
| ./scripts/check-anchors.sh "${FILES[@]}" > /tmp/anchor-check-output.txt 2>&1 || BROKEN=1 | |
| if [ "$BROKEN" -eq 1 ]; then | |
| grep '^\s' /tmp/anchor-check-output.txt > /tmp/anchor-errors.txt || true | |
| BROKEN=$(grep -oE 'Found [0-9]+' /tmp/anchor-check-output.txt | grep -oE '[0-9]+' | tail -1 || echo "0") | |
| echo "Broken anchors found:" | |
| cat /tmp/anchor-check-output.txt | |
| fi | |
| echo "broken=$BROKEN" >> "$GITHUB_OUTPUT" | |
| - name: Commit all fixes | |
| if: steps.bot-check.outputs.skip != 'true' && steps.changed-files.outputs.count > 0 | |
| run: | | |
| git add -A docs/ | |
| if git diff --cached --quiet; then | |
| echo "No changes to commit" | |
| else | |
| git commit -m "fix(vale): auto-fix style issues (Vale + Dale)" | |
| fi | |
| - name: Push all fixes | |
| if: steps.bot-check.outputs.skip != 'true' && steps.changed-files.outputs.count > 0 | |
| env: | |
| VALE_TOKEN: ${{ secrets.VALE_TOKEN }} | |
| run: | | |
| # Re-configure git credentials with VALE_TOKEN (claude-code-action | |
| # overrides credentials with GITHUB_TOKEN, which doesn't trigger workflows) | |
| git remote set-url origin "https://x-access-token:${VALE_TOKEN}@github.com/${{ github.repository }}.git" | |
| if [ "$(git rev-list @{u}..HEAD --count 2>/dev/null)" -gt 0 ]; then | |
| echo "Pushing $(git rev-list @{u}..HEAD --count) commit(s)..." | |
| git push | |
| else | |
| echo "No new commits to push" | |
| fi | |
| - name: Build and post summary comment | |
| if: steps.bot-check.outputs.skip != 'true' && steps.changed-files.outputs.count > 0 | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PR_NUMBER=${{ github.event.pull_request.number }} | |
| REPO=${{ github.repository }} | |
| # Collect Phase 1 stats | |
| PHASE1_TOTAL=0 | |
| PHASE1_BODY="" | |
| if [ -f /tmp/phase1-summary.json ]; then | |
| PHASE1_TOTAL=$(jq '.total' /tmp/phase1-summary.json) | |
| # Build category rows from Phase 1 | |
| PHASE1_BODY=$(jq -r ' | |
| .by_category | to_entries | sort_by(.key) | .[] | | |
| "| \(.key) | \(.value) |" | |
| ' /tmp/phase1-summary.json) | |
| fi | |
| # Collect Phase 2 stats | |
| PHASE2_FIXED=0 | |
| PHASE2_SKIPPED=0 | |
| PHASE2_BODY="" | |
| SKIPPED_BODY="" | |
| if [ -f /tmp/phase2-summary.json ]; then | |
| PHASE2_FIXED=$(jq '.fixed | length' /tmp/phase2-summary.json) | |
| PHASE2_SKIPPED=$(jq '.skipped | length' /tmp/phase2-summary.json) | |
| if [ "$PHASE2_FIXED" -gt 0 ]; then | |
| PHASE2_BODY=$(jq -r ' | |
| [.fixed[] | .check] | group_by(.) | .[] | | |
| "| \(.[0] | sub("Netwrix\\."; "")) (rewrite) | \(length) |" | |
| ' /tmp/phase2-summary.json) | |
| fi | |
| if [ "$PHASE2_SKIPPED" -gt 0 ]; then | |
| SKIPPED_BODY=$(jq -r ' | |
| .skipped[] | | |
| "| `\(.path):\(.line)` — \(.check) | \(.reason) |" | |
| ' /tmp/phase2-summary.json) | |
| fi | |
| fi | |
| # Collect Phase 3 (Dale) stats | |
| DALE_FIXED=0 | |
| DALE_SKIPPED=0 | |
| DALE_BODY="" | |
| DALE_SKIPPED_BODY="" | |
| if [ -f /tmp/dale-summary.json ]; then | |
| DALE_FIXED=$(jq '.fixed | length' /tmp/dale-summary.json) | |
| DALE_SKIPPED=$(jq '.skipped | length' /tmp/dale-summary.json) | |
| if [ "$DALE_FIXED" -gt 0 ]; then | |
| DALE_BODY=$(jq -r ' | |
| [.fixed[] | .rule] | group_by(.) | .[] | | |
| "| Dale: \(.[0]) | \(length) |" | |
| ' /tmp/dale-summary.json) | |
| fi | |
| if [ "$DALE_SKIPPED" -gt 0 ]; then | |
| DALE_SKIPPED_BODY=$(jq -r ' | |
| .skipped[] | | |
| "| `\(.path):\(.line)` — Dale: \(.rule) | \(.reason) |" | |
| ' /tmp/dale-summary.json) | |
| fi | |
| fi | |
| TOTAL_FIXED=$((PHASE1_TOTAL + PHASE2_FIXED + DALE_FIXED)) | |
| TOTAL_SKIPPED=$((PHASE2_SKIPPED + DALE_SKIPPED)) | |
| # Count affected files | |
| FILE_COUNT=$(wc -l < /tmp/changed-files.txt | tr -d ' ') | |
| # Collect anchor check results | |
| BROKEN_ANCHORS=0 | |
| ANCHOR_BODY="" | |
| if [ -f /tmp/anchor-check-output.txt ] && [ -s /tmp/anchor-check-output.txt ]; then | |
| BROKEN_ANCHORS=$(grep -oE 'Found [0-9]+' /tmp/anchor-check-output.txt | grep -oE '[0-9]+' | tail -1 || echo "0") | |
| ANCHOR_BODY=$(cat /tmp/anchor-errors.txt 2>/dev/null || true) | |
| fi | |
| # Build the summary comment | |
| { | |
| if [ "$BROKEN_ANCHORS" -gt 0 ]; then | |
| echo "## ⚠️ Broken Anchor Links" | |
| echo "" | |
| echo "**${BROKEN_ANCHORS} broken anchor link(s) found — these will cause the build to fail.**" | |
| echo "" | |
| echo "\`\`\`" | |
| echo "$ANCHOR_BODY" | |
| echo "\`\`\`" | |
| echo "" | |
| fi | |
| echo "## Auto-Fix Summary" | |
| echo "" | |
| echo "**${TOTAL_FIXED} issues fixed, ${TOTAL_SKIPPED} skipped across ${FILE_COUNT} files**" | |
| echo "" | |
| if [ "$TOTAL_FIXED" -gt 0 ]; then | |
| echo "| Category | Fixes |" | |
| echo "|----------|-------|" | |
| if [ -n "$PHASE1_BODY" ]; then | |
| echo "$PHASE1_BODY" | |
| fi | |
| if [ -n "$PHASE2_BODY" ]; then | |
| echo "$PHASE2_BODY" | |
| fi | |
| if [ -n "$DALE_BODY" ]; then | |
| echo "$DALE_BODY" | |
| fi | |
| echo "" | |
| fi | |
| if [ "$TOTAL_SKIPPED" -gt 0 ]; then | |
| echo "| Skipped (needs manual review) | Reason |" | |
| echo "|-------------------------------|--------|" | |
| echo "$SKIPPED_BODY" | |
| if [ -n "$DALE_SKIPPED_BODY" ]; then | |
| echo "$DALE_SKIPPED_BODY" | |
| fi | |
| echo "" | |
| fi | |
| echo 'Ask `@claude` on this PR if you'\''d like an explanation of any fix.' | |
| } > /tmp/vale-summary.md | |
| # Delete previous Vale Auto-Fix comments | |
| COMMENT_IDS=$(gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" \ | |
| --jq '[.[] | select(.user.login == "github-actions[bot]" and (.body | contains("## Auto-Fix Summary") or .body | contains("## ⚠️ Broken Anchor Links"))) | .id] | .[]' 2>/dev/null || true) | |
| for ID in $COMMENT_IDS; do | |
| gh api "repos/${REPO}/issues/comments/${ID}" -X DELETE 2>/dev/null || true | |
| done | |
| # Post new summary | |
| gh pr comment "$PR_NUMBER" --repo "$REPO" --body-file /tmp/vale-summary.md |