mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
Pipeline audit follow-up: reduce wasted runner time on PRs and tighten CI security, without reducing what actually gets validated. Runner-time waste: - Concurrency with PR-only cancel-in-progress on CI, E2E, and docker-build, so a new push cancels the previous commit's still-running checks. Non-PR runs use the unique run_id as the group, because GitHub keeps at most one pending run per group even with cancel-in-progress: false — a shared ref group could silently drop a queued master run. - paths-ignore for docs-only changes (Markdown, docs/, .plans/, .codex/, .claude/) on the Electron build matrix and the E2E suites; E2E also skips apps/website/**. The build workflow keeps apps/website/** because its Linux job builds the website to verify AppStream assets. Tag pushes are unaffected: GitHub does not evaluate paths filters for tags. - PRs lint affected projects only; master pushes keep the full run-many. Lint-global inputs (eslint.config.mjs, tools/eslint/**) now mark all 41 lint projects affected, including the run-commands targets database and packaging, so the max-lines baseline cannot be widened without lint. Hardening: - Explicit least-privilege permissions on CI, E2E, and build-and-make; the create-release job keeps its job-level contents: write. The repository default workflow token was switched to read-only. - New actionlint job (image pinned by digest, shellcheck at warning+), with the shared-anchor false positive suppressed in .github/actionlint.yaml. Fixed one real finding: unquoted $GITHUB_OUTPUT. - .github/dependabot.yml: weekly cadence, minor+patch grouped per ecosystem (npm, GitHub Actions, Docker), majors stay individual PRs. Docs updated: CLAUDE.md, docs/architecture/nx-workspace-boundaries.md, and docs/architecture/validation-map.md now describe affected-lint on PRs and the E2E path-filter exceptions.
145 lines
4.8 KiB
YAML
145 lines
4.8 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- master
|
|
pull_request:
|
|
branches:
|
|
- master
|
|
workflow_dispatch:
|
|
|
|
# Superseded PR pushes cancel their still-running checks. Non-PR runs get a
|
|
# unique group (run_id) because GitHub keeps at most one pending run per
|
|
# group even with cancel-in-progress: false — a shared ref group would let a
|
|
# rapid master push silently replace a queued sibling and leave a merged
|
|
# commit without a lint/test record.
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
|
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
actionlint:
|
|
name: Workflow lint
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
# Image pinned by digest (tag 1.7.12). False positives are
|
|
# suppressed in .github/actionlint.yaml; shellcheck runs at
|
|
# warning+ severity so style/info notes in long release scripts
|
|
# don't fail CI while real quoting/logic bugs still do.
|
|
- name: Run actionlint
|
|
uses: docker://rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667
|
|
with:
|
|
args: -color
|
|
env:
|
|
SHELLCHECK_OPTS: --severity=warning
|
|
|
|
lint:
|
|
name: Lint
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
# nx affected needs the merge-base with the PR target branch.
|
|
fetch-depth: 0
|
|
|
|
- name: Install pnpm
|
|
uses: pnpm/action-setup@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
cache: 'pnpm'
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
# PRs lint only affected projects for faster feedback; root config
|
|
# or lockfile changes make every project affected, so the
|
|
# module-boundary and max-lines rules cannot be dodged this way.
|
|
- name: Lint affected projects (PR)
|
|
if: github.event_name == 'pull_request'
|
|
run: pnpm nx affected --target=lint --base=origin/${{ github.base_ref }} --head=HEAD --parallel=3 --output-style=static
|
|
env:
|
|
CI: true
|
|
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: false
|
|
|
|
- name: Lint all projects (master)
|
|
if: github.event_name != 'pull_request'
|
|
run: pnpm nx run-many --target=lint --all --parallel=3 --output-style=static
|
|
env:
|
|
CI: true
|
|
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: false
|
|
|
|
unit-and-typecheck:
|
|
name: Unit Tests and Typechecks
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 45
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install pnpm
|
|
uses: pnpm/action-setup@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
cache: 'pnpm'
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Typecheck web and Electron entry points
|
|
run: pnpm run typecheck:ci
|
|
|
|
- name: Check i18n drift
|
|
run: pnpm run i18n:check
|
|
|
|
- name: Run Tier A unit coverage suite
|
|
run: pnpm run coverage:ci
|
|
env:
|
|
CI: true
|
|
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: false
|
|
|
|
- name: Run Tier B/C validation commands
|
|
run: node tools/coverage/check-coverage-policy.mjs --run-non-tier-a
|
|
env:
|
|
CI: true
|
|
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: false
|
|
|
|
- name: Upload unit coverage artifact
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: unit-coverage
|
|
path: |
|
|
coverage/merged/
|
|
retention-days: 14
|
|
|
|
- name: Upload unit coverage to Codecov
|
|
if: always()
|
|
uses: codecov/codecov-action@v6
|
|
with:
|
|
files: ./coverage/merged/lcov.info,./coverage/merged/cobertura-coverage.xml
|
|
flags: unit
|
|
name: iptvnator-unit
|
|
fail_ci_if_error: false
|
|
handle_no_reports_found: true
|
|
disable_search: true
|
|
token: ${{ secrets.CODECOV_TOKEN }}
|