flowey_lib_common/
run_cargo_nextest_archive.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Build and archive cargo-nextest tests (for cross-job execution).
5//!
6//! Respects common cargo flags specified by the `cfg_cargo_common_flags` node.
7
8use crate::run_cargo_nextest_run::build_params::NextestBuildParams;
9use flowey::node::prelude::*;
10
11flowey_request! {
12    pub struct Request {
13        /// Friendly label for this request that shows up in logs.
14        pub friendly_label: String,
15        /// Directory to run `cargo nextest archive` within
16        pub working_dir: ReadVar<PathBuf>,
17        /// Build parameters to use when compiling the tests.
18        pub build_params: NextestBuildParams,
19        /// Wait for specified side-effects to resolve before building / running any
20        /// tests. (e.g: to allow for some ambient packages / dependencies to
21        /// get installed).
22        pub pre_run_deps: Vec<ReadVar<SideEffect>>,
23        /// Resulting nextest archive file
24        pub archive_file: WriteVar<PathBuf>,
25    }
26}
27
28new_flow_node!(struct Node);
29
30impl FlowNode for Node {
31    type Request = Request;
32
33    fn imports(ctx: &mut ImportCtx<'_>) {
34        ctx.import::<crate::cfg_cargo_common_flags::Node>();
35        ctx.import::<crate::install_cargo_nextest::Node>();
36        ctx.import::<crate::install_rust::Node>();
37    }
38
39    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
40        let cargo_flags = ctx.reqv(crate::cfg_cargo_common_flags::Request::GetFlags);
41
42        let nextest_installed = ctx.reqv(crate::install_cargo_nextest::Request);
43
44        let rust_toolchain = ctx.reqv(crate::install_rust::Request::GetRustupToolchain);
45
46        for Request {
47            friendly_label,
48            working_dir,
49            build_params:
50                NextestBuildParams {
51                    packages,
52                    features,
53                    no_default_features,
54                    target,
55                    profile,
56                    extra_env,
57                },
58            pre_run_deps,
59            archive_file,
60        } in requests
61        {
62            ctx.req(crate::install_rust::Request::InstallTargetTriple(
63                target.clone(),
64            ));
65
66            ctx.emit_rust_step(
67                format!("build + archive '{friendly_label}' nextests"),
68                |ctx| {
69                    pre_run_deps.claim(ctx);
70                    nextest_installed.clone().claim(ctx);
71                    let cargo_flags = cargo_flags.clone().claim(ctx);
72                    let rust_toolchain = rust_toolchain.clone().claim(ctx);
73                    let working_dir = working_dir.claim(ctx);
74                    let archive_file = archive_file.claim(ctx);
75                    let packages = packages.claim(ctx);
76                    let extra_env = extra_env.claim(ctx);
77                    move |rt| {
78                        let cargo_flags = rt.read(cargo_flags);
79                        let working_dir = rt.read(working_dir);
80                        let rust_toolchain = rt.read(rust_toolchain);
81                        let packages = rt.read(packages);
82                        let extra_env = rt.read(extra_env);
83
84                        let rust_toolchain = rust_toolchain.map(|s| format!("+{s}"));
85                        let (build_args, build_env) =
86                            crate::gen_cargo_nextest_run_cmd::cargo_nextest_build_args_and_env(
87                                cargo_flags,
88                                profile,
89                                target,
90                                packages,
91                                features,
92                                no_default_features,
93                                extra_env,
94                            );
95
96                        let sh = xshell::Shell::new()?;
97
98                        let out_archive_file = sh.current_dir().absolute()?.join("archive.tar.zst");
99
100                        sh.change_dir(working_dir);
101                        let mut cmd = xshell::cmd!(
102                            sh,
103                            "cargo {rust_toolchain...} nextest archive
104                                {build_args...}
105                                --archive-file {out_archive_file}
106                            "
107                        );
108
109                        // if running in CI, no need to waste time with incremental
110                        // build artifacts
111                        if !matches!(rt.backend(), FlowBackend::Local) {
112                            cmd = cmd.env("CARGO_INCREMENTAL", "0");
113                        }
114
115                        for (k, v) in build_env {
116                            cmd = cmd.env(k, v);
117                        }
118
119                        cmd.run()?;
120
121                        rt.write(archive_file, &out_archive_file);
122
123                        Ok(())
124                    }
125                },
126            );
127        }
128
129        Ok(())
130    }
131}