Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: CI

on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened]

Expand Down Expand Up @@ -48,5 +51,22 @@ jobs:
- name: Type Check
run: pnpm type:check

- name: Test
run: pnpm test
- name: Test with Coverage
run: pnpm test:coverage

- name: Upload coverage artifact
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-node-${{ matrix.node-version }}-${{ github.run_id }}
path: coverage/coverage-final.json
retention-days: 7

- name: Upload master branch coverage
uses: actions/upload-artifact@v4
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && matrix.node-version == '22'
with:
name: coverage-main
path: coverage/coverage-final.json
retention-days: 30
overwrite: true
126 changes: 126 additions & 0 deletions .github/workflows/coverage-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
name: Coverage Report

on:
workflow_run:
workflows: ["CI"]
types: [completed]

env:
COVERAGE_THRESHOLD: "1.0"

jobs:
coverage:
runs-on: ubuntu-latest
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
permissions:
contents: read
pull-requests: write
actions: read

steps:
# Checkout the default branch (trusted code), NOT the PR head.
# This prevents a malicious PR from modifying scripts/coverage-report.cjs
# to exfiltrate secrets via the pull-requests:write permission.
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "22"

# Pass workflow_run context as environment variables to avoid
# shell injection via attacker-controlled branch names.
- name: Get PR number
id: pr
env:
GH_TOKEN: ${{ github.token }}
HEAD_OWNER: ${{ github.event.workflow_run.head_repository.owner.login }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
FALLBACK_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
run: |
PR_NUMBER=$(gh pr view --repo "${{ github.repository }}" \
"${HEAD_OWNER}:${HEAD_BRANCH}" \
--json 'number' --jq '.number' 2>/dev/null || echo "")

if [ -z "$PR_NUMBER" ]; then
PR_NUMBER="$FALLBACK_PR_NUMBER"
echo "Using fallback PR number from workflow_run"
fi

if [ -z "$PR_NUMBER" ]; then
echo "::error::Could not determine PR number"
exit 1
fi

echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT
echo "Found PR #$PR_NUMBER"

# Download base branch coverage (from latest master push)
- name: Download base coverage
uses: dawidd6/action-download-artifact@v6
continue-on-error: true
with:
workflow: ci.yml
branch: master
name: coverage-main
path: ./base-coverage/

# Download PR branch coverage (Node 22 artifact from the triggering run)
- name: Download PR coverage
uses: dawidd6/action-download-artifact@v6
continue-on-error: true
with:
run_id: ${{ github.event.workflow_run.id }}
name: coverage-node-22-${{ github.event.workflow_run.id }}
path: ./pr-coverage/

- name: Ensure coverage files exist
run: |
mkdir -p base-coverage pr-coverage
[ -f base-coverage/coverage-final.json ] || echo '{}' > base-coverage/coverage-final.json
[ -f pr-coverage/coverage-final.json ] || echo '{}' > pr-coverage/coverage-final.json

# Use the GitHub API to get changed files instead of git-based detection.
# This avoids checking out the PR head (untrusted code).
- name: Get changed files
id: changed
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
run: |
CHANGED=$(gh pr diff "$PR_NUMBER" \
--repo "${{ github.repository }}" \
--name-only 2>/dev/null | paste -sd ',' - || echo "")
echo "files=$CHANGED" >> $GITHUB_OUTPUT

- name: Generate coverage report
id: report
env:
CHANGED_FILES: ${{ steps.changed.outputs.files }}
run: |
node scripts/coverage-report.cjs \
--base base-coverage/coverage-final.json \
--pr pr-coverage/coverage-final.json \
--changed-files "$CHANGED_FILES" \
--threshold ${{ env.COVERAGE_THRESHOLD }} \
--base-path "$(pwd)/" \
--output coverage-report.md
continue-on-error: true

- name: Find existing comment
id: find-comment
uses: peter-evans/find-comment@v3
with:
issue-number: ${{ steps.pr.outputs.number }}
body-includes: "<!-- coverage-report-marker -->"

- name: Post PR comment
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ steps.pr.outputs.number }}
comment-id: ${{ steps.find-comment.outputs.comment-id }}
body-path: coverage-report.md
edit-mode: replace
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules/
dist/
coverage/
.idea/
.DS_Store

Expand Down
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
#
pnpm verify-version
pnpm lint
pnpm test
pnpm test:coverage
Binary file modified app.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.14/schema.json",
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
"files": { "includes": ["**", "!!**/dist"] },
"files": { "includes": ["**", "!!**/dist", "!!**/coverage"] },
"formatter": {
"enabled": true,
"formatWithErrors": false,
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
"name": "write-wall",
"version": "2.5.0",
"version": "2.6.0",
"description": "A simple, sync-able text pad similar to Write Space",
"license": "CC-BY-SA-4.0",
"private": true,
"type": "module",
"scripts": {
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:coverage:summary": "vitest run --coverage --coverage.reporter=text-summary",
"lint": "biome check --diagnostic-level=error",
"lint:fix": "biome check --write --diagnostic-level=error",
"develop": "vite build --watch",
Expand All @@ -25,6 +27,7 @@
"@biomejs/biome": "2.3.14",
"@testing-library/user-event": "^14.6.1",
"@types/chrome": "^0.1.36",
"@vitest/coverage-v8": "^4.0.18",
"adm-zip": "^0.5.16",
"corepack": "^0.34.6",
"globals": "^17.3.0",
Expand Down
Loading