Skip to content

Update databasecustompathwindows.md #808

Update databasecustompathwindows.md

Update databasecustompathwindows.md #808

Workflow file for this run

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