Files
projectsend/.github/workflows/tests.yml
T
Workflow config file is invalid. Please check your config file: model.ReadWorkflow: yaml: unmarshal errors: line 66: mapping key "concurrency" already defined at line 49
ignacionelson c05927c190 Let a newer push cancel the test run it supersedes
The linter has had this since it was written; the suite, which is the
expensive one, never got it. Two pushes landing together ran two full
suites to the end, and the earlier one was checking a subset of what the
later one checks.

Keyed on the ref, so main and a branch never cancel each other, and a
branch with an open pull request does not fight itself — push and
pull_request arrive under two different refs.

One consequence worth stating rather than discovering: on main an
intermediate commit can end up with no run of its own when two pushes
land close together. That is the right trade when what is being verified
is the state of the branch, but it is not free — a bisect or a release
audit that needs a particular commit's own green tick needs that commit
pushed on its own.
2026-08-27 01:50:09 -03:00

161 lines
5.8 KiB
YAML

name: tests
on:
push:
branches:
- develop
- main
paths-ignore:
# Files no code reads and no test covers. Deliberately NOT listed:
# CHANGELOG.md, which ReleaseNotes parses and ReleaseNotesTest
# covers, and docs/, whose only two tracked files are served by
# ApiDocsController and OpenApiController. A malformed edit to
# either is exactly the thing that must not skip the suite.
#
# Repeated verbatim under pull_request: GitHub Actions does not
# support YAML anchors.
- 'README.md'
- 'CONTRIBUTING.md'
- 'SECURITY.md'
- 'LICENSING.md'
- 'CLA-ENTITY.md'
- 'CLA-INDIVIDUAL.md'
- 'INSTALL.md'
- 'UPDATE.md'
- 'DOCKER.md'
- 'MIGRATING-FROM-V1.md'
- 'docker/production/dockerhub-overview.md'
- '.github/screenshots/**'
pull_request:
branches:
- develop
- main
paths-ignore:
- 'README.md'
- 'CONTRIBUTING.md'
- 'SECURITY.md'
- 'LICENSING.md'
- 'CLA-ENTITY.md'
- 'CLA-INDIVIDUAL.md'
- 'INSTALL.md'
- 'UPDATE.md'
- 'DOCKER.md'
- 'MIGRATING-FROM-V1.md'
- 'docker/production/dockerhub-overview.md'
- '.github/screenshots/**'
# A second push supersedes the first: there is no value in finishing a run
# for a commit nobody will look at again.
concurrency:
group: tests-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# A second push supersedes the first — the later run covers a superset of
# what the earlier one was checking, so finishing both buys nothing and
# costs a runner.
#
# Keyed on the ref, so `main` and a branch never cancel each other. A push
# to a branch that also has a pull request open produces two events with
# two different refs, which is why they do not fight either.
#
# The tradeoff worth naming: on `main` this means an intermediate commit
# can end up with no run of its own when two pushes land together. That is
# accepted here — what is being verified is the state of the branch, and
# the run that survives is the one that includes both commits. If a commit
# ever needs its own green tick (a bisect, a release audit), push it alone.
concurrency:
group: tests-${{ github.ref }}
cancel-in-progress: true
jobs:
ci:
runs-on: ubuntu-latest
# This job has no MySQL/db service — it's SQLite-only (see
# phpunit.xml) — but .env.example's DB_CONNECTION=mysql/DB_HOST=db is
# for the local docker-compose stack. Bare artisan calls that run
# outside phpunit.xml's env (composer's package:discover,
# key:generate) would otherwise try to reach a "db" host that
# doesn't exist here. Same story for CACHE_STORE: every process
# boot reads a mail-config cache entry (PlatformServiceProvider::
# boot() -> MailConfigApplier::apply()), which needs a store that
# works without a migrated schema this early.
env:
CACHE_STORE: array
DB_CONNECTION: sqlite
# config/database.php's sqlite connection reuses DB_DATABASE for
# the file path — .env.example's DB_DATABASE=projectsend (the
# MySQL database name) would otherwise make sqlite look for a
# file literally named "projectsend".
DB_DATABASE: database/database.sqlite
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.4
tools: composer:v2
coverage: xdebug
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
# community-modules is the community edition's companion package,
# resolved from its public GitHub repository (the vcs entry in
# composer.json). A plain clone installs it with no local packages/
# checkout — cloud-modules is not required at all. COMPOSER_AUTH just
# hands composer the runner's token so the GitHub API calls it makes
# to fetch the package are not subject to the anonymous rate limit.
# composer install's post-autoload-dump script boots the app
# (package:discover), which needs the sqlite file to already exist
# even before .env is copied — config/database.php defaults to it.
- name: Create SQLite Database
run: touch database/database.sqlite
- name: Install PHP Dependencies
env:
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GITHUB_TOKEN }}"}}'
run: composer install --no-interaction --prefer-dist --optimize-autoloader
- name: Install Node Dependencies
run: npm ci
# tsconfig.json maps the "ziggy-js" import to vendor/tightenco/ziggy,
# so this needs PHP deps installed first.
- name: Typecheck Frontend
run: npm run types
- name: Build Assets
run: npm run build
- name: Copy Environment File
run: cp .env.example .env
- name: Generate Application Key
run: php artisan key:generate
- name: Static Analysis
run: ./vendor/bin/phpstan analyse --no-progress
# `--parallel` rather than a shorter suite. One process took 191s of
# this job's 4m30s; the same 1763 tests across the runner's cores
# take about a third of that, with nothing skipped. paratest is
# already a dev dependency (via Pest), so this needs no new install.
#
# `:memory:` explicitly: parallel testing gives each process its own
# database, and an in-memory one per process is what the suite is
# verified against locally. The job-level DB_DATABASE above is a file
# path, which parallel workers would have to create and migrate
# individually — a difference in behaviour with nothing to gain.
- name: Tests
run: ./vendor/bin/pest --parallel
env:
DB_DATABASE: ':memory:'