diff --git a/.github/workflows/auto-issue-fix.yaml b/.github/workflows/auto-issue-fix.yaml deleted file mode 100644 index 15c2a8ec..00000000 --- a/.github/workflows/auto-issue-fix.yaml +++ /dev/null @@ -1,500 +0,0 @@ -name: ๐Ÿค– Auto Issue Fix Pipeline - -# Multi-agent pipeline that: -# 1. Scans and triages recent GitHub issues (issue-scanner agent) -# 2. Fixes the selected issue and pushes a fix branch (issue-fixer agent) -# 3. Verifies the fix branch against the DTS emulator (pr-verification agent) -# -# Agents are chained sequentially via file-based handoff: -# issue-scanner โ†’ /tmp/selected-issue.json โ†’ issue-fixer โ†’ /tmp/fix-branch-info.json โ†’ pr-verification -# -# Note: GitHub Copilot CLI agents do not support built-in handoffs in CI. -# Chaining is achieved by running agents as sequential workflow steps and -# injecting the previous agent's output into the next agent's prompt. -# -# The fixer agent pushes a branch (not a PR) because the workflow only has -# pull-requests: read permission. A human opens the PR from the branch. - -on: - # Run every day at 09:00 UTC - schedule: - - cron: "0 9 * * *" - # Allow manual trigger for testing - workflow_dispatch: - -permissions: - contents: write - issues: write - pull-requests: read - -jobs: - auto-issue-fix: - runs-on: ubuntu-latest - timeout-minutes: 150 - - env: - DOTNET_VER_6: "6.0.x" - DOTNET_VER_8: "8.0.x" - DOTNET_VER_10: "10.0.x" - SOLUTION: "Microsoft.DurableTask.sln" - - steps: - # โ”€โ”€โ”€ Setup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - - name: ๐Ÿ“ฅ Checkout code (full history for analysis) - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: โš™๏ธ Setup .NET 6.0 - uses: actions/setup-dotnet@v4 - with: - dotnet-version: ${{ env.DOTNET_VER_6 }} - - - name: โš™๏ธ Setup .NET 8.0 - uses: actions/setup-dotnet@v4 - with: - dotnet-version: ${{ env.DOTNET_VER_8 }} - - - name: โš™๏ธ Setup .NET 10.0 - uses: actions/setup-dotnet@v4 - with: - dotnet-version: ${{ env.DOTNET_VER_10 }} - - - name: โš™๏ธ Setup .NET from global.json - uses: actions/setup-dotnet@v4 - with: - global-json-file: global.json - - - name: ๐Ÿ”จ Restore and build - run: | - dotnet restore $SOLUTION - dotnet build $SOLUTION --configuration Release --no-restore - - - name: ๐Ÿงช Run tests (non-blocking baseline before analysis) - continue-on-error: true - run: | - dotnet test $SOLUTION --configuration Release --no-build --verbosity normal - - # โ”€โ”€โ”€ Deduplication Context โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - - name: ๐Ÿ” Collect existing work to avoid duplicates - id: dedup - run: | - echo "Fetching open PRs and issues with copilot-finds label..." - - # Get open PRs with copilot-finds label (include file paths for targeted dedup) - OPEN_PRS=$(gh pr list \ - --label "copilot-finds" \ - --state open \ - --limit 50 \ - --json title,url,headRefName,files \ - --jq '[.[] | {title: .title, url: .url, branch: .headRefName, files: [.files[].path]}]' \ - 2>/dev/null || echo "[]") - - # Get open issues with copilot-finds label - OPEN_ISSUES=$(gh issue list \ - --label "copilot-finds" \ - --state open \ - --limit 50 \ - --json title,url \ - --jq '[.[] | {title: .title, url: .url}]' \ - 2>/dev/null || echo "[]") - - # Get recently merged PRs (last 14 days) โ€” title/url only to avoid prompt bloat - RECENT_MERGED=$(gh pr list \ - --label "copilot-finds" \ - --state merged \ - --limit 50 \ - --json title,url,mergedAt \ - --jq '[.[] | select((.mergedAt | fromdateiso8601) > (now - 14*86400)) | {title: .title, url: .url}]' \ - 2>/dev/null || echo "[]") - - # Write dedup context - cat < /tmp/exclusion-context.txt - === EXISTING WORK (DO NOT DUPLICATE) === - - ## Open PRs with copilot-finds label: - $OPEN_PRS - - ## Open issues with copilot-finds label: - $OPEN_ISSUES - - ## Recently merged copilot-finds PRs (last 14 days): - $RECENT_MERGED - - === END EXISTING WORK === - DEDUP_EOF - - echo "Dedup context collected." - env: - GH_TOKEN: ${{ github.token }} - GH_REPO: ${{ github.repository }} - - # โ”€โ”€โ”€ Labels โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - - name: ๐Ÿท๏ธ Ensure required labels exist - run: | - set -euo pipefail - - ensure_label() { - local name="$1" - local description="$2" - local color="$3" - if gh label list --limit 200 --json name --jq '.[].name' | grep -Fxq "$name"; then - echo "Label '$name' already exists; skipping." - else - echo "Creating label '$name'." - gh label create "$name" --description "$description" --color "$color" - fi - } - - # Pipeline labels - ensure_label "copilot-finds" \ - "Findings from automated code review agents" "7057ff" - ensure_label "pending-verification" \ - "PR awaiting automated verification" "fbca04" - ensure_label "sample-verification-added" \ - "PR has been verified by the PR verification agent" "0e8a16" - - # Triage labels (used by issue-scanner agent) - ensure_label "triage/actionable" \ - "Issue is ready for automated fix โ€” clear scope, no blockers" "1d76db" - ensure_label "triage/needs-human-verification" \ - "Requires human judgment or domain expertise to verify" "c5def5" - ensure_label "triage/known-blocker" \ - "Has a known dependency or blocker preventing fix" "e4e669" - ensure_label "triage/requires-redesign" \ - "Needs architectural changes or design discussion" "d4c5f9" - ensure_label "triage/needs-info" \ - "Missing reproduction steps or unclear description" "d93f0b" - ensure_label "triage/already-fixed" \ - "Already resolved by a merged PR or closed" "bfdadc" - ensure_label "triage/too-large" \ - "Scope too large for a single automated fix" "f9d0c4" - ensure_label "triage/external-dependency" \ - "Depends on changes in another repo or service" "c2e0c6" - ensure_label "triage/duplicate" \ - "Duplicate of another issue" "cfd3d7" - ensure_label "triage/feature-request" \ - "Feature request, not a bug fix" "a2eeef" - env: - GH_TOKEN: ${{ github.token }} - GH_REPO: ${{ github.repository }} - - # โ”€โ”€โ”€ Agent 1: Issue Scanner โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - - name: ๐Ÿค– Install GitHub Copilot CLI - run: npm install -g @github/copilot - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_TOKEN: ${{ github.token }} - - - name: ๐Ÿ” Agent 1 โ€” Issue Scanner - id: issue_scanner - run: | - EXCLUSION_CONTEXT=$(cat /tmp/exclusion-context.txt) - AGENT_PROMPT=$(cat .github/agents/issue-scanner.agent.md) - - FULL_PROMPT=$(cat <&1 || EXIT_CODE=$? - - if [ $EXIT_CODE -eq 124 ]; then - echo "::warning::Issue scanner agent timed out after 20 minutes" - fi - - # Check if an issue was found - if [ -f /tmp/selected-issue.json ]; then - FOUND=$(cat /tmp/selected-issue.json | jq -r '.found // false') - echo "issue_found=$FOUND" >> $GITHUB_OUTPUT - if [ "$FOUND" = "true" ]; then - ISSUE_NUM=$(cat /tmp/selected-issue.json | jq -r '.issueNumber') - echo "issue_number=$ISSUE_NUM" >> $GITHUB_OUTPUT - echo "Issue #$ISSUE_NUM selected for fixing." - else - echo "No actionable issue found. Pipeline will stop." - fi - else - echo "issue_found=false" >> $GITHUB_OUTPUT - echo "::warning::Handoff file not created โ€” no issue found." - fi - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_TOKEN: ${{ github.token }} - CI: "true" - NO_COLOR: "1" - TERM: "dumb" - - # โ”€โ”€โ”€ Agent 2: Issue Fixer โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - - name: ๐Ÿ”ง Agent 2 โ€” Issue Fixer - id: issue_fixer - if: steps.issue_scanner.outputs.issue_found == 'true' - run: | - ISSUE_CONTEXT=$(cat /tmp/selected-issue.json) - AGENT_PROMPT=$(cat .github/agents/issue-fixer.agent.md) - - FULL_PROMPT=$(cat <&1 || EXIT_CODE=$? - - if [ $EXIT_CODE -eq 124 ]; then - echo "::warning::Issue fixer agent timed out after 40 minutes" - fi - - # Check if a fix branch was pushed - if [ -f /tmp/fix-branch-info.json ]; then - CREATED=$(cat /tmp/fix-branch-info.json | jq -r '.created // false') - echo "branch_created=$CREATED" >> $GITHUB_OUTPUT - if [ "$CREATED" = "true" ]; then - BRANCH_NAME=$(cat /tmp/fix-branch-info.json | jq -r '.branchName') - echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT - echo "Fix branch '$BRANCH_NAME' pushed successfully." - else - echo "No fix branch was pushed. Pipeline will stop before verification." - fi - else - echo "branch_created=false" >> $GITHUB_OUTPUT - echo "::warning::Handoff file not created โ€” no fix branch pushed." - fi - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_TOKEN: ${{ github.token }} - CI: "true" - NO_COLOR: "1" - TERM: "dumb" - - # โ”€โ”€โ”€ Agent 3: Branch Verification โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - - name: ๐Ÿณ Start DTS Emulator - if: steps.issue_fixer.outputs.branch_created == 'true' - run: | - docker run --name dts-emulator -d --rm -p 4001:8080 \ - mcr.microsoft.com/dts/dts-emulator:latest - - echo "Waiting for emulator to be ready..." - for i in $(seq 1 30); do - if nc -z localhost 4001 2>/dev/null; then - echo "Emulator is ready!" - break - fi - if [ "$i" -eq 30 ]; then - echo "Emulator failed to start within 30 seconds" - exit 1 - fi - sleep 1 - done - - - name: ๐Ÿ”Ž Agent 3 โ€” Branch Verification - if: steps.issue_fixer.outputs.branch_created == 'true' - run: | - BRANCH_CONTEXT=$(cat /tmp/fix-branch-info.json) - AGENT_PROMPT=$(cat .github/agents/pr-verification.agent.md) - - FULL_PROMPT=$(cat <&1 || EXIT_CODE=$? - - if [ $EXIT_CODE -eq 124 ]; then - echo "::warning::Branch verification agent timed out after 30 minutes" - elif [ $EXIT_CODE -ne 0 ]; then - echo "::warning::Branch verification agent exited with code $EXIT_CODE" - fi - - echo "Branch verification agent completed." - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_TOKEN: ${{ github.token }} - DTS_ENDPOINT: localhost:4001 - DTS_TASKHUB: default - CI: "true" - NO_COLOR: "1" - TERM: "dumb" - - - name: ๐Ÿงน Stop DTS Emulator - if: always() - run: docker stop dts-emulator 2>/dev/null || true - - # โ”€โ”€โ”€ Summary โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - - - name: ๐Ÿ“Š Pipeline Summary - if: always() - run: | - echo "## ๐Ÿค– Auto Issue Fix Pipeline Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Date:** $(date +%Y-%m-%d)" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - # Agent 1 results - echo "### Agent 1: Issue Scanner" >> $GITHUB_STEP_SUMMARY - if [ -f /tmp/selected-issue.json ]; then - FOUND=$(cat /tmp/selected-issue.json | jq -r '.found // false') - if [ "$FOUND" = "true" ]; then - ISSUE_NUM=$(cat /tmp/selected-issue.json | jq -r '.issueNumber') - ISSUE_TITLE=$(cat /tmp/selected-issue.json | jq -r '.issueTitle') - echo "- โœ… Selected issue: #$ISSUE_NUM โ€” $ISSUE_TITLE" >> $GITHUB_STEP_SUMMARY - else - REASON=$(cat /tmp/selected-issue.json | jq -r '.reason // "Unknown"') - echo "- โญ๏ธ No actionable issue found: $REASON" >> $GITHUB_STEP_SUMMARY - fi - else - echo "- โŒ Handoff file not created" >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - - # Agent 2 results - echo "### Agent 2: Issue Fixer" >> $GITHUB_STEP_SUMMARY - if [ "${{ steps.issue_scanner.outputs.issue_found }}" != "true" ]; then - echo "- โญ๏ธ Skipped (no issue selected)" >> $GITHUB_STEP_SUMMARY - elif [ -f /tmp/fix-branch-info.json ]; then - CREATED=$(cat /tmp/fix-branch-info.json | jq -r '.created // false') - if [ "$CREATED" = "true" ]; then - BRANCH_NAME=$(cat /tmp/fix-branch-info.json | jq -r '.branchName') - BRANCH_URL=$(cat /tmp/fix-branch-info.json | jq -r '.branchUrl') - echo "- โœ… Fix branch pushed: [$BRANCH_NAME]($BRANCH_URL)" >> $GITHUB_STEP_SUMMARY - else - echo "- โญ๏ธ No fix branch pushed" >> $GITHUB_STEP_SUMMARY - fi - else - echo "- โŒ Fixer agent ran but handoff file was not created (agent may have crashed or timed out)" >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - - # Agent 3 results - echo "### Agent 3: Branch Verification" >> $GITHUB_STEP_SUMMARY - if [ "${{ steps.issue_fixer.outputs.branch_created }}" = "true" ]; then - echo "- โœ… Verification completed (check issue comments for results)" >> $GITHUB_STEP_SUMMARY - else - echo "- โญ๏ธ Skipped (no fix branch to verify)" >> $GITHUB_STEP_SUMMARY - fi - env: - GH_TOKEN: ${{ github.token }} - GH_REPO: ${{ github.repository }}