From 6b0f9448e22ddd46cf237962b91270b211acb023 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Mon, 19 Oct 2026 12:13:38 +0700 Subject: [PATCH] ci(linux): run Flatpak, MSRV and packages nightly, cap docker tests --- .claude/rules/ci.md | 3 +- .github/workflows/build-linux.yml | 59 +++++++++---------- .github/workflows/linux-packages.yml | 14 ++--- linux/CONTRIBUTING.md | 2 +- .../0018-ppa-copr-and-flathub-later.md | 4 +- linux/docs/testing.md | 13 ++-- 6 files changed, 44 insertions(+), 51 deletions(-) diff --git a/.claude/rules/ci.md b/.claude/rules/ci.md index 715f41e411..f36f81044a 100644 --- a/.claude/rules/ci.md +++ b/.claude/rules/ci.md @@ -135,7 +135,8 @@ The required check names are in `AGENTS.md` (CI). Reading a red check: `.claude/ - A push to main or `release/**`: the same minus PR title; never cancelled, the SPM cache saved on a miss. Every code push runs both plans in full; a docs-only or changelog-only push skips the suites through the detector. A `release/**` push also runs Release Build; main gets it nightly. - A `v*` tag runs only `release.yml`, and a `linux-v*` tag only `release-linux.yml`, which calls `linux-packages.yml`. The test workflows never run on a tag. - `workflow_dispatch` exists on every workflow except `pr-title.yml` and `release.yml`. -- `build-linux.yml` builds and tests the Linux app (`linux/docs/testing.md`, CI). Its `Changes (Linux)` job skips the rest when nothing under `linux/` or the scripts and workflows it reads changed, and its `Linux` job gates on all of them. +- `build-linux.yml` builds and tests the Linux app, and `linux-packages.yml` builds its packages (`linux/docs/testing.md`, CI). What starts each is in its `on:` and job `if:` lines. Flatpak Devel and Minimum Rust version never run on a PR or push, and `linux-packages.yml` never on a push. +- `Changes (Linux)` skips the other build-linux jobs when nothing under `linux/` or the scripts and workflows they read changed, and the `Linux` job gates on all of them. ## Caches and runner budget diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index d5daae3526..ed1a1d6691 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -5,7 +5,7 @@ on: push: branches: [main] schedule: - - cron: "13 14 * * 1" + - cron: "13 14 * * *" workflow_dispatch: permissions: @@ -105,6 +105,22 @@ jobs: xvfb \ xauth \ dbus-daemon + # On the bare checkout: the glob ignores .gitignore, so once Cargo + # fills _build it would read every crate's Markdown too. + - name: Install lychee + run: | + curl --fail --silent --show-error --location --output "$RUNNER_TEMP/lychee.tar.gz" \ + "https://github.com/lycheeverse/lychee/releases/download/lychee-v$LYCHEE_VERSION/lychee-x86_64-unknown-linux-gnu.tar.gz" + echo "$LYCHEE_SHA256 $RUNNER_TEMP/lychee.tar.gz" | sha256sum --check --strict + mkdir "$RUNNER_TEMP/lychee" + tar -xzf "$RUNNER_TEMP/lychee.tar.gz" -C "$RUNNER_TEMP/lychee" --strip-components=1 \ + lychee-x86_64-unknown-linux-gnu/lychee + echo "$RUNNER_TEMP/lychee" >> "$GITHUB_PATH" + - name: Links and anchors in the Linux docs resolve + # Offline, so only links to files and headings in the tree are + # checked: the ones a rename or a move breaks. + working-directory: . + run: lychee --offline --include-fragments --no-progress 'linux/**/*.md' - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master with: toolchain: "1.98" @@ -227,8 +243,8 @@ jobs: # compiler and not with rustup's. msrv: name: Minimum Rust version - needs: changes - if: ${{ !cancelled() && needs.changes.outputs.run != 'false' }} + # Nightly and by hand only, to keep a pull request under GitHub Free's 20 concurrent jobs. + if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-24.04 timeout-minutes: 60 container: @@ -260,30 +276,6 @@ jobs: "cargo-$RUST_VERSION" check --workspace --all-targets --locked "cargo-$RUST_VERSION" check --workspace --all-targets --locked --no-default-features - docs: - name: Documentation links - needs: changes - if: ${{ !cancelled() && needs.changes.outputs.run != 'false' }} - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - name: Install lychee - run: | - curl --fail --silent --show-error --location --output "$RUNNER_TEMP/lychee.tar.gz" \ - "https://github.com/lycheeverse/lychee/releases/download/lychee-v$LYCHEE_VERSION/lychee-x86_64-unknown-linux-gnu.tar.gz" - echo "$LYCHEE_SHA256 $RUNNER_TEMP/lychee.tar.gz" | sha256sum --check --strict - mkdir "$RUNNER_TEMP/lychee" - tar -xzf "$RUNNER_TEMP/lychee.tar.gz" -C "$RUNNER_TEMP/lychee" --strip-components=1 \ - lychee-x86_64-unknown-linux-gnu/lychee - echo "$RUNNER_TEMP/lychee" >> "$GITHUB_PATH" - - name: Links and anchors in the Linux docs resolve - # Offline, so only links to files and headings in the tree are - # checked: the ones a rename or a move breaks. - run: lychee --offline --include-fragments --no-progress 'linux/**/*.md' - supply-chain: name: Supply chain needs: changes @@ -395,8 +387,8 @@ jobs: flatpak-devel: name: Flatpak Devel (${{ matrix.arch }}) - needs: changes - if: ${{ !cancelled() && needs.changes.outputs.run != 'false' }} + # Nightly and by hand only, to keep a pull request under GitHub Free's 20 concurrent jobs. + if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} strategy: fail-fast: false matrix: @@ -440,6 +432,8 @@ jobs: timeout-minutes: 90 strategy: fail-fast: false + # GitHub Free runs 20 jobs at once across the account. + max-parallel: 3 matrix: package: - tablepro-driver-postgres @@ -653,11 +647,12 @@ jobs: name: junit-tablepro path: linux/target/nextest/ci/junit.xml - # The one check a branch rule requires: a job skipped by a path decision - # reports success, and this fails when any Linux job failed or was cancelled. + # The one check a branch rule requires: a job skipped by a path or event + # decision reports success, and this fails when any Linux job failed or was + # cancelled. linux: name: Linux - needs: [changes, fast, msrv, docs, supply-chain, i18n, flatpak-devel, integration, integration-session, integration-app] + needs: [changes, fast, msrv, supply-chain, i18n, flatpak-devel, integration, integration-session, integration-app] if: always() runs-on: ubuntu-24.04 timeout-minutes: 5 diff --git a/.github/workflows/linux-packages.yml b/.github/workflows/linux-packages.yml index c2292ee4b5..888c4f1532 100644 --- a/.github/workflows/linux-packages.yml +++ b/.github/workflows/linux-packages.yml @@ -8,7 +8,7 @@ name: Linux packages # fedora:44 with only its BuildRequires. Each package is then installed in # another fresh container with only its runtime dependencies and started. # release-linux.yml calls this workflow and uploads the source packages. -# A run by hand can add arm64, which pushes and pull requests leave out. +# A run by hand can add arm64, which the nightly and pull requests leave out. # Given a release tag, it packages that release's tarballs instead, with # the packaging from this checkout, for a PPA upload with a new revision. @@ -26,13 +26,11 @@ on: - "linux/data/**/meson.build" - "linux/po/meson.build" - ".github/workflows/linux-packages.yml" - # After a merge every change runs, so a failure only one distribution's - # build shows turns up then and not at tag time. - push: - branches: [main] - paths: - - "linux/**" - - ".github/workflows/linux-packages.yml" + # Nightly on main, so a failure only one distribution's build shows turns + # up before tag time. Three hours after build-linux.yml's nightly, so the + # two do not share the account's 20 concurrent jobs. + schedule: + - cron: "13 17 * * *" workflow_dispatch: inputs: arm64: diff --git a/linux/CONTRIBUTING.md b/linux/CONTRIBUTING.md index 34021a136c..40b32ef8d8 100644 --- a/linux/CONTRIBUTING.md +++ b/linux/CONTRIBUTING.md @@ -54,7 +54,7 @@ meson dist -C _build --no-tests --formats xztar Inside a desktop session, `dbus-run-session -- meson test -C _build` runs the same suites without xvfb. -The fast job also runs a few source greps and `scripts/check-doc-symbols.sh` from the repository root. The supply-chain, documentation and Docker jobs run these, among others; [docs/testing.md](docs/testing.md#ci) describes every job, and the Docker job runs the last line once per package that has Docker tests: +The fast job also runs a few source greps, `scripts/check-doc-symbols.sh` and the lychee line below, from the repository root. The supply-chain and Docker jobs run the rest, among others; [docs/testing.md](docs/testing.md#ci) describes every job, and the Docker job runs the last line once per package that has Docker tests: ```bash cargo deny --locked check advisories bans licenses sources diff --git a/linux/docs/decisions/0018-ppa-copr-and-flathub-later.md b/linux/docs/decisions/0018-ppa-copr-and-flathub-later.md index e76c2bbca4..ce3ec138d0 100644 --- a/linux/docs/decisions/0018-ppa-copr-and-flathub-later.md +++ b/linux/docs/decisions/0018-ppa-copr-and-flathub-later.md @@ -61,8 +61,8 @@ tarballs: `tablepro-X.Y.Z.tar.xz` from `meson dist`, and --versioned-dirs` and the source replacement it printed. They build offline and run every Meson suite during the build, the gtk suite under `xvfb-run` and `dbus-run-session`. `linux-packages.yml` builds them the -same way before a release, on pull requests that touch the packaging and -on pushes to `linux` (`docs/testing.md`, CI). +same way before a release and on the events its `on:` lists +(`docs/testing.md`, CI). `debian/copyright` and the spec's `License` tag come from `data/licenses/third-party.json`, the cargo-about output the About diff --git a/linux/docs/testing.md b/linux/docs/testing.md index 8b373304da..641958db9e 100644 --- a/linux/docs/testing.md +++ b/linux/docs/testing.md @@ -406,19 +406,18 @@ The tests in `crates/app/src/ui/editor/script_runner.rs` drive `run_batches` und ## CI -GitHub Actions (`.github/workflows/build-linux.yml`), Ubuntu runners. It runs on a pull request, and on a push to `main`, `linux`, `linux/**` or `feat/linux-**`, that touches `linux/` or one of the three Linux workflows: `build-linux.yml`, `linux-packages.yml` and `release-linux.yml`. It also runs every Monday and by hand. Every action is pinned by commit SHA and every tool by version. +GitHub Actions (`.github/workflows/build-linux.yml`), Ubuntu runners. Its `on:` lists what starts it. Flatpak Devel and Minimum Rust version run only on its schedule and by hand. Every action is pinned by commit SHA and every tool by version. -1. **Fast checks**: `meson setup`, `cargo fmt --all -- --check`, the source greps (no `thread_local!` in services, no blocking file I/O under `ui`, no action group inserted as `win`, no `set_qdata`, no em dash in user-facing text), `scripts/check-doc-symbols.sh` over the docs that name code, clippy with and without default features, `meson compile`, `xvfb-run -a dbus-run-session -- meson test --print-errorlogs`, a Secret Service step under `gnome-keyring-daemon`, then `meson dist`. Runs in an `ubuntu:26.04` container, which ships GLib 2.88 plus the meson, appstream and desktop-file-utils packages. A failed run keeps `_build/meson-logs/testlog.txt` as the `meson-testlog` artifact. [CONTRIBUTING.md](../CONTRIBUTING.md#fast-job-commands) lists the same commands. +1. **Fast checks**: lychee, offline, over every Markdown file under `linux/`, with heading anchors checked, then `meson setup`, `cargo fmt --all -- --check`, the source greps (no `thread_local!` in services, no blocking file I/O under `ui`, no action group inserted as `win`, no `set_qdata`, no em dash in user-facing text), `scripts/check-doc-symbols.sh` over the docs that name code, clippy with and without default features, `meson compile`, `xvfb-run -a dbus-run-session -- meson test --print-errorlogs`, a Secret Service step under `gnome-keyring-daemon`, then `meson dist`. Runs in an `ubuntu:26.04` container, which ships GLib 2.88 plus the meson, appstream and desktop-file-utils packages. A failed run keeps `_build/meson-logs/testlog.txt` as the `meson-testlog` artifact. [CONTRIBUTING.md](../CONTRIBUTING.md#fast-job-commands) lists the same commands. 2. **Docker tests** (`integration`, `integration-session`, `integration-app`): runs after fast checks pass, and keeps each package's JUnit report as a `junit-` artifact, `junit--` for a release entry. One matrix entry per package with docker tests (the PostgreSQL driver with PgBouncer, the MySQL driver with MariaDB, the SQL Server and ClickHouse drivers, all four with their TLS suites, `tablepro-ssh` against an OpenSSH server container, and `tablepro-test-fixtures` for the fixtures themselves) runs that package's ignored docker tests through cargo-nextest on the host runner's Docker, one test at a time per package. The driver packages have an entry more for each older or newer server release ([Server releases](#server-releases)). `tablepro-session` builds storage, which needs GLib 2.88, so its job runs in the fast job's `ubuntu:26.04` image with the host's Docker socket mounted. The app's docker tests (`crates/app/tests/tracker_save_postgres.rs`) run the same way, since the app links GTK; that job names its test targets, because the app's `startup` test needs Meson. The SQLite driver needs no container: its suites run in the fast job. 3. **Supply chain**: `cargo deny check` against `deny.toml` (advisories, bans, licenses and sources, with every feature, both Linux targets and the dev-dependencies), `cargo shear` for unused or misplaced dependencies, and `build-aux/update-third-party-licenses.sh`, failing when `data/licenses`, `build-aux/debian/copyright` or the spec's `License` tag differ from what it writes. Then `zizmor` over the three Linux workflows. 4. **Translations**: in `ubuntu:26.10`, whose gettext 1.0 reads path-qualified Rust calls such as `crate::i18n::gettext(...)`. `po/POTFILES.in` must match `git ls-files`, `meson setup --fatal-meson-warnings` must pass, and `po/tablepro.pot` must match a fresh `meson compile -C _build tablepro-pot` in everything but its creation date. Regenerating it locally needs gettext 1.0 or newer (`po/README.md`). A failed run keeps the template it wrote as the `tablepro-pot` artifact. -5. **Documentation links**: lychee, offline, over every Markdown file under `linux/`, with heading anchors checked. -6. **Flatpak Devel**: the Devel manifest built in the `gnome-51` Flatpak image for x86_64 and aarch64, with every Meson suite run inside the build sandbox from a tree with no `.git`. The x86_64 job lints the manifest with `flatpak-builder-lint` and `build-aux/flatpak/lint-exceptions.json`. The repository holds no Flathub manifest ([ADR 0018](decisions/0018-ppa-copr-and-flathub-later.md)). -7. **Minimum Rust version**: in `ubuntu:26.04`, `build-aux/packaging/add-rust-toolchain-ppa.sh` adds `ppa:rust-toolchain/staging`, `apt-get build-dep -P nocheck` installs the .deb's build dependencies without the test-only ones, and `cargo-1.97 check --workspace --all-targets --locked` runs with and without default features: the compiler the PPA builds with, at the workspace `rust-version`. +5. **Flatpak Devel**: the Devel manifest built in the `gnome-51` Flatpak image for x86_64 and aarch64, with every Meson suite run inside the build sandbox from a tree with no `.git`. The x86_64 job lints the manifest with `flatpak-builder-lint` and `build-aux/flatpak/lint-exceptions.json`. The repository holds no Flathub manifest ([ADR 0018](decisions/0018-ppa-copr-and-flathub-later.md)). +6. **Minimum Rust version**: in `ubuntu:26.04`, `build-aux/packaging/add-rust-toolchain-ppa.sh` adds `ppa:rust-toolchain/staging`, `apt-get build-dep -P nocheck` installs the .deb's build dependencies without the test-only ones, and `cargo-1.97 check --workspace --all-targets --locked` runs with and without default features: the compiler the PPA builds with, at the workspace `rust-version`. -A `Changes (Linux)` job runs `scripts/ci/detect-changed-paths.sh linux` and every other job waits for it: a change that touches nothing the Linux jobs read skips them, and a schedule or manual run takes every job. The `Linux` job needs all of them and fails when any failed or was cancelled, so it is the one check a branch rule requires; a skipped job counts as passed. +A `Changes (Linux)` job runs `scripts/ci/detect-changed-paths.sh linux`, and every job but Flatpak Devel and Minimum Rust version waits for it: a change that touches nothing the Linux jobs read skips them, and a schedule or manual run takes every job. The `Linux` job needs all of them and fails when any failed or was cancelled, so it is the one check a branch rule requires; a skipped job counts as passed. -`.github/workflows/linux-packages.yml` builds the packages from the release source and vendor tarballs. For each Ubuntu series the PPA builds for, 26.04 and 26.10, it writes the Debian source package with `build-aux/packaging/build-source.sh`, then `build-deb.sh` builds the binaries from it the way Launchpad does: in a fresh container of that series with only the declared build dependencies, offline, as a user that is not root, running every Meson suite, then lintian. `build-rpm.sh` builds the .rpm in `fedora:44` with only its BuildRequires, running every Meson suite, and checks it with `rpmlint --strict`. Each package is then installed in a fresh container and started. It runs on a pull request that touches the packaging (`build-aux/debian`, `build-aux/rpm`, `build-aux/packaging`), `Cargo.toml`, `Cargo.lock` or a Meson file, and on every push to `linux` that touches `linux/`, on x86_64 only. Run by hand with `arm64` ticked, it builds, tests and installs both packages on an arm64 runner too. `.github/workflows/release-linux.yml` calls it on a `linux-v*` tag before it publishes, on both architectures ([ADR 0018](decisions/0018-ppa-copr-and-flathub-later.md)). Run by hand on a branch with a released tag and a revision, `release-linux.yml` calls it on that release's tarballs with the branch's .deb packaging, then uploads the result to the PPA as a new revision ([releasing.md](releasing.md#a-packaging-fix)). `build-aux/packaging/build-packages.sh` runs the same steps locally. +`.github/workflows/linux-packages.yml` builds the packages from the release source and vendor tarballs. For each Ubuntu series the PPA builds for, 26.04 and 26.10, it writes the Debian source package with `build-aux/packaging/build-source.sh`, then `build-deb.sh` builds the binaries from it the way Launchpad does: in a fresh container of that series with only the declared build dependencies, offline, as a user that is not root, running every Meson suite, then lintian. `build-rpm.sh` builds the .rpm in `fedora:44` with only its BuildRequires, running every Meson suite, and checks it with `rpmlint --strict`. Each package is then installed in a fresh container and started. Its `on:` lists what starts it. A pull request or the nightly run builds x86_64 only. Run by hand with `arm64` ticked, it builds, tests and installs both packages on an arm64 runner too. `.github/workflows/release-linux.yml` calls it on a `linux-v*` tag before it publishes, on both architectures ([ADR 0018](decisions/0018-ppa-copr-and-flathub-later.md)). Run by hand on a branch with a released tag and a revision, `release-linux.yml` calls it on that release's tarballs with the branch's .deb packaging, then uploads the result to the PPA as a new revision ([releasing.md](releasing.md#a-packaging-fix)). `build-aux/packaging/build-packages.sh` runs the same steps locally. ## Coverage