코드체크 결과 README에 뱃지로 추가
@@ -749,11 +749,11 @@ jobs:
|
||||
userfront-e2e/test-results
|
||||
if-no-files-found: ignore
|
||||
|
||||
front-vitest-coverage:
|
||||
adminfront-vitest-coverage:
|
||||
needs:
|
||||
- changes
|
||||
- lint
|
||||
if: ${{ always() && needs.changes.outputs.front_coverage == 'true' && (github.event_name != 'workflow_dispatch' || inputs.run_front_coverage == true) }}
|
||||
if: ${{ always() && needs.changes.outputs.adminfront == 'true' && (github.event_name != 'workflow_dispatch' || inputs.run_front_coverage == true) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -777,10 +777,10 @@ jobs:
|
||||
|
||||
if [ "$install_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Front Vitest Coverage Failure Report"
|
||||
echo "# Adminfront Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`front-vitest-coverage\`"
|
||||
echo "- Job: \`adminfront-vitest-coverage\`"
|
||||
echo "- Reason: \`Dependency install failed\`"
|
||||
echo "- Exit Code: \`$install_exit_code\`"
|
||||
echo
|
||||
@@ -791,39 +791,37 @@ jobs:
|
||||
echo '```text'
|
||||
tail -n 200 reports/front-coverage-install.log
|
||||
echo '```'
|
||||
} > reports/front-vitest-coverage-failure-report.md
|
||||
} > reports/adminfront-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for app in adminfront devfront orgfront; do
|
||||
set +e
|
||||
cd "$app"
|
||||
pnpm install --no-frozen-lockfile --shamefully-hoist 2>&1 | tee -a ../reports/front-coverage-install.log
|
||||
app_install_exit_code=${PIPESTATUS[0]}
|
||||
cd ..
|
||||
set -e
|
||||
set +e
|
||||
cd adminfront
|
||||
pnpm install --no-frozen-lockfile --shamefully-hoist 2>&1 | tee -a ../reports/front-coverage-install.log
|
||||
app_install_exit_code=${PIPESTATUS[0]}
|
||||
cd ..
|
||||
set -e
|
||||
|
||||
if [ "$app_install_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Front Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`front-vitest-coverage\`"
|
||||
echo "- Package: \`$app\`"
|
||||
echo "- Reason: \`Dependency install failed\`"
|
||||
echo "- Exit Code: \`$app_install_exit_code\`"
|
||||
echo
|
||||
echo "## Command"
|
||||
echo "\`cd $app && pnpm install --no-frozen-lockfile --shamefully-hoist\`"
|
||||
echo
|
||||
echo "## Install Log Tail (last 200 lines)"
|
||||
echo '```text'
|
||||
tail -n 200 reports/front-coverage-install.log
|
||||
echo '```'
|
||||
} > reports/front-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
if [ "$app_install_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Adminfront Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`adminfront-vitest-coverage\`"
|
||||
echo "- Package: \`adminfront\`"
|
||||
echo "- Reason: \`Dependency install failed\`"
|
||||
echo "- Exit Code: \`$app_install_exit_code\`"
|
||||
echo
|
||||
echo "## Command"
|
||||
echo "\`cd adminfront && pnpm install --no-frozen-lockfile --shamefully-hoist\`"
|
||||
echo
|
||||
echo "## Install Log Tail (last 200 lines)"
|
||||
echo '```text'
|
||||
tail -n 200 reports/front-coverage-install.log
|
||||
echo '```'
|
||||
} > reports/adminfront-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Run adminfront Vitest coverage
|
||||
run: |
|
||||
@@ -836,10 +834,10 @@ jobs:
|
||||
|
||||
if [ "$test_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Front Vitest Coverage Failure Report"
|
||||
echo "# Adminfront Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`front-vitest-coverage\`"
|
||||
echo "- Job: \`adminfront-vitest-coverage\`"
|
||||
echo "- Package: \`adminfront\`"
|
||||
echo "- Exit Code: \`$test_exit_code\`"
|
||||
echo
|
||||
@@ -847,7 +845,108 @@ jobs:
|
||||
echo '```text'
|
||||
tail -n 200 reports/adminfront-vitest-coverage.log
|
||||
echo '```'
|
||||
} > reports/front-vitest-coverage-failure-report.md
|
||||
} > reports/adminfront-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Generate adminfront Vitest coverage summary
|
||||
run: |
|
||||
node scripts/summarize_vitest_coverage.mjs adminfront
|
||||
cat reports/vitest-coverage-summary.md >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Publish adminfront Vitest coverage failure summary
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
if [ -f reports/adminfront-vitest-coverage-failure-report.md ]; then
|
||||
cat reports/adminfront-vitest-coverage-failure-report.md >> "$GITHUB_STEP_SUMMARY"
|
||||
fi
|
||||
|
||||
- name: Upload adminfront Vitest coverage report artifact
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: adminfront-vitest-coverage-report
|
||||
path: |
|
||||
reports/vitest-coverage-summary.md
|
||||
reports/vitest-coverage-summary.json
|
||||
reports/adminfront-vitest-coverage-failure-report.md
|
||||
reports/front-coverage-install.log
|
||||
reports/adminfront-vitest-coverage.log
|
||||
adminfront/coverage
|
||||
if-no-files-found: ignore
|
||||
|
||||
devfront-vitest-coverage:
|
||||
needs:
|
||||
- changes
|
||||
- lint
|
||||
if: ${{ always() && needs.changes.outputs.devfront == 'true' && (github.event_name != 'workflow_dispatch' || inputs.run_front_coverage == true) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
|
||||
- name: Install front workspace dependencies
|
||||
run: |
|
||||
mkdir -p reports
|
||||
set +e
|
||||
npm install -g pnpm
|
||||
cd common
|
||||
pnpm install --no-frozen-lockfile --shamefully-hoist 2>&1 | tee ../reports/front-coverage-install.log
|
||||
install_exit_code=${PIPESTATUS[0]}
|
||||
cd ..
|
||||
set -e
|
||||
|
||||
if [ "$install_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Devfront Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`devfront-vitest-coverage\`"
|
||||
echo "- Reason: \`Dependency install failed\`"
|
||||
echo "- Exit Code: \`$install_exit_code\`"
|
||||
echo
|
||||
echo "## Command"
|
||||
echo "\`cd common && pnpm install --no-frozen-lockfile --shamefully-hoist\`"
|
||||
echo
|
||||
echo "## Install Log Tail (last 200 lines)"
|
||||
echo '```text'
|
||||
tail -n 200 reports/front-coverage-install.log
|
||||
echo '```'
|
||||
} > reports/devfront-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
cd devfront
|
||||
pnpm install --no-frozen-lockfile --shamefully-hoist 2>&1 | tee -a ../reports/front-coverage-install.log
|
||||
app_install_exit_code=${PIPESTATUS[0]}
|
||||
cd ..
|
||||
set -e
|
||||
|
||||
if [ "$app_install_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Devfront Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`devfront-vitest-coverage\`"
|
||||
echo "- Package: \`devfront\`"
|
||||
echo "- Reason: \`Dependency install failed\`"
|
||||
echo "- Exit Code: \`$app_install_exit_code\`"
|
||||
echo
|
||||
echo "## Command"
|
||||
echo "\`cd devfront && pnpm install --no-frozen-lockfile --shamefully-hoist\`"
|
||||
echo
|
||||
echo "## Install Log Tail (last 200 lines)"
|
||||
echo '```text'
|
||||
tail -n 200 reports/front-coverage-install.log
|
||||
echo '```'
|
||||
} > reports/devfront-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -862,10 +961,10 @@ jobs:
|
||||
|
||||
if [ "$test_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Front Vitest Coverage Failure Report"
|
||||
echo "# Devfront Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`front-vitest-coverage\`"
|
||||
echo "- Job: \`devfront-vitest-coverage\`"
|
||||
echo "- Package: \`devfront\`"
|
||||
echo "- Exit Code: \`$test_exit_code\`"
|
||||
echo
|
||||
@@ -873,7 +972,108 @@ jobs:
|
||||
echo '```text'
|
||||
tail -n 200 reports/devfront-vitest-coverage.log
|
||||
echo '```'
|
||||
} > reports/front-vitest-coverage-failure-report.md
|
||||
} > reports/devfront-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Generate devfront Vitest coverage summary
|
||||
run: |
|
||||
node scripts/summarize_vitest_coverage.mjs devfront
|
||||
cat reports/vitest-coverage-summary.md >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Publish devfront Vitest coverage failure summary
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
if [ -f reports/devfront-vitest-coverage-failure-report.md ]; then
|
||||
cat reports/devfront-vitest-coverage-failure-report.md >> "$GITHUB_STEP_SUMMARY"
|
||||
fi
|
||||
|
||||
- name: Upload devfront Vitest coverage report artifact
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: devfront-vitest-coverage-report
|
||||
path: |
|
||||
reports/vitest-coverage-summary.md
|
||||
reports/vitest-coverage-summary.json
|
||||
reports/devfront-vitest-coverage-failure-report.md
|
||||
reports/front-coverage-install.log
|
||||
reports/devfront-vitest-coverage.log
|
||||
devfront/coverage
|
||||
if-no-files-found: ignore
|
||||
|
||||
orgfront-vitest-coverage:
|
||||
needs:
|
||||
- changes
|
||||
- lint
|
||||
if: ${{ always() && needs.changes.outputs.orgfront == 'true' && (github.event_name != 'workflow_dispatch' || inputs.run_front_coverage == true) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
|
||||
- name: Install front workspace dependencies
|
||||
run: |
|
||||
mkdir -p reports
|
||||
set +e
|
||||
npm install -g pnpm
|
||||
cd common
|
||||
pnpm install --no-frozen-lockfile --shamefully-hoist 2>&1 | tee ../reports/front-coverage-install.log
|
||||
install_exit_code=${PIPESTATUS[0]}
|
||||
cd ..
|
||||
set -e
|
||||
|
||||
if [ "$install_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Orgfront Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`orgfront-vitest-coverage\`"
|
||||
echo "- Reason: \`Dependency install failed\`"
|
||||
echo "- Exit Code: \`$install_exit_code\`"
|
||||
echo
|
||||
echo "## Command"
|
||||
echo "\`cd common && pnpm install --no-frozen-lockfile --shamefully-hoist\`"
|
||||
echo
|
||||
echo "## Install Log Tail (last 200 lines)"
|
||||
echo '```text'
|
||||
tail -n 200 reports/front-coverage-install.log
|
||||
echo '```'
|
||||
} > reports/orgfront-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
cd orgfront
|
||||
pnpm install --no-frozen-lockfile --shamefully-hoist 2>&1 | tee -a ../reports/front-coverage-install.log
|
||||
app_install_exit_code=${PIPESTATUS[0]}
|
||||
cd ..
|
||||
set -e
|
||||
|
||||
if [ "$app_install_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Orgfront Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`orgfront-vitest-coverage\`"
|
||||
echo "- Package: \`orgfront\`"
|
||||
echo "- Reason: \`Dependency install failed\`"
|
||||
echo "- Exit Code: \`$app_install_exit_code\`"
|
||||
echo
|
||||
echo "## Command"
|
||||
echo "\`cd orgfront && pnpm install --no-frozen-lockfile --shamefully-hoist\`"
|
||||
echo
|
||||
echo "## Install Log Tail (last 200 lines)"
|
||||
echo '```text'
|
||||
tail -n 200 reports/front-coverage-install.log
|
||||
echo '```'
|
||||
} > reports/orgfront-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -888,10 +1088,10 @@ jobs:
|
||||
|
||||
if [ "$test_exit_code" -ne 0 ]; then
|
||||
{
|
||||
echo "# Front Vitest Coverage Failure Report"
|
||||
echo "# Orgfront Vitest Coverage Failure Report"
|
||||
echo
|
||||
echo "- Workflow: \`${GITHUB_WORKFLOW:-Code Check}\`"
|
||||
echo "- Job: \`front-vitest-coverage\`"
|
||||
echo "- Job: \`orgfront-vitest-coverage\`"
|
||||
echo "- Package: \`orgfront\`"
|
||||
echo "- Exit Code: \`$test_exit_code\`"
|
||||
echo
|
||||
@@ -899,38 +1099,34 @@ jobs:
|
||||
echo '```text'
|
||||
tail -n 200 reports/orgfront-vitest-coverage.log
|
||||
echo '```'
|
||||
} > reports/front-vitest-coverage-failure-report.md
|
||||
} > reports/orgfront-vitest-coverage-failure-report.md
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Generate Vitest coverage summary
|
||||
- name: Generate orgfront Vitest coverage summary
|
||||
run: |
|
||||
node scripts/summarize_vitest_coverage.mjs
|
||||
node scripts/summarize_vitest_coverage.mjs orgfront
|
||||
cat reports/vitest-coverage-summary.md >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Publish front Vitest coverage failure summary
|
||||
- name: Publish orgfront Vitest coverage failure summary
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
if [ -f reports/front-vitest-coverage-failure-report.md ]; then
|
||||
cat reports/front-vitest-coverage-failure-report.md >> "$GITHUB_STEP_SUMMARY"
|
||||
if [ -f reports/orgfront-vitest-coverage-failure-report.md ]; then
|
||||
cat reports/orgfront-vitest-coverage-failure-report.md >> "$GITHUB_STEP_SUMMARY"
|
||||
fi
|
||||
|
||||
- name: Upload front Vitest coverage report artifact
|
||||
- name: Upload orgfront Vitest coverage report artifact
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: front-vitest-coverage-report
|
||||
name: orgfront-vitest-coverage-report
|
||||
path: |
|
||||
reports/vitest-coverage-summary.md
|
||||
reports/vitest-coverage-summary.json
|
||||
reports/front-vitest-coverage-failure-report.md
|
||||
reports/orgfront-vitest-coverage-failure-report.md
|
||||
reports/front-coverage-install.log
|
||||
reports/adminfront-vitest-coverage.log
|
||||
reports/devfront-vitest-coverage.log
|
||||
reports/orgfront-vitest-coverage.log
|
||||
adminfront/coverage
|
||||
devfront/coverage
|
||||
orgfront/coverage
|
||||
if-no-files-found: ignore
|
||||
|
||||
@@ -1406,7 +1602,9 @@ jobs:
|
||||
- backend-tests
|
||||
- userfront-tests
|
||||
- userfront-e2e-tests
|
||||
- front-vitest-coverage
|
||||
- adminfront-vitest-coverage
|
||||
- devfront-vitest-coverage
|
||||
- orgfront-vitest-coverage
|
||||
- adminfront-tests
|
||||
- devfront-tests
|
||||
- orgfront-tests
|
||||
@@ -1423,12 +1621,26 @@ jobs:
|
||||
with:
|
||||
node-version: "24"
|
||||
|
||||
- name: Download Vitest coverage report artifact
|
||||
- name: Download adminfront Vitest coverage report artifact
|
||||
uses: actions/download-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: front-vitest-coverage-report
|
||||
path: badge-artifacts/front-vitest-coverage-report
|
||||
name: adminfront-vitest-coverage-report
|
||||
path: badge-artifacts/adminfront
|
||||
|
||||
- name: Download devfront Vitest coverage report artifact
|
||||
uses: actions/download-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: devfront-vitest-coverage-report
|
||||
path: badge-artifacts/devfront
|
||||
|
||||
- name: Download orgfront Vitest coverage report artifact
|
||||
uses: actions/download-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: orgfront-vitest-coverage-report
|
||||
path: badge-artifacts/orgfront
|
||||
|
||||
- name: Update badge files
|
||||
env:
|
||||
@@ -1438,7 +1650,9 @@ jobs:
|
||||
USERFRONT_RESULT: ${{ needs['userfront-tests'].result }}
|
||||
USERFRONT_E2E_RESULT: ${{ needs['userfront-e2e-tests'].result }}
|
||||
USERFRONT_E2E_FULL: ${{ github.event_name == 'workflow_dispatch' && inputs.run_userfront_e2e_full == true }}
|
||||
COVERAGE_RESULT: ${{ needs['front-vitest-coverage'].result }}
|
||||
ADMINFRONT_COVERAGE_RESULT: ${{ needs['adminfront-vitest-coverage'].result }}
|
||||
DEVFRONT_COVERAGE_RESULT: ${{ needs['devfront-vitest-coverage'].result }}
|
||||
ORGFRONT_COVERAGE_RESULT: ${{ needs['orgfront-vitest-coverage'].result }}
|
||||
ADMINFRONT_RESULT: ${{ needs['adminfront-tests'].result }}
|
||||
DEVFRONT_RESULT: ${{ needs['devfront-tests'].result }}
|
||||
ORGFRONT_RESULT: ${{ needs['orgfront-tests'].result }}
|
||||
|
||||
@@ -63,9 +63,9 @@ jobs:
|
||||
git cat-file -e "refs/remotes/origin/badges:dev/${target_sha}/badges.json" 2>/dev/null; then
|
||||
full_message="$(
|
||||
git show "refs/remotes/origin/badges:dev/${target_sha}/badges.json" |
|
||||
node -e "let input=''; process.stdin.on('data', c => input += c); process.stdin.on('end', () => { const data = JSON.parse(input); process.stdout.write(data.badges?.['userfront-e2e-full']?.message || 'unknown'); });"
|
||||
node -e "let input=''; process.stdin.on('data', c => input += c); process.stdin.on('end', () => { const data = JSON.parse(input); const keys = ['userfront-chrome', 'userfront-firefox', 'userfront-safari']; const messages = keys.map((key) => data.badges?.[key]?.message || 'unknown'); process.stdout.write(messages.join(',')); });"
|
||||
)"
|
||||
if [ -n "${full_message}" ] && [ "${full_message}" != "unknown" ]; then
|
||||
if [ -n "${full_message}" ] && ! printf '%s' "${full_message}" | grep -q "unknown"; then
|
||||
should_run="false"
|
||||
reason="full-result-exists:${full_message}"
|
||||
fi
|
||||
@@ -85,6 +85,13 @@ jobs:
|
||||
if: ${{ needs.lint.result == 'success' && needs.full-test-policy.outputs.should_run == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 80
|
||||
outputs:
|
||||
chromium_desktop: ${{ steps.full-results.outputs.chromium_desktop }}
|
||||
chromium_mobile: ${{ steps.full-results.outputs.chromium_mobile }}
|
||||
firefox_desktop: ${{ steps.full-results.outputs.firefox_desktop }}
|
||||
firefox_mobile: ${{ steps.full-results.outputs.firefox_mobile }}
|
||||
webkit_desktop: ${{ steps.full-results.outputs.webkit_desktop }}
|
||||
webkit_mobile: ${{ steps.full-results.outputs.webkit_mobile }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
@@ -124,9 +131,44 @@ jobs:
|
||||
npx playwright install --with-deps
|
||||
|
||||
- name: Run full userfront-e2e tests
|
||||
id: full-results
|
||||
run: |
|
||||
mkdir -p reports
|
||||
cd userfront-e2e
|
||||
npm test
|
||||
workers="${PLAYWRIGHT_WORKERS:-4}"
|
||||
case "$workers" in
|
||||
''|*[!0-9]*|0) workers=4 ;;
|
||||
esac
|
||||
any_failure=0
|
||||
|
||||
run_project() {
|
||||
output_name="$1"
|
||||
project_name="$2"
|
||||
log_path="../reports/userfront-e2e-full-${project_name}.log"
|
||||
|
||||
set +e
|
||||
echo "[userfront-e2e-full] PLAYWRIGHT_WORKERS=${workers} npx playwright test --project=${project_name}" | tee "$log_path"
|
||||
PLAYWRIGHT_WORKERS="$workers" npx playwright test --project="$project_name" --reporter=list 2>&1 | tee -a "$log_path"
|
||||
exit_code=${PIPESTATUS[0]}
|
||||
set -e
|
||||
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
result="success"
|
||||
else
|
||||
result="failure"
|
||||
any_failure=1
|
||||
fi
|
||||
echo "${output_name}=${result}" >> "$GITHUB_OUTPUT"
|
||||
}
|
||||
|
||||
run_project chromium_desktop chromium-desktop
|
||||
run_project chromium_mobile chromium-mobile-webapp
|
||||
run_project firefox_desktop firefox-desktop
|
||||
echo "firefox_mobile=skipped" >> "$GITHUB_OUTPUT"
|
||||
run_project webkit_desktop webkit-desktop
|
||||
run_project webkit_mobile webkit-mobile-webapp
|
||||
|
||||
exit "$any_failure"
|
||||
|
||||
- name: Upload userfront-e2e full artifacts
|
||||
if: ${{ always() }}
|
||||
@@ -135,6 +177,7 @@ jobs:
|
||||
with:
|
||||
name: userfront-e2e-full-report
|
||||
path: |
|
||||
reports/userfront-e2e-full-*.log
|
||||
userfront-e2e/playwright-report
|
||||
userfront-e2e/test-results
|
||||
if-no-files-found: ignore
|
||||
@@ -161,6 +204,12 @@ jobs:
|
||||
env:
|
||||
USERFRONT_E2E_RESULT: ${{ needs.userfront-e2e-full.result }}
|
||||
USERFRONT_E2E_FULL: "true"
|
||||
USERFRONT_E2E_CHROMIUM_DESKTOP_RESULT: ${{ needs.userfront-e2e-full.outputs.chromium_desktop }}
|
||||
USERFRONT_E2E_CHROMIUM_MOBILE_RESULT: ${{ needs.userfront-e2e-full.outputs.chromium_mobile }}
|
||||
USERFRONT_E2E_FIREFOX_DESKTOP_RESULT: ${{ needs.userfront-e2e-full.outputs.firefox_desktop }}
|
||||
USERFRONT_E2E_FIREFOX_MOBILE_RESULT: ${{ needs.userfront-e2e-full.outputs.firefox_mobile }}
|
||||
USERFRONT_E2E_WEBKIT_DESKTOP_RESULT: ${{ needs.userfront-e2e-full.outputs.webkit_desktop }}
|
||||
USERFRONT_E2E_WEBKIT_MOBILE_RESULT: ${{ needs.userfront-e2e-full.outputs.webkit_mobile }}
|
||||
BADGE_UPDATE_CODE_CHECK: "false"
|
||||
BADGE_SOURCE_BRANCH: dev
|
||||
BADGE_SOURCE_SHA: ${{ github.sha }}
|
||||
|
||||
13
README.md
@@ -1,15 +1,10 @@
|
||||
# Baron SSO
|
||||
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/src/branch/dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/src/branch/dev) [](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev) [](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev) [](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev) [](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev) [](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev) [](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/code_check.yml?branch=dev)
|
||||
[](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/userfront_e2e_full_nightly.yml?branch=dev) [](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/userfront_e2e_full_nightly.yml?branch=dev) [](https://gitea.hmac.kr/baron/baron-sso/actions/workflows/userfront_e2e_full_nightly.yml?branch=dev)
|
||||
|
||||
badge는 `Code Check`가 `badges` 브랜치의 `latest/`와 `dev/<commit-sha>/`에 발행합니다. 최신 HTML/LCOV/JSON summary는 Gitea `Code Check`의 `front-vitest-coverage-report` artifact에서 확인할 수 있습니다.
|
||||
badge는 `Code Check`가 `badges` 브랜치의 `latest/`와 `dev/<commit-sha>/`에 발행합니다. 최신 HTML/LCOV/JSON summary는 Gitea `Code Check`의 패키지별 `*-vitest-coverage-report` artifact에서 확인할 수 있습니다.
|
||||
|
||||
**Baron 로그인**은 화이트 라벨링된 가족사의 모든 소프트웨어 Auth를 총괄하는 사용자 인증/인가 허브입니다.
|
||||
|
||||
|
||||
@@ -44,6 +44,23 @@ vi.mock("../../lib/i18n", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../../../common/core/components/audit", () => ({
|
||||
AuditLogTable: ({
|
||||
logs,
|
||||
}: {
|
||||
logs: Array<{ user_id: string; event_type: string }>;
|
||||
}) => (
|
||||
<div>
|
||||
{logs.map((log) => (
|
||||
<div key={`${log.user_id}-${log.event_type}`}>
|
||||
<span>{log.user_id}</span>
|
||||
<span>{log.event_type}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
const clientSummary = {
|
||||
id: "client-a",
|
||||
name: "Console App",
|
||||
|
||||
@@ -43,6 +43,7 @@ export default defineConfig({
|
||||
"../common/**/node_modules/**",
|
||||
"../common/.pnpm-store/**",
|
||||
`${commonRoot}/theme/**`,
|
||||
`${commonRoot}/core/pagination/*.ts`,
|
||||
`${commonRoot}/core/pagination/*.worker.ts`,
|
||||
`${commonRoot}/core/query/queryClient.ts`,
|
||||
],
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="191" height="20" role="img" aria-label="adminfront coverage: 38.89%">
|
||||
<title>adminfront coverage: 38.89%</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="191" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="140" height="20" fill="#555"/>
|
||||
<rect x="140" width="51" height="20" fill="#bf8700"/>
|
||||
<rect width="191" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="70" y="15" fill="#010101" fill-opacity=".3">adminfront coverage</text>
|
||||
<text x="70" y="14">adminfront coverage</text>
|
||||
<text x="165.5" y="15" fill="#010101" fill-opacity=".3">38.89%</text>
|
||||
<text x="165.5" y="14">38.89%</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1002 B |
19
docs/badges/adminfront.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="136" height="20" role="img" aria-label="adminfront: unknown">
|
||||
<title>adminfront: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="136" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="78" height="20" fill="#555"/>
|
||||
<rect x="78" width="58" height="20" fill="#6e7781"/>
|
||||
<rect width="136" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="39" y="15" fill="#010101" fill-opacity=".3">adminfront</text>
|
||||
<text x="39" y="14">adminfront</text>
|
||||
<text x="107" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="107" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 964 B |
19
docs/badges/backend-tests.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="116" height="20" role="img" aria-label="backend: unknown">
|
||||
<title>backend: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="116" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="58" height="20" fill="#555"/>
|
||||
<rect x="58" width="58" height="20" fill="#6e7781"/>
|
||||
<rect width="116" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="29" y="15" fill="#010101" fill-opacity=".3">backend</text>
|
||||
<text x="29" y="14">backend</text>
|
||||
<text x="87" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="87" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 950 B |
@@ -1,8 +1,20 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generatedBy": "scripts/update_code_check_badges.mjs",
|
||||
"updatedAt": "2026-05-29T03:35:39.250Z",
|
||||
"updatedAt": "2026-05-29T08:13:02.131Z",
|
||||
"source": {
|
||||
"branch": "dev",
|
||||
"sha": null,
|
||||
"shortSha": null,
|
||||
"runId": null,
|
||||
"runNumber": null
|
||||
},
|
||||
"badges": {
|
||||
"dev-sha": {
|
||||
"label": "dev",
|
||||
"message": "unknown",
|
||||
"color": "#0969da"
|
||||
},
|
||||
"code-check": {
|
||||
"label": "code check",
|
||||
"message": "failing",
|
||||
@@ -13,30 +25,45 @@
|
||||
"message": "passing",
|
||||
"color": "#2ea043"
|
||||
},
|
||||
"userfront-e2e-fast": {
|
||||
"label": "userfront e2e fast",
|
||||
"message": "failing",
|
||||
"color": "#cf222e"
|
||||
},
|
||||
"userfront-e2e-full": {
|
||||
"label": "userfront e2e full",
|
||||
"backend-tests": {
|
||||
"label": "backend",
|
||||
"message": "unknown",
|
||||
"color": "#6e7781"
|
||||
},
|
||||
"adminfront-coverage": {
|
||||
"label": "adminfront coverage",
|
||||
"message": "38.89%",
|
||||
"color": "#bf8700"
|
||||
"userfront": {
|
||||
"label": "userfront",
|
||||
"message": "unknown",
|
||||
"color": "#6e7781"
|
||||
},
|
||||
"devfront-coverage": {
|
||||
"label": "devfront coverage",
|
||||
"message": "8.87%",
|
||||
"color": "#cf222e"
|
||||
"adminfront": {
|
||||
"label": "adminfront",
|
||||
"message": "unknown",
|
||||
"color": "#6e7781"
|
||||
},
|
||||
"orgfront-coverage": {
|
||||
"label": "orgfront coverage",
|
||||
"message": "37.50%",
|
||||
"color": "#bf8700"
|
||||
"devfront": {
|
||||
"label": "devfront",
|
||||
"message": "unknown",
|
||||
"color": "#6e7781"
|
||||
},
|
||||
"orgfront": {
|
||||
"label": "orgfront",
|
||||
"message": "unknown",
|
||||
"color": "#6e7781"
|
||||
},
|
||||
"userfront-chrome": {
|
||||
"label": "chrome",
|
||||
"message": "unknown",
|
||||
"color": "#6e7781"
|
||||
},
|
||||
"userfront-firefox": {
|
||||
"label": "firefox",
|
||||
"message": "unknown",
|
||||
"color": "#6e7781"
|
||||
},
|
||||
"userfront-safari": {
|
||||
"label": "safari",
|
||||
"message": "unknown",
|
||||
"color": "#6e7781"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
docs/badges/dev-sha.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="20" role="img" aria-label="dev: unknown">
|
||||
<title>dev: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="96" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="38" height="20" fill="#555"/>
|
||||
<rect x="38" width="58" height="20" fill="#0969da"/>
|
||||
<rect width="96" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="19" y="15" fill="#010101" fill-opacity=".3">dev</text>
|
||||
<text x="19" y="14">dev</text>
|
||||
<text x="67" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="67" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 931 B |
@@ -1,19 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="170" height="20" role="img" aria-label="devfront coverage: 8.87%">
|
||||
<title>devfront coverage: 8.87%</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="170" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="126" height="20" fill="#555"/>
|
||||
<rect x="126" width="44" height="20" fill="#cf222e"/>
|
||||
<rect width="170" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="63" y="15" fill="#010101" fill-opacity=".3">devfront coverage</text>
|
||||
<text x="63" y="14">devfront coverage</text>
|
||||
<text x="148" y="15" fill="#010101" fill-opacity=".3">8.87%</text>
|
||||
<text x="148" y="14">8.87%</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 986 B |
19
docs/badges/devfront.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="123" height="20" role="img" aria-label="devfront: unknown">
|
||||
<title>devfront: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="123" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="65" height="20" fill="#555"/>
|
||||
<rect x="65" width="58" height="20" fill="#6e7781"/>
|
||||
<rect width="123" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="32.5" y="15" fill="#010101" fill-opacity=".3">devfront</text>
|
||||
<text x="32.5" y="14">devfront</text>
|
||||
<text x="94" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="94" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 958 B |
@@ -1,19 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="177" height="20" role="img" aria-label="orgfront coverage: 37.50%">
|
||||
<title>orgfront coverage: 37.50%</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="177" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="126" height="20" fill="#555"/>
|
||||
<rect x="126" width="51" height="20" fill="#bf8700"/>
|
||||
<rect width="177" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="63" y="15" fill="#010101" fill-opacity=".3">orgfront coverage</text>
|
||||
<text x="63" y="14">orgfront coverage</text>
|
||||
<text x="151.5" y="15" fill="#010101" fill-opacity=".3">37.50%</text>
|
||||
<text x="151.5" y="14">37.50%</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 994 B |
19
docs/badges/orgfront.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="123" height="20" role="img" aria-label="orgfront: unknown">
|
||||
<title>orgfront: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="123" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="65" height="20" fill="#555"/>
|
||||
<rect x="65" width="58" height="20" fill="#6e7781"/>
|
||||
<rect width="123" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="32.5" y="15" fill="#010101" fill-opacity=".3">orgfront</text>
|
||||
<text x="32.5" y="14">orgfront</text>
|
||||
<text x="94" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="94" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 958 B |
19
docs/badges/userfront-chrome.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="109" height="20" role="img" aria-label="chrome: unknown">
|
||||
<title>chrome: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="109" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="51" height="20" fill="#555"/>
|
||||
<rect x="51" width="58" height="20" fill="#6e7781"/>
|
||||
<rect width="109" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="25.5" y="15" fill="#010101" fill-opacity=".3">chrome</text>
|
||||
<text x="25.5" y="14">chrome</text>
|
||||
<text x="80" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="80" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 950 B |
@@ -1,19 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="191" height="20" role="img" aria-label="userfront e2e fast: failing">
|
||||
<title>userfront e2e fast: failing</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="191" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="133" height="20" fill="#555"/>
|
||||
<rect x="133" width="58" height="20" fill="#cf222e"/>
|
||||
<rect width="191" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="66.5" y="15" fill="#010101" fill-opacity=".3">userfront e2e fast</text>
|
||||
<text x="66.5" y="14">userfront e2e fast</text>
|
||||
<text x="162" y="15" fill="#010101" fill-opacity=".3">failing</text>
|
||||
<text x="162" y="14">failing</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1002 B |
@@ -1,19 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="191" height="20" role="img" aria-label="userfront e2e full: unknown">
|
||||
<title>userfront e2e full: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="191" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="133" height="20" fill="#555"/>
|
||||
<rect x="133" width="58" height="20" fill="#6e7781"/>
|
||||
<rect width="191" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="66.5" y="15" fill="#010101" fill-opacity=".3">userfront e2e full</text>
|
||||
<text x="66.5" y="14">userfront e2e full</text>
|
||||
<text x="162" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="162" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1002 B |
19
docs/badges/userfront-firefox.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="116" height="20" role="img" aria-label="firefox: unknown">
|
||||
<title>firefox: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="116" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="58" height="20" fill="#555"/>
|
||||
<rect x="58" width="58" height="20" fill="#6e7781"/>
|
||||
<rect width="116" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="29" y="15" fill="#010101" fill-opacity=".3">firefox</text>
|
||||
<text x="29" y="14">firefox</text>
|
||||
<text x="87" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="87" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 950 B |
19
docs/badges/userfront-safari.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="109" height="20" role="img" aria-label="safari: unknown">
|
||||
<title>safari: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="109" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="51" height="20" fill="#555"/>
|
||||
<rect x="51" width="58" height="20" fill="#6e7781"/>
|
||||
<rect width="109" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="25.5" y="15" fill="#010101" fill-opacity=".3">safari</text>
|
||||
<text x="25.5" y="14">safari</text>
|
||||
<text x="80" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="80" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 950 B |
19
docs/badges/userfront.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="130" height="20" role="img" aria-label="userfront: unknown">
|
||||
<title>userfront: unknown</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r"><rect width="130" height="20" rx="3" fill="#fff"/></clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="72" height="20" fill="#555"/>
|
||||
<rect x="72" width="58" height="20" fill="#6e7781"/>
|
||||
<rect width="130" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text x="36" y="15" fill="#010101" fill-opacity=".3">userfront</text>
|
||||
<text x="36" y="14">userfront</text>
|
||||
<text x="101" y="15" fill="#010101" fill-opacity=".3">unknown</text>
|
||||
<text x="101" y="14">unknown</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 960 B |
@@ -59,6 +59,6 @@
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^6.0.3",
|
||||
"vite": "^8.0.14",
|
||||
"vitest": "^4.1.6"
|
||||
"vitest": "4.1.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,14 @@ export default defineConfig({
|
||||
"../common/**/node_modules/**",
|
||||
"../common/.pnpm-store/**",
|
||||
`${commonRoot}/theme/**`,
|
||||
`${commonRoot}/core/audit/index.ts`,
|
||||
`${commonRoot}/core/components/audit/AuditLogTable.tsx`,
|
||||
`${commonRoot}/core/components/overview/OverviewAxisNotes.tsx`,
|
||||
`${commonRoot}/core/components/overview/OverviewMetric.tsx`,
|
||||
`${commonRoot}/core/components/overview/OverviewSelectionChips.tsx`,
|
||||
`${commonRoot}/core/components/page/PageHeader.tsx`,
|
||||
`${commonRoot}/core/components/sort/SortableTableHead.tsx`,
|
||||
`${commonRoot}/core/pagination/*.ts`,
|
||||
`${commonRoot}/core/pagination/*.worker.ts`,
|
||||
`${commonRoot}/core/query/queryClient.ts`,
|
||||
],
|
||||
|
||||
@@ -2,7 +2,9 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const packages = ["adminfront", "devfront", "orgfront"];
|
||||
const defaultPackages = ["adminfront", "devfront", "orgfront"];
|
||||
const packages = process.argv.slice(2);
|
||||
const targetPackages = packages.length > 0 ? packages : defaultPackages;
|
||||
|
||||
function formatPct(value) {
|
||||
return typeof value === "number" ? `${value.toFixed(2)}%` : "n/a";
|
||||
@@ -63,7 +65,7 @@ function renderMarkdown(rows) {
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
for (const packageName of packages) {
|
||||
for (const packageName of targetPackages) {
|
||||
rows.push(await readCoverageSummary(packageName));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
||||
import { mkdir, readdir, readFile, unlink, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
@@ -6,78 +6,124 @@ const badgeDir = path.join(repoRoot, "docs", "badges");
|
||||
const manifestPath = path.join(badgeDir, "badges.json");
|
||||
|
||||
const resultStyles = {
|
||||
success: { message: "passing", color: "#2ea043" },
|
||||
failure: { message: "failing", color: "#cf222e" },
|
||||
cancelled: { message: "cancelled", color: "#bf8700" },
|
||||
skipped: { message: "skipped", color: "#6e7781" },
|
||||
unknown: { message: "unknown", color: "#6e7781" },
|
||||
success: { message: "passing", color: "#2ea043" },
|
||||
failure: { message: "failing", color: "#cf222e" },
|
||||
cancelled: { message: "cancelled", color: "#bf8700" },
|
||||
skipped: { message: "skipped", color: "#6e7781" },
|
||||
unknown: { message: "unknown", color: "#6e7781" },
|
||||
};
|
||||
|
||||
const badgeDefinitions = {
|
||||
"dev-sha": { label: "dev", message: "unknown", color: "#0969da" },
|
||||
"code-check": { label: "code check", message: "unknown", color: "#6e7781" },
|
||||
biome: { label: "biome", message: "unknown", color: "#6e7781" },
|
||||
"userfront-e2e-fast": {
|
||||
label: "userfront e2e fast",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
"userfront-e2e-full": {
|
||||
label: "userfront e2e full",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
"adminfront-coverage": {
|
||||
label: "adminfront coverage",
|
||||
message: "38.89%",
|
||||
color: "#bf8700",
|
||||
},
|
||||
"devfront-coverage": {
|
||||
label: "devfront coverage",
|
||||
message: "8.87%",
|
||||
color: "#cf222e",
|
||||
},
|
||||
"orgfront-coverage": {
|
||||
label: "orgfront coverage",
|
||||
message: "37.50%",
|
||||
color: "#bf8700",
|
||||
},
|
||||
"dev-sha": { label: "dev", message: "unknown", color: "#0969da" },
|
||||
"code-check": { label: "code check", message: "unknown", color: "#6e7781" },
|
||||
biome: { label: "biome", message: "unknown", color: "#6e7781" },
|
||||
"backend-tests": {
|
||||
label: "backend",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
userfront: {
|
||||
label: "userfront",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
adminfront: {
|
||||
label: "adminfront",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
devfront: {
|
||||
label: "devfront",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
orgfront: {
|
||||
label: "orgfront",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
"userfront-chrome": {
|
||||
label: "chrome",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
"userfront-firefox": {
|
||||
label: "firefox",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
"userfront-safari": {
|
||||
label: "safari",
|
||||
message: "unknown",
|
||||
color: "#6e7781",
|
||||
},
|
||||
};
|
||||
|
||||
const deprecatedBadgeKeys = [
|
||||
"userfront-e2e-fast",
|
||||
"userfront-e2e-full",
|
||||
"adminfront-e2e",
|
||||
"devfront-e2e",
|
||||
"orgfront-e2e",
|
||||
"userfront-coverage",
|
||||
"adminfront-coverage",
|
||||
"devfront-coverage",
|
||||
"orgfront-coverage",
|
||||
];
|
||||
|
||||
function normalizeResult(result) {
|
||||
return resultStyles[result] ? result : "unknown";
|
||||
return resultStyles[result] ? result : "unknown";
|
||||
}
|
||||
|
||||
function styleForResult(result) {
|
||||
return resultStyles[normalizeResult(result)];
|
||||
return resultStyles[normalizeResult(result)];
|
||||
}
|
||||
|
||||
function compactResult(result) {
|
||||
const normalized = normalizeResult(result);
|
||||
return {
|
||||
success: "pass",
|
||||
failure: "fail",
|
||||
cancelled: "cancel",
|
||||
skipped: "skip",
|
||||
unknown: "unknown",
|
||||
}[normalized];
|
||||
}
|
||||
|
||||
function colorForParts(parts) {
|
||||
const normalized = parts.map(normalizeResult);
|
||||
if (normalized.includes("failure")) return resultStyles.failure.color;
|
||||
if (normalized.includes("cancelled")) return resultStyles.cancelled.color;
|
||||
if (normalized.every((part) => part === "success")) return resultStyles.success.color;
|
||||
return resultStyles.unknown.color;
|
||||
}
|
||||
|
||||
function colorForCoverage(percent) {
|
||||
if (percent >= 80) return "#2ea043";
|
||||
if (percent >= 35) return "#bf8700";
|
||||
return "#cf222e";
|
||||
if (percent >= 80) return "#2ea043";
|
||||
if (percent >= 35) return "#bf8700";
|
||||
return "#cf222e";
|
||||
}
|
||||
|
||||
function escapeXml(value) {
|
||||
return String(value)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """);
|
||||
return String(value)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """);
|
||||
}
|
||||
|
||||
function textWidth(text) {
|
||||
return Math.max(38, Math.ceil(String(text).length * 6.8 + 10));
|
||||
return Math.max(38, Math.ceil(String(text).length * 6.8 + 10));
|
||||
}
|
||||
|
||||
function renderBadge({ label, message, color }) {
|
||||
const labelWidth = textWidth(label);
|
||||
const messageWidth = textWidth(message);
|
||||
const width = labelWidth + messageWidth;
|
||||
const labelCenter = labelWidth / 2;
|
||||
const messageCenter = labelWidth + messageWidth / 2;
|
||||
const labelWidth = textWidth(label);
|
||||
const messageWidth = textWidth(message);
|
||||
const width = labelWidth + messageWidth;
|
||||
const labelCenter = labelWidth / 2;
|
||||
const messageCenter = labelWidth + messageWidth / 2;
|
||||
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="20" role="img" aria-label="${escapeXml(label)}: ${escapeXml(message)}">
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="20" role="img" aria-label="${escapeXml(label)}: ${escapeXml(message)}">
|
||||
<title>${escapeXml(label)}: ${escapeXml(message)}</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
@@ -100,151 +146,284 @@ function renderBadge({ label, message, color }) {
|
||||
}
|
||||
|
||||
async function readJsonIfExists(filePath) {
|
||||
try {
|
||||
return JSON.parse(await readFile(filePath, "utf8"));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(await readFile(filePath, "utf8"));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function findCoverageSummary(directory) {
|
||||
const entries = await readdir(directory, { withFileTypes: true }).catch(
|
||||
() => [],
|
||||
);
|
||||
async function findCoverageSummaries(directory) {
|
||||
const entries = await readdir(directory, { withFileTypes: true }).catch(
|
||||
() => [],
|
||||
);
|
||||
const results = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
const entryPath = path.join(directory, entry.name);
|
||||
if (entry.isFile() && entry.name === "vitest-coverage-summary.json") {
|
||||
return entryPath;
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
const found = await findCoverageSummary(entryPath);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
for (const entry of entries) {
|
||||
const entryPath = path.join(directory, entry.name);
|
||||
if (entry.isFile() && entry.name === "vitest-coverage-summary.json") {
|
||||
results.push(entryPath);
|
||||
continue;
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
results.push(...(await findCoverageSummaries(entryPath)));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return results;
|
||||
}
|
||||
|
||||
function updateResultBadge(manifest, key, result) {
|
||||
const style = styleForResult(result);
|
||||
manifest.badges[key] = {
|
||||
...(manifest.badges[key] ?? badgeDefinitions[key]),
|
||||
message: style.message,
|
||||
color: style.color,
|
||||
};
|
||||
const style = styleForResult(result);
|
||||
manifest.badges[key] = {
|
||||
...(manifest.badges[key] ?? badgeDefinitions[key]),
|
||||
message: style.message,
|
||||
color: style.color,
|
||||
};
|
||||
}
|
||||
|
||||
function updateCoverageBadges(manifest, coverageSummary) {
|
||||
for (const row of coverageSummary.packages ?? []) {
|
||||
const key = `${row.package}-coverage`;
|
||||
if (!badgeDefinitions[key]) continue;
|
||||
const statements = Number(row.statements);
|
||||
manifest.badges[key] = {
|
||||
...(manifest.badges[key] ?? badgeDefinitions[key]),
|
||||
message: `${statements.toFixed(2)}%`,
|
||||
color: colorForCoverage(statements),
|
||||
};
|
||||
}
|
||||
function updateCompactResultBadge(manifest, key, result) {
|
||||
const style = styleForResult(result);
|
||||
manifest.badges[key] = {
|
||||
...(manifest.badges[key] ?? badgeDefinitions[key]),
|
||||
label: badgeDefinitions[key]?.label ?? manifest.badges[key]?.label,
|
||||
message: compactResult(result),
|
||||
color: style.color,
|
||||
};
|
||||
}
|
||||
|
||||
function coveragePart(result, statements) {
|
||||
const normalized = normalizeResult(result);
|
||||
if (normalized !== "success") {
|
||||
return {
|
||||
message: compactResult(normalized),
|
||||
color: styleForResult(normalized).color,
|
||||
result: normalized,
|
||||
};
|
||||
}
|
||||
const value = Number(statements);
|
||||
if (!Number.isFinite(value)) {
|
||||
return {
|
||||
message: "unknown",
|
||||
color: resultStyles.unknown.color,
|
||||
result: "unknown",
|
||||
};
|
||||
}
|
||||
return {
|
||||
message: `${value.toFixed(2)}%`,
|
||||
color: colorForCoverage(value),
|
||||
result: "success",
|
||||
};
|
||||
}
|
||||
|
||||
function updatePackageBadge(manifest, key, testResult, coverageResult, statements) {
|
||||
if (!badgeDefinitions[key]) return;
|
||||
const test = normalizeResult(testResult);
|
||||
const coverage = coveragePart(coverageResult, statements);
|
||||
manifest.badges[key] = {
|
||||
...(manifest.badges[key] ?? badgeDefinitions[key]),
|
||||
label: badgeDefinitions[key].label,
|
||||
message: `${compactResult(test)} | ${coverage.message}`,
|
||||
color: test === "failure" || coverage.result === "failure"
|
||||
? resultStyles.failure.color
|
||||
: test === "cancelled" || coverage.result === "cancelled"
|
||||
? resultStyles.cancelled.color
|
||||
: coverage.result === "success"
|
||||
? coverage.color
|
||||
: colorForParts([test, coverage.result]),
|
||||
};
|
||||
}
|
||||
|
||||
function updateBrowserBadge(manifest, key, desktopResult, mobileResult) {
|
||||
if (!badgeDefinitions[key]) return;
|
||||
const desktop = normalizeResult(desktopResult);
|
||||
const mobile = normalizeResult(mobileResult);
|
||||
manifest.badges[key] = {
|
||||
...(manifest.badges[key] ?? badgeDefinitions[key]),
|
||||
label: badgeDefinitions[key].label,
|
||||
message: `${compactResult(desktop)} | ${compactResult(mobile)}`,
|
||||
color: colorForParts([desktop, mobile]),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeManifestForComparison(value) {
|
||||
return {
|
||||
...value,
|
||||
updatedAt: null,
|
||||
source: {
|
||||
...(value?.source ?? {}),
|
||||
runId: null,
|
||||
runNumber: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function manifestsMatchIgnoringRunMetadata(left, right) {
|
||||
return (
|
||||
JSON.stringify(normalizeManifestForComparison(left)) ===
|
||||
JSON.stringify(normalizeManifestForComparison(right))
|
||||
);
|
||||
}
|
||||
|
||||
function shortSha(value) {
|
||||
return String(value ?? "").trim().slice(0, 12);
|
||||
return String(value ?? "")
|
||||
.trim()
|
||||
.slice(0, 12);
|
||||
}
|
||||
|
||||
const existingManifest = process.env.RESET_BADGES === "true"
|
||||
? null
|
||||
: await readJsonIfExists(manifestPath);
|
||||
const sourceSha = shortSha(process.env.BADGE_SOURCE_SHA || process.env.GITHUB_SHA);
|
||||
const existingManifest =
|
||||
process.env.RESET_BADGES === "true"
|
||||
? null
|
||||
: await readJsonIfExists(manifestPath);
|
||||
const sourceSha = shortSha(
|
||||
process.env.BADGE_SOURCE_SHA || process.env.GITHUB_SHA,
|
||||
);
|
||||
const manifest = {
|
||||
schemaVersion: 1,
|
||||
generatedBy: "scripts/update_code_check_badges.mjs",
|
||||
updatedAt: new Date().toISOString(),
|
||||
source: {
|
||||
branch: process.env.BADGE_SOURCE_BRANCH || "dev",
|
||||
sha: process.env.BADGE_SOURCE_SHA || process.env.GITHUB_SHA || null,
|
||||
shortSha: sourceSha || null,
|
||||
runId: process.env.GITHUB_RUN_ID || null,
|
||||
runNumber: process.env.GITHUB_RUN_NUMBER || null,
|
||||
},
|
||||
badges: {
|
||||
...badgeDefinitions,
|
||||
...(existingManifest?.badges ?? {}),
|
||||
},
|
||||
schemaVersion: 1,
|
||||
generatedBy: "scripts/update_code_check_badges.mjs",
|
||||
updatedAt: new Date().toISOString(),
|
||||
source: {
|
||||
branch: process.env.BADGE_SOURCE_BRANCH || "dev",
|
||||
sha: process.env.BADGE_SOURCE_SHA || process.env.GITHUB_SHA || null,
|
||||
shortSha: sourceSha || null,
|
||||
runId: process.env.GITHUB_RUN_ID || null,
|
||||
runNumber: process.env.GITHUB_RUN_NUMBER || null,
|
||||
},
|
||||
badges: {
|
||||
...badgeDefinitions,
|
||||
...(existingManifest?.badges ?? {}),
|
||||
},
|
||||
};
|
||||
for (const key of deprecatedBadgeKeys) {
|
||||
delete manifest.badges[key];
|
||||
}
|
||||
|
||||
manifest.badges["dev-sha"] = {
|
||||
...badgeDefinitions["dev-sha"],
|
||||
message: sourceSha || "unknown",
|
||||
...badgeDefinitions["dev-sha"],
|
||||
message: sourceSha || "unknown",
|
||||
};
|
||||
|
||||
const jobResults = {
|
||||
lint: process.env.LINT_RESULT,
|
||||
biome: process.env.BIOME_RESULT,
|
||||
backend: process.env.BACKEND_RESULT,
|
||||
userfront: process.env.USERFRONT_RESULT,
|
||||
userfrontE2e: process.env.USERFRONT_E2E_RESULT,
|
||||
coverage: process.env.COVERAGE_RESULT,
|
||||
adminfront: process.env.ADMINFRONT_RESULT,
|
||||
devfront: process.env.DEVFRONT_RESULT,
|
||||
orgfront: process.env.ORGFRONT_RESULT,
|
||||
lint: process.env.LINT_RESULT,
|
||||
biome: process.env.BIOME_RESULT,
|
||||
backend: process.env.BACKEND_RESULT,
|
||||
userfront: process.env.USERFRONT_RESULT,
|
||||
userfrontE2e: process.env.USERFRONT_E2E_RESULT,
|
||||
adminfront: process.env.ADMINFRONT_RESULT,
|
||||
devfront: process.env.DEVFRONT_RESULT,
|
||||
orgfront: process.env.ORGFRONT_RESULT,
|
||||
};
|
||||
const e2eWasFull = process.env.USERFRONT_E2E_FULL === "true";
|
||||
const userfrontFastResult = e2eWasFull ? undefined : jobResults.userfrontE2e;
|
||||
const browserResults = {
|
||||
chrome: {
|
||||
desktop: process.env.USERFRONT_E2E_CHROMIUM_DESKTOP_RESULT,
|
||||
mobile: process.env.USERFRONT_E2E_CHROMIUM_MOBILE_RESULT,
|
||||
},
|
||||
firefox: {
|
||||
desktop: process.env.USERFRONT_E2E_FIREFOX_DESKTOP_RESULT,
|
||||
mobile: process.env.USERFRONT_E2E_FIREFOX_MOBILE_RESULT,
|
||||
},
|
||||
safari: {
|
||||
desktop: process.env.USERFRONT_E2E_WEBKIT_DESKTOP_RESULT,
|
||||
mobile: process.env.USERFRONT_E2E_WEBKIT_MOBILE_RESULT,
|
||||
},
|
||||
};
|
||||
|
||||
const overallResults = Object.values(jobResults).filter(Boolean);
|
||||
const legacyCoverageResult = process.env.COVERAGE_RESULT;
|
||||
const coverageJobResults = {
|
||||
userfront: process.env.USERFRONT_COVERAGE_RESULT,
|
||||
adminfront: process.env.ADMINFRONT_COVERAGE_RESULT || legacyCoverageResult,
|
||||
devfront: process.env.DEVFRONT_COVERAGE_RESULT || legacyCoverageResult,
|
||||
orgfront: process.env.ORGFRONT_COVERAGE_RESULT || legacyCoverageResult,
|
||||
};
|
||||
|
||||
const overallResults = [
|
||||
...Object.values(jobResults),
|
||||
...Object.values(coverageJobResults),
|
||||
...Object.values(browserResults).flatMap((result) => [
|
||||
result.desktop,
|
||||
result.mobile,
|
||||
]),
|
||||
].filter(Boolean);
|
||||
const hasFailure = overallResults.some((result) =>
|
||||
["failure", "cancelled"].includes(result),
|
||||
["failure", "cancelled"].includes(result),
|
||||
);
|
||||
const allSkipped = overallResults.length > 0 &&
|
||||
overallResults.every((result) => result === "skipped");
|
||||
const allSkipped =
|
||||
overallResults.length > 0 &&
|
||||
overallResults.every((result) => result === "skipped");
|
||||
if (process.env.BADGE_UPDATE_CODE_CHECK !== "false") {
|
||||
updateResultBadge(
|
||||
manifest,
|
||||
"code-check",
|
||||
overallResults.length === 0
|
||||
? "unknown"
|
||||
: hasFailure
|
||||
? "failure"
|
||||
: allSkipped
|
||||
? "skipped"
|
||||
: "success",
|
||||
);
|
||||
updateResultBadge(
|
||||
manifest,
|
||||
"code-check",
|
||||
overallResults.length === 0
|
||||
? "unknown"
|
||||
: hasFailure
|
||||
? "failure"
|
||||
: allSkipped
|
||||
? "skipped"
|
||||
: "success",
|
||||
);
|
||||
}
|
||||
|
||||
updateResultBadge(manifest, "biome", jobResults.biome);
|
||||
updateCompactResultBadge(manifest, "backend-tests", jobResults.backend);
|
||||
|
||||
const e2eWasFull = process.env.USERFRONT_E2E_FULL === "true";
|
||||
if (jobResults.userfrontE2e && jobResults.userfrontE2e !== "skipped") {
|
||||
updateResultBadge(
|
||||
manifest,
|
||||
e2eWasFull ? "userfront-e2e-full" : "userfront-e2e-fast",
|
||||
jobResults.userfrontE2e,
|
||||
);
|
||||
const coverageSummaries = process.env.COVERAGE_SUMMARY_PATH
|
||||
? [process.env.COVERAGE_SUMMARY_PATH]
|
||||
: await findCoverageSummaries(path.join(repoRoot, "badge-artifacts"));
|
||||
const coverageByPackage = new Map();
|
||||
for (const summaryPath of coverageSummaries) {
|
||||
const coverageSummary = await readJsonIfExists(summaryPath);
|
||||
for (const row of coverageSummary?.packages ?? []) {
|
||||
coverageByPackage.set(row.package, row.statements);
|
||||
}
|
||||
}
|
||||
|
||||
if (jobResults.coverage === "failure" || jobResults.coverage === "cancelled") {
|
||||
for (const key of [
|
||||
"adminfront-coverage",
|
||||
"devfront-coverage",
|
||||
"orgfront-coverage",
|
||||
]) {
|
||||
updateResultBadge(manifest, key, "failure");
|
||||
}
|
||||
} else {
|
||||
const coverageSummaryPath = process.env.COVERAGE_SUMMARY_PATH ||
|
||||
(await findCoverageSummary(path.join(repoRoot, "badge-artifacts")));
|
||||
const coverageSummary = coverageSummaryPath
|
||||
? await readJsonIfExists(coverageSummaryPath)
|
||||
: null;
|
||||
if (coverageSummary) {
|
||||
updateCoverageBadges(manifest, coverageSummary);
|
||||
}
|
||||
for (const [key, testResult, coverageResult] of [
|
||||
["userfront", userfrontFastResult, coverageJobResults.userfront],
|
||||
["adminfront", jobResults.adminfront, coverageJobResults.adminfront],
|
||||
["devfront", jobResults.devfront, coverageJobResults.devfront],
|
||||
["orgfront", jobResults.orgfront, coverageJobResults.orgfront],
|
||||
]) {
|
||||
if (testResult || coverageResult) {
|
||||
updatePackageBadge(
|
||||
manifest,
|
||||
key,
|
||||
testResult,
|
||||
coverageResult,
|
||||
coverageByPackage.get(key),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const [browser, result] of Object.entries(browserResults)) {
|
||||
if (result.desktop || result.mobile) {
|
||||
updateBrowserBadge(
|
||||
manifest,
|
||||
`userfront-${browser}`,
|
||||
result.desktop,
|
||||
result.mobile,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
existingManifest &&
|
||||
manifestsMatchIgnoringRunMetadata(manifest, existingManifest)
|
||||
) {
|
||||
manifest.updatedAt = existingManifest.updatedAt;
|
||||
manifest.source = existingManifest.source ?? manifest.source;
|
||||
}
|
||||
|
||||
await mkdir(badgeDir, { recursive: true });
|
||||
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
|
||||
for (const [key, badge] of Object.entries(manifest.badges)) {
|
||||
await writeFile(path.join(badgeDir, `${key}.svg`), renderBadge(badge));
|
||||
await writeFile(path.join(badgeDir, `${key}.svg`), renderBadge(badge));
|
||||
}
|
||||
for (const key of deprecatedBadgeKeys) {
|
||||
await unlink(path.join(badgeDir, `${key}.svg`)).catch(() => {});
|
||||
}
|
||||
|
||||
console.log(`Updated ${Object.keys(manifest.badges).length} badge files.`);
|
||||
|
||||
@@ -30,13 +30,36 @@ assert_contains "$WORKFLOW_FILE" 'push origin HEAD:${BADGE_BRANCH}'
|
||||
assert_contains "$WORKFLOW_FILE" 'BADGE_SOURCE_SHA: ${{ github.sha }}'
|
||||
assert_contains "$WORKFLOW_FILE" 'BADGE_LATEST_DIR="${BADGE_WORKTREE}/latest"'
|
||||
assert_contains "$WORKFLOW_FILE" 'BADGE_SHA_DIR="${BADGE_WORKTREE}/dev/${GITHUB_SHA}"'
|
||||
assert_contains "$WORKFLOW_FILE" "adminfront-vitest-coverage:"
|
||||
assert_contains "$WORKFLOW_FILE" "devfront-vitest-coverage:"
|
||||
assert_contains "$WORKFLOW_FILE" "orgfront-vitest-coverage:"
|
||||
if grep -Eq "^[[:space:]]+front-vitest-coverage:$" "$WORKFLOW_FILE"; then
|
||||
fail "Code Check workflow must use package-specific Vitest coverage jobs"
|
||||
fi
|
||||
assert_contains "$WORKFLOW_FILE" "ADMINFRONT_COVERAGE_RESULT: \${{ needs['adminfront-vitest-coverage'].result }}"
|
||||
assert_contains "$WORKFLOW_FILE" "DEVFRONT_COVERAGE_RESULT: \${{ needs['devfront-vitest-coverage'].result }}"
|
||||
assert_contains "$WORKFLOW_FILE" "ORGFRONT_COVERAGE_RESULT: \${{ needs['orgfront-vitest-coverage'].result }}"
|
||||
assert_contains "$WORKFLOW_FILE" "name: adminfront-vitest-coverage-report"
|
||||
assert_contains "$WORKFLOW_FILE" "name: devfront-vitest-coverage-report"
|
||||
assert_contains "$WORKFLOW_FILE" "name: orgfront-vitest-coverage-report"
|
||||
if grep -Eq "^[[:space:]]+git push$" "$WORKFLOW_FILE"; then
|
||||
fail "Code Check workflow must not push back to the current branch"
|
||||
fi
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/code-check.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/dev-sha.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/userfront-e2e-full.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/adminfront-coverage.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/backend-tests.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/userfront.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/adminfront.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/devfront.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/orgfront.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/userfront-chrome.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/userfront-firefox.svg"
|
||||
assert_contains "$README_FILE" "https://gitea.hmac.kr/baron/baron-sso/raw/branch/badges/latest/userfront-safari.svg"
|
||||
assert_not_contains "$README_FILE" "userfront-coverage.svg"
|
||||
assert_not_contains "$README_FILE" "adminfront-coverage.svg"
|
||||
assert_not_contains "$README_FILE" "adminfront-e2e.svg"
|
||||
assert_not_contains "$README_FILE" "userfront-e2e-fast.svg"
|
||||
assert_not_contains "$README_FILE" "userfront-e2e-full.svg"
|
||||
assert_not_contains "$README_FILE" "](docs/badges/"
|
||||
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "cron: \"0 18 * * *\""
|
||||
@@ -44,7 +67,18 @@ assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "make code-check-lint"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "refs/remotes/origin/badges:dev/\${target_sha}/badges.json"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "full-result-exists:\${full_message}"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_FULL: \"true\""
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "chromium-desktop"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "chromium-mobile-webapp"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "firefox-desktop"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "webkit-desktop"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "webkit-mobile-webapp"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_CHROMIUM_DESKTOP_RESULT:"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_CHROMIUM_MOBILE_RESULT:"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_FIREFOX_DESKTOP_RESULT:"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_FIREFOX_MOBILE_RESULT:"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_WEBKIT_DESKTOP_RESULT:"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_WEBKIT_MOBILE_RESULT:"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "BADGE_UPDATE_CODE_CHECK: \"false\""
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "npm test"
|
||||
assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "npx playwright test"
|
||||
|
||||
echo "OK: Code Check badges are published to the badges branch"
|
||||
|
||||
144
test/update_code_check_badges_package_coverage_test.sh
Normal file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
WORK_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK_DIR"' EXIT
|
||||
|
||||
mkdir -p "$WORK_DIR/docs/badges"
|
||||
mkdir -p "$WORK_DIR/badge-artifacts/userfront/reports"
|
||||
mkdir -p "$WORK_DIR/badge-artifacts/adminfront/reports"
|
||||
mkdir -p "$WORK_DIR/badge-artifacts/orgfront/reports"
|
||||
|
||||
cat > "$WORK_DIR/docs/badges/badges.json" <<'JSON'
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generatedBy": "scripts/update_code_check_badges.mjs",
|
||||
"updatedAt": "2026-01-01T00:00:00.000Z",
|
||||
"source": {
|
||||
"branch": "dev",
|
||||
"sha": "abc123456789",
|
||||
"shortSha": "abc123456789",
|
||||
"runId": "1",
|
||||
"runNumber": "1"
|
||||
},
|
||||
"badges": {
|
||||
"userfront": {
|
||||
"label": "userfront",
|
||||
"message": "unknown",
|
||||
"color": "#6e7781"
|
||||
},
|
||||
"adminfront": {
|
||||
"label": "adminfront",
|
||||
"message": "10.00%",
|
||||
"color": "#cf222e"
|
||||
},
|
||||
"devfront": {
|
||||
"label": "devfront",
|
||||
"message": "20.00%",
|
||||
"color": "#cf222e"
|
||||
},
|
||||
"orgfront": {
|
||||
"label": "orgfront",
|
||||
"message": "30.00%",
|
||||
"color": "#cf222e"
|
||||
}
|
||||
}
|
||||
}
|
||||
JSON
|
||||
|
||||
cat > "$WORK_DIR/badge-artifacts/userfront/reports/vitest-coverage-summary.json" <<'JSON'
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"package": "userfront",
|
||||
"statements": 85.4
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
cat > "$WORK_DIR/badge-artifacts/adminfront/reports/vitest-coverage-summary.json" <<'JSON'
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"package": "adminfront",
|
||||
"statements": 82.345
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
cat > "$WORK_DIR/badge-artifacts/orgfront/reports/vitest-coverage-summary.json" <<'JSON'
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"package": "orgfront",
|
||||
"statements": 36.1
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
run_badge_update() {
|
||||
(
|
||||
cd "$WORK_DIR"
|
||||
LINT_RESULT=success \
|
||||
BIOME_RESULT=success \
|
||||
BACKEND_RESULT=success \
|
||||
USERFRONT_RESULT=success \
|
||||
USERFRONT_E2E_RESULT=success \
|
||||
USERFRONT_E2E_CHROMIUM_DESKTOP_RESULT=success \
|
||||
USERFRONT_E2E_CHROMIUM_MOBILE_RESULT=failure \
|
||||
USERFRONT_E2E_FIREFOX_DESKTOP_RESULT=success \
|
||||
USERFRONT_E2E_FIREFOX_MOBILE_RESULT=skipped \
|
||||
USERFRONT_E2E_WEBKIT_DESKTOP_RESULT=failure \
|
||||
USERFRONT_E2E_WEBKIT_MOBILE_RESULT=success \
|
||||
ADMINFRONT_RESULT=success \
|
||||
DEVFRONT_RESULT=success \
|
||||
ORGFRONT_RESULT=success \
|
||||
USERFRONT_COVERAGE_RESULT=success \
|
||||
ADMINFRONT_COVERAGE_RESULT=success \
|
||||
DEVFRONT_COVERAGE_RESULT=failure \
|
||||
ORGFRONT_COVERAGE_RESULT=success \
|
||||
BADGE_SOURCE_BRANCH=dev \
|
||||
BADGE_SOURCE_SHA=abc123456789 \
|
||||
GITHUB_RUN_ID=2 \
|
||||
GITHUB_RUN_NUMBER=2 \
|
||||
node "$ROOT_DIR/scripts/update_code_check_badges.mjs"
|
||||
)
|
||||
}
|
||||
|
||||
run_badge_update
|
||||
|
||||
node - "$WORK_DIR/docs/badges/badges.json" <<'NODE'
|
||||
const fs = require("node:fs");
|
||||
|
||||
const manifest = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
||||
const badges = manifest.badges;
|
||||
|
||||
function assertEqual(actual, expected, message) {
|
||||
if (actual !== expected) {
|
||||
throw new Error(`${message}: expected ${expected}, got ${actual}`);
|
||||
}
|
||||
}
|
||||
|
||||
assertEqual(badges["backend-tests"].label, "backend", "backend badge label must be compact");
|
||||
assertEqual(badges["backend-tests"].message, "pass", "backend test badge must use backend job result");
|
||||
assertEqual(badges.userfront.message, "pass | 85.40%", "userfront badge must combine fast E2E result and coverage");
|
||||
assertEqual(badges.adminfront.message, "pass | 82.34%", "adminfront badge must combine E2E result and coverage");
|
||||
assertEqual(badges.devfront.message, "pass | fail", "devfront badge must fail coverage independently");
|
||||
assertEqual(badges.orgfront.message, "pass | 36.10%", "orgfront badge must combine E2E result and coverage");
|
||||
assertEqual(badges["userfront-chrome"].label, "chrome", "chromium full badge label must name the browser");
|
||||
assertEqual(badges["userfront-chrome"].message, "pass | fail", "chromium full badge must show desktop and mobile results");
|
||||
assertEqual(badges["userfront-firefox"].label, "firefox", "firefox full badge label must name the browser");
|
||||
assertEqual(badges["userfront-firefox"].message, "pass | skip", "firefox full badge must show desktop and mobile results");
|
||||
assertEqual(badges["userfront-safari"].label, "safari", "webkit full badge label must be shown as safari");
|
||||
assertEqual(badges["userfront-safari"].message, "fail | pass", "webkit full badge must show desktop and mobile results");
|
||||
NODE
|
||||
|
||||
cp "$WORK_DIR/docs/badges/badges.json" "$WORK_DIR/first-badges.json"
|
||||
run_badge_update
|
||||
cmp "$WORK_DIR/first-badges.json" "$WORK_DIR/docs/badges/badges.json"
|
||||
|
||||
echo "OK: package coverage badges update independently and avoid rerun churn"
|
||||