ci: check formatting of our Rust code

Introduce a CI check that verifies that our Rust code is well-formatted. This check uses `cargo fmt`, which is a wrapper around rustfmt(1) that executes formatting for all Rust source files. rustfmt(1) itself is the de-facto standard for formatting code in the Rust ecosystem. The rustfmt(1) tool allows to tweak the final format in theory. In practice though, the Rust ecosystem has aligned on style "editions". These editions only exist to ensure that any potential changes to the style don't cause reformats to existing code bases. Other than that, most Rust projects out there accept this default style of a specific edition. Let's do the same and use that default style. It may not be anyone's favorite, but it is consistent and by making it part of our CI we also enforce it right from the start. Note that we don't have to pick a specific style edition here, as the edition is automatically derived from the edition we have specified in our "Cargo.toml" file. The implemented script looks somewhat weird as we perfom manual error handling instead of using something like `set -e`. The intent here is that subsequent commits will add more checks, and we want to execute all of these checks regardless of whether or not a previous check failed. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Oct 15, 2025 at 08:04 UTC e75cd059001ab49bd92040418660bcdfc7981c84
4 files changed +43
.github/workflows/main.yml
+15
@@ -458,6 +458,21 @@ jobs:
458 - run: ci/install-dependencies.sh
459 - run: ci/run-static-analysis.sh
460 - run: ci/check-directional-formatting.bash
461 + rust-analysis:
462 + needs: ci-config
463 + if: needs.ci-config.outputs.enabled == 'yes'
464 + env:
465 + jobname: RustAnalysis
466 + CI_JOB_IMAGE: ubuntu:rolling
467 + runs-on: ubuntu-latest
468 + container: ubuntu:rolling
469 + concurrency:
470 + group: rust-analysis-${{ github.ref }}
471 + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
472 + steps:
473 + - uses: actions/checkout@v4
474 + - run: ci/install-dependencies.sh
475 + - run: ci/run-rust-checks.sh
476 sparse:
477 needs: ci-config
478 if: needs.ci-config.outputs.enabled == 'yes'
.gitlab-ci.yml
+11
@@ -212,6 +212,17 @@ static-analysis:
212 - ./ci/run-static-analysis.sh
213 - ./ci/check-directional-formatting.bash
214
215 +rust-analysis:
216 + image: ubuntu:rolling
217 + stage: analyze
218 + needs: [ ]
219 + variables:
220 + jobname: RustAnalysis
221 + before_script:
222 + - ./ci/install-dependencies.sh
223 + script:
224 + - ./ci/run-rust-checks.sh
225 +
226 check-whitespace:
227 image: ubuntu:latest
228 stage: analyze
ci/install-dependencies.sh
+5
@@ -126,6 +126,11 @@ StaticAnalysis)
126 sudo apt-get -q -y install coccinelle libcurl4-openssl-dev libssl-dev \
127 libexpat-dev gettext make
128 ;;
129 +RustAnalysis)
130 + sudo apt-get -q -y install rustup
131 + rustup default stable
132 + rustup component add rustfmt
133 + ;;
134 sparse)
135 sudo apt-get -q -y install libssl-dev libcurl4-openssl-dev \
136 libexpat-dev gettext zlib1g-dev sparse
ci/run-rust-checks.sh new
+12
@@ -0,0 +1,12 @@
1 +#!/bin/sh
2 +
3 +. ${0%/*}/lib.sh
4 +
5 +set +x
6 +
7 +if ! group "Check Rust formatting" cargo fmt --all --check
8 +then
9 + RET=1
10 +fi
11 +
12 +exit $RET