Skip to content

Commit e1c9574

Browse files
authored
Release Teacher 2.2.0 (84)
2 parents 5773a1a + ce7d449 commit e1c9574

File tree

1,262 files changed

+112376
-41693
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,262 files changed

+112376
-41693
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Claude Code Review
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize]
6+
# Optional: Only run on specific file changes
7+
# paths:
8+
# - "src/**/*.ts"
9+
# - "src/**/*.tsx"
10+
# - "src/**/*.js"
11+
# - "src/**/*.jsx"
12+
13+
jobs:
14+
claude-review:
15+
# Optional: Filter by PR author
16+
# if: |
17+
# github.event.pull_request.user.login == 'external-contributor' ||
18+
# github.event.pull_request.user.login == 'new-developer' ||
19+
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
20+
21+
runs-on: ubuntu-latest
22+
permissions:
23+
contents: read
24+
pull-requests: write
25+
issues: read
26+
id-token: write
27+
28+
steps:
29+
- name: Checkout repository
30+
uses: actions/checkout@v4
31+
with:
32+
fetch-depth: 1
33+
34+
- name: Run Claude Code Review
35+
id: claude-review
36+
uses: anthropics/claude-code-action@v1
37+
with:
38+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
39+
prompt: |
40+
REPO: ${{ github.repository }}
41+
PR NUMBER: ${{ github.event.pull_request.number }}
42+
43+
Please review this pull request and provide inline feedback using the GitHub review system.
44+
45+
Review focus areas:
46+
- Code quality and best practices
47+
- Potential bugs or issues
48+
- Performance considerations
49+
- Security concerns
50+
- Test coverage
51+
52+
Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback.
53+
54+
Instructions:
55+
1. Use the GitHub MCP tools to fetch the PR diff
56+
2. Add inline comments using the appropriate MCP tools for each specific piece of feedback on particular lines
57+
3. Submit the review with event type 'COMMENT' (not 'REQUEST_CHANGES') to publish as non-blocking feedback
58+
59+
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
60+
# or https://docs.claude.com/en/docs/claude-code/cli-reference for available options
61+
claude_args: '--allowedTools "mcp__github__create_pending_pull_request_review,mcp__github__add_comment_to_pending_review,mcp__github__submit_pending_pull_request_review,mcp__github__get_pull_request_diff"'
62+

