Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,25 @@ else
fi

# ── clang-tidy (advisory) ────────────────────────────────────────────────
# Needs a compile_commands.json. We generate one in build-debug via CMake
# Needs a compile_commands.json. The debug preset (CMakePresets.json) writes
# one into build/, the same tree CI lints against
# (CMAKE_EXPORT_COMPILE_COMMANDS is ON in CMakeLists.txt). Match CI: report
# warnings but don't block the commit on stylistic findings — .clang-tidy's
# WarningsAsErrors='' is authoritative.
if command -v clang-tidy >/dev/null 2>&1; then
if [ -f build-debug/compile_commands.json ]; then
if [ -f build/compile_commands.json ]; then
cpp_files=()
while IFS= read -r f; do
case "$f" in
*.cpp) cpp_files+=("$f") ;;
esac
done <<<"$staged"
if [ "${#cpp_files[@]}" -gt 0 ]; then
echo "▶ clang-tidy -p build-debug (${#cpp_files[@]} file(s))"
clang-tidy -p build-debug --quiet "${cpp_files[@]}" || true
echo "▶ clang-tidy -p build (${#cpp_files[@]} file(s))"
clang-tidy -p build --quiet "${cpp_files[@]}" || true
fi
else
echo "⚠ build-debug/compile_commands.json missing — run scripts/build.sh debug"
echo "⚠ build/compile_commands.json missing — run scripts/build.sh debug"
fi
else
echo "⚠ clang-tidy not installed — skipping (sudo apt install clang-tidy)"
Expand Down
17 changes: 12 additions & 5 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ jobs:
Acquire::Retries "2";
CONF
sudo apt-get update
# catch2: the shared release preset configures with tests ON, and a
# system Catch2 keeps the configure off tests/' FetchContent fallback
# (a network fetch this lane does not otherwise need).
sudo apt-get install -y --no-install-recommends \
build-essential cmake ninja-build pkg-config \
libsodium-dev libsdl2-dev libssl-dev libopus-dev
libsodium-dev libsdl2-dev libssl-dev libopus-dev catch2

# Not apt: noble ships Qt 6.4.2 and this project's floor is 6.7. The
# action pulls the official binaries and exports CMAKE_PREFIX_PATH.
Expand All @@ -65,12 +68,16 @@ jobs:
languages: ${{ matrix.language }}
queries: security-extended,security-and-quality

# The configure flags live in CMakePresets.json (preset release), shared
# with linux-ci.yml and the local scripts. Two deliberate deltas against
# the old inline configure: the tree is build-release (the preset's
# binaryDir), and tests + translations are configured ON like the ci job
# (the traced build still compiles only Dish; setup-qt above provides
# the Linguist tools the translations flag requires).
- name: Build
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DDISH_BUILD_TESTS=OFF
cmake --build build --parallel --target Dish
cmake --preset release
cmake --build build-release --parallel --target Dish

- name: Perform CodeQL analysis
# SARIF upload requires GitHub Advanced Security on private repos.
Expand Down
56 changes: 22 additions & 34 deletions .github/workflows/linux-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,30 +72,30 @@ jobs:
pipx ensurepath
echo "$HOME/.local/bin" >> "$GITHUB_PATH"

# The gate itself lives in scripts/check-format.sh so this workflow and
# scripts/ci-local.sh cannot drift on the file set or the invocation.
- name: clang-format (check only)
if: env.DISH_LINTS == 'true'
run: |
find src tests -type f \( -name '*.cpp' -o -name '*.h' \) \
-print0 | xargs -0 clang-format --dry-run --Werror
run: ./scripts/check-format.sh

# The configure line lives in CMakePresets.json (preset debug), shared
# with scripts/build.sh and scripts/ci-local.sh. The ccache launcher is
# layered on top here rather than in the preset because a local box need
# not have ccache; CC/CXX come from the matrix env, which CMake respects
# natively.
- name: Configure (Debug, tests on)
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DDISH_BUILD_TESTS=ON \
-DDISH_REQUIRE_TRANSLATIONS=ON \
cmake --preset debug \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache

