# This workflow checks if a PR requires documentation updates. # It creates a Coder Agent chat session that uses AI to analyze the PR # changes, search existing docs, and comment with recommendations. # # Triggers: # - New PR opened: Initial documentation review # - PR updated (synchronize): Re-review after changes # - Label "doc-check" added: Manual trigger for review # - PR marked ready for review: Review when draft is promoted # - Workflow dispatch: Manual run with PR URL # # Note: This workflow requires access to secrets and will be skipped for: # - Any PR where secrets are not available # For these PRs, maintainers can manually trigger via workflow_dispatch. name: AI Documentation Check on: pull_request: types: - opened - synchronize - labeled - ready_for_review workflow_dispatch: inputs: pr_url: description: "Pull Request URL to check" required: true type: string permissions: contents: read jobs: doc-check: name: Analyze PR for Documentation Updates Needed runs-on: ubuntu-latest # Run on: opened, synchronize, labeled (with doc-check label), ready_for_review, or workflow_dispatch # Skip draft PRs unless manually triggered if: | ( github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.label.name == 'doc-check' || github.event.action == 'ready_for_review' || github.event_name == 'workflow_dispatch' ) && (github.event.pull_request.draft == false || github.event_name == 'workflow_dispatch') && (github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository) timeout-minutes: 30 permissions: contents: read pull-requests: write steps: - name: Check if secrets are available id: check-secrets env: CODER_URL: ${{ secrets.DOC_CHECK_CODER_URL }} CODER_TOKEN: ${{ secrets.DOC_CHECK_CODER_SESSION_TOKEN }} run: | if [[ -z "${CODER_URL}" || -z "${CODER_TOKEN}" ]]; then echo "skip=true" >> "${GITHUB_OUTPUT}" echo "Secrets not available - skipping doc-check." echo "This is expected for PRs where secrets are not available." echo "Maintainers can manually trigger via workflow_dispatch if needed." { echo "⚠️ Workflow skipped: Secrets not available" echo "" echo "This workflow requires secrets that are unavailable for this run." echo "Maintainers can manually trigger via workflow_dispatch if needed." } >> "${GITHUB_STEP_SUMMARY}" else echo "skip=false" >> "${GITHUB_OUTPUT}" fi - name: Determine PR Context if: steps.check-secrets.outputs.skip != 'true' id: determine-context env: GITHUB_EVENT_NAME: ${{ github.event_name }} GITHUB_EVENT_ACTION: ${{ github.event.action }} GITHUB_EVENT_PR_HTML_URL: ${{ github.event.pull_request.html_url }} GITHUB_EVENT_PR_NUMBER: ${{ github.event.pull_request.number }} INPUTS_PR_URL: ${{ inputs.pr_url }} run: | # Determine trigger type for context if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then echo "trigger_type=manual" >> "${GITHUB_OUTPUT}" echo "Using PR URL: ${INPUTS_PR_URL}" # Validate PR URL format if [[ ! "${INPUTS_PR_URL}" =~ ^https://github\.com/[^/]+/[^/]+/pull/[0-9]+$ ]]; then echo "::error::Invalid PR URL format: ${INPUTS_PR_URL}" echo "::error::Expected format: https://github.com/owner/repo/pull/NUMBER" exit 1 fi ISSUE_URL="${INPUTS_PR_URL/\/pull\//\/issues\/}" echo "pr_url=${ISSUE_URL}" >> "${GITHUB_OUTPUT}" PR_NUMBER=$(echo "${INPUTS_PR_URL}" | grep -oP '(?<=pull/)\d+') echo "pr_number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}" elif [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then echo "Using PR URL: ${GITHUB_EVENT_PR_HTML_URL}" ISSUE_URL="${GITHUB_EVENT_PR_HTML_URL/\/pull\//\/issues\/}" echo "pr_url=${ISSUE_URL}" >> "${GITHUB_OUTPUT}" echo "pr_number=${GITHUB_EVENT_PR_NUMBER}" >> "${GITHUB_OUTPUT}" # Set trigger type based on action case "${GITHUB_EVENT_ACTION}" in opened) echo "trigger_type=new_pr" >> "${GITHUB_OUTPUT}" ;; synchronize) echo "trigger_type=pr_updated" >> "${GITHUB_OUTPUT}" ;; labeled) echo "trigger_type=label_requested" >> "${GITHUB_OUTPUT}" ;; ready_for_review) echo "trigger_type=ready_for_review" >> "${GITHUB_OUTPUT}" ;; *) echo "trigger_type=unknown" >> "${GITHUB_OUTPUT}" ;; esac else echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}" exit 1 fi - name: Build chat prompt if: steps.check-secrets.outputs.skip != 'true' id: extract-context env: PR_NUMBER: ${{ steps.determine-context.outputs.pr_number }} TRIGGER_TYPE: ${{ steps.determine-context.outputs.trigger_type }} run: | echo "Analyzing PR #${PR_NUMBER} (trigger: ${TRIGGER_TYPE})" # Build context based on trigger type case "${TRIGGER_TYPE}" in new_pr) CONTEXT="This is a NEW PR. Perform initial documentation review." ;; pr_updated) CONTEXT="This PR was UPDATED with new commits. Check if previous feedback was addressed or if new doc needs arose." ;; label_requested) CONTEXT="A documentation review was REQUESTED via label. Perform a thorough review." ;; ready_for_review) CONTEXT="This PR was marked READY FOR REVIEW. Perform a thorough review." ;; manual) CONTEXT="This is a MANUAL review request. Perform a thorough review." ;; *) CONTEXT="Perform a documentation review." ;; esac # Build chat prompt with sticky comment logic CHAT_PROMPT="Use the doc-check skill to review PR #${PR_NUMBER} in coder/coder. ${CONTEXT} When creating a new workspace, use the \"coder-workflow-bot\" template. Use \`gh\` to get PR details, diff, and all comments. Look for an existing doc-check comment containing \`\` - if one exists, you'll update it instead of creating a new one. **Do not comment if no documentation changes are needed.** If a sticky comment already exists, compare your current findings against it: - Check off \`[x]\` items that are now addressed - Strikethrough items no longer needed (e.g., code was reverted) - Add new unchecked \`[ ]\` items for newly discovered needs - If an item is checked but you can't verify the docs were added, add a warning note below it - If nothing meaningful changed, don't update the comment at all ## Comment format Use this structure (only include relevant sections): \`\`\` ## Documentation Check ### Updates Needed - [ ] \`docs/path/file.md\` - What needs to change - [x] \`docs/other/file.md\` - This was addressed - ~~\`docs/removed.md\` - No longer needed~~ *(reverted in abc123)* ### New Documentation Needed - [ ] \`docs/suggested/path.md\` - What should be documented > ⚠️ *Checked but no corresponding documentation changes found in this PR* --- *Automated review via [Coder Agents](https://coder.com/docs/ai-coder/agents)* \`\`\` The \`\` marker must be at the end so future runs can find and update this comment." # Output the prompt { echo "chat_prompt<> "${GITHUB_OUTPUT}" - name: Run doc-check via Coder Agent Chat if: steps.check-secrets.outputs.skip != 'true' uses: coder/agents-chat-action@f0b975f503d3ff3e4478517baae290d4d01a2c7e # v0 with: coder-url: ${{ secrets.DOC_CHECK_CODER_URL }} coder-token: ${{ secrets.DOC_CHECK_CODER_SESSION_TOKEN }} chat-prompt: ${{ steps.extract-context.outputs.chat_prompt }} github-url: ${{ steps.determine-context.outputs.pr_url }} github-token: ${{ github.token }} wait: complete wait-timeout-seconds: "600" # The doc-check agent posts its own sticky comment when there # are findings; failures surface in the workflow run log. comment-on-issue: "false"