|
73 | 73 | git config user.name "aieng-bot-maintain[bot]" |
74 | 74 | git config user.email "aieng-bot@vectorinstitute.ai" |
75 | 75 |
|
76 | | - - name: Analyze failure type |
77 | | - id: analyze |
78 | | - working-directory: target-repo |
79 | | - run: | |
80 | | - FAILED_CHECKS='${{ steps.pr-details.outputs.failed-checks }}' |
81 | | -
|
82 | | - echo "Analyzing failures..." |
83 | | - echo "$FAILED_CHECKS" | jq -r '.[] | "\(.name): \(.conclusion)"' |
84 | | -
|
85 | | - # Check for merge conflicts first |
86 | | - if git status | grep -q "Unmerged paths\|merge conflict"; then |
87 | | - echo "primary-type=merge_conflict" >> $GITHUB_OUTPUT |
88 | | - echo "failed-names=merge-conflict" >> $GITHUB_OUTPUT |
89 | | - echo "Detected merge conflicts" |
90 | | - exit 0 |
91 | | - fi |
92 | | -
|
93 | | - # Categorize failures |
94 | | - TEST_FAILURES=$(echo "$FAILED_CHECKS" | jq '[.[] | select(.name | test("test|spec|jest|pytest|unittest"; "i"))]') |
95 | | - LINT_FAILURES=$(echo "$FAILED_CHECKS" | jq '[.[] | select(.name | test("lint|format|pre-commit|eslint|prettier|black|flake8|ruff"; "i"))]') |
96 | | - SECURITY_FAILURES=$(echo "$FAILED_CHECKS" | jq '[.[] | select(.name | test("audit|security|snyk|dependabot|pip-audit"; "i"))]') |
97 | | - BUILD_FAILURES=$(echo "$FAILED_CHECKS" | jq '[.[] | select(.name | test("build|compile|webpack|vite|tsc"; "i"))]') |
98 | | - MERGE_CONFLICT_FAILURES=$(echo "$FAILED_CHECKS" | jq '[.[] | select(.name | test("merge|conflict"; "i"))]') |
99 | | -
|
100 | | - # Determine primary failure type |
101 | | - if [ "$(echo "$MERGE_CONFLICT_FAILURES" | jq 'length')" -gt 0 ]; then |
102 | | - echo "primary-type=merge_conflict" >> $GITHUB_OUTPUT |
103 | | - elif [ "$(echo "$TEST_FAILURES" | jq 'length')" -gt 0 ]; then |
104 | | - echo "primary-type=test" >> $GITHUB_OUTPUT |
105 | | - elif [ "$(echo "$LINT_FAILURES" | jq 'length')" -gt 0 ]; then |
106 | | - echo "primary-type=lint" >> $GITHUB_OUTPUT |
107 | | - elif [ "$(echo "$SECURITY_FAILURES" | jq 'length')" -gt 0 ]; then |
108 | | - echo "primary-type=security" >> $GITHUB_OUTPUT |
109 | | - elif [ "$(echo "$BUILD_FAILURES" | jq 'length')" -gt 0 ]; then |
110 | | - echo "primary-type=build" >> $GITHUB_OUTPUT |
111 | | - else |
112 | | - echo "primary-type=unknown" >> $GITHUB_OUTPUT |
113 | | - fi |
114 | | -
|
115 | | - FAILED_NAMES=$(echo "$FAILED_CHECKS" | jq -r '.[].name' | paste -sd "," -) |
116 | | - echo "failed-names=$FAILED_NAMES" >> $GITHUB_OUTPUT |
117 | | -
|
118 | 76 | - name: Get failure logs |
119 | 77 | id: get-logs |
120 | 78 | run: | |
@@ -142,19 +100,85 @@ jobs: |
142 | 100 | env: |
143 | 101 | GH_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }} |
144 | 102 |
|
| 103 | + - name: Setup Python for classification |
| 104 | + uses: actions/setup-python@v5 |
| 105 | + with: |
| 106 | + python-version: '3.12' |
| 107 | + |
| 108 | + - name: Install classifier dependencies |
| 109 | + run: | |
| 110 | + cd bot-repo |
| 111 | + pip install -e . |
| 112 | +
|
| 113 | + - name: Analyze failure type with Claude |
| 114 | + id: analyze |
| 115 | + working-directory: target-repo |
| 116 | + run: | |
| 117 | + FAILED_CHECKS='${{ steps.pr-details.outputs.failed-checks }}' |
| 118 | +
|
| 119 | + echo "Analyzing failures with Claude-based classifier..." |
| 120 | + echo "$FAILED_CHECKS" | jq -r '.[] | "\(.name): \(.conclusion)"' |
| 121 | +
|
| 122 | + # Check for merge conflicts first (quick local check) |
| 123 | + if git status | grep -q "Unmerged paths\|merge conflict"; then |
| 124 | + echo "failure-type=merge_conflict" >> $GITHUB_OUTPUT |
| 125 | + echo "failed-check-names=merge-conflict" >> $GITHUB_OUTPUT |
| 126 | + echo "confidence=1.0" >> $GITHUB_OUTPUT |
| 127 | + echo "reasoning=Git merge conflicts detected in working tree" >> $GITHUB_OUTPUT |
| 128 | + echo "Detected merge conflicts via git status" |
| 129 | + exit 0 |
| 130 | + fi |
| 131 | +
|
| 132 | + # Prepare PR context JSON |
| 133 | + PR_INFO=$(jq -n \ |
| 134 | + --arg repo "${{ github.event.inputs.target_repo }}" \ |
| 135 | + --arg pr_number "${{ github.event.inputs.pr_number }}" \ |
| 136 | + --arg pr_title "${{ steps.pr-details.outputs.pr-title }}" \ |
| 137 | + --arg pr_author "${{ steps.pr-details.outputs.pr-author }}" \ |
| 138 | + --arg base_ref "${{ steps.pr-details.outputs.base-ref }}" \ |
| 139 | + --arg head_ref "${{ steps.pr-details.outputs.head-ref }}" \ |
| 140 | + '{repo: $repo, pr_number: $pr_number, pr_title: $pr_title, pr_author: $pr_author, base_ref: $base_ref, head_ref: $head_ref}') |
| 141 | +
|
| 142 | + # Get failure logs |
| 143 | + FAILURE_LOGS="" |
| 144 | + if [ -f /tmp/failure-logs.txt ]; then |
| 145 | + FAILURE_LOGS=$(cat /tmp/failure-logs.txt) |
| 146 | + fi |
| 147 | +
|
| 148 | + # Run Python classifier |
| 149 | + cd ../bot-repo |
| 150 | + CLASSIFICATION=$(python3 scripts/classify_pr_failure.py \ |
| 151 | + --pr-info "$PR_INFO" \ |
| 152 | + --failed-checks "$FAILED_CHECKS" \ |
| 153 | + --failure-logs "$FAILURE_LOGS" \ |
| 154 | + --output-format github) |
| 155 | +
|
| 156 | + # Parse and output results |
| 157 | + echo "$CLASSIFICATION" >> $GITHUB_OUTPUT |
| 158 | + echo "Classification results:" |
| 159 | + echo "$CLASSIFICATION" |
| 160 | + env: |
| 161 | + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} |
| 162 | + |
145 | 163 | - name: Load and customize prompt |
146 | 164 | id: prepare-prompt |
147 | 165 | run: | |
148 | | - FAILURE_TYPE="${{ steps.analyze.outputs.primary-type }}" |
| 166 | + FAILURE_TYPE="${{ steps.analyze.outputs.failure-type }}" |
| 167 | + CONFIDENCE="${{ steps.analyze.outputs.confidence }}" |
| 168 | + REASONING="${{ steps.analyze.outputs.reasoning }}" |
149 | 169 | REPO="${{ github.event.inputs.target_repo }}" |
150 | 170 | PR_NUMBER="${{ github.event.inputs.pr_number }}" |
151 | 171 | PR_TITLE="${{ steps.pr-details.outputs.pr-title }}" |
152 | 172 | PR_AUTHOR="${{ steps.pr-details.outputs.pr-author }}" |
153 | | - FAILED_NAMES="${{ steps.analyze.outputs.failed-names }}" |
| 173 | + FAILED_NAMES="${{ steps.analyze.outputs.failed-check-names }}" |
| 174 | +
|
| 175 | + echo "Classification: $FAILURE_TYPE (confidence: $CONFIDENCE)" |
| 176 | + echo "Reasoning: $REASONING" |
154 | 177 |
|
155 | | - # Skip unknown failure types |
| 178 | + # Skip unknown failure types or low confidence |
156 | 179 | if [ "$FAILURE_TYPE" = "unknown" ]; then |
157 | 180 | echo "Failure type is unknown - skipping automated fix attempt" |
| 181 | + echo "Reasoning: $REASONING" |
158 | 182 | echo "should-skip=true" >> $GITHUB_OUTPUT |
159 | 183 | exit 0 |
160 | 184 | fi |
|
0 commit comments