Skip to content

Commit 68de8ea

Browse files
committed
Add GitHub Action to test master rustfmt formatting vs a feature branch
This new action is intended to help us maintainers determine when feature branches cause breaking formatting changes by running rustfmt (master) and the feature branch on various rust repositories. Over time I expect the list of checked projects to increase. With this action in place we can more easily test that a new feature or bug fix doesn't introduce breaking changes. Although this action needs to be manually triggered right now, we might consider adding it to our CI runs in the future.
1 parent 3fa81c6 commit 68de8ea

File tree

2 files changed

+225
-0
lines changed

2 files changed

+225
-0
lines changed

.github/workflows/check_diff.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Diff Check
2+
on:
3+
workflow_dispatch:
4+
inputs:
5+
clone_url:
6+
description: 'Git url of a rustfmt fork to compare against the latest master rustfmt'
7+
required: true
8+
branch_name:
9+
description: 'Name of the feature branch on the forked repo'
10+
required: true
11+
commit_hash:
12+
description: 'Optional commit hash from the feature branch'
13+
required: false
14+
rustfmt_configs:
15+
description: 'Optional comma separated list of rustfmt config options to pass when running the feature branch'
16+
required: false
17+
18+
jobs:
19+
diff_check:
20+
runs-on: ubuntu-latest
21+
22+
steps:
23+
- name: checkout
24+
uses: actions/checkout@v3
25+
26+
- name: install rustup
27+
run: |
28+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
29+
sh rustup-init.sh -y --default-toolchain none
30+
rustup target add x86_64-unknown-linux-gnu
31+
32+
- name: check diff
33+
run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash }} ${{ github.event.inputs.rustfmt_configs }}

