Skip to content

Commit 80cd0ae

Browse files
authored
Merge branch 'alpha' into feature/live-query-query
2 parents 466d789 + 9ed9af4 commit 80cd0ae

File tree

73 files changed

+5346
-521
lines changed

Some content is hidden

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

73 files changed

+5346
-521
lines changed
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
name: ci-performance
2+
on:
3+
pull_request_target:
4+
branches:
5+
- alpha
6+
- beta
7+
- release
8+
- 'release-[0-9]+.x.x'
9+
- next-major
10+
paths-ignore:
11+
- '**.md'
12+
- 'docs/**'
13+
14+
env:
15+
NODE_VERSION: 24.11.0
16+
MONGODB_VERSION: 8.0.4
17+
18+
permissions:
19+
contents: read
20+
pull-requests: write
21+
issues: write
22+
23+
jobs:
24+
performance-check:
25+
name: Benchmarks
26+
runs-on: ubuntu-latest
27+
timeout-minutes: 30
28+
29+
steps:
30+
- name: Checkout PR branch (for benchmark script)
31+
uses: actions/checkout@v4
32+
with:
33+
ref: ${{ github.event.pull_request.head.sha }}
34+
fetch-depth: 1
35+
36+
- name: Save PR benchmark script
37+
run: |
38+
mkdir -p /tmp/pr-benchmark
39+
cp -r benchmark /tmp/pr-benchmark/ || echo "No benchmark directory"
40+
cp package.json /tmp/pr-benchmark/ || true
41+
42+
- name: Checkout base branch
43+
uses: actions/checkout@v4
44+
with:
45+
ref: ${{ github.base_ref }}
46+
fetch-depth: 1
47+
clean: true
48+
49+
- name: Restore PR benchmark script
50+
run: |
51+
if [ -d "/tmp/pr-benchmark/benchmark" ]; then
52+
rm -rf benchmark
53+
cp -r /tmp/pr-benchmark/benchmark .
54+
fi
55+
56+
- name: Setup Node.js
57+
uses: actions/setup-node@v4
58+
with:
59+
node-version: ${{ env.NODE_VERSION }}
60+
cache: 'npm'
61+
62+
- name: Install dependencies (base)
63+
run: npm ci
64+
65+
- name: Build Parse Server (base)
66+
run: npm run build
67+
68+
- name: Run baseline benchmarks
69+
id: baseline
70+
env:
71+
NODE_ENV: production
72+
run: |
73+
echo "Running baseline benchmarks..."
74+
if [ ! -f "benchmark/performance.js" ]; then
75+
echo "⚠️ Benchmark script not found - this is expected for new features"
76+
echo "Skipping baseline benchmark"
77+
echo '[]' > baseline.json
78+
echo "Baseline: N/A (no benchmark script)" > baseline-output.txt
79+
exit 0
80+
fi
81+
taskset -c 0 npm run benchmark > baseline-output.txt 2>&1 || npm run benchmark > baseline-output.txt 2>&1 || true
82+
echo "Benchmark command completed with exit code: $?"
83+
echo "Output file size: $(wc -c < baseline-output.txt) bytes"
84+
echo "--- Begin baseline-output.txt ---"
85+
cat baseline-output.txt
86+
echo "--- End baseline-output.txt ---"
87+
# Extract JSON from output (everything between first [ and last ])
88+
sed -n '/^\[/,/^\]/p' baseline-output.txt > baseline.json || echo '[]' > baseline.json
89+
echo "Extracted JSON size: $(wc -c < baseline.json) bytes"
90+
echo "Baseline benchmark results:"
91+
cat baseline.json
92+
continue-on-error: true
93+
94+
- name: Save baseline results to temp location
95+
run: |
96+
mkdir -p /tmp/benchmark-results
97+
cp baseline.json /tmp/benchmark-results/ || echo '[]' > /tmp/benchmark-results/baseline.json
98+
cp baseline-output.txt /tmp/benchmark-results/ || echo 'No baseline output' > /tmp/benchmark-results/baseline-output.txt
99+
100+
- name: Upload baseline results
101+
uses: actions/upload-artifact@v4
102+
with:
103+
name: baseline-benchmark
104+
path: |
105+
/tmp/benchmark-results/baseline.json
106+
/tmp/benchmark-results/baseline-output.txt
107+
retention-days: 7
108+
109+
- name: Checkout PR branch
110+
uses: actions/checkout@v4
111+
with:
112+
ref: ${{ github.event.pull_request.head.sha }}
113+
fetch-depth: 1
114+
clean: true
115+
116+
- name: Restore baseline results
117+
run: |
118+
cp /tmp/benchmark-results/baseline.json ./ || echo '[]' > baseline.json
119+
cp /tmp/benchmark-results/baseline-output.txt ./ || echo 'No baseline output' > baseline-output.txt
120+
121+
- name: Setup Node.js (PR)
122+
uses: actions/setup-node@v4
123+
with:
124+
node-version: ${{ env.NODE_VERSION }}
125+
cache: 'npm'
126+
127+
- name: Install dependencies (PR)
128+
run: npm ci
129+
130+
- name: Build Parse Server (PR)
131+
run: npm run build
132+
133+
- name: Run PR benchmarks
134+
id: pr-bench
135+
env:
136+
NODE_ENV: production
137+
run: |
138+
echo "Running PR benchmarks..."
139+
taskset -c 0 npm run benchmark > pr-output.txt 2>&1 || npm run benchmark > pr-output.txt 2>&1 || true
140+
echo "Benchmark command completed with exit code: $?"
141+
echo "Output file size: $(wc -c < pr-output.txt) bytes"
142+
echo "--- Begin pr-output.txt ---"
143+
cat pr-output.txt
144+
echo "--- End pr-output.txt ---"
145+
# Extract JSON from output (everything between first [ and last ])
146+
sed -n '/^\[/,/^\]/p' pr-output.txt > pr.json || echo '[]' > pr.json
147+
echo "Extracted JSON size: $(wc -c < pr.json) bytes"
148+
echo "PR benchmark results:"
149+
cat pr.json
150+
continue-on-error: true
151+
152+
- name: Upload PR results
153+
uses: actions/upload-artifact@v4
154+
with:
155+
name: pr-benchmark
156+
path: |
157+
pr.json
158+
pr-output.txt
159+
retention-days: 7
160+
161+
- name: Verify benchmark files exist
162+
run: |
163+
echo "Checking for benchmark result files..."
164+
if [ ! -f baseline.json ] || [ ! -s baseline.json ]; then
165+
echo "⚠️ baseline.json is missing or empty, creating empty array"
166+
echo '[]' > baseline.json
167+
fi
168+
if [ ! -f pr.json ] || [ ! -s pr.json ]; then
169+
echo "⚠️ pr.json is missing or empty, creating empty array"
170+
echo '[]' > pr.json
171+
fi
172+
echo "baseline.json size: $(wc -c < baseline.json) bytes"
173+
echo "pr.json size: $(wc -c < pr.json) bytes"
174+
175+
- name: Store benchmark result (PR)
176+
uses: benchmark-action/github-action-benchmark@v1
177+
if: github.event_name == 'pull_request' && hashFiles('pr.json') != ''
178+
continue-on-error: true
179+
with:
180+
name: Parse Server Performance
181+
tool: 'customSmallerIsBetter'
182+
output-file-path: pr.json
183+
github-token: ${{ secrets.GITHUB_TOKEN }}
184+
auto-push: false
185+
save-data-file: false
186+
alert-threshold: '110%'
187+
comment-on-alert: true
188+
fail-on-alert: false
189+
alert-comment-cc-users: '@parse-community/maintainers'
190+
summary-always: true
191+
192+
- name: Compare benchmark results
193+
id: compare
194+
run: |
195+
node -e "
196+
const fs = require('fs');
197+
198+
let baseline, pr;
199+
try {
200+
baseline = JSON.parse(fs.readFileSync('baseline.json', 'utf8'));
201+
pr = JSON.parse(fs.readFileSync('pr.json', 'utf8'));
202+
} catch (e) {
203+
console.log('⚠️ Could not parse benchmark results');
204+
process.exit(0);
205+
}
206+
207+
// Handle case where baseline doesn't exist (new feature)
208+
if (!Array.isArray(baseline) || baseline.length === 0) {
209+
if (!Array.isArray(pr) || pr.length === 0) {
210+
console.log('⚠️ Benchmark results are empty or invalid');
211+
process.exit(0);
212+
}
213+
console.log('# Performance Benchmark Results\n');
214+
console.log('> ℹ️ Baseline not available - this appears to be a new feature\n');
215+
console.log('| Benchmark | Value | Details |');
216+
console.log('|-----------|-------|---------|');
217+
pr.forEach(result => {
218+
console.log(\`| \${result.name} | \${result.value.toFixed(2)} ms | \${result.extra} |\`);
219+
});
220+
console.log('');
221+
console.log('✅ **New benchmarks established for this feature.**');
222+
process.exit(0);
223+
}
224+
225+
if (!Array.isArray(pr) || pr.length === 0) {
226+
console.log('⚠️ PR benchmark results are empty or invalid');
227+
process.exit(0);
228+
}
229+
230+
console.log('# Performance Comparison\n');
231+
console.log('| Benchmark | Baseline | PR | Change | Status |');
232+
console.log('|-----------|----------|----|---------| ------ |');
233+
234+
let hasRegression = false;
235+
let hasImprovement = false;
236+
237+
baseline.forEach(baseResult => {
238+
const prResult = pr.find(p => p.name === baseResult.name);
239+
if (!prResult) {
240+
console.log(\`| \${baseResult.name} | \${baseResult.value.toFixed(2)} ms | N/A | - | ⚠️ Missing |\`);
241+
return;
242+
}
243+
244+
const baseValue = parseFloat(baseResult.value);
245+
const prValue = parseFloat(prResult.value);
246+
const change = ((prValue - baseValue) / baseValue * 100);
247+
const changeStr = change > 0 ? \`+\${change.toFixed(1)}%\` : \`\${change.toFixed(1)}%\`;
248+
249+
let status = '✅';
250+
if (change > 50) {
251+
status = '❌ Much Slower';
252+
hasRegression = true;
253+
} else if (change > 25) {
254+
status = '⚠️ Slower';
255+
hasRegression = true;
256+
} else if (change < -25) {
257+
status = '🚀 Faster';
258+
hasImprovement = true;
259+
}
260+
261+
console.log(\`| \${baseResult.name} | \${baseValue.toFixed(2)} ms | \${prValue.toFixed(2)} ms | \${changeStr} | \${status} |\`);
262+
});
263+
264+
console.log('');
265+
if (hasRegression) {
266+
console.log('⚠️ **Performance regressions detected.** Please review the changes.');
267+
} else if (hasImprovement) {
268+
console.log('🚀 **Performance improvements detected!** Great work!');
269+
} else {
270+
console.log('✅ **No significant performance changes.**');
271+
}
272+
" | tee comparison.md
273+
274+
- name: Upload comparison
275+
uses: actions/upload-artifact@v4
276+
with:
277+
name: benchmark-comparison
278+
path: comparison.md
279+
retention-days: 30
280+
281+
- name: Prepare comment body
282+
if: github.event_name == 'pull_request'
283+
run: |
284+
echo "## Performance Impact Report" > comment.md
285+
echo "" >> comment.md
286+
if [ -f comparison.md ]; then
287+
cat comparison.md >> comment.md
288+
else
289+
echo "⚠️ Could not generate performance comparison." >> comment.md
290+
fi
291+
echo "" >> comment.md
292+
echo "<details>" >> comment.md
293+
echo "<summary>📊 View detailed results</summary>" >> comment.md
294+
echo "" >> comment.md
295+
echo "### Baseline Results" >> comment.md
296+
echo "\`\`\`json" >> comment.md
297+
cat baseline.json >> comment.md
298+
echo "\`\`\`" >> comment.md
299+
echo "" >> comment.md
300+
echo "### PR Results" >> comment.md
301+
echo "\`\`\`json" >> comment.md
302+
cat pr.json >> comment.md
303+
echo "\`\`\`" >> comment.md
304+
echo "" >> comment.md
305+
echo "</details>" >> comment.md
306+
echo "" >> comment.md
307+
echo "> **Note:** Thresholds: ⚠️ >25%, ❌ >50%." >> comment.md
308+
309+
- name: Comment PR with results
310+
if: github.event_name == 'pull_request'
311+
uses: thollander/actions-comment-pull-request@v2
312+
continue-on-error: true
313+
with:
314+
filePath: comment.md
315+
comment_tag: performance-benchmark
316+
mode: recreate
317+
318+
- name: Generate job summary
319+
if: always()
320+
run: |
321+
if [ -f comparison.md ]; then
322+
cat comparison.md >> $GITHUB_STEP_SUMMARY
323+
else
324+
echo "⚠️ Benchmark comparison not available" >> $GITHUB_STEP_SUMMARY
325+
fi
326+
concurrency:
327+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
328+
cancel-in-progress: true

0 commit comments

Comments
 (0)