Skip to content

fix: remove shouldUnregister bug + CI pipeline restructure #350

fix: remove shouldUnregister bug + CI pipeline restructure

fix: remove shouldUnregister bug + CI pipeline restructure #350

Workflow file for this run

name: CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:
permissions:
contents: read
pull-requests: read
# Cancel in-progress runs for the same PR/branch when a new commit arrives.
# Pushes to `main` are allowed to run to completion so we don't lose history.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
DOTNET_VERSION: '10.0.x'
CONFIGURATION: Release
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
changes:
name: Detect changes
runs-on: ubuntu-latest
outputs:
code: ${{ steps.filter.outputs.code }}
frontend: ${{ steps.filter.outputs.frontend }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Filter paths
uses: dorny/paths-filter@v3
id: filter
with:
# The `code` filter is true when any file relevant to building or testing
# the .NET solution has changed; the `frontend` filter is true when the
# client/ SPA workspace changes. Doc-only PRs (e.g. README, docs/**, *.md,
# LICENSE, CODE_OF_CONDUCT) match neither, and the build/test/frontend jobs
# are skipped — the final `ci` aggregator job then succeeds so branch
# protection still passes. A change to this workflow file trips both filters
# so the full suite re-validates when CI itself changes.
filters: |
code:
- 'src/**'
- 'tests/**'
- '**/*.csproj'
- '**/*.slnx'
- '**/*.sln'
- 'Directory.Build.props'
- 'Directory.Packages.props'
- 'global.json'
- 'nuget.config'
- '.editorconfig'
- '.github/workflows/ci.yml'
frontend:
- 'client/**'
- '.github/workflows/ci.yml'
build:
name: Build
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
run: dotnet restore CritterBids.slnx
- name: Build
run: dotnet build CritterBids.slnx --no-restore --configuration ${{ env.CONFIGURATION }}
- name: Publish API
run: dotnet publish src/CritterBids.Api/CritterBids.Api.csproj --no-build --configuration ${{ env.CONFIGURATION }} --output ./publish
- name: Upload API artifact
uses: actions/upload-artifact@v4
with:
name: critterbids-api
path: ./publish
retention-days: 5
integration-tests:
name: Integration — ${{ matrix.name }}
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- name: Contracts
project: tests/CritterBids.Contracts.Tests/CritterBids.Contracts.Tests.csproj
trx: contracts-tests.trx
- name: Api
project: tests/CritterBids.Api.Tests/CritterBids.Api.Tests.csproj
trx: api-tests.trx
- name: Participants
project: tests/CritterBids.Participants.Tests/CritterBids.Participants.Tests.csproj
trx: participants-tests.trx
- name: Selling
project: tests/CritterBids.Selling.Tests/CritterBids.Selling.Tests.csproj
trx: selling-tests.trx
- name: Auctions
project: tests/CritterBids.Auctions.Tests/CritterBids.Auctions.Tests.csproj
trx: auctions-tests.trx
- name: Listings
project: tests/CritterBids.Listings.Tests/CritterBids.Listings.Tests.csproj
trx: listings-tests.trx
- name: Settlement
project: tests/CritterBids.Settlement.Tests/CritterBids.Settlement.Tests.csproj
trx: settlement-tests.trx
- name: Obligations
project: tests/CritterBids.Obligations.Tests/CritterBids.Obligations.Tests.csproj
trx: obligations-tests.trx
- name: Relay
project: tests/CritterBids.Relay.Tests/CritterBids.Relay.Tests.csproj
trx: relay-tests.trx
- name: Operations
project: tests/CritterBids.Operations.Tests/CritterBids.Operations.Tests.csproj
trx: operations-tests.trx
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
run: dotnet restore CritterBids.slnx
- name: Build
run: dotnet build CritterBids.slnx --no-restore --configuration ${{ env.CONFIGURATION }}
- name: Test — ${{ matrix.name }}
run: >
dotnet test ${{ matrix.project }}
--no-build --configuration ${{ env.CONFIGURATION }}
--verbosity normal
--logger "trx;LogFileName=${{ matrix.trx }}"
--results-directory ./test-results
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: integration-test-results-${{ matrix.name }}
path: ./test-results
retention-days: 5
frontend:
name: Frontend
needs: changes
if: needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-latest
defaults:
run:
working-directory: client
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: client/package-lock.json
- name: Install dependencies
run: npm ci
- name: Typecheck shared (tsc strict)
run: npx tsc --noEmit -p shared/tsconfig.json
- name: Build bidder (tsc strict + vite build)
run: npm run build -w @critterbids/bidder
- name: Test bidder (vitest)
run: npm test -w @critterbids/bidder
- name: Build ops (tsc strict + vite build)
run: npm run build -w @critterbids/ops
- name: Test ops (vitest)
run: npm test -w @critterbids/ops
- name: Build seller (tsc strict + vite build)
run: npm run build -w @critterbids/seller
- name: Test seller (vitest)
run: npm test -w @critterbids/seller
# The Playwright e2e workspace member (client/e2e) is deliberately NOT run here
# (M8-S7 recorded deferral): it needs the full Aspire-orchestrated stack — Postgres,
# RabbitMQ, the API host, and the bidder dev server — live, which is its own piece of
# CI infrastructure work, not a step addition. It runs locally pre-merge; see
# client/e2e/README.md. Its tsconfig still type-checks against the shared strict base.
- name: Typecheck e2e (tsc strict, no run)
run: npm run typecheck -w @critterbids/e2e
# Aggregator job suitable for use as the single required status check in
# branch protection. A dependent job result of `success` or `skipped` is
# acceptable (a job skips when its path filter did not match — e.g. a
# frontend-only PR skips the .NET jobs, a backend-only PR skips Frontend,
# a doc-only PR skips all). The aggregator fails only when a job that
# actually ran reports `failure` or `cancelled`.
ci:
name: CI
needs: [ changes, build, integration-tests, frontend ]
if: always()
runs-on: ubuntu-latest
steps:
- name: Verify required jobs
env:
BUILD_RESULT: ${{ needs.build.result }}
INTEGRATION_RESULT: ${{ needs.integration-tests.result }}
FRONTEND_RESULT: ${{ needs.frontend.result }}
run: |
set -euo pipefail
failed=0
for entry in \
"build:${BUILD_RESULT}" \
"integration-tests:${INTEGRATION_RESULT}" \
"frontend:${FRONTEND_RESULT}"; do
name="${entry%%:*}"
result="${entry##*:}"
# `success` and `skipped` pass; only a job that ran and did not
# succeed (failure/cancelled) blocks the aggregator.
if [ "${result}" = "failure" ] || [ "${result}" = "cancelled" ]; then
echo "::error::Required job '${name}' did not succeed (result: ${result})"
failed=1
fi
done
if [ "${failed}" -ne 0 ]; then
exit 1
fi
echo "All required jobs passed or were skipped."