diff --git a/.github/workflows/doc-check.yaml b/.github/workflows/doc-check.yaml new file mode 100644 index 0000000000..dde36f45e2 --- /dev/null +++ b/.github/workflows/doc-check.yaml @@ -0,0 +1,205 @@ +# This workflow checks if a PR requires documentation updates. +# It creates a Coder Task that uses AI to analyze the PR changes, +# search existing docs, and comment with recommendations. +# +# Triggered by: Adding the "doc-check" label to a PR, or manual dispatch. + +name: AI Documentation Check + +on: + pull_request: + types: + - labeled + workflow_dispatch: + inputs: + pr_url: + description: "Pull Request URL to check" + required: true + type: string + template_preset: + description: "Template preset to use" + required: false + default: "" + type: string + +jobs: + doc-check: + name: Analyze PR for Documentation Updates Needed + runs-on: ubuntu-latest + if: | + (github.event.label.name == 'doc-check' || github.event_name == 'workflow_dispatch') && + (github.event.pull_request.draft == false || github.event_name == 'workflow_dispatch') + timeout-minutes: 30 + env: + CODER_URL: ${{ secrets.DOC_CHECK_CODER_URL }} + CODER_SESSION_TOKEN: ${{ secrets.DOC_CHECK_CODER_SESSION_TOKEN }} + permissions: + contents: read + pull-requests: write + actions: write + + steps: + - name: Determine PR Context + id: determine-context + env: + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_EVENT_NAME: ${{ github.event_name }} + GITHUB_EVENT_PR_HTML_URL: ${{ github.event.pull_request.html_url }} + GITHUB_EVENT_PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_EVENT_SENDER_ID: ${{ github.event.sender.id }} + GITHUB_EVENT_SENDER_LOGIN: ${{ github.event.sender.login }} + INPUTS_PR_URL: ${{ inputs.pr_url }} + INPUTS_TEMPLATE_PRESET: ${{ inputs.template_preset || '' }} + GH_TOKEN: ${{ github.token }} + run: | + echo "Using template preset: ${INPUTS_TEMPLATE_PRESET}" + echo "template_preset=${INPUTS_TEMPLATE_PRESET}" >> "${GITHUB_OUTPUT}" + + # For workflow_dispatch, use the provided PR URL + if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then + if ! GITHUB_USER_ID=$(gh api "users/${GITHUB_ACTOR}" --jq '.id'); then + echo "::error::Failed to get GitHub user ID for actor ${GITHUB_ACTOR}" + exit 1 + fi + echo "Using workflow_dispatch actor: ${GITHUB_ACTOR} (ID: ${GITHUB_USER_ID})" + echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}" + echo "github_username=${GITHUB_ACTOR}" >> "${GITHUB_OUTPUT}" + + echo "Using PR URL: ${INPUTS_PR_URL}" + # Convert /pull/ to /issues/ for create-task-action compatibility + ISSUE_URL="${INPUTS_PR_URL/\/pull\//\/issues\/}" + echo "pr_url=${ISSUE_URL}" >> "${GITHUB_OUTPUT}" + + # Extract PR number from URL for later use + PR_NUMBER=$(echo "${INPUTS_PR_URL}" | grep -oP '(?<=pull/)\d+') + echo "pr_number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}" + + elif [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then + GITHUB_USER_ID=${GITHUB_EVENT_SENDER_ID} + echo "Using label adder: ${GITHUB_EVENT_SENDER_LOGIN} (ID: ${GITHUB_USER_ID})" + echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}" + echo "github_username=${GITHUB_EVENT_SENDER_LOGIN}" >> "${GITHUB_OUTPUT}" + + echo "Using PR URL: ${GITHUB_EVENT_PR_HTML_URL}" + # Convert /pull/ to /issues/ for create-task-action compatibility + 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}" + + else + echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}" + exit 1 + fi + + - name: Extract changed files and build prompt + id: extract-context + env: + PR_URL: ${{ steps.determine-context.outputs.pr_url }} + PR_NUMBER: ${{ steps.determine-context.outputs.pr_number }} + GH_TOKEN: ${{ github.token }} + run: | + echo "Analyzing PR #${PR_NUMBER}" + + # Build task prompt - using unquoted heredoc so variables expand + TASK_PROMPT=$(cat <> "${GITHUB_OUTPUT}" + + - name: Checkout create-task-action + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 1 + path: ./.github/actions/create-task-action + persist-credentials: false + ref: main + repository: coder/create-task-action + + - name: Create Coder Task for Documentation Check + id: create_task + uses: ./.github/actions/create-task-action + with: + coder-url: ${{ secrets.DOC_CHECK_CODER_URL }} + coder-token: ${{ secrets.DOC_CHECK_CODER_SESSION_TOKEN }} + coder-organization: "default" + coder-template-name: coder + coder-template-preset: ${{ steps.determine-context.outputs.template_preset }} + coder-task-name-prefix: doc-check + coder-task-prompt: ${{ steps.extract-context.outputs.task_prompt }} + github-user-id: ${{ steps.determine-context.outputs.github_user_id }} + github-token: ${{ github.token }} + github-issue-url: ${{ steps.determine-context.outputs.pr_url }} + comment-on-issue: true + + - name: Write outputs + env: + TASK_CREATED: ${{ steps.create_task.outputs.task-created }} + TASK_NAME: ${{ steps.create_task.outputs.task-name }} + TASK_URL: ${{ steps.create_task.outputs.task-url }} + PR_URL: ${{ steps.determine-context.outputs.pr_url }} + run: | + { + echo "## Documentation Check Task" + echo "" + echo "**PR:** ${PR_URL}" + echo "**Task created:** ${TASK_CREATED}" + echo "**Task name:** ${TASK_NAME}" + echo "**Task URL:** ${TASK_URL}" + echo "" + echo "The Coder task is analyzing the PR changes and will comment with documentation recommendations." + } >> "${GITHUB_STEP_SUMMARY}"