From 8f3e03ad401ae55fb5ac83805e2bccdd9541703c Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 24 Sep 2025 11:54:44 +0100 Subject: [PATCH] ci: add auto-generated summary and GitHub issue comment workflows to triage.yaml (#19925) --- .github/workflows/traiage.yaml | 60 +++++++++++++++++++++------------- scripts/traiage.sh | 46 +++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 23 deletions(-) diff --git a/.github/workflows/traiage.yaml b/.github/workflows/traiage.yaml index e2b10ea0b1..50fe47384f 100644 --- a/.github/workflows/traiage.yaml +++ b/.github/workflows/traiage.yaml @@ -4,18 +4,18 @@ on: workflow_dispatch: inputs: issue_url: - description: 'GitHub Issue URL to process' + description: "GitHub Issue URL to process" required: true type: string template_name: - description: 'Coder template to use for workspace' + description: "Coder template to use for workspace" required: true - default: 'traiage' + default: "traiage" type: string prefix: - description: 'Prefix for workspace name' + description: "Prefix for workspace name" required: false - default: 'traiage' + default: "traiage" type: string jobs: @@ -89,7 +89,7 @@ jobs: ISSUE_URL: ${{ inputs.issue_url }} GITHUB_TOKEN: ${{ github.token }} run: | - PROMPT_FILE=/tmp/prompt.txt + PROMPT_FILE=$(mktemp) trap 'rm -f "${PROMPT_FILE}"' EXIT # Fetch issue description using `gh` CLI @@ -108,7 +108,7 @@ jobs: echo "WORKSPACE_NAME: ${WORKSPACE_NAME}" # This command will run the prompt inside the workspace # and exit once the agent has completed the task. - PROMPT=$(cat $PROMPT_FILE) ./scripts/traiage.sh prompt + PROMPT=$(cat "${PROMPT_FILE}") ./scripts/traiage.sh prompt - name: Create and upload archive id: create-archive @@ -119,27 +119,43 @@ jobs: ./scripts/traiage.sh archive echo "archive_url=${BUCKET_PREFIX%%/}/$WORKSPACE_NAME.tar.gz" >> "${GITHUB_OUTPUT}" - - name: Report results + - name: Generate a summary of the changes and post a comment on GitHub. + id: generate-summary env: - ISSUE_URL: ${{ inputs.issue_url }} - CONTEXT_KEY: ${{ steps.extract-context.outputs.context_key }} - WORKSPACE_NAME: ${{ steps.create-workspace.outputs.workspace_name }} ARCHIVE_URL: ${{ steps.create-archive.outputs.archive_url }} BUCKET_PREFIX: "gs://coder-traiage-outputs/traiage" + CONTEXT_KEY: ${{ steps.extract-context.outputs.context_key }} + GITHUB_TOKEN: ${{ github.token }} + GITHUB_REPOSITORY: ${{ github.repository }} + ISSUE_URL: ${{ inputs.issue_url }} + WORKSPACE_NAME: ${{ steps.create-workspace.outputs.workspace_name }} run: | + SUMMARY_FILE=$(mktemp) + trap 'rm -f "${SUMMARY_FILE}"' EXIT + AUTO_SUMMARY=$(./scripts/traiage.sh summary) { - echo "## TrAIage Results"; - echo "- **Issue URL:** ${ISSUE_URL}"; - echo "- **Context Key:** ${CONTEXT_KEY}"; - echo "- **Workspace:** ${WORKSPACE_NAME}"; - echo "- **Archive URL:** ${ARCHIVE_URL}"; - - echo "To fetch the output to your own workspace:"; - echo ''; - echo '```bash'; - echo "BUCKET_PREFIX=${BUCKET_PREFIX} WORKSPACE_NAME=${WORKSPACE_NAME} ./scripts/traiage.sh resume"; + echo "## TrAIage Results" + echo "- **Issue URL:** ${ISSUE_URL}" + echo "- **Context Key:** ${CONTEXT_KEY}" + echo "- **Workspace:** ${WORKSPACE_NAME}" + echo "- **Archive URL:** ${ARCHIVE_URL}" + echo + echo "${AUTO_SUMMARY}" + echo + echo "To fetch the output to your own workspace:" + echo + echo '```bash' + echo "BUCKET_PREFIX=${BUCKET_PREFIX} WORKSPACE_NAME=${WORKSPACE_NAME} ./scripts/traiage.sh resume" echo '```' - } >> "${GITHUB_STEP_SUMMARY}" + echo + } >> "${SUMMARY_FILE}" + + if [[ "${ISSUE_URL}" == "https://github.com/${GITHUB_REPOSITORY}"* ]]; then + gh issue comment "${ISSUE_URL}" --body-file "${SUMMARY_FILE}" --create-if-none --edit-last + else + echo "Skipping comment on other repo." + fi + cat "${SUMMARY_FILE}" >> "${GITHUB_STEP_SUMMARY}" - name: Cleanup workspace if: steps.create-workspace.outputs.workspace_name != '' && steps.create-archive.outputs.archive_url != '' diff --git a/scripts/traiage.sh b/scripts/traiage.sh index 8d31a09869..a94ca25794 100755 --- a/scripts/traiage.sh +++ b/scripts/traiage.sh @@ -20,6 +20,18 @@ usage() { create() { requiredenvs CODER_URL CODER_SESSION_TOKEN WORKSPACE_NAME TEMPLATE_NAME TEMPLATE_PARAMETERS + # Check if a workspace already exists + exists=$("${CODER_BIN}" \ + --url "${CODER_URL}" \ + --token "${CODER_SESSION_TOKEN}" \ + list \ + --search "owner:me" \ + --output json | + jq -r --arg name "${WORKSPACE_NAME}" 'any(.[]; select(.name == $name))') + if [[ "${exists}" == "true" ]]; then + echo "Workspace ${WORKSPACE_NAME} already exists." + exit 0 + fi "${CODER_BIN}" \ --url "${CODER_URL}" \ --token "${CODER_SESSION_TOKEN}" \ @@ -54,7 +66,8 @@ ssh_config() { --url "${CODER_URL}" \ --token "${CODER_SESSION_TOKEN}" \ --ssh-config-file="${OPENSSH_CONFIG_FILE}" \ - --yes + --yes \ + >/dev/null 2>&1 export OPENSSH_CONFIG_FILE } @@ -169,6 +182,34 @@ archive() { exit 0 } +summary() { + requiredenvs CODER_URL CODER_SESSION_TOKEN WORKSPACE_NAME + ssh_config + + # We want the heredoc to be expanded locally and not remotely. + # shellcheck disable=SC2087 + ssh \ + -F "${OPENSSH_CONFIG_FILE}" \ + "${WORKSPACE_NAME}.coder" \ + -- \ + bash <<-EOF + #!/usr/bin/env bash + set -eu + summary=\$(echo -n 'You are a CLI utility that generates a human-readable Markdown summary for the currently staged AND unstaged changes. Print ONLY the summary and nothing else.' | \${HOME}/.local/bin/claude --print) + if [[ -z "\${summary}" ]]; then + echo "Generating a summary failed." + echo "Here is a short overview of the changes:" + echo + echo "" + echo "\$(git diff --stat)" + echo "" + exit 0 + fi + echo "\${summary}" + exit 0 + EOF +} + commit_push() { requiredenvs CODER_URL CODER_SESSION_TOKEN WORKSPACE_NAME ssh_config @@ -265,6 +306,9 @@ main() { resume) resume ;; + summary) + summary + ;; *) echo "Unknown option: $1" usage