-
Notifications
You must be signed in to change notification settings - Fork 1.2k
168 lines (148 loc) · 7.56 KB
/
changeset-review.yml
File metadata and controls
168 lines (148 loc) · 7.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
name: Changeset Review
on:
pull_request:
paths:
- ".changeset/*.md"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
jobs:
review-changesets:
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository
steps:
- name: Checkout changesets
uses: actions/checkout@v4
with:
fetch-depth: 0
sparse-checkout: |
.changeset
.github/opencode.json
- name: Install OpenCode
run: |
npm install -g opencode-ai
cp .github/opencode.json ./opencode.json
- name: Get changed changeset files
id: changed-changesets
uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c # v45
with:
files: |
.changeset/*.md
files_ignore: |
.changeset/README.md
# Recover deleted files so Claude can read them (needed for Version Packages PRs)
recover_deleted_files: ${{ github.event.pull_request.title == 'Version Packages' }}
- name: Clean up prior changeset reviews
if: github.event.pull_request.title == 'Version Packages' || steps.changed-changesets.outputs.added_files_count > 0
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: |
COMMENTS=$(gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" --paginate | jq -s 'add')
# Delete sticky OK comments (identified by embedded HTML marker)
echo "$COMMENTS" | jq -r '.[] | select(.body | contains("<!-- changeset-review -->")) | .id' | while read -r COMMENT_ID; do
echo "Deleting sticky OK comment ${COMMENT_ID}"
gh api "repos/${REPO}/issues/comments/${COMMENT_ID}" -X DELETE || true
done
# Find marker comments from prior issue-review runs, delete the associated review comments and the marker
echo "$COMMENTS" | jq -c '.[] | select(.body | contains("<!-- changeset-review-marker"))' | while read -r ITEM; do
COMMENT_ID=$(echo "$ITEM" | jq -r '.id')
BODY=$(echo "$ITEM" | jq -r '.body')
REVIEW_ID=$(echo "$BODY" | grep -oP '(?<=review-id:)\d+')
if [ -n "$REVIEW_ID" ]; then
echo "Deleting comments on prior review ${REVIEW_ID}"
# Submitted reviews cannot be deleted via the API; delete each review comment individually instead
gh api "repos/${REPO}/pulls/${PR_NUMBER}/reviews/${REVIEW_ID}/comments" \
| jq -r '.[].id' | while read -r RC_ID; do
gh api "repos/${REPO}/pulls/comments/${RC_ID}" -X DELETE || true
done
fi
echo "Deleting marker comment ${COMMENT_ID}"
gh api "repos/${REPO}/issues/comments/${COMMENT_ID}" -X DELETE || true
done
- name: Review Changesets with OpenCode
id: opencode-review
# Run for Version Packages PRs (which delete changesets) or regular PRs with new changesets
if: github.event.pull_request.title == 'Version Packages' || steps.changed-changesets.outputs.added_files_count > 0
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_AI_GATEWAY_ACCOUNT_ID }}
CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }}
DELETED_FILES: ${{ steps.changed-changesets.outputs.deleted_files }}
ADDED_FILES: ${{ steps.changed-changesets.outputs.added_files }}
run: |
opencode run --print-logs \
"Review the changeset files in this PR.
For \"Version Packages\" PRs, review: ${DELETED_FILES}
For regular PRs, review: ${ADDED_FILES}
Read \`.changeset/README.md\` for guidelines, then validate:
1. **Version Type**: Accept the author's choice of patch/minor unless clearly incorrect
2. **Changelog Quality**: Meaningful descriptions (examples encouraged but not required for features)
3. **Markdown Headers**: No h1/h2/h3 headers (breaks changelog formatting)
4. **Analytics**: If the change collects more analytics, it should be a minor even though there is no user-visible change
5. **Dependabot**: Do not validate dependency update changesets for create-cloudflare
6. **Experimental features**: Changesets for experimental features should include note on how users can opt in.
Write your review as JSON to \`changeset-review.json\` in this exact format (no other output):
{
\"status\": \"ok\",
\"summary\": \"✅ All changesets look good.\",
\"files\": []
}
or when there are issues:
{
\"status\": \"issues\",
\"summary\": \"⚠️ Issues found in N of M changesets.\",
\"files\": [
{
\"path\": \".changeset/foo.md\",
\"status\": \"issues\",
\"comment\": \"<specific problems with this file>\"
}
]
}
Only include files in the array when they have status \"issues\".
The top-level status must be \"issues\" if ANY file has issues, otherwise \"ok\".
Do not review other files, only the changesets. This is specifically a changeset review action."
- name: Post review results
if: steps.opencode-review.outcome == 'success'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
STATUS=$(jq -r '.status' changeset-review.json)
SUMMARY=$(jq -r '.summary' changeset-review.json)
if [ "$STATUS" = "issues" ]; then
# Build the request body: file-level comments (subject_type: "file") for each problematic changeset
REQUEST_BODY=$(jq -n \
--arg commit_id "$HEAD_SHA" \
--argjson comments "$(jq '[.files[] | select(.status == "issues") | {path: .path, subject_type: "file", body: .comment}]' changeset-review.json)" \
'{commit_id: $commit_id, event: "COMMENT", body: "", comments: $comments}')
# Post a pull request review with inline file-level comments
REVIEW_RESPONSE=$(echo "$REQUEST_BODY" | gh api "repos/${REPO}/pulls/${PR_NUMBER}/reviews" \
-X POST \
--input -)
REVIEW_ID=$(echo "$REVIEW_RESPONSE" | jq -r '.id')
echo "Posted review ${REVIEW_ID}"
# Post a hidden marker comment so the next run can find and delete this review
gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" \
-X POST \
-f "body=<!-- changeset-review-marker review-id:${REVIEW_ID} -->"
else
# Post a normal (non-resolvable) PR comment with a hidden marker for cleanup
gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" \
-X POST \
-f "body=<!-- changeset-review -->
${SUMMARY}"
fi
- name: Skip notice
if: github.event.pull_request.title != 'Version Packages' && steps.changed-changesets.outputs.added_files_count == 0
run: |
echo "No new changesets to review (only minor edits to pre-existing changesets detected)"