Node.js CI #3783
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Node.js CI | |
on: | |
pull_request: | |
branches: ['**'] | |
merge_group: | |
types: [checks_requested] | |
jobs: | |
verify_files: | |
name: Verify Files | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: 18 | |
cache: npm | |
- run: npm ci | |
- run: npm run typecheck | |
- run: npm run lint | |
- run: npm run build:embedded # check that build works | |
- run: npm run package # check that package build works | |
unit_tests: | |
name: Unit Tests | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: 18 | |
- run: npm ci | |
- run: npm test | |
e2e_tests: | |
name: Playwright Tests | |
runs-on: ubuntu-latest | |
if: ${{github.event.action != 'checks_requested'}} | |
permissions: | |
contents: read | |
services: | |
backend: | |
image: ghcr.io/ydb-platform/local-ydb:nightly | |
ports: | |
- 2135:2135 | |
- 8765:8765 | |
options: --hostname localhost -e YDB_ALLOW_ORIGIN="http://localhost:3000" | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Setup Node.js | |
uses: actions/setup-node@v4 | |
with: | |
node-version: 18 | |
cache: npm | |
- name: Install dependencies | |
run: npm ci | |
- name: Install Playwright deps | |
run: npm run test:e2e:install | |
- name: Run Playwright tests | |
id: run_tests | |
run: npm run test:e2e | |
env: | |
CI: true | |
PLAYWRIGHT_VIDEO: 'on' | |
- name: Upload Playwright artifacts | |
if: always() | |
uses: actions/upload-artifact@v3 | |
with: | |
name: playwright-artifacts | |
path: playwright-artifacts | |
retention-days: 5 | |
- name: Get test results | |
if: always() | |
id: test-results | |
run: | | |
echo "Current directory: $(pwd)" | |
echo "Listing playwright-artifacts directory:" | |
ls -R playwright-artifacts | |
if [ -f "playwright-artifacts/test-results.json" ]; then | |
echo "Parsing JSON file:" | |
total=$(jq '.stats.expected + .stats.unexpected + .stats.flaky + .stats.skipped' playwright-artifacts/test-results.json) | |
passed=$(jq '.stats.expected' playwright-artifacts/test-results.json) | |
failed=$(jq '.stats.unexpected' playwright-artifacts/test-results.json) | |
flaky=$(jq '.stats.flaky' playwright-artifacts/test-results.json) | |
skipped=$(jq '.stats.skipped' playwright-artifacts/test-results.json) | |
echo "Parsed values:" | |
echo "Total: $total" | |
echo "Passed: $passed" | |
echo "Failed: $failed" | |
echo "Flaky: $flaky" | |
echo "Skipped: $skipped" | |
else | |
echo "test-results.json file not found" | |
total=0 | |
passed=0 | |
failed=0 | |
flaky=0 | |
skipped=0 | |
fi | |
echo "total=$total" >> $GITHUB_OUTPUT | |
echo "passed=$passed" >> $GITHUB_OUTPUT | |
echo "failed=$failed" >> $GITHUB_OUTPUT | |
echo "flaky=$flaky" >> $GITHUB_OUTPUT | |
echo "skipped=$skipped" >> $GITHUB_OUTPUT | |
bundle_size: | |
name: Check Bundle Size | |
runs-on: ubuntu-latest | |
if: ${{github.event.action != 'checks_requested'}} | |
outputs: | |
current_size: ${{ steps.current_size.outputs.size }} | |
main_size: ${{ steps.main_size.outputs.size }} | |
diff: ${{ steps.size_diff.outputs.diff }} | |
percent: ${{ steps.size_diff.outputs.percent }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Setup Node.js | |
uses: actions/setup-node@v4 | |
with: | |
node-version: 18 | |
cache: npm | |
- name: Install dependencies | |
run: npm ci | |
- name: Build bundle (current branch) | |
run: npm run build | |
- name: Get current bundle size | |
id: current_size | |
run: | | |
size=$(du -sb build | cut -f1) | |
echo "size=$size" >> $GITHUB_OUTPUT | |
- name: Checkout main branch | |
uses: actions/checkout@v4 | |
with: | |
ref: main | |
- name: Install dependencies (main) | |
run: npm ci | |
- name: Build bundle (main branch) | |
run: npm run build | |
- name: Get main bundle size | |
id: main_size | |
run: | | |
size=$(du -sb build | cut -f1) | |
echo "size=$size" >> $GITHUB_OUTPUT | |
- name: Calculate size difference | |
id: size_diff | |
run: | | |
current=${{ steps.current_size.outputs.size }} | |
main=${{ steps.main_size.outputs.size }} | |
diff=$((current - main)) | |
if [ "$main" -ne "0" ]; then | |
percent=$(awk "BEGIN {printf \"%.2f\", ($diff/$main) * 100}") | |
else | |
percent="N/A" | |
fi | |
echo "diff=$diff" >> $GITHUB_OUTPUT | |
echo "percent=$percent" >> $GITHUB_OUTPUT | |
deploy_and_update: | |
name: Deploy and Update PR | |
needs: [e2e_tests, bundle_size] | |
if: ${{always() && github.event.pull_request.head.repo.full_name == github.repository && github.event.action != 'checks_requested'}} | |
runs-on: ubuntu-latest | |
permissions: | |
contents: write | |
pages: write | |
pull-requests: write | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Download artifacts | |
uses: actions/download-artifact@v3 | |
with: | |
name: playwright-artifacts | |
path: playwright-artifacts | |
- name: Setup Pages | |
uses: actions/configure-pages@v3 | |
- name: Deploy report to GitHub Pages | |
uses: peaceiris/actions-gh-pages@v3 | |
with: | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
publish_dir: ./playwright-artifacts/playwright-report | |
destination_dir: ${{ github.event.pull_request.number }} | |
force_orphan: true | |
- name: Update PR description | |
uses: actions/github-script@v6 | |
with: | |
github-token: ${{secrets.GITHUB_TOKEN}} | |
script: | | |
const fs = require('fs'); | |
const testResultsPath = 'playwright-artifacts/test-results.json'; | |
let testResults; | |
if (fs.existsSync(testResultsPath)) { | |
const rawData = fs.readFileSync(testResultsPath); | |
const data = JSON.parse(rawData); | |
testResults = { | |
total: data.stats.expected + data.stats.unexpected + data.stats.flaky + data.stats.skipped, | |
passed: data.stats.expected, | |
failed: data.stats.unexpected, | |
flaky: data.stats.flaky, | |
skipped: data.stats.skipped | |
}; | |
} else { | |
console.log('Test results file not found'); | |
testResults = { total: 0, passed: 0, failed: 0, flaky: 0, skipped: 0 }; | |
} | |
const reportUrl = `https://${context.repo.owner}.github.io/${context.repo.repo}/${context.issue.number}/`; | |
const status = testResults.failed > 0 ? '❌ FAILED' : (testResults.flaky > 0 ? '⚠️ FLAKY' : '✅ PASSED'); | |
const statusColor = testResults.failed > 0 ? 'red' : (testResults.flaky > 0 ? 'orange' : 'green'); | |
const currentSize = parseInt('${{ needs.bundle_size.outputs.current_size }}'); | |
const mainSize = parseInt('${{ needs.bundle_size.outputs.main_size }}'); | |
const diff = parseInt('${{ needs.bundle_size.outputs.diff }}'); | |
const percent = '${{ needs.bundle_size.outputs.percent }}'; | |
const formatSize = (size) => { | |
if (size >= 1024) { | |
return `${(size / (1024 * 1024)).toFixed(2)} MB`; | |
} | |
return `${(size / 1024).toFixed(2)} KB`; | |
}; | |
const bundleStatus = percent === 'N/A' ? '⚠️' : | |
parseFloat(percent) > 0 ? '🔺' : | |
parseFloat(percent) < 0 ? '🔽' : '✅'; | |
const ciSection = `## CI Results | |
### Test Status: <span style="color: ${statusColor};">${status}</span> | |
📊 [Full Report](${reportUrl}) | |
| Total | Passed | Failed | Flaky | Skipped | | |
|:-----:|:------:|:------:|:-----:|:-------:| | |
| ${testResults.total} | ${testResults.passed} | ${testResults.failed} | ${testResults.flaky} | ${testResults.skipped} | | |
### Bundle Size: ${bundleStatus} | |
Current: ${formatSize(currentSize)} | Main: ${formatSize(mainSize)} | |
Diff: ${diff > 0 ? '+' : ''}${formatSize(Math.abs(diff))} (${percent === 'N/A' ? 'N/A' : `${percent}%`}) | |
${ | |
percent === 'N/A' ? '⚠️ Unable to calculate change.' : | |
parseFloat(percent) > 0 ? '⚠️ Bundle size increased. Please review.' : | |
parseFloat(percent) < 0 ? '✅ Bundle size decreased.' : '✅ Bundle size unchanged.' | |
} | |
<details> | |
<summary>ℹ️ CI Information</summary> | |
- Test recordings for failed tests are available in the full report. | |
- Bundle size is measured for the entire 'dist' directory. | |
- 📊 indicates links to detailed reports. | |
- 🔺 indicates increase, 🔽 decrease, and ✅ no change in bundle size. | |
</details>`; | |
const { data: pullRequest } = await github.rest.pulls.get({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
pull_number: context.issue.number, | |
}); | |
const currentBody = pullRequest.body || ''; | |
const ciSectionRegex = /## CI Results[\s\S]*?(?=\n## (?!CI Results)|$)/; | |
let newBody = currentBody; | |
if (ciSectionRegex.test(newBody)) { | |
newBody = newBody.replace(ciSectionRegex, ciSection); | |
} else { | |
newBody += '\n\n' + ciSection; | |
} | |
await github.rest.pulls.update({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
pull_number: context.issue.number, | |
body: newBody, | |
}); |