doc review test 10 #30
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: Documentation Fixer | |
| on: | |
| issue_comment: | |
| types: [created] | |
| jobs: | |
| claude-response: | |
| runs-on: ubuntu-latest | |
| if: | | |
| github.event.issue.pull_request && | |
| contains(github.event.comment.body, '@claude') && | |
| github.event.comment.user.login != 'github-actions[bot]' | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| issues: write | |
| id-token: write | |
| actions: read | |
| steps: | |
| - name: Get PR info | |
| id: pr-info | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PR_NUMBER="${{ github.event.issue.number }}" | |
| PR_DATA=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName,isCrossRepository) | |
| echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT" | |
| echo "branch=$(echo "$PR_DATA" | jq -r '.headRefName')" >> "$GITHUB_OUTPUT" | |
| echo "is_fork=$(echo "$PR_DATA" | jq -r '.isCrossRepository')" >> "$GITHUB_OUTPUT" | |
| - name: Post fork notice | |
| if: steps.pr-info.outputs.is_fork == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh pr comment ${{ steps.pr-info.outputs.number }} --repo ${{ github.repository }} \ | |
| --body "This PR is from a fork. Automated fixes cannot be pushed directly. Apply the suggested changes from the inline comments manually." | |
| - name: Checkout repository | |
| if: steps.pr-info.outputs.is_fork == 'false' | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ steps.pr-info.outputs.branch }} | |
| fetch-depth: 0 | |
| - name: Checkout system prompt repository | |
| if: steps.pr-info.outputs.is_fork == 'false' | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: netwrix-eng/internal-agents | |
| token: ${{ secrets.PRIVATE_AGENTS_REPO }} | |
| path: system-prompt-repo | |
| ref: builds | |
| sparse-checkout: | | |
| engineering/technical_writing/system-prompt.md | |
| sparse-checkout-cone-mode: false | |
| - name: Read system prompt | |
| id: read-prompt | |
| if: steps.pr-info.outputs.is_fork == 'false' | |
| run: | | |
| { | |
| echo "prompt<<EOF" | |
| cat system-prompt-repo/engineering/technical_writing/system-prompt.md | |
| echo "" # Forces a newline to prevent EOF delimiter errors | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Detect command type | |
| id: cmd-type | |
| if: steps.pr-info.outputs.is_fork == 'false' | |
| run: | | |
| COMMENT="${{ github.event.comment.body }}" | |
| if echo "$COMMENT" | grep -qi 'preexisting'; then | |
| echo "is_preexisting=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "is_preexisting=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Install Vale | |
| if: steps.pr-info.outputs.is_fork == 'false' && steps.cmd-type.outputs.is_preexisting == 'false' | |
| run: | | |
| VERSION=$(curl -s "https://api.github.com/repos/errata-ai/vale/releases/latest" | jq -r '.tag_name') | |
| curl -sfL "https://github.com/errata-ai/vale/releases/download/${VERSION}/vale_${VERSION#v}_Linux_64-bit.tar.gz" \ | |
| | sudo tar -xz -C /usr/local/bin vale | |
| - name: Apply fixes | |
| if: steps.pr-info.outputs.is_fork == 'false' && steps.cmd-type.outputs.is_preexisting == 'false' | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| show_full_output: true | |
| claude_args: | | |
| --model claude-sonnet-4-5-20250929 | |
| --allowedTools "Read,Write,Edit,Bash(vale:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(git config:*),Bash(git add:*),Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*)" | |
| --append-system-prompt "${{ steps.read-prompt.outputs.prompt }}" | |
| - name: Record last comment ID | |
| id: pre-claude | |
| if: steps.pr-info.outputs.is_fork == 'false' && steps.cmd-type.outputs.is_preexisting == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| LAST_ID=$(gh api repos/${{ github.repository }}/issues/${{ steps.pr-info.outputs.number }}/comments \ | |
| --jq 'if length > 0 then .[-1].id else 0 end' 2>/dev/null || echo "0") | |
| echo "last_comment_id=$LAST_ID" >> "$GITHUB_OUTPUT" | |
| - name: Detect preexisting issues | |
| if: steps.pr-info.outputs.is_fork == 'false' && steps.cmd-type.outputs.is_preexisting == 'true' | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| show_full_output: false | |
| prompt: | | |
| Detect preexisting issues in PR ${{ steps.pr-info.outputs.number }}. | |
| Follow these steps in order: | |
| 1. Use `gh pr diff ${{ steps.pr-info.outputs.number }}` to identify which lines are part of the PR diff. | |
| 2. Use `gh pr view ${{ steps.pr-info.outputs.number }}` to get the list of changed files, then read the full content of each changed markdown file. | |
| 3. Run all three review passes on each file per your instructions, but report ONLY issues on lines that are NOT part of the PR diff. | |
| 4. You MUST write your results ONLY to `/tmp/preexisting-issues.md` — always, even if there are no issues. Do not post a comment. Do not write anything else. Use this exact format: | |
| ## Preexisting issues | |
| ### path/to/file.md | |
| - Line N: issue. Suggested change: '...' | |
| Or if there are no issues: | |
| ## Preexisting issues | |
| None. | |
| claude_args: | | |
| --model claude-sonnet-4-5-20250929 | |
| --allowedTools "Read,Write,Edit,Bash(gh pr view:*),Bash(gh pr diff:*)" | |
| --append-system-prompt "${{ steps.read-prompt.outputs.prompt }}" | |
| - name: Post preexisting issues comment | |
| if: steps.pr-info.outputs.is_fork == 'false' && steps.cmd-type.outputs.is_preexisting == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PR_NUMBER: ${{ steps.pr-info.outputs.number }} | |
| REPO: ${{ github.repository }} | |
| LAST_COMMENT_ID: ${{ steps.pre-claude.outputs.last_comment_id }} | |
| run: | | |
| python3 << 'PYTHON_EOF' | |
| import os | |
| import json | |
| import subprocess | |
| pr_number = os.environ['PR_NUMBER'] | |
| repo = os.environ['REPO'] | |
| last_comment_id = int(os.environ.get('LAST_COMMENT_ID', '0')) | |
| FOOTER = ( | |
| "\n\n---\n\n" | |
| "To apply the suggested fixes to preexisting issues, comment `@claude` on this PR followed by your instructions\n" | |
| "(`@claude fix all issues` or `@claude fix only the first issue`).\n" | |
| "Note: Automated fixes are only available for branches in this repository, not forks." | |
| ) | |
| def normalize_body(body): | |
| """Keep only the expected structured content from the preexisting issues output.""" | |
| idx = body.find('## Preexisting issues') | |
| if idx == -1: | |
| return '## Preexisting issues\nNone.' | |
| body = body[idx:] | |
| clean_lines = [] | |
| for line in body.split('\n'): | |
| s = line.strip() | |
| if (s == '## Preexisting issues' or | |
| s.startswith('### ') or | |
| s.startswith('- Line ') or | |
| s == 'None.' or | |
| s == ''): | |
| clean_lines.append(line) | |
| while clean_lines and not clean_lines[-1].strip(): | |
| clean_lines.pop() | |
| return '\n'.join(clean_lines) | |
| summary_path = '/tmp/preexisting-issues.md' | |
| if os.path.exists(summary_path): | |
| with open(summary_path) as f: | |
| clean_body = normalize_body(f.read()) + FOOTER | |
| else: | |
| clean_body = '## Preexisting issues\nNone.' + FOOTER | |
| # Find the action's auto-posted comment (ID > last recorded, posted by a bot) | |
| result = subprocess.run( | |
| ['gh', 'api', f'repos/{repo}/issues/{pr_number}/comments'], | |
| capture_output=True, text=True, check=True, | |
| ) | |
| comments = json.loads(result.stdout) | |
| new_bot_comments = [c for c in comments | |
| if c['id'] > last_comment_id | |
| and c['user']['login'].endswith('[bot]')] | |
| if new_bot_comments: | |
| # Replace the action's auto-comment in-place with our formatted output | |
| target_id = new_bot_comments[-1]['id'] | |
| subprocess.run( | |
| ['gh', 'api', f'repos/{repo}/issues/comments/{target_id}', | |
| '-X', 'PATCH', '--input', '-'], | |
| input=json.dumps({'body': clean_body}), | |
| capture_output=True, text=True, check=True, | |
| ) | |
| else: | |
| subprocess.run( | |
| ['gh', 'pr', 'comment', pr_number, '--repo', repo, '--body', clean_body], | |
| check=True, | |
| ) | |
| PYTHON_EOF |