- name: Build
run: cmake --build build --parallel
run: cmake --build --preset debug --parallel

# QT_QPA_PLATFORM=offscreen comes from the test preset: no display on
# the runner, and the QML tests construct QGuiApplication.
- name: Run tests (Debug)
working-directory: build
# No display on the runner; the QML tests construct QGuiApplication.
env:
QT_QPA_PLATFORM: offscreen
run: ctest --output-on-failure --parallel
run: ctest --preset debug --parallel

- name: qmllint (QML static analysis)
if: env.DISH_LINTS == 'true'
Expand Down Expand Up @@ -133,26 +133,22 @@ jobs:
-print0 | xargs -0 -n1 -P"$(nproc)" \
clang-tidy -p build --quiet --warnings-as-errors='*'

# The configure line lives in CMakePresets.json (preset release); same
# ccache-on-top note as the Debug configure above.
- name: Configure (Release, tests on)
run: |
cmake -S . -B build-release -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DDISH_BUILD_TESTS=ON \
-DDISH_REQUIRE_TRANSLATIONS=ON \
cmake --preset release \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache

- name: Build release
run: cmake --build build-release --parallel
run: cmake --build --preset release --parallel

# -O3 plus LTO is a different compiler: undefined behaviour that Debug
# tolerates surfaces here, and until now nothing ever ran the suite
# against the configuration that actually ships.
- name: Run tests (Release)
working-directory: build-release
env:
QT_QPA_PLATFORM: offscreen
run: ctest --output-on-failure --parallel
run: ctest --preset release --parallel

# Ubuntu patches PIE, partial RELRO and stack protection into its gcc
# defaults, so these pass by accident on this runner and would silently
Expand Down Expand Up @@ -275,19 +271,11 @@ jobs:
desktop-file-validate packaging/dish.desktop
appstreamcli validate --no-net packaging/com.tinkernorth.Dish.metainfo.xml

- name: Configure and build
run: |
cmake -S . -B build-release -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
-DDISH_BUILD_TESTS=OFF
cmake --build build-release --parallel

# Configure + build + cpack live in scripts/build-deb.sh (the `package`
# preset), the same path release.yml's deb job and a local
# `scripts/build-deb.sh` run.
- name: Build the .deb
run: |
set -euo pipefail
cpack --config build-release/CPackConfig.cmake -G DEB -B build-release/packages
mkdir -p dist && cp build-release/packages/*.deb dist/
run: ./scripts/build-deb.sh

# A lintian error means the package is malformed, not merely untidy.
- name: lintian
Expand Down
35 changes: 9 additions & 26 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,19 +179,11 @@ jobs:
desktop-file-validate packaging/dish.desktop
appstreamcli validate --no-net packaging/com.tinkernorth.Dish.metainfo.xml

- name: Configure and build
run: |
cmake -S . -B build-release -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
-DDISH_BUILD_TESTS=OFF
cmake --build build-release --parallel

- name: Package
run: |
set -euo pipefail
cpack --config build-release/CPackConfig.cmake -G DEB -B build-release/packages
mkdir -p dist && cp build-release/packages/*.deb dist/
# Configure + build + cpack live in scripts/build-deb.sh (the `package`
# preset), the same path linux-ci.yml's package job and a local
# `scripts/build-deb.sh` run.
- name: Build the .deb
run: ./scripts/build-deb.sh

- name: lintian
run: lintian --fail-on error --tag-display-limit 0 dist/*.deb
Expand Down Expand Up @@ -331,19 +323,10 @@ jobs:
with:
ref: ${{ inputs.tag || github.ref }}

- name: Configure and build
run: |
cmake -S . -B build-release -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
-DDISH_BUILD_TESTS=OFF
cmake --build build-release --parallel

- name: Package
run: |
set -euo pipefail
cpack --config build-release/CPackConfig.cmake -G RPM -B build-release/packages
mkdir -p dist && cp build-release/packages/*.rpm dist/
# Same rails as the .deb: scripts/build-rpm.sh drives the `package`
# preset and swaps the cpack generator.
- name: Build the .rpm
run: ./scripts/build-rpm.sh

- name: Assert package contents and scriptlets
run: |
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ out/
cmake-build-*/
_deps/

