From f335d230d532587343c49f44e313d398e96bbd12 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Mon, 3 Aug 2026 15:19:16 -0300 Subject: [PATCH] chore(ci): promote draft-aware CI policy and fixtures to main Align blocking CI and ci-matrix with flext-infra SSOT on main: draft PRs skip, integration pushes run ci.yml only, main runs full matrix; Dockerfiles under tests/fixtures/ci/docker. Co-authored-by: Cursor --- .github/workflows/ci-matrix.yml | 116 +++++++++++++++++++++ .github/workflows/ci.yml | 63 ++++++++--- tests/fixtures/ci/docker/alpine.Dockerfile | 52 +++++++++ tests/fixtures/ci/docker/arch.Dockerfile | 54 ++++++++++ tests/fixtures/ci/docker/debian.Dockerfile | 55 ++++++++++ tests/fixtures/ci/docker/fedora.Dockerfile | 54 ++++++++++ tests/fixtures/ci/docker/ubuntu.Dockerfile | 55 ++++++++++ 7 files changed, 432 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/ci-matrix.yml create mode 100644 tests/fixtures/ci/docker/alpine.Dockerfile create mode 100644 tests/fixtures/ci/docker/arch.Dockerfile create mode 100644 tests/fixtures/ci/docker/debian.Dockerfile create mode 100644 tests/fixtures/ci/docker/fedora.Dockerfile create mode 100644 tests/fixtures/ci/docker/ubuntu.Dockerfile diff --git a/.github/workflows/ci-matrix.yml b/.github/workflows/ci-matrix.yml new file mode 100644 index 000000000..8e975ba13 --- /dev/null +++ b/.github/workflows/ci-matrix.yml @@ -0,0 +1,116 @@ +# Generated by `flext_infra codegen conform` for flext-cli. +# === SECTION: header (managed) === +# Source: template (base/.github/workflows/ci-matrix.yml.j2) +# Free: no +# End SECTION: header +# Multi-environment CI base: proves the project bootstrap and canonical Make +# verbs work identically across distros, macOS, and Windows. The CI invokes +# the project's own Make surface; it never reimplements bootstrap. +# Runs only on main (direct push or non-draft PR targeting main). +--- +name: ci-matrix + +# === SECTION: triggers (managed) === +# Source: main promotion only (integration branch uses blocking ci.yml alone) +"on": + push: + branches: [main] + pull_request: + branches: [main] + types: [opened, synchronize, reopened, ready_for_review] + workflow_dispatch: {} +# End SECTION: triggers + +# === SECTION: permissions (managed) === +# Source: template (minimal read-only permissions) +permissions: + contents: read +# End SECTION: permissions + +# === SECTION: concurrency (managed) === +# Source: template (one run per workflow+ref) +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +# End SECTION: concurrency + +jobs: + # === SECTION: distro-matrix (managed) === + # Source: template + config:github_actions.checkout (distro list is template literal by design) + distro-matrix: + # Clean-machine proof per distro: build the distro image (which runs the + # full project bootstrap at image-build time), then smoke the verb surface + # inside the built container. + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + distro: [ubuntu, debian, fedora, alpine, arch] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + submodules: false + - name: Build ${{ matrix.distro }} image + run: >- + docker build + -f tests/fixtures/ci/docker/${{ matrix.distro }}.Dockerfile + -t ci-matrix-${{ matrix.distro }} + . + - name: Bootstrap + verb smoke (${{ matrix.distro }}) + run: | + docker run --rm ci-matrix-${{ matrix.distro }} make help + docker run --rm ci-matrix-${{ matrix.distro }} make check + # End SECTION: distro-matrix + + # === SECTION: macos (managed) === + # Source: template + config:github_actions.checkout/setup-python/mise/setup-uv + macos: + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} + runs-on: macos-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + submodules: false + - name: Setup Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version-file: .python-version + - name: Install mise toolchain + uses: jdx/mise-action@dba19683ed58901619b14f395a24841710cb4925 # v4.1.0 + - name: Install uv + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 + with: + enable-cache: true + - name: Bootstrap + run: make setup + - name: Verb surface + run: make help + # End SECTION: macos + + # === SECTION: windows (managed) === + # Source: template + config:github_actions.checkout/setup-python/mise/setup-uv + windows: + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} + runs-on: windows-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + submodules: false + - name: Setup Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version-file: .python-version + - name: Install mise toolchain + uses: jdx/mise-action@dba19683ed58901619b14f395a24841710cb4925 # v4.1.0 + - name: Install uv + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 + with: + enable-cache: true + - name: Bootstrap + shell: bash + run: make setup + - name: Verb surface + shell: bash + run: make help + # End SECTION: windows diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfa738595..8ac283eff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,44 +1,73 @@ -# Generated by flext_infra.github.workflows - DO NOT EDIT +# Generated by flext_infra codegen for flext-cli — DO NOT EDIT +# === SECTION: header (managed) === +# Source: template (base/.github/workflows/ci.yml.j2) +# Free: no +# End SECTION: header + name: CI -on: - pull_request: +# === SECTION: triggers (managed) === +# Source: operator CI policy — integration push = blocking CI only; +# main push/PR (non-draft) = blocking CI; draft and other branches = none. +"on": push: + branches: + - dev + - develop + - 0.12.0-dev + - main + pull_request: branches: - main - workflow_dispatch: + types: [opened, synchronize, reopened, ready_for_review] +# End SECTION: triggers +# === SECTION: permissions (managed) === +# Source: template (minimal read-only permissions) permissions: contents: read +# End SECTION: permissions jobs: + # === SECTION: ci job (managed) === + # Source: template + config:github_actions.* ci: name: ci + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} runs-on: ubuntu-latest timeout-minutes: 60 + env: + CI: Y steps: - name: Checkout - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - submodules: recursive + submodules: false fetch-depth: 0 - - name: Setup Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 - with: - python-version: "3.13" + - name: Install mise toolchain + uses: jdx/mise-action@dba19683ed58901619b14f395a24841710cb4925 # v4.1.0 - name: Install uv - uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5 - with: - enable-cache: true + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 + - - name: Setup (blocking) + - name: setup (blocking) run: make setup - - name: Check (blocking) + - name: gen (blocking) + run: make gen APPLY=Y + + - name: fmt (blocking) + run: make fmt APPLY=Y + + - name: fix (blocking) + run: make fix APPLY=Y + + - name: check (blocking) run: make check - - name: Test (advisory) - continue-on-error: true + - name: test (blocking) run: make test + + # End SECTION: ci job diff --git a/tests/fixtures/ci/docker/alpine.Dockerfile b/tests/fixtures/ci/docker/alpine.Dockerfile new file mode 100644 index 000000000..f7a3c6c97 --- /dev/null +++ b/tests/fixtures/ci/docker/alpine.Dockerfile @@ -0,0 +1,52 @@ +# Generated by `flext_infra codegen conform` for flext_cli. +# === SECTION: header (managed) === +# Source: template (base/tests/fixtures/ci/docker/alpine.Dockerfile.j2) +# Free: no +# End SECTION: header +# Clean-machine proof: project bootstrap + canonical make verbs on Alpine +# (musl, POSIX /bin/sh at runtime; bash installed for the project scripts). +FROM alpine:3.21 + +# === SECTION: base packages (managed) === +# Source: template (distro-specific package list) +RUN apk add --no-cache \ + bash ca-certificates curl git make build-base icu-dev icu-libs +# End SECTION: base packages + +# === SECTION: managed tool bootstrap (managed) === +# Source: config:python_version, template (installer URLs) +# mise installs the supported Python 3.13 family. +# uv is supplied by the managed environment without a project patch pin. +RUN curl -fsSL https://mise.run | sh +# uv is intentionally supplied by the caller environment; install it explicitly +# in clean-machine images so the project bootstrap can resolve dependencies. +RUN curl -fsSL https://astral.sh/uv/install.sh | sh +# tokei (and any future cargo-backed mise tool) needs a Rust toolchain. +RUN curl -fsSL https://sh.rustup.rs | sh -s -- -y --default-toolchain stable +# go is required for mise-managed beads (go:github.com/steveyegge/beads/cmd/bd). +RUN curl -fsSL https://go.dev/dl/go1.23.4.linux-amd64.tar.gz | tar -C /usr/local -xzf - \ + && ln -sf /usr/local/go/bin/go /usr/local/bin/go +ENV PATH="/usr/local/go/bin:/root/.local/bin:/root/.cargo/bin:/root/.local/share/mise/shims:${PATH}" +# End SECTION: managed tool bootstrap + +WORKDIR /workspace +COPY . . + +# === SECTION: mise install (managed) === +# Source: computed (reads .mise.toml from copied workspace) +RUN mise trust .mise.toml && mise install --yes +# End SECTION: mise install + +# === SECTION: bootstrap proof (managed) === +# Source: template (clean-machine bootstrap through the canonical verb) +# The image exists to PROVE that a clean machine can bootstrap this project +# with nothing but the declared toolchain. It therefore runs the canonical +# setup verb fail-closed: any non-zero status fails the build. An earlier +# revision wrapped this in `set +e` and soft-passed whenever the output +# mentioned uv.lock/flext-core, which turned the proof into a bypass -- a +# broken bootstrap still produced a green image. +RUN make setup +# End SECTION: bootstrap proof + +ENTRYPOINT [] +CMD ["/bin/bash", "-lc", "make help"] diff --git a/tests/fixtures/ci/docker/arch.Dockerfile b/tests/fixtures/ci/docker/arch.Dockerfile new file mode 100644 index 000000000..24abaffd0 --- /dev/null +++ b/tests/fixtures/ci/docker/arch.Dockerfile @@ -0,0 +1,54 @@ +# Generated by `flext_infra codegen conform` for flext_cli. +# === SECTION: header (managed) === +# Source: template (base/tests/fixtures/ci/docker/arch.Dockerfile.j2) +# Free: no +# End SECTION: header +# Clean-machine proof: project bootstrap + canonical make verbs on Arch Linux. +FROM archlinux:base + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +# === SECTION: base packages (managed) === +# Source: template (distro-specific package list) +RUN pacman -Syu --noconfirm --needed \ + bash ca-certificates curl git make base-devel icu \ + && pacman -Scc --noconfirm +# End SECTION: base packages + +# === SECTION: managed tool bootstrap (managed) === +# Source: config:python_version, template (installer URLs) +# mise installs the supported Python 3.13 family. +# uv is supplied by the managed environment without a project patch pin. +RUN curl -fsSL https://mise.run | sh +# uv is intentionally supplied by the caller environment; install it explicitly +# in clean-machine images so the project bootstrap can resolve dependencies. +RUN curl -fsSL https://astral.sh/uv/install.sh | sh +# tokei (and any future cargo-backed mise tool) needs a Rust toolchain. +RUN curl -fsSL https://sh.rustup.rs | sh -s -- -y --default-toolchain stable +# go is required for mise-managed beads (go:github.com/steveyegge/beads/cmd/bd). +RUN curl -fsSL https://go.dev/dl/go1.23.4.linux-amd64.tar.gz | tar -C /usr/local -xzf - \ + && ln -sf /usr/local/go/bin/go /usr/local/bin/go +ENV PATH="/usr/local/go/bin:/root/.local/bin:/root/.cargo/bin:/root/.local/share/mise/shims:${PATH}" +# End SECTION: managed tool bootstrap + +WORKDIR /workspace +COPY . . + +# === SECTION: mise install (managed) === +# Source: computed (reads .mise.toml from copied workspace) +RUN mise trust .mise.toml && mise install --yes +# End SECTION: mise install + +# === SECTION: bootstrap proof (managed) === +# Source: template (clean-machine bootstrap through the canonical verb) +# The image exists to PROVE that a clean machine can bootstrap this project +# with nothing but the declared toolchain. It therefore runs the canonical +# setup verb fail-closed: any non-zero status fails the build. An earlier +# revision wrapped this in `set +e` and soft-passed whenever the output +# mentioned uv.lock/flext-core, which turned the proof into a bypass -- a +# broken bootstrap still produced a green image. +RUN make setup +# End SECTION: bootstrap proof + +ENTRYPOINT [] +CMD ["make", "help"] diff --git a/tests/fixtures/ci/docker/debian.Dockerfile b/tests/fixtures/ci/docker/debian.Dockerfile new file mode 100644 index 000000000..c3db00466 --- /dev/null +++ b/tests/fixtures/ci/docker/debian.Dockerfile @@ -0,0 +1,55 @@ +# Generated by `flext_infra codegen conform` for flext_cli. +# === SECTION: header (managed) === +# Source: template (base/tests/fixtures/ci/docker/debian.Dockerfile.j2) +# Free: no +# End SECTION: header +# Clean-machine proof: project bootstrap + canonical make verbs on Debian. +FROM debian:bookworm-slim + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +# === SECTION: base packages (managed) === +# Source: template (distro-specific package list) +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + bash ca-certificates curl git make build-essential libicu-dev \ + && rm -rf /var/lib/apt/lists/* +# End SECTION: base packages + +# === SECTION: managed tool bootstrap (managed) === +# Source: config:python_version, template (installer URLs) +# mise installs the supported Python 3.13 family. +# uv is supplied by the managed environment without a project patch pin. +RUN curl -fsSL https://mise.run | sh +# uv is intentionally supplied by the caller environment; install it explicitly +# in clean-machine images so the project bootstrap can resolve dependencies. +RUN curl -fsSL https://astral.sh/uv/install.sh | sh +# tokei (and any future cargo-backed mise tool) needs a Rust toolchain. +RUN curl -fsSL https://sh.rustup.rs | sh -s -- -y --default-toolchain stable +# go is required for mise-managed beads (go:github.com/steveyegge/beads/cmd/bd). +RUN curl -fsSL https://go.dev/dl/go1.23.4.linux-amd64.tar.gz | tar -C /usr/local -xzf - \ + && ln -sf /usr/local/go/bin/go /usr/local/bin/go +ENV PATH="/usr/local/go/bin:/root/.local/bin:/root/.cargo/bin:/root/.local/share/mise/shims:${PATH}" +# End SECTION: managed tool bootstrap + +WORKDIR /workspace +COPY . . + +# === SECTION: mise install (managed) === +# Source: computed (reads .mise.toml from copied workspace) +RUN mise trust .mise.toml && mise install --yes +# End SECTION: mise install + +# === SECTION: bootstrap proof (managed) === +# Source: template (clean-machine bootstrap through the canonical verb) +# The image exists to PROVE that a clean machine can bootstrap this project +# with nothing but the declared toolchain. It therefore runs the canonical +# setup verb fail-closed: any non-zero status fails the build. An earlier +# revision wrapped this in `set +e` and soft-passed whenever the output +# mentioned uv.lock/flext-core, which turned the proof into a bypass -- a +# broken bootstrap still produced a green image. +RUN make setup +# End SECTION: bootstrap proof + +ENTRYPOINT [] +CMD ["make", "help"] diff --git a/tests/fixtures/ci/docker/fedora.Dockerfile b/tests/fixtures/ci/docker/fedora.Dockerfile new file mode 100644 index 000000000..cdd83030d --- /dev/null +++ b/tests/fixtures/ci/docker/fedora.Dockerfile @@ -0,0 +1,54 @@ +# Generated by `flext_infra codegen conform` for flext_cli. +# === SECTION: header (managed) === +# Source: template (base/tests/fixtures/ci/docker/fedora.Dockerfile.j2) +# Free: no +# End SECTION: header +# Clean-machine proof: project bootstrap + canonical make verbs on Fedora. +FROM fedora:41 + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +# === SECTION: base packages (managed) === +# Source: template (distro-specific package list) +RUN dnf install -y \ + bash ca-certificates curl git make gcc gcc-c++ libatomic libicu-devel \ + && dnf clean all +# End SECTION: base packages + +# === SECTION: managed tool bootstrap (managed) === +# Source: config:python_version, template (installer URLs) +# mise installs the supported Python 3.13 family. +# uv is supplied by the managed environment without a project patch pin. +RUN curl -fsSL https://mise.run | sh +# uv is intentionally supplied by the caller environment; install it explicitly +# in clean-machine images so the project bootstrap can resolve dependencies. +RUN curl -fsSL https://astral.sh/uv/install.sh | sh +# tokei (and any future cargo-backed mise tool) needs a Rust toolchain. +RUN curl -fsSL https://sh.rustup.rs | sh -s -- -y --default-toolchain stable +# go is required for mise-managed beads (go:github.com/steveyegge/beads/cmd/bd). +RUN curl -fsSL https://go.dev/dl/go1.23.4.linux-amd64.tar.gz | tar -C /usr/local -xzf - \ + && ln -sf /usr/local/go/bin/go /usr/local/bin/go +ENV PATH="/usr/local/go/bin:/root/.local/bin:/root/.cargo/bin:/root/.local/share/mise/shims:${PATH}" +# End SECTION: managed tool bootstrap + +WORKDIR /workspace +COPY . . + +# === SECTION: mise install (managed) === +# Source: computed (reads .mise.toml from copied workspace) +RUN mise trust .mise.toml && mise install --yes +# End SECTION: mise install + +# === SECTION: bootstrap proof (managed) === +# Source: template (clean-machine bootstrap through the canonical verb) +# The image exists to PROVE that a clean machine can bootstrap this project +# with nothing but the declared toolchain. It therefore runs the canonical +# setup verb fail-closed: any non-zero status fails the build. An earlier +# revision wrapped this in `set +e` and soft-passed whenever the output +# mentioned uv.lock/flext-core, which turned the proof into a bypass -- a +# broken bootstrap still produced a green image. +RUN make setup +# End SECTION: bootstrap proof + +ENTRYPOINT [] +CMD ["make", "help"] diff --git a/tests/fixtures/ci/docker/ubuntu.Dockerfile b/tests/fixtures/ci/docker/ubuntu.Dockerfile new file mode 100644 index 000000000..01e2ab82d --- /dev/null +++ b/tests/fixtures/ci/docker/ubuntu.Dockerfile @@ -0,0 +1,55 @@ +# Generated by `flext_infra codegen conform` for flext_cli. +# === SECTION: header (managed) === +# Source: template (base/tests/fixtures/ci/docker/ubuntu.Dockerfile.j2) +# Free: no +# End SECTION: header +# Clean-machine proof: project bootstrap + canonical make verbs on Ubuntu. +FROM ubuntu:24.04 + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +# === SECTION: base packages (managed) === +# Source: template (distro-specific package list) +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + bash ca-certificates curl git make build-essential libicu-dev \ + && rm -rf /var/lib/apt/lists/* +# End SECTION: base packages + +# === SECTION: managed tool bootstrap (managed) === +# Source: config:python_version, template (installer URLs) +# mise installs the supported Python 3.13 family. +# uv is supplied by the managed environment without a project patch pin. +RUN curl -fsSL https://mise.run | sh +# uv is intentionally supplied by the caller environment; install it explicitly +# in clean-machine images so the project bootstrap can resolve dependencies. +RUN curl -fsSL https://astral.sh/uv/install.sh | sh +# tokei (and any future cargo-backed mise tool) needs a Rust toolchain. +RUN curl -fsSL https://sh.rustup.rs | sh -s -- -y --default-toolchain stable +# go is required for mise-managed beads (go:github.com/steveyegge/beads/cmd/bd). +RUN curl -fsSL https://go.dev/dl/go1.23.4.linux-amd64.tar.gz | tar -C /usr/local -xzf - \ + && ln -sf /usr/local/go/bin/go /usr/local/bin/go +ENV PATH="/usr/local/go/bin:/root/.local/bin:/root/.cargo/bin:/root/.local/share/mise/shims:${PATH}" +# End SECTION: managed tool bootstrap + +WORKDIR /workspace +COPY . . + +# === SECTION: mise install (managed) === +# Source: computed (reads .mise.toml from copied workspace) +RUN mise trust .mise.toml && mise install --yes +# End SECTION: mise install + +# === SECTION: bootstrap proof (managed) === +# Source: template (clean-machine bootstrap through the canonical verb) +# The image exists to PROVE that a clean machine can bootstrap this project +# with nothing but the declared toolchain. It therefore runs the canonical +# setup verb fail-closed: any non-zero status fails the build. An earlier +# revision wrapped this in `set +e` and soft-passed whenever the output +# mentioned uv.lock/flext-core, which turned the proof into a bypass -- a +# broken bootstrap still produced a green image. +RUN make setup +# End SECTION: bootstrap proof + +ENTRYPOINT [] +CMD ["make", "help"]