ci/check_diff.sh

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#!/bin/bash
2+
3+
function print_usage() {
4+
echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]"
5+
}
6+
7+
if [ $# -le 1 ]; then
8+
print_usage
9+
exit 1
10+
fi
11+
12+
REMOTE_REPO=$1
13+
FEATURE_BRANCH=$2
14+
OPTIONAL_COMMIT_HASH=$3
15+
OPTIONAL_RUSTFMT_CONFIGS=$4
16+
17+
# OUTPUT array used to collect all the status of running diffs on various repos
18+
STATUSES=()
19+
20+
# Clone a git repository and cd into it.
21+
#
22+
# Parameters:
23+
# $1: git clone url
24+
# $2: directory where the repo should be cloned
25+
function clone_repo() {
26+
GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2
27+
}
28+
29+
# Initialize Git submoduels for the repo.
30+
#
31+
# Parameters
32+
# $1: list of directories to initialize
33+
function init_submodules() {
34+
git submodule update --init $1
35+
}
36+
37+
# Run rusfmt with the --check flag to see if a diff is produced.
38+
#
39+
# Parameters:
40+
# $1: Path to a rustfmt binary
41+
# $2: Output file path for the diff
42+
# $3: Any additional configuration options to pass to rustfmt
43+
#
44+
# Globlas:
45+
# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
46+
function create_diff() {
47+
local config;
48+
if [ -z "$3" ]; then
49+
config="--config=error_on_line_overflow=false,error_on_unformatted=false"
50+
else
51+
config="--config=error_on_line_overflow=false,error_on_unformatted=false,$OPTIONAL_RUSTFMT_CONFIGS"
52+
fi
53+
54+
for i in `find . | grep "\.rs$"`
55+
do
56+
$1 --unstable-features --skip-children --check --color=always $config $i >> $2 2>/dev/null
57+
done
58+
}
59+
60+
# Run the master rustfmt binary and the feature branch binary in the current directory and compare the diffs
61+
#
62+
# Parameters
63+
# $1: Name of the repository (used for logging)
64+
#
65+
# Globlas:
66+
# $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt`
67+
# $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt`
68+
# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
69+
function check_diff() {
70+
echo "running rustfmt (master) on $1"
71+
create_diff $RUSFMT_BIN rustfmt_diff.txt
72+
73+
echo "running rustfmt (feature) on $1"
74+
create_diff $FEATURE_BIN feature_diff.txt $OPTIONAL_RUSTFMT_CONFIGS
75+
76+
echo "checking diff"
77+
local diff;
78+
diff=$(git --no-pager diff --color-words --unified=0 --no-index rustfmt_diff.txt feature_diff.txt 2>&1 | tail -n +6)
79+
80+
if [ -z "$diff" ]; then
81+
echo "no diff detected between rustfmt and the feture branch"
82+
return 0
83+
else
84+
echo "$diff"
85+
return 1
86+
fi
87+
}
88+
89+
# Compiles and produces two rustfmt binaries.
90+
# One for the current master, and another for the feature branch
91+
#
92+
# Parameters:
93+
# $1: Directory where rustfmt will be cloned
94+
#
95+
# Globlas:
96+
# $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test
97+
# $FEATURE_BRANCH: Name of the feature branch
98+
# $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided
99+
function compile_rustfmt() {
100+
RUSTFMT_REPO="https://github.com/rust-lang/rustfmt.git"
101+
clone_repo $RUSTFMT_REPO $1
102+
git remote add feature $REMOTE_REPO
103+
git fetch feature $FEATURE_BRANCH
104+
105+
cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
106+
if [ -z "$OPTIONAL_COMMIT_HASH" ]; then
107+
git switch $FEATURE_BRANCH
108+
else
109+
git switch $OPTIONAL_COMMIT_HASH --detach
110+
fi
111+
cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt
112+
RUSFMT_BIN=$1/rustfmt
113+
FEATURE_BIN=$1/feature_rustfmt
114+
}
115+
116+
# Check the diff for running rustfmt and the feature branch on all the .rs files in the repo.
117+
#
118+
# Parameters
119+
# $1: Clone URL for the repo
120+
# $2: Name of the repo (mostly used for logging)
121+
# $3: Path to any submodules that should be initialized
122+
function check_repo() {
123+
WORKDIR=$(pwd)
124+
REPO_URL=$1
125+
REPO_NAME=$2
126+
SUBMODULES=$3
127+
128+
local tmp_dir;
129+
tmp_dir=$(mktemp -d -t $REPO_NAME-XXXXXXXX)
130+
clone_repo $REPO_URL $tmp_dir
131+
132+
if [ ! -z "$SUBMODULES" ]; then
133+
init_submodules $SUBMODULES
134+
fi
135+
136+
check_diff $REPO_NAME
137+
# append the status of running `check_diff` to the STATUSES array
138+
STATUSES+=($?)
139+
140+
echo "removing tmp_dir $tmp_dir"
141+
rm -rf $tmp_dir
142+
cd $WORKDIR
143+
}
144+
145+
function main() {
146+
tmp_dir=$(mktemp -d -t rustfmt-XXXXXXXX)
147+
echo Created tmp_dir $tmp_dir
148+
149+
compile_rustfmt $tmp_dir
150+
151+
# run checks
152+
check_repo "https://github.com/rust-lang/rust.git" rust-lang-rust
153+
check_repo "https://github.com/rust-lang/cargo.git" cargo
154+
check_repo "https://github.com/rust-lang/miri.git" miri
155+
check_repo "https://github.com/rust-lang/rust-analyzer.git" rust-analyzer
156+
check_repo "https://github.com/bitflags/bitflags.git" bitflags
157+
check_repo "https://github.com/rust-lang/log.git" log
158+
check_repo "https://github.com/rust-lang/mdBook.git" mdBook
159+
check_repo "https://github.com/rust-lang/packed_simd.git" packed_simd
160+
check_repo "https://github.com/rust-lang/rust-semverver.git" check_repo
161+
check_repo "https://github.com/Stebalien/tempfile.git" tempfile
162+
check_repo "https://github.com/rust-lang/futures-rs.git" futures-rs
163+
check_repo "https://github.com/dtolnay/anyhow.git" anyhow
164+
check_repo "https://github.com/dtolnay/thiserror.git" thiserror
165+
check_repo "https://github.com/dtolnay/syn.git" syn
166+
check_repo "https://github.com/serde-rs/serde.git" serde
167+
check_repo "https://github.com/rust-lang/rustlings.git" rustlings
168+
check_repo "https://github.com/rust-lang/rustup.git" rustup
169+
check_repo "https://github.com/SergioBenitez/Rocket.git" Rocket
170+
check_repo "https://github.com/rustls/rustls.git" rustls
171+
check_repo "https://github.com/rust-lang/rust-bindgen.git" rust-bindgen
172+
check_repo "https://github.com/hyperium/hyper.git" hyper
173+
check_repo "https://github.com/actix/actix.git" actix
174+
check_repo "https://github.com/denoland/deno.git" denoland_deno
175+
176+
# cleanup temp dir
177+
echo removing tmp_dir $tmp_dir
178+
rm -rf $tmp_dir
179+
180+
# figure out the exit code
181+
for status in ${STATUSES[@]}
182+
do
183+
if [ $status -eq 1 ]; then
184+
echo "formatting diff found 💔"
185+
return 1
186+
fi
187+
done
188+
189+
echo "no diff found 😊"
190+
}
191+
192+
main

0 commit comments

Comments
 (0)