.github/workflows/claude.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Claude Code
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
pull_request_review_comment:
7+
types: [created]
8+
issues:
9+
types: [opened, assigned]
10+
pull_request_review:
11+
types: [submitted]
12+
13+
jobs:
14+
claude:
15+
if: |
16+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
17+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
18+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
19+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
20+
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read
23+
pull-requests: read
24+
issues: read
25+
id-token: write
26+
actions: read # Required for Claude to read CI results on PRs
27+
steps:
28+
- name: Checkout repository
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 1
32+
33+
- name: Run Claude Code
34+
id: claude
35+
uses: anthropics/claude-code-action@v1
36+
with:
37+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
38+
39+
# This is an optional setting that allows Claude to read CI results on PRs
40+
additional_permissions: |
41+
actions: read
42+
43+
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
44+
# prompt: 'Update the pull request description to include a summary of changes.'
45+
46+
# Optional: Add claude_args to customize behavior and configuration
47+
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
48+
# or https://docs.claude.com/en/docs/claude-code/cli-reference for available options
49+
# claude_args: '--allowed-tools Bash(gh pr:*)'
50+
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
name: Unit Test Coverage
2+
3+
on:
4+
pull_request:
5+
branches: [ master ]
6+
7+
jobs:
8+
test-pr:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Checkout PR branch
13+
uses: actions/checkout@v4
14+
15+
- name: Set up JDK 17
16+
uses: actions/setup-java@v4
17+
with:
18+
java-version: '17'
19+
distribution: 'temurin'
20+
21+
- name: Setup Gradle
22+
uses: gradle/actions/setup-gradle@v3
23+
24+
- name: Setup open source build
25+
run: ./open_source.sh
26+
27+
- name: Run unit tests and generate coverage for PR
28+
run: |
29+
# Run tests in parallel - Gradle will handle parallelization
30+
./gradle/gradlew -p apps :student:testQaDebugUnitTest :teacher:testQaDebugUnitTest :pandautils:testDebugUnitTest --parallel
31+
32+
# Copy exec files to expected locations for jacoco.gradle
33+
mkdir -p apps/student/build/jacoco apps/teacher/build/jacoco libs/pandautils/build/jacoco
34+
35+
cp apps/student/build/outputs/unit_test_code_coverage/qaDebugUnitTest/testQaDebugUnitTest.exec apps/student/build/jacoco/testQaDebugUnitTest.exec 2>/dev/null || echo "Student exec not found"
36+
cp apps/teacher/build/outputs/unit_test_code_coverage/qaDebugUnitTest/testQaDebugUnitTest.exec apps/teacher/build/jacoco/testQaDebugUnitTest.exec 2>/dev/null || echo "Teacher exec not found"
37+
cp libs/pandautils/build/outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec libs/pandautils/build/jacoco/testDebugUnitTest.exec 2>/dev/null || echo "Pandautils exec not found"
38+
39+
# Generate JaCoCo reports in parallel
40+
./gradle/gradlew -p apps :student:jacocoReport :teacher:jacocoReport :pandautils:jacocoReport --parallel
41+
continue-on-error: false
42+
43+
- name: Upload PR coverage reports
44+
uses: actions/upload-artifact@v4
45+
with:
46+
name: pr-coverage
47+
path: |
48+
apps/student/build/reports/jacoco/jacocoReport/jacocoReport.csv
49+
apps/teacher/build/reports/jacoco/jacocoReport/jacocoReport.csv
50+
libs/pandautils/build/reports/jacoco/jacocoReport/jacocoReport.csv
51+
retention-days: 1
52+
53+
test-master:
54+
runs-on: ubuntu-latest
55+
56+
steps:
57+
- name: Checkout master branch
58+
uses: actions/checkout@v4
59+
with:
60+
ref: master
61+
62+
- name: Set up JDK 17
63+
uses: actions/setup-java@v4
64+
with:
65+
java-version: '17'
66+
distribution: 'temurin'
67+
68+
- name: Setup Gradle
69+
uses: gradle/actions/setup-gradle@v3
70+
71+
- name: Setup open source build
72+
run: ./open_source.sh
73+
74+
- name: Run unit tests and generate coverage for master
75+
run: |
76+
# Run tests in parallel - Gradle will handle parallelization
77+
./gradle/gradlew -p apps :student:testQaDebugUnitTest :teacher:testQaDebugUnitTest :pandautils:testDebugUnitTest --parallel
78+
79+
# Copy exec files to expected locations for jacoco.gradle
80+
mkdir -p apps/student/build/jacoco apps/teacher/build/jacoco libs/pandautils/build/jacoco
81+
82+
cp apps/student/build/outputs/unit_test_code_coverage/qaDebugUnitTest/testQaDebugUnitTest.exec apps/student/build/jacoco/testQaDebugUnitTest.exec 2>/dev/null || echo "Student exec not found"
83+
cp apps/teacher/build/outputs/unit_test_code_coverage/qaDebugUnitTest/testQaDebugUnitTest.exec apps/teacher/build/jacoco/testQaDebugUnitTest.exec 2>/dev/null || echo "Teacher exec not found"
84+
cp libs/pandautils/build/outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec libs/pandautils/build/jacoco/testDebugUnitTest.exec 2>/dev/null || echo "Pandautils exec not found"
85+
86+
# Generate JaCoCo reports in parallel
87+
./gradle/gradlew -p apps :student:jacocoReport :teacher:jacocoReport :pandautils:jacocoReport --parallel
88+
continue-on-error: true
89+
90+
- name: Upload master coverage reports
91+
uses: actions/upload-artifact@v4
92+
with:
93+
name: master-coverage
94+
path: |
95+
apps/student/build/reports/jacoco/jacocoReport/jacocoReport.csv
96+
apps/teacher/build/reports/jacoco/jacocoReport/jacocoReport.csv
97+
libs/pandautils/build/reports/jacoco/jacocoReport/jacocoReport.csv
98+
retention-days: 1
99+
100+
coverage-report:
101+
runs-on: ubuntu-latest
102+
needs: [test-pr, test-master]
103+
if: always()
104+
105+
steps:
106+
- name: Download PR coverage
107+
uses: actions/download-artifact@v4
108+
with:
109+
name: pr-coverage
110+
path: coverage-reports/pr
111+
112+
- name: Download master coverage
113+
uses: actions/download-artifact@v4
114+
with:
115+
name: master-coverage
116+
path: coverage-reports/master
117+
continue-on-error: true
118+
119+
- name: Reorganize coverage files
120+
run: |
121+
# Reorganize downloaded artifacts to expected structure
122+
mkdir -p coverage-reports/pr coverage-reports/master
123+
124+
# PR coverage
125+
find coverage-reports/pr -name "jacocoReport.csv" -path "*/student/*" -exec cp {} coverage-reports/pr/student.csv \; 2>/dev/null || echo "Student PR coverage not found"
126+
find coverage-reports/pr -name "jacocoReport.csv" -path "*/teacher/*" -exec cp {} coverage-reports/pr/teacher.csv \; 2>/dev/null || echo "Teacher PR coverage not found"
127+
find coverage-reports/pr -name "jacocoReport.csv" -path "*/pandautils/*" -exec cp {} coverage-reports/pr/pandautils.csv \; 2>/dev/null || echo "Pandautils PR coverage not found"
128+
129+
# Master coverage
130+
find coverage-reports/master -name "jacocoReport.csv" -path "*/student/*" -exec cp {} coverage-reports/master/student.csv \; 2>/dev/null || echo "Student master coverage not found"
131+
find coverage-reports/master -name "jacocoReport.csv" -path "*/teacher/*" -exec cp {} coverage-reports/master/teacher.csv \; 2>/dev/null || echo "Teacher master coverage not found"
132+
find coverage-reports/master -name "jacocoReport.csv" -path "*/pandautils/*" -exec cp {} coverage-reports/master/pandautils.csv \; 2>/dev/null || echo "Pandautils master coverage not found"
133+
134+
- name: Calculate coverage delta
135+
id: coverage
136+
run: |
137+
python3 << 'EOF' | tee coverage-report.txt
138+
import csv
139+
import os
140+
from pathlib import Path
141+
142+
def parse_jacoco_csv(file_path):
143+
"""Parse JaCoCo CSV and return instruction coverage percentage"""
144+
if not Path(file_path).exists():
145+
return None
146+
147+
total_missed = 0
148+
total_covered = 0
149+
150+
with open(file_path, 'r') as f:
151+
reader = csv.DictReader(f)
152+
for row in reader:
153+
total_missed += int(row['INSTRUCTION_MISSED'])
154+
total_covered += int(row['INSTRUCTION_COVERED'])
155+
156+
if total_missed + total_covered == 0:
157+
return 0.0
158+
159+
return (total_covered / (total_missed + total_covered)) * 100
160+
161+
modules = ['student', 'teacher', 'pandautils']
162+
results = []
163+
164+
print("## 📊 Code Coverage Report\n")
165+
166+
overall_pr_coverage = []
167+
overall_master_coverage = []
168+
169+
for module in modules:
170+
pr_file = f'coverage-reports/pr/{module}.csv'
171+
master_file = f'coverage-reports/master/{module}.csv'
172+
173+
pr_cov = parse_jacoco_csv(pr_file)
174+
master_cov = parse_jacoco_csv(master_file)
175+
176+
if pr_cov is not None and master_cov is not None:
177+
delta = pr_cov - master_cov
178+
emoji = '✅' if delta >= 0 else '⚠️'
179+
sign = '+' if delta >= 0 else ''
180+
181+
print(f"### {emoji} {module.capitalize()}")
182+
print(f"- **PR Coverage:** {pr_cov:.2f}%")
183+
print(f"- **Master Coverage:** {master_cov:.2f}%")
184+
print(f"- **Delta:** {sign}{delta:.2f}%\n")
185+
186+
overall_pr_coverage.append(pr_cov)
187+
overall_master_coverage.append(master_cov)
188+
elif pr_cov is not None:
189+
print(f"### ℹ️ {module.capitalize()}")
190+
print(f"- **PR Coverage:** {pr_cov:.2f}%")
191+
print(f"- **Master Coverage:** N/A\n")
192+
else:
193+
print(f"### ⚠️ {module.capitalize()}")
194+
print(f"- Coverage data not available\n")
195+
196+
if overall_pr_coverage and overall_master_coverage:
197+
avg_pr = sum(overall_pr_coverage) / len(overall_pr_coverage)
198+
avg_master = sum(overall_master_coverage) / len(overall_master_coverage)
199+
overall_delta = avg_pr - avg_master
200+
201+
print("---")
202+
print(f"### 📈 Overall Average")
203+
print(f"- **PR Coverage:** {avg_pr:.2f}%")
204+
print(f"- **Master Coverage:** {avg_master:.2f}%")
205+
sign = '+' if overall_delta >= 0 else ''
206+
print(f"- **Delta:** {sign}{overall_delta:.2f}%")
207+
208+
# Set output for potential failure condition
209+
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
210+
f.write(f"delta={overall_delta}\n")
211+
212+
EOF
213+
214+
- name: Comment PR (sticky)
215+
if: github.event_name == 'pull_request'
216+
uses: actions/github-script@v7
217+
with:
218+
script: |
219+
const fs = require('fs');
220+
const output = fs.readFileSync('coverage-report.txt', 'utf8');
221+
const marker = '<!-- unit-test-coverage-comment -->';
222+
const body = marker + '\n' + output;
223+
224+
// Find existing coverage comment
225+
const { data: comments } = await github.rest.issues.listComments({
226+
owner: context.repo.owner,
227+
repo: context.repo.repo,
228+
issue_number: context.issue.number,
229+
});
230+
231+
const existingComment = comments.find(comment =>
232+
comment.body.includes(marker)
233+
);
234+
235+
if (existingComment) {
236+
// Update existing comment
237+
await github.rest.issues.updateComment({
238+
owner: context.repo.owner,
239+
repo: context.repo.repo,
240+
comment_id: existingComment.id,
241+
body: body
242+
});
243+
} else {
244+
// Create new comment
245+
await github.rest.issues.createComment({
246+
issue_number: context.issue.number,
247+
owner: context.repo.owner,
248+
repo: context.repo.repo,
249+
body: body
250+
});
251+
}
252+
253+
# Optional: Fail if coverage decreases by more than 1%
254+
# - name: Check coverage threshold
255+
# if: steps.coverage.outputs.delta < -1.0
256+
# run: |
257+
# echo "Coverage decreased by more than 1%"
258+
# exit 1

PULL_REQUEST_TEMPLATE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ release note:
2222
- [ ] Run E2E test suite
2323
- [ ] Tested in dark mode
2424
- [ ] Tested in light mode
25+
- [ ] Test in landscape mode and/or tablet
2526
- [ ] A11y checked
2627
- [ ] Approve from product

0 commit comments

Comments
 (0)