Skip to content

Commit 949da52

Browse files
ytmimicalebcartwright
authored andcommitted
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 ea017d7 commit 949da52

File tree

2 files changed

+232
-0
lines changed

2 files changed

+232
-0
lines changed

Diff for: .github/workflows/check_diff.yml

+33
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 }}

Diff for: ci/check_diff.sh

+199
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
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+
# we don't add color to the diff since we added color when running rustfmt --check.
79+
# tail -n + 6 removes the git diff header info
80+
# cut -c 2- removes the leading diff characters("+","-"," ") from running git diff.
81+
# Again, the diff output we care about was already added when we ran rustfmt --check
82+
diff=$(
83+
git --no-pager diff --color=never \
84+
--unified=0 --no-index rustfmt_diff.txt feature_diff.txt 2>&1 | tail -n +6 | cut -c 2-
85+
)
86+
87+
if [ -z "$diff" ]; then
88+
echo "no diff detected between rustfmt and the feture branch"
89+
return 0
90+
else
91+
echo "$diff"
92+
return 1
93+
fi
94+
}
95+
96+
# Compiles and produces two rustfmt binaries.
97+
# One for the current master, and another for the feature branch
98+
#
99+
# Parameters:
100+
# $1: Directory where rustfmt will be cloned
101+
#
102+
# Globlas:
103+
# $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test
104+
# $FEATURE_BRANCH: Name of the feature branch
105+
# $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided
106+
function compile_rustfmt() {
107+
RUSTFMT_REPO="https://github.com/rust-lang/rustfmt.git"
108+
clone_repo $RUSTFMT_REPO $1
109+
git remote add feature $REMOTE_REPO
110+
git fetch feature $FEATURE_BRANCH
111+
112+
cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
113+
if [ -z "$OPTIONAL_COMMIT_HASH" ]; then
114+
git switch $FEATURE_BRANCH
115+
else
116+
git switch $OPTIONAL_COMMIT_HASH --detach
117+
fi
118+
cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt
119+
RUSFMT_BIN=$1/rustfmt
120+
FEATURE_BIN=$1/feature_rustfmt
121+
}
122+
123+
# Check the diff for running rustfmt and the feature branch on all the .rs files in the repo.
124+
#
125+
# Parameters
126+
# $1: Clone URL for the repo
127+
# $2: Name of the repo (mostly used for logging)
128+
# $3: Path to any submodules that should be initialized
129+
function check_repo() {
130+
WORKDIR=$(pwd)
131+
REPO_URL=$1
132+
REPO_NAME=$2
133+
SUBMODULES=$3
134+
135+
local tmp_dir;
136+
tmp_dir=$(mktemp -d -t $REPO_NAME-XXXXXXXX)
137+
clone_repo $REPO_URL $tmp_dir
138+
139+
if [ ! -z "$SUBMODULES" ]; then
140+
init_submodules $SUBMODULES
141+
fi
142+
143+
check_diff $REPO_NAME
144+
# append the status of running `check_diff` to the STATUSES array
145+
STATUSES+=($?)
146+
147+
echo "removing tmp_dir $tmp_dir"
148+
rm -rf $tmp_dir
149+
cd $WORKDIR
150+
}
151+
152+
function main() {
153+
tmp_dir=$(mktemp -d -t rustfmt-XXXXXXXX)
154+
echo Created tmp_dir $tmp_dir
155+
156+
compile_rustfmt $tmp_dir
157+
158+
# run checks
159+
check_repo "https://github.com/rust-lang/rust.git" rust-lang-rust
160+
check_repo "https://github.com/rust-lang/cargo.git" cargo
161+
check_repo "https://github.com/rust-lang/miri.git" miri
162+
check_repo "https://github.com/rust-lang/rust-analyzer.git" rust-analyzer
163+
check_repo "https://github.com/bitflags/bitflags.git" bitflags
164+
check_repo "https://github.com/rust-lang/log.git" log
165+
check_repo "https://github.com/rust-lang/mdBook.git" mdBook
166+
check_repo "https://github.com/rust-lang/packed_simd.git" packed_simd
167+
check_repo "https://github.com/rust-lang/rust-semverver.git" check_repo
168+
check_repo "https://github.com/Stebalien/tempfile.git" tempfile
169+
check_repo "https://github.com/rust-lang/futures-rs.git" futures-rs
170+
check_repo "https://github.com/dtolnay/anyhow.git" anyhow
171+
check_repo "https://github.com/dtolnay/thiserror.git" thiserror
172+
check_repo "https://github.com/dtolnay/syn.git" syn
173+
check_repo "https://github.com/serde-rs/serde.git" serde
174+
check_repo "https://github.com/rust-lang/rustlings.git" rustlings
175+
check_repo "https://github.com/rust-lang/rustup.git" rustup
176+
check_repo "https://github.com/SergioBenitez/Rocket.git" Rocket
177+
check_repo "https://github.com/rustls/rustls.git" rustls
178+
check_repo "https://github.com/rust-lang/rust-bindgen.git" rust-bindgen
179+
check_repo "https://github.com/hyperium/hyper.git" hyper
180+
check_repo "https://github.com/actix/actix.git" actix
181+
check_repo "https://github.com/denoland/deno.git" denoland_deno
182+
183+
# cleanup temp dir
184+
echo removing tmp_dir $tmp_dir
185+
rm -rf $tmp_dir
186+
187+
# figure out the exit code
188+
for status in ${STATUSES[@]}
189+
do
190+
if [ $status -eq 1 ]; then
191+
echo "formatting diff found 💔"
192+
return 1
193+
fi
194+
done
195+
196+
echo "no diff found 😊"
197+
}
198+
199+
main

0 commit comments

Comments
 (0)