|
| 1 | +# This workflow checks if a PR requires documentation updates. |
| 2 | +# It creates a Coder Task that uses AI to analyze the PR changes, |
| 3 | +# search existing docs, and comment with recommendations. |
| 4 | +# |
| 5 | +# Triggered by: Adding the "doc-check" label to a PR, or manual dispatch. |
| 6 | + |
| 7 | +name:AI Documentation Check |
| 8 | + |
| 9 | +on: |
| 10 | +pull_request: |
| 11 | +types: |
| 12 | + -labeled |
| 13 | +workflow_dispatch: |
| 14 | +inputs: |
| 15 | +pr_url: |
| 16 | +description:"Pull Request URL to check" |
| 17 | +required:true |
| 18 | +type:string |
| 19 | +template_preset: |
| 20 | +description:"Template preset to use" |
| 21 | +required:false |
| 22 | +default:"" |
| 23 | +type:string |
| 24 | + |
| 25 | +jobs: |
| 26 | +doc-check: |
| 27 | +name:Analyze PR for Documentation Updates Needed |
| 28 | +runs-on:ubuntu-latest |
| 29 | +if:| |
| 30 | + (github.event.label.name == 'doc-check' || github.event_name == 'workflow_dispatch') && |
| 31 | + (github.event.pull_request.draft == false || github.event_name == 'workflow_dispatch') |
| 32 | +timeout-minutes:30 |
| 33 | +env: |
| 34 | +CODER_URL:${{ secrets.DOC_CHECK_CODER_URL }} |
| 35 | +CODER_SESSION_TOKEN:${{ secrets.DOC_CHECK_CODER_SESSION_TOKEN }} |
| 36 | +permissions: |
| 37 | +contents:read |
| 38 | +pull-requests:write |
| 39 | +actions:write |
| 40 | + |
| 41 | +steps: |
| 42 | + -name:Determine PR Context |
| 43 | +id:determine-context |
| 44 | +env: |
| 45 | +GITHUB_ACTOR:${{ github.actor }} |
| 46 | +GITHUB_EVENT_NAME:${{ github.event_name }} |
| 47 | +GITHUB_EVENT_PR_HTML_URL:${{ github.event.pull_request.html_url }} |
| 48 | +GITHUB_EVENT_PR_NUMBER:${{ github.event.pull_request.number }} |
| 49 | +GITHUB_EVENT_SENDER_ID:${{ github.event.sender.id }} |
| 50 | +GITHUB_EVENT_SENDER_LOGIN:${{ github.event.sender.login }} |
| 51 | +INPUTS_PR_URL:${{ inputs.pr_url }} |
| 52 | +INPUTS_TEMPLATE_PRESET:${{ inputs.template_preset || '' }} |
| 53 | +GH_TOKEN:${{ github.token }} |
| 54 | +run:| |
| 55 | + echo "Using template preset: ${INPUTS_TEMPLATE_PRESET}" |
| 56 | + echo "template_preset=${INPUTS_TEMPLATE_PRESET}" >> "${GITHUB_OUTPUT}" |
| 57 | +
|
| 58 | + # For workflow_dispatch, use the provided PR URL |
| 59 | + if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then |
| 60 | + if ! GITHUB_USER_ID=$(gh api "users/${GITHUB_ACTOR}" --jq '.id'); then |
| 61 | + echo "::error::Failed to get GitHub user ID for actor ${GITHUB_ACTOR}" |
| 62 | + exit 1 |
| 63 | + fi |
| 64 | + echo "Using workflow_dispatch actor: ${GITHUB_ACTOR} (ID: ${GITHUB_USER_ID})" |
| 65 | + echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}" |
| 66 | + echo "github_username=${GITHUB_ACTOR}" >> "${GITHUB_OUTPUT}" |
| 67 | +
|
| 68 | + echo "Using PR URL: ${INPUTS_PR_URL}" |
| 69 | + # Convert /pull/ to /issues/ for create-task-action compatibility |
| 70 | + ISSUE_URL="${INPUTS_PR_URL/\/pull\//\/issues\/}" |
| 71 | + echo "pr_url=${ISSUE_URL}" >> "${GITHUB_OUTPUT}" |
| 72 | +
|
| 73 | + # Extract PR number from URL for later use |
| 74 | + PR_NUMBER=$(echo "${INPUTS_PR_URL}" | grep -oP '(?<=pull/)\d+') |
| 75 | + echo "pr_number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}" |
| 76 | +
|
| 77 | + elif [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then |
| 78 | + GITHUB_USER_ID=${GITHUB_EVENT_SENDER_ID} |
| 79 | + echo "Using label adder: ${GITHUB_EVENT_SENDER_LOGIN} (ID: ${GITHUB_USER_ID})" |
| 80 | + echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}" |
| 81 | + echo "github_username=${GITHUB_EVENT_SENDER_LOGIN}" >> "${GITHUB_OUTPUT}" |
| 82 | +
|
| 83 | + echo "Using PR URL: ${GITHUB_EVENT_PR_HTML_URL}" |
| 84 | + # Convert /pull/ to /issues/ for create-task-action compatibility |
| 85 | + ISSUE_URL="${GITHUB_EVENT_PR_HTML_URL/\/pull\//\/issues\/}" |
| 86 | + echo "pr_url=${ISSUE_URL}" >> "${GITHUB_OUTPUT}" |
| 87 | + echo "pr_number=${GITHUB_EVENT_PR_NUMBER}" >> "${GITHUB_OUTPUT}" |
| 88 | +
|
| 89 | + else |
| 90 | + echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}" |
| 91 | + exit 1 |
| 92 | + fi |
| 93 | +
|
| 94 | + -name:Extract changed files and build prompt |
| 95 | +id:extract-context |
| 96 | +env: |
| 97 | +PR_URL:${{ steps.determine-context.outputs.pr_url }} |
| 98 | +PR_NUMBER:${{ steps.determine-context.outputs.pr_number }} |
| 99 | +GH_TOKEN:${{ github.token }} |
| 100 | +run:| |
| 101 | + echo "Analyzing PR #${PR_NUMBER}" |
| 102 | +
|
| 103 | + # Build task prompt - using unquoted heredoc so variables expand |
| 104 | + TASK_PROMPT=$(cat <<EOF |
| 105 | + Review PR #${PR_NUMBER} and determine if documentation needs updating or creating. |
| 106 | +
|
| 107 | + PR URL: ${PR_URL} |
| 108 | +
|
| 109 | + WORKFLOW: |
| 110 | + 1. Setup (repo is pre-cloned at ~/coder) |
| 111 | + cd ~/coder |
| 112 | + git fetch origin pull/${PR_NUMBER}/head:pr-${PR_NUMBER} |
| 113 | + git checkout pr-${PR_NUMBER} |
| 114 | +
|
| 115 | + 2. Get PR info |
| 116 | + Use GitHub MCP tools to get PR title, body, and diff |
| 117 | + Or use: git diff main...pr-${PR_NUMBER} |
| 118 | +
|
| 119 | + 3. Understand Changes |
| 120 | + Read the diff and identify what changed |
| 121 | + Ask: Is this user-facing? Does it change behavior? Is it a new feature? |
| 122 | +
|
| 123 | + 4. Search for Related Docs |
| 124 | + cat ~/coder/docs/manifest.json | jq '.routes[] | {title, path}' | head -50 |
| 125 | + grep -ri "relevant_term" ~/coder/docs/ --include="*.md" |
| 126 | +
|
| 127 | + 5. Decide |
| 128 | + NEEDS DOCS if: New feature, API change, CLI change, behavior change, user-visible |
| 129 | + NO DOCS if: Internal refactor, test-only, already documented, non-user-facing, dependency updates |
| 130 | + FIRST check: Did this PR already update docs? If yes and complete, say "No Changes Needed" |
| 131 | +
|
| 132 | + 6. Comment on the PR using this format |
| 133 | +
|
| 134 | + COMMENT FORMAT: |
| 135 | + ## 📚 Documentation Check |
| 136 | +
|
| 137 | + ### ✅ Updates Needed |
| 138 | + - **[docs/path/file.md](github_link)** - Brief what needs changing |
| 139 | +
|
| 140 | + ### 📝 New Docs Needed |
| 141 | + - **docs/suggested/location.md** - What should be documented |
| 142 | +
|
| 143 | + ### ✨ No Changes Needed |
| 144 | + [Reason: Documents already updated in PR | Internal changes only | Test-only | No user-facing impact] |
| 145 | +
|
| 146 | + --- |
| 147 | + *This comment was generated by an AI Agent through [Coder Tasks](https://coder.com/docs/ai-coder/tasks)* |
| 148 | +
|
| 149 | + DOCS STRUCTURE: |
| 150 | + Read ~/coder/docs/manifest.json for the complete documentation structure. |
| 151 | + Common areas include: reference/, admin/, user-guides/, ai-coder/, install/, tutorials/ |
| 152 | + But check manifest.json - it has everything. |
| 153 | +
|
| 154 | + EOF |
| 155 | + ) |
| 156 | +
|
| 157 | + # Output the prompt |
| 158 | + { |
| 159 | + echo "task_prompt<<EOFOUTPUT" |
| 160 | + echo "${TASK_PROMPT}" |
| 161 | + echo "EOFOUTPUT" |
| 162 | + } >> "${GITHUB_OUTPUT}" |
| 163 | +
|
| 164 | + -name:Checkout create-task-action |
| 165 | +uses:actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8# v5.0.0 |
| 166 | +with: |
| 167 | +fetch-depth:1 |
| 168 | +path:./.github/actions/create-task-action |
| 169 | +persist-credentials:false |
| 170 | +ref:main |
| 171 | +repository:coder/create-task-action |
| 172 | + |
| 173 | + -name:Create Coder Task for Documentation Check |
| 174 | +id:create_task |
| 175 | +uses:./.github/actions/create-task-action |
| 176 | +with: |
| 177 | +coder-url:${{ secrets.DOC_CHECK_CODER_URL }} |
| 178 | +coder-token:${{ secrets.DOC_CHECK_CODER_SESSION_TOKEN }} |
| 179 | +coder-organization:"default" |
| 180 | +coder-template-name:coder |
| 181 | +coder-template-preset:${{ steps.determine-context.outputs.template_preset }} |
| 182 | +coder-task-name-prefix:doc-check |
| 183 | +coder-task-prompt:${{ steps.extract-context.outputs.task_prompt }} |
| 184 | +github-user-id:${{ steps.determine-context.outputs.github_user_id }} |
| 185 | +github-token:${{ github.token }} |
| 186 | +github-issue-url:${{ steps.determine-context.outputs.pr_url }} |
| 187 | +comment-on-issue:true |
| 188 | + |
| 189 | + -name:Write outputs |
| 190 | +env: |
| 191 | +TASK_CREATED:${{ steps.create_task.outputs.task-created }} |
| 192 | +TASK_NAME:${{ steps.create_task.outputs.task-name }} |
| 193 | +TASK_URL:${{ steps.create_task.outputs.task-url }} |
| 194 | +PR_URL:${{ steps.determine-context.outputs.pr_url }} |
| 195 | +run:| |
| 196 | + { |
| 197 | + echo "## Documentation Check Task" |
| 198 | + echo "" |
| 199 | + echo "**PR:** ${PR_URL}" |
| 200 | + echo "**Task created:** ${TASK_CREATED}" |
| 201 | + echo "**Task name:** ${TASK_NAME}" |
| 202 | + echo "**Task URL:** ${TASK_URL}" |
| 203 | + echo "" |
| 204 | + echo "The Coder task is analyzing the PR changes and will comment with documentation recommendations." |
| 205 | + } >> "${GITHUB_STEP_SUMMARY}" |