mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-08 01:43:55 +00:00
da94599411
release-please stores the release notes in the Release PR body when it opens that PR, and builds the GitHub Release from that stored body at merge time. The contributor credit step runs afterwards and only rewrites CHANGELOG.md on the branch, so credits reached the changelog but never the published notes. Everything that reads release bodies, including the releases page and the website changelog, showed uncredited text. Add a step that re-publishes the notes from CHANGELOG.md after a release is created. The two are otherwise byte-identical, so the edit is a no-op when there is nothing to credit. It runs before the credit step on purpose: a single run can both publish a release and open the next Release PR, and the credit step checks out that new branch, which would leave the wrong CHANGELOG.md in the working tree.
257 lines
9.3 KiB
YAML
257 lines
9.3 KiB
YAML
name: Sencho CI
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
# Cancel previous runs on the same branch/PR
|
|
concurrency:
|
|
group: ci-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
# Least-privilege default for every job.
|
|
permissions:
|
|
contents: read
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Build & Validation (PRs only, skipped for release-please PRs)
|
|
# ---------------------------------------------------------------------------
|
|
jobs:
|
|
backend:
|
|
name: Backend (Build, Test, Lint)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
# Skip on the release-please bot PR. It only touches version metadata,
|
|
# so the full build+test+lint+audit stack is pure action-minute waste.
|
|
if: >-
|
|
github.event_name == 'pull_request'
|
|
&& github.head_ref != 'release-please--branches--main--components--sencho'
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
|
with:
|
|
node-version-file: '.node-version'
|
|
cache: 'npm'
|
|
cache-dependency-path: backend/package-lock.json
|
|
|
|
- name: Install Dependencies
|
|
working-directory: ./backend
|
|
run: npm ci
|
|
|
|
- name: Build (TypeScript)
|
|
working-directory: ./backend
|
|
run: npm run build
|
|
|
|
- name: Unit Tests (Vitest)
|
|
working-directory: ./backend
|
|
run: npm test
|
|
|
|
- name: Docker integration tests (dedicated Vitest config)
|
|
working-directory: ./backend
|
|
run: npm run test:docker-integration
|
|
|
|
- name: Lint (ESLint)
|
|
working-directory: ./backend
|
|
run: npm run lint
|
|
|
|
- name: Audit Dependencies
|
|
working-directory: ./backend
|
|
run: npm audit --audit-level=high
|
|
|
|
# Hand the freshly-verified dist/ to the E2E job so it does not have to
|
|
# re-run `tsc` on the same source. retention-days is the minimum; this
|
|
# artifact is only needed for the downstream e2e job in the same run.
|
|
- name: Upload backend dist
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: backend-dist
|
|
path: backend/dist
|
|
retention-days: 1
|
|
if-no-files-found: error
|
|
|
|
frontend:
|
|
name: Frontend (Build, Lint)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
# See backend job rationale: skip bot PRs that cannot affect the frontend.
|
|
if: >-
|
|
github.event_name == 'pull_request'
|
|
&& github.head_ref != 'release-please--branches--main--components--sencho'
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
|
with:
|
|
node-version-file: '.node-version'
|
|
cache: 'npm'
|
|
cache-dependency-path: frontend/package-lock.json
|
|
|
|
- name: Install Dependencies
|
|
working-directory: ./frontend
|
|
run: npm ci
|
|
|
|
- name: Build (Vite/React)
|
|
working-directory: ./frontend
|
|
run: npm run build
|
|
|
|
- name: Unit Tests (Vitest)
|
|
working-directory: ./frontend
|
|
run: npm test
|
|
|
|
- name: Lint (ESLint)
|
|
working-directory: ./frontend
|
|
run: npm run lint
|
|
|
|
- name: Audit Dependencies
|
|
working-directory: ./frontend
|
|
run: npm audit --audit-level=high
|
|
|
|
docker-validate:
|
|
name: Docker Build & Scan
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
# See backend job rationale.
|
|
if: >-
|
|
github.event_name == 'pull_request'
|
|
&& github.head_ref != 'release-please--branches--main--components--sencho'
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
|
|
|
|
# Computed once per job run. Feeds Dockerfile's APK_CACHE_BUST arg so
|
|
# the `apk upgrade` layer rebuilds at least once per calendar day, even
|
|
# when every other input to the layer is cached. See Dockerfile:115-122
|
|
# for the rationale.
|
|
- name: Compute daily apk cache bust value
|
|
id: apk-bust
|
|
run: echo "date=$(date -u +%Y-%m-%d)" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Build Docker image (validation only)
|
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
|
with:
|
|
context: .
|
|
push: false
|
|
load: true
|
|
tags: sencho:pr-test
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
build-args: |
|
|
APK_CACHE_BUST=${{ steps.apk-bust.outputs.date }}
|
|
|
|
- name: Scan image for vulnerabilities (Trivy)
|
|
# Hard-fails the PR on any HIGH or CRITICAL finding not suppressed by
|
|
# the OpenVEX document at security/vex/sencho.openvex.json (loaded via
|
|
# trivy.yaml). The VEX document is the canonical triage record and is
|
|
# also attached as a cosign attestation on the published image.
|
|
# If a new CVE must be triaged, add a VEX statement with a
|
|
# justification — do NOT recreate .trivyignore.
|
|
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
|
with:
|
|
image-ref: sencho:pr-test
|
|
exit-code: '1'
|
|
severity: 'CRITICAL,HIGH'
|
|
format: 'table'
|
|
trivy-config: trivy.yaml
|
|
|
|
# Mirror of the release-time pre-publish smoke gate in docker-publish.yml.
|
|
# Catches the class of failure where the source-built Docker CLI or
|
|
# Compose plugin compiles cleanly but does not exec at runtime (e.g. -o
|
|
# pointed at a non-main Go package, ABI breakage in a base image bump).
|
|
# The release workflow additionally polls /api/health; PR CI keeps just
|
|
# the binary check to bound job duration without losing the gate.
|
|
- name: Smoke test built image (binaries)
|
|
run: |
|
|
set -euo pipefail
|
|
docker run --rm --entrypoint sh sencho:pr-test -c \
|
|
'docker --version && docker compose version'
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# E2E Tests (PRs only, skipped for release-please PRs)
|
|
# ---------------------------------------------------------------------------
|
|
e2e:
|
|
name: E2E Tests (Playwright)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
needs: [backend, frontend]
|
|
# See backend job rationale.
|
|
if: >-
|
|
github.event_name == 'pull_request'
|
|
&& github.head_ref != 'release-please--branches--main--components--sencho'
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
# Reuse the dist/ that the `backend` job produced and verified, instead
|
|
# of running `tsc` a second time against the same source tree. The
|
|
# composite action's `skip-backend-build` input short-circuits its build
|
|
# step when this artifact is already in place.
|
|
- name: Download backend dist
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: backend-dist
|
|
path: backend/dist
|
|
|
|
- name: Start app & install Playwright
|
|
uses: ./.github/actions/start-app
|
|
with:
|
|
skip-backend-build: 'true'
|
|
|
|
- name: Run E2E tests
|
|
# `--project=chromium` is explicit because playwright.config.ts also
|
|
# defines a `screenshots` project that captures docs/images/ for
|
|
# manual review. That project must not run in CI: its output would
|
|
# be discarded after the run, wasting minutes per PR. Keep this
|
|
# flag; do not "simplify" back to `npx playwright test`.
|
|
run: npx playwright test --project=chromium
|
|
|
|
- name: Upload E2E report and service logs
|
|
if: failure()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: playwright-report
|
|
path: |
|
|
e2e/report/
|
|
test-results/
|
|
ci-logs/
|
|
retention-days: 7
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Changelog Credit Script (PRs only, skipped for release-please PRs)
|
|
# ---------------------------------------------------------------------------
|
|
changelog-script:
|
|
name: Changelog credit script
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
if: >-
|
|
github.event_name == 'pull_request'
|
|
&& github.head_ref != 'release-please--branches--main--components--sencho'
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
|
with:
|
|
node-version-file: '.node-version'
|
|
|
|
- name: Validate workflows
|
|
uses: docker://rhysd/actionlint@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 # v1.7.12
|
|
with:
|
|
args: .github/workflows/release-please.yml .github/workflows/ci.yml
|
|
|
|
- name: Syntax check
|
|
run: |
|
|
node --check scripts/credit-changelog-contributors.mjs
|
|
node --check scripts/release-notes-from-changelog.mjs
|
|
|
|
- name: Unit tests
|
|
run: |
|
|
node --test scripts/credit-changelog-contributors.test.mjs
|
|
node --test scripts/release-notes-from-changelog.test.mjs
|