# Packaged artifacts (scripts/build-deb.sh, build-rpm.sh, build-appimage.sh)
dist/

# CMake
CMakeFiles/
CMakeCache.txt
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,26 @@ the repos share a version number.
is the honest maximum rather than a shortcut. The two host rumble streams mix
per motor by maximum, so neither can cancel the other.

### Changed

- **Build system: local builds and CI run the same rails.** `CMakePresets.json`
(new) carries the `debug`, `release` and `package` configure lines;
`linux-ci.yml`, `codeql.yml` and `release.yml` call the presets, the shared
`scripts/check-format.sh` gate, and the new `scripts/build-deb.sh` /
`scripts/build-rpm.sh` packaging scripts instead of inline copies (matrix
compilers stay env-injected CC/CXX and the ccache launcher stays
workflow-side, so presets never pin what the matrix varies). Locally:
`scripts/install-deps.sh` (the README apt list plus CI's pinned
clang-format; `--ci-qt` installs the exact Qt 6.9.3 CI builds against),
`scripts/build.sh` rewritten onto the presets (the debug tree is now
`build/`, CI's name, instead of `build-debug/`; the pre-commit hook's
`clang-tidy -p` target follows), and `scripts/ci_local.sh` renamed to
`scripts/ci-local.sh` (a forwarder keeps the old name) with its known gaps
closed: the Debug and Release configures now carry
`DISH_REQUIRE_TRANSLATIONS=ON` like CI, qmllint gains CI's
`-I "$QT_ROOT_DIR/qml"` include, and a `--compiler gcc|clang` flag
reproduces either side of CI's compiler matrix.

### Fixed

- Moonlight motion samples were forwarded as the satellite's raw fixed-point
Expand Down
74 changes: 74 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"version": 3,
"cmakeMinimumRequired": { "major": 3, "minor": 21, "patch": 0 },
"configurePresets": [
{
"name": "debug",
"displayName": "Debug (tests, what linux-ci.yml builds first)",
"description": "The Debug lane linux-ci.yml configures: Ninja, tests on, translations required. No compiler is named: CI's gcc/clang matrix sets CC/CXX in the environment and CMake respects them natively, so a preset naming one would break the other leg. CI adds -DCMAKE_C[XX]_COMPILER_LAUNCHER=ccache on top of the preset; that stays workflow-side because a local box need not have ccache. DISH_REQUIRE_TRANSLATIONS is ON here, unlike CMakeLists' local-friendly OFF default, because local == CI is the point of the preset; note the gate itself also needs lupdate >= 6.9 (see .github/actions/setup-qt), which distro Qt may predate.",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"DISH_BUILD_TESTS": "ON",
"DISH_REQUIRE_TRANSLATIONS": "ON"
}
},
{
"name": "release",
"displayName": "Release (tests on, the shipping optimisation level)",
"description": "The Release lane linux-ci.yml configures and TESTS: -O3 plus LTO is a different compiler, so the suite runs against the configuration that ships, not only against Debug. Same compiler/ccache notes as the debug preset.",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"DISH_BUILD_TESTS": "ON",
"DISH_REQUIRE_TRANSLATIONS": "ON"
}
},
{
"name": "package",
"displayName": "Package (Release, /usr prefix, no tests)",
"description": "What the .deb/.rpm jobs configure (linux-ci.yml package, release.yml deb + rpm, via scripts/build-deb.sh / build-rpm.sh): install rules against /usr, tests off. Its own tree so a local package build never clobbers the release preset's build-release/. Translations are not required here: the package builds against the distro's Qt inside the target container, where the catalogues are compiled but the sync gate (which needs lupdate >= 6.9) is the ci job's business.",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-package",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_INSTALL_PREFIX": "/usr",
"DISH_BUILD_TESTS": "OFF"
}
}
],
"buildPresets": [
{
"name": "debug",
"configurePreset": "debug"
},
{
"name": "release",
"configurePreset": "release"
},
{
"name": "package",
"configurePreset": "package"
}
],
"testPresets": [
{
"name": "debug",
"configurePreset": "debug",
"output": { "outputOnFailure": true },
"environment": {
"QT_QPA_PLATFORM": "offscreen"
}
},
{
"name": "release",
"configurePreset": "release",
"output": { "outputOnFailure": true },
"environment": {
"QT_QPA_PLATFORM": "offscreen"
}
}
]
}
33 changes: 23 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,24 @@ captures the conventions that aren't obvious from skimming the code.
## Getting set up

