diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..79ef30b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +# Default PR / main CI: full `make test` (not selfhost fixed-point — see selfhost-loop.yml). +name: ci + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: make test + runs-on: ubuntu-latest + timeout-minutes: 90 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Nim + uses: jiro4989/setup-nim-action@v2 + with: + nim-version: "2.0.x" + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install build deps + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + gcc make binutils libssl-dev python3 + + - name: Bootstrap + full test suite + env: + # Ensure registry / selfhost smokes see a clean env + BUX_NO_LINE: "" + run: | + unset BUX_DEBUG_FILE || true + unset BUX_SELFHOST_FIXED_POINT || true + make test + + - name: Upload selfhost artifacts on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: ci-failure-logs + path: | + build/selfhost/build/main.c + _test_tmp_pkg/** + if-no-files-found: ignore diff --git a/.github/workflows/selfhost-loop.yml b/.github/workflows/selfhost-loop.yml index 535a888..2e3441e 100644 --- a/.github/workflows/selfhost-loop.yml +++ b/.github/workflows/selfhost-loop.yml @@ -1,13 +1,13 @@ # Optional / not on every PR: bootstrap selfhost determinism (make selfhost-loop). -# Triggers: manual, weekly, or push to main that touches compiler/stdlib/loop. -# Fixed-point buxc2→buxc3 is opt-in via BUX_SELFHOST_FIXED_POINT=1 (experimental). +# Default PR CI is .github/workflows/ci.yml (`make test`). +# Fixed-point gen2 vs gen3: BUX_SELFHOST_FIXED_POINT=1 (workflow_dispatch input). name: selfhost-loop on: workflow_dispatch: inputs: fixed_point: - description: "Also run experimental buxc2→buxc3 fixed-point" + description: "Also run fixed-point buxc2→buxc3→buxc4 (gen2 vs gen3)" type: boolean default: false schedule: diff --git a/README.md b/README.md index d7f7ca2..94b9195 100644 --- a/README.md +++ b/README.md @@ -318,7 +318,7 @@ make test-examples # Golden diagnostic tests (Rust-style error format) make test-errors -# Full unit + example suite +# Full unit + example suite (also run on every PR via GitHub Actions `ci.yml`) make test # Full-tree format check (lib/ examples/ src/ tests/ apps/) diff --git a/docs/BuildAndTest.md b/docs/BuildAndTest.md index 9c429ce..0575038 100644 --- a/docs/BuildAndTest.md +++ b/docs/BuildAndTest.md @@ -189,17 +189,25 @@ summary table and exits: Use `Std::Test` module for assertions inside test code. +### Continuous integration +```bash +make test # what PR CI runs +``` +| Workflow | When | Command | +|----------|------|---------| +| **`.github/workflows/ci.yml`** | every PR + push to `main` | `make test` | +| **`.github/workflows/selfhost-loop.yml`** | weekly / manual / path-filtered main | `make selfhost-loop` | + +`make test` includes examples, goldens, registry, apps, DWARF, and selfhost smoke +(not the slow gen2↔gen3 fixed-point). + ### Selfhost loop (optional CI) ```bash make selfhost-loop # bootstrap builds src/ twice; C+ELF match BUX_SELFHOST_FIXED_POINT=1 make selfhost-loop # buxc2→buxc3→buxc4 fixed-point ``` Fixed-point compares **gen2 vs gen3** (same selfhost C backend), not bootstrap -vs selfhost. Not part of default `make test`. GitHub Actions workflow -`.github/workflows/selfhost-loop.yml` runs the fast determinism check on: -- manual `workflow_dispatch` (optional fixed_point input) -- weekly schedule -- pushes to `main` that touch `src/`, `lib/`, bootstrap, or the loop script +vs selfhost. Not part of default `make test`. ### Format (`bux fmt`) ```bash diff --git a/docs/QUALITY_PLAN.md b/docs/QUALITY_PLAN.md index bba8c3e..62f8fb6 100644 --- a/docs/QUALITY_PLAN.md +++ b/docs/QUALITY_PLAN.md @@ -1,7 +1,7 @@ # Bux — План към „добър“ език (v0.5 → v1.0) > **Дата:** 2026-07-19 -> **Текущо:** v0.5.x — **selfhost fixed-point green**, Expr/Stmt sourceFile, LSP 0.14 +> **Текущо:** v0.5.x — **CI `make test`**, selfhost fixed-point, LSP 0.14 > **Цел:** Език, с който се пишат реални проекти комфортно, безопасно (по избор) и с надежден toolchain. --- @@ -112,7 +112,7 @@ A (stdlib ergonomics) → B (compiler holes) → C (ownership depth) ## Acceptance criteria за „добър v1.0“ -- [ ] Всички examples + selfhost-loop + 3 apps минават на CI (apps: `make test-apps` ready) +- [x] Всички examples + apps + selfhost smoke на CI (`make test` via `.github/workflows/ci.yml`); selfhost-loop optional - [ ] Array/Map/String/Test API покрива 90% от ежедневните нужди - [x] `@[Checked]` хваща use-after-move + double `&mut` + dangling return / elision fail - [x] `bux test` + `bux fmt` + `bux check` са default developer loop (`--filter` / `--check` shipped) @@ -826,9 +826,21 @@ A (stdlib ergonomics) → B (compiler holes) → C (ownership depth) --- +## Сесия 53 (main CI workflow — `make test`) + +1. **`.github/workflows/ci.yml`** + - triggers: `pull_request`, `push` to `main`, `workflow_dispatch` + - job: install Nim 2.0.x + gcc/make/ssl → **`make test`** + - timeout 90m; concurrency cancel-in-progress + - failure artifact: selfhost `main.c` (best-effort) +2. **selfhost-loop.yml** remains optional (not on every PR) +3. Docs: README / BuildAndTest / QUALITY_PLAN point to ci vs selfhost-loop + +--- + ## Следващи стъпки -1. Main PR CI workflow (`make test`) beyond optional selfhost-loop -2. LSP type hierarchy / prepareTypeHierarchy (optional) -3. Macro / quote hygiene using Expr.sourceFile grafts -4. Parenthesize binary ops in CBE for full C precedence safety +1. LSP type hierarchy / prepareTypeHierarchy (optional) +2. Macro / quote hygiene using Expr.sourceFile grafts +3. Parenthesize binary ops in CBE for full C precedence safety +4. CI matrix (macOS) or split jobs for faster PR feedback diff --git a/src/hir_lower.bux b/src/hir_lower.bux index bf7dffd..3b75965 100644 --- a/src/hir_lower.bux +++ b/src/hir_lower.bux @@ -4134,7 +4134,7 @@ module HirLower { var tn: String = ftype.typeName; if ftype.typeArgCount >= 1 && !String_Eq(ftype.typeArgName0, "") { if String_Eq(tn, "Array") || String_Eq(tn, "Set") || - String_Eq(tn, "Channel") || String_Eq(tn, "Iter") { + String_Eq(tn, "Channel") || String_Eq(tn, "Iter") { tn = String_Concat(String_Concat(tn, "_"), ftype.typeArgName0); } else if String_Eq(tn, "Map") && ftype.typeArgCount >= 2 { tn = String_Concat(String_Concat(String_Concat("Map_", ftype.typeArgName0), "_"), ftype.typeArgName1);