Skip to content

Commit 4182321

Browse files
committed
feat(ci): batch same-category issues into existing PRs to avoid conflicts
1 parent a5111e6 commit 4182321

2 files changed

Lines changed: 118 additions & 26 deletions

File tree

.github/scripts/auto-fix.sh

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4-
MAIN=$(git rev-parse --abbrev-ref HEAD)
4+
MAIN="main"
55
NUM=$(echo "$ISSUE_JSON" | jq -r '.number')
66
TITLE=$(echo "$ISSUE_JSON" | jq -r '.title')
77
BODY=$(echo "$ISSUE_JSON" | jq -r '.body')
8-
BRANCH="auto-fix/issue-${NUM}"
98

10-
echo "=== #${NUM}: ${TITLE} ==="
9+
# Reuse existing PR branch if provided, otherwise create new
10+
if [ -n "${EXISTING_BRANCH:-}" ]; then
11+
BRANCH="$EXISTING_BRANCH"
12+
echo "=== #${NUM}: ${TITLE} (appending to ${BRANCH}) ==="
13+
git fetch origin "$BRANCH"
14+
git checkout "$BRANCH"
15+
else
16+
BRANCH="auto-fix/issue-${NUM}"
17+
echo "=== #${NUM}: ${TITLE} ==="
18+
fi
1119

1220
# Rollback label on failure
1321
cleanup_on_failure() {
1422
gh issue edit "$NUM" --repo "$REPO" --add-label auto-fix --remove-label auto-fix-in-progress 2>/dev/null || true
1523
}
1624
trap cleanup_on_failure ERR
1725

18-
# Skip if PR exists
19-
if [ "$(gh pr list --repo "$REPO" --head "$BRANCH" --json number --jq 'length')" -gt 0 ]; then
20-
echo "PR exists, skip"
21-
gh issue edit "$NUM" --repo "$REPO" --add-label auto-fix-done --remove-label auto-fix-in-progress
22-
exit 0
26+
# Skip if PR exists (only for new branches, not when appending)
27+
if [ -z "${EXISTING_BRANCH:-}" ]; then
28+
if [ "$(gh pr list --repo "$REPO" --head "$BRANCH" --json number --jq 'length')" -gt 0 ]; then
29+
echo "PR exists, skip"
30+
gh issue edit "$NUM" --repo "$REPO" --add-label auto-fix-done --remove-label auto-fix-in-progress
31+
exit 0
32+
fi
2333
fi
2434

