name: Architecture contracts on: pull_request: push: branches: [main] merge_group: workflow_dispatch: permissions: contents: read concurrency: group: architecture-${{ github.ref }} cancel-in-progress: true jobs: architecture-contracts: name: architecture-contracts runs-on: ubuntu-24.04 timeout-minutes: 15 env: PYTHONUTF8: "1" PYTHONDONTWRITEBYTECODE: "1" steps: - uses: actions/checkout@v4 with: fetch-depth: 0 persist-credentials: false - uses: actions/setup-python@v5 with: python-version: "3.13" - name: Test the guardrails themselves run: >- python3 -m unittest scripts.tests.test_architecture_budgets scripts.tests.test_architecture_dependencies scripts.tests.test_architecture_governance scripts.tests.test_prohibited_names - name: Check prohibited product names in the new range env: PROHIBITED_NAMES_BASE: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }} PROHIBITED_NAMES_HEAD: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha || github.sha }} run: | set -euo pipefail base="$PROHIBITED_NAMES_BASE" head="$PROHIBITED_NAMES_HEAD" # The first push has no before SHA. Derive its known parent when one # exists; an unresolved/zero base must still fail closed in the checker. if [[ -z "$base" || "$base" =~ ^0+$ ]]; then base="$(git rev-parse "${head}^" 2>/dev/null || true)" fi if [[ -z "$base" || "$base" =~ ^0+$ || -z "$head" || "$head" =~ ^0+$ ]]; then echo "::error::Cannot determine a non-zero base/head for prohibited-name range" >&2 exit 1 fi python3 scripts/check_prohibited_names.py range \ --base "$base" \ --head "$head" - name: Check source size and dependency direction env: ARCHITECTURE_BASE: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }} run: | arguments=() if [[ -n "$ARCHITECTURE_BASE" && ! "$ARCHITECTURE_BASE" =~ ^0+$ ]]; then arguments+=(--base "$ARCHITECTURE_BASE") fi python3 scripts/check_architecture.py "${arguments[@]}" - uses: dtolnay/rust-toolchain@stable with: toolchain: "1.97.1" - name: Test shared settings without the UI dependency graph run: | mkdir -p "$RUNNER_TEMP/pebrel-contracts" rustc --test --edition 2024 --crate-name nebula_settings \ nebula_settings/src/lib.rs -o "$RUNNER_TEMP/pebrel-contracts/settings" "$RUNNER_TEMP/pebrel-contracts/settings" - name: Test the Rust line-budget adapter env: CARGO_MANIFEST_DIR: ${{ github.workspace }}/nebula_app run: | rustc --test --edition 2024 nebula_app/tests/file_line_budget.rs \ -o "$RUNNER_TEMP/pebrel-contracts/line-budget" "$RUNNER_TEMP/pebrel-contracts/line-budget" - name: Test renderer-independent translation and allocation contracts env: CARGO_TARGET_DIR: ${{ runner.temp }}/pebrel-i18n-contract run: cargo test --manifest-path tools/i18n-contract/Cargo.toml --locked - name: Test branding and image compatibility run: >- python3 -m unittest scripts.tests.test_pebrel_branding scripts.tests.test_windows_resources scripts.tests.test_app_icons scripts.tests.test_ai_session_probe