```bash
# 1) Install build deps for your distro (see README "Install build dependencies")
# 2) Generate compile_commands.json + run the test suite
# 1) Install the toolchain CI uses (apt; --ci-qt adds CI's exact Qt 6.9.3)
scripts/install-deps.sh
# 2) Generate compile_commands.json + run the test suite (debug preset -> build/)
scripts/build.sh debug test
# 3) Point git at the in-tree pre-commit hook
scripts/setup-hooks.sh
# 4) Before pushing: every CI gate, in CI's order
scripts/ci-local.sh
```

`CMakePresets.json` is the single source of configure truth: the `debug`,
`release` and `package` presets are what `linux-ci.yml`, `codeql.yml` and
`release.yml` drive, and the `scripts/` wrappers drive the same ones. The
debug preset writes to `build/` (CI's tree name; this repo used
`build-debug/` before the presets existed).

The pre-commit hook runs `clang-format -i` (autofix, re-stages) and
`clang-tidy -p build-debug` (advisory) on staged C++ files. It skips
`clang-tidy -p build` (advisory) on staged C++ files. It skips
gracefully if the tools aren't installed — CI re-runs `clang-format
--dry-run --Werror` and `clang-tidy` in strict mode, so anything that
slips locally fails the PR.
Expand Down Expand Up @@ -161,11 +170,15 @@ Security gates (also blocking):
- `codeql.yml`: CodeQL `cpp` analysis (security-extended +
security-and-quality query packs).

`scripts/ci_local.sh` runs those gates in the same order against your worktree,
so a green run there means a green run in CI. `--no-tidy` skips the slowest step
for a fast loop; `--with-package` adds the CPack/lintian leg. A gate whose tool
is missing FAILS rather than printing a notice — pass `--allow-missing` if you
really want to skip it, and know that you did.
`scripts/ci-local.sh` runs those gates in the same order against your worktree
(through the same presets and `scripts/check-format.sh` the workflow calls), so
a green run there means a green run in CI. `--no-tidy` skips the slowest step
for a fast loop; `--with-package` adds the CPack/lintian leg;
`--with-sanitizers` adds the ASan/UBSan and TSan legs; `--compiler gcc|clang`
sets CC/CXX so you can reproduce either side of CI's compiler matrix (one run
covers one compiler). A gate whose tool is missing FAILS rather than printing
a notice — pass `--allow-missing` if you really want to skip it, and know that
you did. `scripts/ci_local.sh` remains as a forwarder for muscle memory.

## Security

Expand Down Expand Up @@ -275,8 +288,8 @@ database globally, so a second tree only re-derives the same `src/` entries and
costs another full build:

```sh
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DDISH_BUILD_TESTS=ON
cmake --build build --parallel
cmake --preset debug
cmake --build --preset debug --parallel
find src -type f \( -name '*.cpp' -o -name '*.h' \) \
! -path 'src/UI/*' ! -path 'src/qml/*' -print0 |
xargs -0 -n1 -P"$(nproc)" clang-tidy -p build --quiet --warnings-as-errors='*'
Expand Down
Loading
Loading