2535
# Build model args
@@ -63,7 +73,10 @@ format_stats() {
6373
PR_LOG=""
6474
log() { PR_LOG="${PR_LOG}${1}\n"; echo "$1"; }
6575

66-
git checkout -b "$BRANCH"
76+
# Create branch only if not appending to existing
77+
if [ -z "${EXISTING_BRANCH:-}" ]; then
78+
git checkout -b "$BRANCH"
79+
fi
6780

6881
# --- Step 1: Generate fix ---
6982
log "### Step 1: Generate (\`${GEN_LABEL}\`)"
@@ -178,14 +191,34 @@ Do NOT run git, gh, or any shell commands that modify the repository state." \
178191
log "</details>"
179192
done
180193

181-
# --- Step 3: Create PR ---
194+
# --- Step 3: Create or update PR ---
182195
git add docs/
183-
git commit -m "docs: ${TITLE}" || { cleanup_on_failure; exit 0; }
196+
git commit -m "docs: ${TITLE} (#${NUM})" || { cleanup_on_failure; exit 0; }
184197
git push origin "$BRANCH" --force
185198

186199
STATUS=$( [ "$APPROVED" = true ] && echo "✅ Approved" || echo "⚠️ Needs human review (not approved after ${REVIEW_ROUND} rounds)" )
187200

188-
PR_BODY="Fixes #${NUM}.
201+
if [ -n "${EXISTING_PR:-}" ] && [ "$EXISTING_PR" != "" ]; then
202+
# Append to existing PR — add comment and update body to reference new issue
203+
gh pr comment "$EXISTING_PR" --repo "$REPO" \
204+
--body "### Also fixes #${NUM}: ${TITLE}
205+
206+
**Status:** ${STATUS}
207+
**Generator:** \`${GEN_LABEL}\` | **Reviewer:** \`${REV_LABEL}\` | **Review rounds:** ${REVIEW_ROUND}
208+
209+
<details><summary>Process log</summary>
210+
211+
$(echo -e "$PR_LOG")
212+
213+
</details>" || true
214+
215+
# Append issue reference to PR body
216+
OLD_BODY=$(gh pr view "$EXISTING_PR" --repo "$REPO" --json body --jq '.body')
217+
gh pr edit "$EXISTING_PR" --repo "$REPO" \
218+
--body "${OLD_BODY}
219+
Also fixes #${NUM}." || true
220+
else
221+
PR_BODY="Fixes #${NUM}.
189222
190223
**Status:** ${STATUS}
191224
**Generator:** \`${GEN_LABEL}\` | **Reviewer:** \`${REV_LABEL}\` | **Review rounds:** ${REVIEW_ROUND}
@@ -196,10 +229,11 @@ PR_BODY="Fixes #${NUM}.
196229
197230
$(echo -e "$PR_LOG")"
198231

199-
gh pr create --repo "$REPO" --base "$MAIN" --head "$BRANCH" \
200-
--title "${TITLE}" \
201-
--body "$PR_BODY" \
202-
--label auto-fix || true
232+
gh pr create --repo "$REPO" --base "$MAIN" --head "$BRANCH" \
233+
--title "${TITLE}" \
234+
--body "$PR_BODY" \
235+
--label auto-fix || true
236+
fi
203237

204238
# Mark done
205239
gh issue edit "$NUM" --repo "$REPO" --add-label auto-fix-done --remove-label auto-fix-in-progress

.github/workflows/auto-fix-issues.yml

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,88 @@ jobs:
1717
check:
1818
runs-on: ubuntu-latest
1919
outputs:
20-
issue: ${{ steps.pick.outputs.issue }}
20+
matrix: ${{ steps.pick.outputs.matrix }}
2121
steps:
2222
- id: pick
2323
env:
2424
GH_TOKEN: ${{ secrets.GH_PAT }}
2525
ISSUE_NUMBER: ${{ inputs.issue_number || '' }}
2626
run: |
2727
REPO="${{ github.repository }}"
28+
29+
# Collect issues
2830
if [ -n "$ISSUE_NUMBER" ]; then
29-
ISSUE=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json number,title,body -q '.')
31+
ISSUES=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json number,title,body -q '[.]')
3032
else
31-
ISSUE=$(gh issue list --repo "$REPO" --label auto-fix --state open --limit 1 --json number,title,body -q '.[0] // empty')
33+
ISSUES=$(gh issue list --repo "$REPO" --label auto-fix --state open --limit 10 --json number,title,body)
3234
fi
33-
if [ -z "$ISSUE" ]; then
35+
36+
COUNT=$(echo "$ISSUES" | jq 'length')
37+
if [ "$COUNT" -eq 0 ]; then
3438
echo "No auto-fix issues"
35-
echo "issue=" >> "$GITHUB_OUTPUT"
36-
else
37-
NUM=$(echo "$ISSUE" | jq -r '.number')
39+
echo "matrix=" >> "$GITHUB_OUTPUT"
40+
exit 0
41+
fi
42+
43+
# Collect open auto-fix PRs and their changed file paths
44+
OPEN_PRS=$(gh pr list --repo "$REPO" --label auto-fix --state open \
45+
--json number,headRefName,files --jq '[.[] | {number, branch: .headRefName, paths: [.files[].path]}]' 2>/dev/null || echo '[]')
46+
47+
# For each issue, check if an existing PR touches the same doc category
48+
# Category = first two path segments under docs/en/ (e.g. docs/en/sql-reference, docs/en/guides)
49+
MATRIX="[]"
50+
for row in $(echo "$ISSUES" | jq -c '.[]'); do
51+
NUM=$(echo "$row" | jq -r '.number')
52+
TITLE=$(echo "$row" | jq -r '.title')
53+
BODY=$(echo "$row" | jq -r '.body')
54+
55+
# Guess the doc category from issue title/body keywords
56+
CATEGORY=""
57+
TEXT=$(echo "${TITLE} ${BODY}" | tr '[:upper:]' '[:lower:]')
58+
if echo "$TEXT" | grep -qE 'function|func[ _-]'; then
59+
CATEGORY="docs/en/sql-reference/20-sql-functions"
60+
elif echo "$TEXT" | grep -qE 'command|statement|ddl|dml|dql'; then
61+
CATEGORY="docs/en/sql-reference/10-sql-commands"
62+
elif echo "$TEXT" | grep -qE 'sql.reference|sql-reference'; then
63+
CATEGORY="docs/en/sql-reference"
64+
elif echo "$TEXT" | grep -qE 'guide|load|unload|stage|warehouse|security'; then
65+
CATEGORY="docs/en/guides"
66+
fi
67+
68+
# Find existing PR with overlapping category
69+
EXISTING_BRANCH=""
70+
EXISTING_PR=""
71+
if [ -n "$CATEGORY" ]; then
72+
MATCH=$(echo "$OPEN_PRS" | jq -c --arg cat "$CATEGORY" \
73+
'[.[] | select(.paths[] | startswith($cat))] | first // empty')
74+
if [ -n "$MATCH" ] && [ "$MATCH" != "null" ]; then
75+
EXISTING_BRANCH=$(echo "$MATCH" | jq -r '.branch')
76+
EXISTING_PR=$(echo "$MATCH" | jq -r '.number')
77+
echo "Issue #${NUM} matches existing PR #${EXISTING_PR} (branch: ${EXISTING_BRANCH})"
78+
fi
79+
fi
80+
81+
# Mark in-progress
3882
gh issue edit "$NUM" --repo "$REPO" --add-label auto-fix-in-progress --remove-label auto-fix
39-
echo "issue=$(echo "$ISSUE" | jq -c .)" >> "$GITHUB_OUTPUT"
83+
84+
ENTRY=$(echo "$row" | jq -c --arg eb "$EXISTING_BRANCH" --arg ep "$EXISTING_PR" \
85+
'. + {existing_branch: $eb, existing_pr: $ep}')
86+
MATRIX=$(echo "$MATRIX" | jq -c --argjson e "$ENTRY" '. + [$e]')
87+
done
88+
89+
if [ "$(echo "$MATRIX" | jq 'length')" -eq 0 ]; then
90+
echo "matrix=" >> "$GITHUB_OUTPUT"
91+
else
92+
echo "matrix=$(echo "$MATRIX" | jq -c '{include: .}')" >> "$GITHUB_OUTPUT"
4093
fi
4194
4295
fix:
4396
needs: check
44-
if: needs.check.outputs.issue != ''
97+
if: needs.check.outputs.matrix != ''
4598
runs-on: ubuntu-latest
99+
strategy:
100+
matrix: ${{ fromJson(needs.check.outputs.matrix) }}
101+
max-parallel: 1
46102
steps:
47103
- uses: actions/checkout@v4
48104

@@ -98,7 +154,9 @@ jobs:
98154
bash .github/scripts/auto-fix.sh
99155
env:
100156
REPO: ${{ github.repository }}
101-
ISSUE_JSON: ${{ needs.check.outputs.issue }}
157+
ISSUE_JSON: ${{ toJson(matrix) }}
158+
EXISTING_BRANCH: ${{ matrix.existing_branch }}
159+
EXISTING_PR: ${{ matrix.existing_pr }}
102160
GENERATOR_MODEL: ''
103161
REVIEWER_MODEL: gpt-5.4
104162
EVOT_ID: auto-fix-ci

0 commit comments

Comments
 (0)