1use gh_workflow::{Concurrency, Event, Expression, PullRequest, Push, Run, Step, Use, Workflow};
2
3use super::{
4 runners::{self, Platform},
5 steps::{self, FluentBuilder, NamedJob, named, release_job},
6};
7
8fn str_vec(values: &'static [&'static str]) -> Vec<String> {
9 values.into_iter().map(ToString::to_string).collect()
10}
11
12pub(crate) fn run_tests_in(paths: &'static [&'static str], workflow: Workflow) -> Workflow {
13 let paths = str_vec(paths);
14 workflow
15 .add_event(Event::default()
16 .push(
17 Push::default()
18 .branches(
19 [
20 "main",
21 "v[0-9]+.[0-9]+.x", // any release branch
22 ]
23 .map(String::from),
24 )
25 .paths(paths.clone())
26 ,
27 )
28 .pull_request(
29 PullRequest::default().branches(
30 [
31 "**", // all branches
32 ]
33 .map(String::from),
34 )
35 .paths(paths),
36 ))
37 .concurrency(Concurrency::default()
38 .group("${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}")
39 .cancel_in_progress(true)
40 )
41 .add_env(( "CARGO_TERM_COLOR", "always" ))
42 .add_env(( "RUST_BACKTRACE", 1 ))
43 .add_env(( "CARGO_INCREMENTAL", 0 ))
44}
45
46pub(crate) fn run_tests() -> Workflow {
47 let windows_tests = run_platform_tests(Platform::Windows);
48 let linux_tests = run_platform_tests(Platform::Linux);
49 let mac_tests = run_platform_tests(Platform::Mac);
50 let migrations = check_postgres_and_protobuf_migrations();
51 let doctests = doctests();
52 let check_dependencies = check_dependencies();
53 let check_other_binaries = check_workspace_binaries();
54
55 named::workflow()
56 .map(|workflow| {
57 run_tests_in(
58 &[
59 "!docs/**",
60 "!script/update_top_ranking_issues/**",
61 "!.github/ISSUE_TEMPLATE/**",
62 "!.github/workflows/**",
63 ".github/workflows/run_tests.yml", // re-include this workflow so it re-runs when changed
64 ],
65 workflow,
66 )
67 })
68 .add_job(windows_tests.name, windows_tests.job)
69 .add_job(linux_tests.name, linux_tests.job)
70 .add_job(mac_tests.name, mac_tests.job)
71 .add_job(migrations.name, migrations.job)
72 .add_job(doctests.name, doctests.job)
73 .add_job(check_dependencies.name, check_dependencies.job)
74 .add_job(check_other_binaries.name, check_other_binaries.job)
75}
76
77fn check_dependencies() -> NamedJob {
78 fn install_cargo_machete() -> Step<Use> {
79 named::uses(
80 "clechasseur",
81 "rs-cargo",
82 "8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386", // v2
83 )
84 .add_with(("command", "install"))
85 .add_with(("args", "cargo-machete@0.7.0"))
86 }
87
88 fn run_cargo_machete() -> Step<Use> {
89 named::uses(
90 "clechasseur",
91 "rs-cargo",
92 "8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386", // v2
93 )
94 .add_with(("command", "machete"))
95 }
96
97 fn check_cargo_lock() -> Step<Run> {
98 named::bash("cargo update --locked --workspace")
99 }
100
101 fn check_vulnerable_dependencies() -> Step<Use> {
102 named::uses(
103 "actions",
104 "dependency-review-action",
105 "67d4f4bd7a9b17a0db54d2a7519187c65e339de8", // v4
106 )
107 .if_condition(Expression::new("github.event_name == 'pull_request'"))
108 .with(("license-check", false))
109 }
110
111 named::job(
112 release_job(&[])
113 .runs_on(runners::LINUX_SMALL)
114 .add_step(steps::checkout_repo())
115 .add_step(install_cargo_machete())
116 .add_step(run_cargo_machete())
117 .add_step(check_cargo_lock())
118 .add_step(check_vulnerable_dependencies()),
119 )
120}
121
122fn check_workspace_binaries() -> NamedJob {
123 named::job(
124 release_job(&[])
125 .runs_on(runners::LINUX_LARGE)
126 .add_step(steps::checkout_repo())
127 .add_step(steps::setup_cargo_config(Platform::Linux))
128 .map(steps::install_linux_dependencies)
129 .add_step(steps::script("cargo build -p collab"))
130 .add_step(steps::script("cargo build --workspace --bins --examples"))
131 .add_step(steps::cleanup_cargo_config(Platform::Linux)),
132 )
133}
134
135pub(crate) fn run_platform_tests(platform: Platform) -> NamedJob {
136 let runner = match platform {
137 Platform::Windows => runners::WINDOWS_DEFAULT,
138 Platform::Linux => runners::LINUX_DEFAULT,
139 Platform::Mac => runners::MAC_DEFAULT,
140 };
141 NamedJob {
142 name: format!("run_tests_{platform}"),
143 job: release_job(&[])
144 .runs_on(runner)
145 .add_step(steps::checkout_repo())
146 .add_step(steps::setup_cargo_config(platform))
147 .when(
148 platform == Platform::Linux,
149 steps::install_linux_dependencies,
150 )
151 .add_step(steps::setup_node())
152 .add_step(steps::clippy(platform))
153 .add_step(steps::cargo_install_nextest(platform))
154 .add_step(steps::clear_target_dir_if_large(platform))
155 .add_step(steps::cargo_nextest(platform))
156 .add_step(steps::cleanup_cargo_config(platform)),
157 }
158}
159
160pub(crate) fn check_postgres_and_protobuf_migrations() -> NamedJob {
161 fn remove_untracked_files() -> Step<Run> {
162 named::bash("git clean -df")
163 }
164
165 fn ensure_fresh_merge() -> Step<Run> {
166 named::bash(indoc::indoc! {r#"
167 if [ -z "$GITHUB_BASE_REF" ];
168 then
169 echo "BUF_BASE_BRANCH=$(git merge-base origin/main HEAD)" >> "$GITHUB_ENV"
170 else
171 git checkout -B temp
172 git merge -q "origin/$GITHUB_BASE_REF" -m "merge main into temp"
173 echo "BUF_BASE_BRANCH=$GITHUB_BASE_REF" >> "$GITHUB_ENV"
174 fi
175 "#})
176 }
177
178 fn bufbuild_setup_action() -> Step<Use> {
179 named::uses("bufbuild", "buf-setup-action", "v1").add_with(("version", "v1.29.0"))
180 }
181
182 fn bufbuild_breaking_action() -> Step<Use> {
183 named::uses("bufbuild", "buf-breaking-action", "v1").add_with(("input", "crates/proto/proto/"))
184 .add_with(("against", "https://github.com/${GITHUB_REPOSITORY}.git#branch=${BUF_BASE_BRANCH},subdir=crates/proto/proto/"))
185 }
186
187 named::job(
188 release_job(&[])
189 .runs_on(runners::MAC_DEFAULT)
190 .add_step(steps::checkout_repo().with(("fetch-depth", 0))) // fetch full history
191 .add_step(remove_untracked_files())
192 .add_step(ensure_fresh_merge())
193 .add_step(bufbuild_setup_action())
194 .add_step(bufbuild_breaking_action()),
195 )
196}
197
198fn doctests() -> NamedJob {
199 fn run_doctests() -> Step<Run> {
200 named::bash(indoc::indoc! {r#"
201 cargo test --workspace --doc --no-fail-fast
202 "#})
203 .id("run_doctests")
204 }
205
206 named::job(
207 release_job(&[])
208 .runs_on(runners::LINUX_DEFAULT)
209 .add_step(steps::checkout_repo())
210 .add_step(steps::cache_rust_dependencies())
211 .map(steps::install_linux_dependencies)
212 .add_step(steps::setup_cargo_config(Platform::Linux))
213 .add_step(run_doctests())
214 .add_step(steps::cleanup_cargo_config(Platform::Linux)),
215 )
216}