flowey_hvlite/pipelines/
checkin_gates.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! See [`CheckinGatesCli`]
5
6use flowey::node::prelude::FlowPlatformLinuxDistro;
7use flowey::node::prelude::GhPermission;
8use flowey::node::prelude::GhPermissionValue;
9use flowey::node::prelude::ReadVar;
10use flowey::pipeline::prelude::*;
11use flowey_lib_common::git_checkout::RepoSource;
12use flowey_lib_hvlite::_jobs::build_and_publish_openhcl_igvm_from_recipe::OpenhclIgvmBuildParams;
13use flowey_lib_hvlite::build_openhcl_igvm_from_recipe::OpenhclIgvmRecipe;
14use flowey_lib_hvlite::build_openvmm_hcl::OpenvmmHclBuildProfile;
15use flowey_lib_hvlite::run_cargo_build::common::CommonArch;
16use flowey_lib_hvlite::run_cargo_build::common::CommonPlatform;
17use flowey_lib_hvlite::run_cargo_build::common::CommonProfile;
18use flowey_lib_hvlite::run_cargo_build::common::CommonTriple;
19use std::path::PathBuf;
20use target_lexicon::Triple;
21use vmm_test_images::KnownTestArtifacts;
22
23#[derive(Copy, Clone, clap::ValueEnum)]
24enum PipelineConfig {
25    /// Run on all PRs targeting the OpenVMM GitHub repo.
26    Pr,
27    /// Run on all commits that land in a branch.
28    ///
29    /// The key difference between the CI and PR pipelines is whether things are
30    /// being built in `release` mode.
31    Ci,
32    /// Release variant of the `Pr` pipeline.
33    PrRelease,
34}
35
36/// A unified pipeline defining all checkin gates required to land a commit in
37/// the OpenVMM repo.
38#[derive(clap::Args)]
39pub struct CheckinGatesCli {
40    /// Which pipeline configuration to use.
41    #[clap(long)]
42    config: PipelineConfig,
43
44    #[clap(flatten)]
45    local_run_args: Option<crate::pipelines_shared::cfg_common_params::LocalRunArgs>,
46
47    /// Set custom path to search for / download VMM tests disk-images
48    #[clap(long)]
49    vmm_tests_disk_cache_dir: Option<PathBuf>,
50}
51
52impl IntoPipeline for CheckinGatesCli {
53    fn into_pipeline(self, backend_hint: PipelineBackendHint) -> anyhow::Result<Pipeline> {
54        let Self {
55            config,
56            local_run_args,
57            vmm_tests_disk_cache_dir,
58        } = self;
59
60        let release = match config {
61            PipelineConfig::Ci | PipelineConfig::PrRelease => true,
62            PipelineConfig::Pr => false,
63        };
64
65        let mut pipeline = Pipeline::new();
66
67        // configure pr/ci branch triggers and add gh pipeline name
68        {
69            let branches = vec!["main".into(), "release/*".into()];
70            match config {
71                PipelineConfig::Ci => {
72                    pipeline
73                        .gh_set_ci_triggers(GhCiTriggers {
74                            branches,
75                            ..Default::default()
76                        })
77                        .gh_set_name("[flowey] OpenVMM CI");
78                }
79                PipelineConfig::Pr => {
80                    pipeline
81                        .gh_set_pr_triggers(GhPrTriggers {
82                            branches,
83                            ..GhPrTriggers::new_draftable()
84                        })
85                        .gh_set_name("[flowey] OpenVMM PR");
86                }
87                PipelineConfig::PrRelease => {
88                    // This workflow is triggered manually.
89                    pipeline.gh_set_name("[flowey] OpenVMM Release PR");
90                }
91            }
92        }
93
94        let openvmm_repo_source = {
95            if matches!(backend_hint, PipelineBackendHint::Local) {
96                RepoSource::ExistingClone(ReadVar::from_static(crate::repo_root()))
97            } else if matches!(backend_hint, PipelineBackendHint::Github) {
98                RepoSource::GithubSelf
99            } else {
100                anyhow::bail!(
101                    "Unsupported backend: Checkin Gates only supports Local and Github backends"
102                );
103            }
104        };
105
106        if let RepoSource::GithubSelf = &openvmm_repo_source {
107            pipeline.gh_set_flowey_bootstrap_template(
108                crate::pipelines_shared::gh_flowey_bootstrap_template::get_template(),
109            );
110        }
111
112        let cfg_common_params = crate::pipelines_shared::cfg_common_params::get_cfg_common_params(
113            &mut pipeline,
114            backend_hint,
115            local_run_args,
116        )?;
117
118        pipeline.inject_all_jobs_with(move |job| {
119            job.dep_on(&cfg_common_params)
120                .dep_on(|_| flowey_lib_hvlite::_jobs::cfg_versions::Request {})
121                .dep_on(
122                    |_| flowey_lib_hvlite::_jobs::cfg_hvlite_reposource::Params {
123                        hvlite_repo_source: openvmm_repo_source.clone(),
124                    },
125                )
126                .gh_grant_permissions::<flowey_lib_common::git_checkout::Node>([(
127                    GhPermission::Contents,
128                    GhPermissionValue::Read,
129                )])
130                .gh_grant_permissions::<flowey_lib_common::gh_task_azure_login::Node>([(
131                    GhPermission::IdToken,
132                    GhPermissionValue::Write,
133                )])
134        });
135
136        let openhcl_musl_target = |arch: CommonArch| -> Triple {
137            CommonTriple::Common {
138                arch,
139                platform: CommonPlatform::LinuxMusl,
140            }
141            .as_triple()
142        };
143
144        // initialize the various VMM tests nextest archive artifacts
145        let (pub_vmm_tests_archive_linux_x86, use_vmm_tests_archive_linux_x86) =
146            pipeline.new_typed_artifact("x64-linux-vmm-tests-archive");
147        let (pub_vmm_tests_archive_windows_x86, use_vmm_tests_archive_windows_x86) =
148            pipeline.new_typed_artifact("x64-windows-vmm-tests-archive");
149        let (pub_vmm_tests_archive_windows_aarch64, use_vmm_tests_archive_windows_aarch64) =
150            pipeline.new_typed_artifact("aarch64-windows-vmm-tests-archive");
151
152        // wrap each publish handle in an option, so downstream code can
153        // `.take()` the handle when emitting the corresponding job
154        let mut pub_vmm_tests_archive_linux_x86 = Some(pub_vmm_tests_archive_linux_x86);
155        let mut pub_vmm_tests_archive_windows_x86 = Some(pub_vmm_tests_archive_windows_x86);
156        let mut pub_vmm_tests_archive_windows_aarch64 = Some(pub_vmm_tests_archive_windows_aarch64);
157
158        // initialize the various "VmmTestsArtifactsBuilder" containers, which
159        // are used to "skim off" various artifacts that the VMM test jobs
160        // require.
161        let mut vmm_tests_artifacts_linux_x86 =
162            vmm_tests_artifact_builders::VmmTestsArtifactsBuilderLinuxX86::default();
163        let mut vmm_tests_artifacts_windows_x86 =
164            vmm_tests_artifact_builders::VmmTestsArtifactsBuilderWindowsX86::default();
165        let mut vmm_tests_artifacts_windows_aarch64 =
166            vmm_tests_artifact_builders::VmmTestsArtifactsBuilderWindowsAarch64::default();
167
168        // We need to maintain a list of all jobs, so we can hang the "all good"
169        // job off of them. This is requires because github status checks only allow
170        // specifying jobs, and not workflows.
171        // There's more info in the following discussion:
172        // <https://github.com/orgs/community/discussions/12395>
173        let mut all_jobs = Vec::new();
174
175        // emit xtask fmt job
176        {
177            let windows_fmt_job = pipeline
178                .new_job(
179                    FlowPlatform::Windows,
180                    FlowArch::X86_64,
181                    "xtask fmt (windows)",
182                )
183                .gh_set_pool(crate::pipelines_shared::gh_pools::default_gh_hosted(
184                    FlowPlatform::Windows,
185                ))
186                .dep_on(|ctx| flowey_lib_hvlite::_jobs::check_xtask_fmt::Request {
187                    target: CommonTriple::X86_64_WINDOWS_MSVC,
188                    done: ctx.new_done_handle(),
189                })
190                .finish();
191
192            let linux_fmt_job = pipeline
193                .new_job(
194                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
195                    FlowArch::X86_64,
196                    "xtask fmt (linux)",
197                )
198                .gh_set_pool(crate::pipelines_shared::gh_pools::default_x86_pool(
199                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
200                ))
201                .dep_on(|ctx| flowey_lib_hvlite::_jobs::check_xtask_fmt::Request {
202                    target: CommonTriple::X86_64_LINUX_GNU,
203                    done: ctx.new_done_handle(),
204                })
205                .finish();
206
207            // cut down on extra noise by having the linux check run first, and
208            // then if it passes, run the windows checks just in case there is a
209            // difference between the two.
210            pipeline.non_artifact_dep(&windows_fmt_job, &linux_fmt_job);
211
212            all_jobs.push(linux_fmt_job);
213            all_jobs.push(windows_fmt_job);
214        }
215
216        // emit windows build machine jobs
217        //
218        // In order to ensure we start running VMM tests as soon as possible, we emit
219        // two separate windows job per arch - one for artifacts in the VMM tests
220        // hotpath, and another for any auxiliary artifacts that aren't
221        // required by VMM tests.
222        for arch in [CommonArch::Aarch64, CommonArch::X86_64] {
223            let arch_tag = match arch {
224                CommonArch::X86_64 => "x64",
225                CommonArch::Aarch64 => "aarch64",
226            };
227
228            // artifacts which _are_ in the VMM tests "hot path"
229            let (pub_openvmm, use_openvmm) =
230                pipeline.new_typed_artifact(format!("{arch_tag}-windows-openvmm"));
231
232            let (pub_pipette_windows, use_pipette_windows) =
233                pipeline.new_typed_artifact(format!("{arch_tag}-windows-pipette"));
234
235            let (pub_tmk_vmm, use_tmk_vmm) =
236                pipeline.new_typed_artifact(format!("{arch_tag}-windows-tmk_vmm"));
237
238            // filter off interesting artifacts required by the VMM tests job
239            match arch {
240                CommonArch::X86_64 => {
241                    vmm_tests_artifacts_linux_x86.use_pipette_windows =
242                        Some(use_pipette_windows.clone());
243                    vmm_tests_artifacts_windows_x86.use_openvmm = Some(use_openvmm.clone());
244                    vmm_tests_artifacts_windows_x86.use_pipette_windows =
245                        Some(use_pipette_windows.clone());
246                    vmm_tests_artifacts_windows_x86.use_tmk_vmm = Some(use_tmk_vmm.clone());
247                }
248                CommonArch::Aarch64 => {
249                    vmm_tests_artifacts_windows_aarch64.use_openvmm = Some(use_openvmm.clone());
250                    vmm_tests_artifacts_windows_aarch64.use_pipette_windows =
251                        Some(use_pipette_windows.clone());
252                    vmm_tests_artifacts_windows_aarch64.use_tmk_vmm = Some(use_tmk_vmm.clone());
253                }
254            }
255            // emit a job for artifacts which _are not_ in the VMM tests "hot
256            // path"
257            // artifacts which _are not_ in the VMM tests "hot path"
258            let (pub_igvmfilegen, _use_igvmfilegen) =
259                pipeline.new_typed_artifact(format!("{arch_tag}-windows-igvmfilegen"));
260            let (pub_vmgs_lib, _use_vmgs_lib) =
261                pipeline.new_typed_artifact(format!("{arch_tag}-windows-vmgs_lib"));
262            let (pub_vmgstool, _use_vmgstool) =
263                pipeline.new_typed_artifact(format!("{arch_tag}-windows-vmgstool"));
264            let (pub_hypestv, _use_hypestv) =
265                pipeline.new_typed_artifact(format!("{arch_tag}-windows-hypestv"));
266            let (pub_ohcldiag_dev, _use_ohcldiag_dev) =
267                pipeline.new_typed_artifact(format!("{arch_tag}-windows-ohcldiag-dev"));
268
269            let job = pipeline
270                .new_job(
271                    FlowPlatform::Windows,
272                    FlowArch::X86_64,
273                    format!("build artifacts (not for VMM tests) [{arch_tag}-windows]"),
274                )
275                .gh_set_pool(crate::pipelines_shared::gh_pools::default_x86_pool(
276                    FlowPlatform::Windows,
277                ))
278                .dep_on(|ctx| flowey_lib_hvlite::build_vmgstool::Request {
279                    target: CommonTriple::Common {
280                        arch,
281                        platform: CommonPlatform::WindowsMsvc,
282                    },
283                    profile: CommonProfile::from_release(release),
284                    with_crypto: true,
285                    vmgstool: ctx.publish_typed_artifact(pub_vmgstool),
286                })
287                .dep_on(|ctx| flowey_lib_hvlite::build_hypestv::Request {
288                    target: CommonTriple::Common {
289                        arch,
290                        platform: CommonPlatform::WindowsMsvc,
291                    },
292                    profile: CommonProfile::from_release(release),
293                    hypestv: ctx.publish_typed_artifact(pub_hypestv),
294                })
295                .dep_on(|ctx| flowey_lib_hvlite::build_and_test_vmgs_lib::Request {
296                    target: CommonTriple::Common {
297                        arch,
298                        platform: CommonPlatform::WindowsMsvc,
299                    },
300                    profile: CommonProfile::from_release(release),
301                    vmgs_lib: ctx.publish_typed_artifact(pub_vmgs_lib),
302                })
303                .dep_on(|ctx| flowey_lib_hvlite::build_igvmfilegen::Request {
304                    build_params: flowey_lib_hvlite::build_igvmfilegen::IgvmfilegenBuildParams {
305                        target: CommonTriple::Common {
306                            arch,
307                            platform: CommonPlatform::WindowsMsvc,
308                        },
309                        profile: CommonProfile::from_release(release).into(),
310                    },
311                    igvmfilegen: ctx.publish_typed_artifact(pub_igvmfilegen),
312                })
313                .dep_on(|ctx| flowey_lib_hvlite::build_ohcldiag_dev::Request {
314                    target: CommonTriple::Common {
315                        arch,
316                        platform: CommonPlatform::WindowsMsvc,
317                    },
318                    profile: CommonProfile::from_release(release),
319                    ohcldiag_dev: ctx.publish_typed_artifact(pub_ohcldiag_dev),
320                })
321                .dep_on(|ctx| flowey_lib_hvlite::build_tmk_vmm::Request {
322                    target: CommonTriple::Common {
323                        arch,
324                        platform: CommonPlatform::WindowsMsvc,
325                    },
326                    unstable_whp: true, // The ARM64 CI runner supports the unstable WHP interface
327                    profile: CommonProfile::from_release(release),
328                    tmk_vmm: ctx.publish_typed_artifact(pub_tmk_vmm),
329                });
330
331            all_jobs.push(job.finish());
332
333            // emit a job for artifacts which _are_ in the VMM tests "hot path"
334            let mut job = pipeline
335                .new_job(
336                    FlowPlatform::Windows,
337                    FlowArch::X86_64,
338                    format!("build artifacts (for VMM tests) [{arch_tag}-windows]"),
339                )
340                .gh_set_pool(crate::pipelines_shared::gh_pools::default_gh_hosted(
341                    FlowPlatform::Windows,
342                ))
343                .dep_on(|ctx| {
344                    flowey_lib_hvlite::build_openvmm::Request {
345                        params: flowey_lib_hvlite::build_openvmm::OpenvmmBuildParams {
346                            target: CommonTriple::Common {
347                                arch,
348                                platform: CommonPlatform::WindowsMsvc,
349                            },
350                            profile: CommonProfile::from_release(release),
351                            // FIXME: this relies on openvmm default features
352                            // Our ARM test runners need the latest WHP changes
353                            features: if matches!(arch, CommonArch::Aarch64) {
354                                [flowey_lib_hvlite::build_openvmm::OpenvmmFeature::UnstableWhp]
355                                    .into()
356                            } else {
357                                [].into()
358                            },
359                        },
360                        openvmm: ctx.publish_typed_artifact(pub_openvmm),
361                    }
362                })
363                .dep_on(|ctx| flowey_lib_hvlite::build_pipette::Request {
364                    target: CommonTriple::Common {
365                        arch,
366                        platform: CommonPlatform::WindowsMsvc,
367                    },
368                    profile: CommonProfile::from_release(release),
369                    pipette: ctx.publish_typed_artifact(pub_pipette_windows),
370                });
371
372            // Hang building the windows VMM tests off this big windows job.
373            match arch {
374                CommonArch::X86_64 => {
375                    let pub_vmm_tests_archive_windows_x86 =
376                        pub_vmm_tests_archive_windows_x86.take().unwrap();
377                    job = job.dep_on(|ctx|
378                        flowey_lib_hvlite::build_nextest_vmm_tests::Request {
379                        target: CommonTriple::X86_64_WINDOWS_MSVC.as_triple(),
380                        profile: CommonProfile::from_release(release),
381                        build_mode: flowey_lib_hvlite::build_nextest_vmm_tests::BuildNextestVmmTestsMode::Archive(
382                            ctx.publish_typed_artifact(pub_vmm_tests_archive_windows_x86),
383                        ),
384                    });
385                }
386                CommonArch::Aarch64 => {
387                    let pub_vmm_tests_archive_windows_aarch64 =
388                        pub_vmm_tests_archive_windows_aarch64.take().unwrap();
389                    job = job.dep_on(|ctx| flowey_lib_hvlite::build_nextest_vmm_tests::Request {
390                        target: CommonTriple::AARCH64_WINDOWS_MSVC.as_triple(),
391                        profile: CommonProfile::from_release(release),
392                        build_mode: flowey_lib_hvlite::build_nextest_vmm_tests::BuildNextestVmmTestsMode::Archive(
393                            ctx.publish_typed_artifact(pub_vmm_tests_archive_windows_aarch64),
394                        ),
395                    });
396                }
397            }
398
399            all_jobs.push(job.finish());
400        }
401
402        // emit linux build machine jobs (without openhcl)
403        for arch in [CommonArch::Aarch64, CommonArch::X86_64] {
404            let arch_tag = match arch {
405                CommonArch::X86_64 => "x64",
406                CommonArch::Aarch64 => "aarch64",
407            };
408
409            let (pub_openvmm, use_openvmm) =
410                pipeline.new_typed_artifact(format!("{arch_tag}-linux-openvmm"));
411            let (pub_igvmfilegen, _) =
412                pipeline.new_typed_artifact(format!("{arch_tag}-linux-igvmfilegen"));
413            let (pub_vmgs_lib, _) =
414                pipeline.new_typed_artifact(format!("{arch_tag}-linux-vmgs_lib"));
415            let (pub_vmgstool, _) =
416                pipeline.new_typed_artifact(format!("{arch_tag}-linux-vmgstool"));
417            let (pub_ohcldiag_dev, _) =
418                pipeline.new_typed_artifact(format!("{arch_tag}-linux-ohcldiag-dev"));
419            let (pub_tmks, use_tmks) = pipeline.new_typed_artifact(format!("{arch_tag}-tmks"));
420
421            // NOTE: the choice to build it as part of this linux job was pretty
422            // arbitrary. It could just as well hang off the windows job.
423            //
424            // At this time though, having it here results in a net-reduction in
425            // E2E pipeline times, owing to how the VMM tests artifact dependency
426            // graph looks like.
427            let (pub_guest_test_uefi, use_guest_test_uefi) =
428                pipeline.new_typed_artifact(format!("{arch_tag}-guest_test_uefi"));
429
430            // skim off interesting artifacts required by the VMM tests job
431            match arch {
432                CommonArch::X86_64 => {
433                    vmm_tests_artifacts_linux_x86.use_openvmm = Some(use_openvmm.clone());
434                    vmm_tests_artifacts_linux_x86.use_guest_test_uefi =
435                        Some(use_guest_test_uefi.clone());
436                    vmm_tests_artifacts_windows_x86.use_guest_test_uefi =
437                        Some(use_guest_test_uefi.clone());
438                    vmm_tests_artifacts_windows_x86.use_tmks = Some(use_tmks.clone());
439                    vmm_tests_artifacts_linux_x86.use_tmks = Some(use_tmks.clone());
440                }
441                CommonArch::Aarch64 => {
442                    vmm_tests_artifacts_windows_aarch64.use_guest_test_uefi =
443                        Some(use_guest_test_uefi.clone());
444                    vmm_tests_artifacts_windows_aarch64.use_tmks = Some(use_tmks.clone());
445                }
446            }
447
448            let mut job = pipeline
449                .new_job(
450                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
451                    FlowArch::X86_64,
452                    format!("build artifacts [{arch_tag}-linux]"),
453                )
454                .gh_set_pool(crate::pipelines_shared::gh_pools::default_x86_pool(
455                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
456                ))
457                .dep_on(|ctx| {
458                    flowey_lib_hvlite::build_openvmm::Request {
459                        params: flowey_lib_hvlite::build_openvmm::OpenvmmBuildParams {
460                            target: CommonTriple::Common {
461                                arch,
462                                platform: CommonPlatform::LinuxGnu,
463                            },
464                            profile: CommonProfile::from_release(release),
465                            // FIXME: this relies on openvmm default features
466                            features: [flowey_lib_hvlite::build_openvmm::OpenvmmFeature::Tpm]
467                                .into(),
468                        },
469                        openvmm: ctx.publish_typed_artifact(pub_openvmm),
470                    }
471                })
472                .dep_on(|ctx| flowey_lib_hvlite::build_vmgstool::Request {
473                    target: CommonTriple::Common {
474                        arch,
475                        platform: CommonPlatform::LinuxGnu,
476                    },
477                    profile: CommonProfile::from_release(release),
478                    with_crypto: true,
479                    vmgstool: ctx.publish_typed_artifact(pub_vmgstool),
480                })
481                .dep_on(|ctx| flowey_lib_hvlite::build_and_test_vmgs_lib::Request {
482                    target: CommonTriple::Common {
483                        arch,
484                        platform: CommonPlatform::LinuxGnu,
485                    },
486                    profile: CommonProfile::from_release(release),
487                    vmgs_lib: ctx.publish_typed_artifact(pub_vmgs_lib),
488                })
489                .dep_on(|ctx| flowey_lib_hvlite::build_igvmfilegen::Request {
490                    build_params: flowey_lib_hvlite::build_igvmfilegen::IgvmfilegenBuildParams {
491                        target: CommonTriple::Common {
492                            arch,
493                            platform: CommonPlatform::LinuxGnu,
494                        },
495                        profile: CommonProfile::from_release(release).into(),
496                    },
497                    igvmfilegen: ctx.publish_typed_artifact(pub_igvmfilegen),
498                })
499                .dep_on(|ctx| flowey_lib_hvlite::build_ohcldiag_dev::Request {
500                    target: CommonTriple::Common {
501                        arch,
502                        platform: CommonPlatform::LinuxGnu,
503                    },
504                    profile: CommonProfile::from_release(release),
505                    ohcldiag_dev: ctx.publish_typed_artifact(pub_ohcldiag_dev),
506                })
507                .dep_on(|ctx| flowey_lib_hvlite::build_guest_test_uefi::Request {
508                    arch,
509                    profile: CommonProfile::from_release(release),
510                    guest_test_uefi: ctx.publish_typed_artifact(pub_guest_test_uefi),
511                })
512                .dep_on(|ctx| flowey_lib_hvlite::build_tmks::Request {
513                    arch,
514                    profile: CommonProfile::from_release(release),
515                    tmks: ctx.publish_typed_artifact(pub_tmks),
516                });
517
518            // Hang building the linux VMM tests off this big linux job.
519            //
520            // No ARM64 VMM tests yet
521            if matches!(arch, CommonArch::X86_64) {
522                let pub_vmm_tests_archive_linux_x86 =
523                    pub_vmm_tests_archive_linux_x86.take().unwrap();
524                job = job.dep_on(|ctx| flowey_lib_hvlite::build_nextest_vmm_tests::Request {
525                    target: CommonTriple::X86_64_LINUX_GNU.as_triple(),
526                    profile: CommonProfile::from_release(release),
527                    build_mode: flowey_lib_hvlite::build_nextest_vmm_tests::BuildNextestVmmTestsMode::Archive(
528                        ctx.publish_typed_artifact(pub_vmm_tests_archive_linux_x86),
529                    ),
530                });
531            }
532
533            all_jobs.push(job.finish());
534        }
535
536        // emit openhcl build job
537        for arch in [CommonArch::Aarch64, CommonArch::X86_64] {
538            let arch_tag = match arch {
539                CommonArch::X86_64 => "x64",
540                CommonArch::Aarch64 => "aarch64",
541            };
542
543            let openvmm_hcl_profile = if release {
544                OpenvmmHclBuildProfile::OpenvmmHclShip
545            } else {
546                OpenvmmHclBuildProfile::Debug
547            };
548
549            let (pub_openhcl_igvm, use_openhcl_igvm) =
550                pipeline.new_artifact(format!("{arch_tag}-openhcl-igvm"));
551            let (pub_openhcl_igvm_extras, _use_openhcl_igvm_extras) =
552                pipeline.new_artifact(format!("{arch_tag}-openhcl-igvm-extras"));
553
554            let (pub_openhcl_baseline, _use_openhcl_baseline) =
555                if matches!(config, PipelineConfig::Ci) {
556                    let (p, u) = pipeline.new_artifact(format!("{arch_tag}-openhcl-baseline"));
557                    (Some(p), Some(u))
558                } else {
559                    (None, None)
560                };
561
562            // also build pipette musl on this job, as until we land the
563            // refactor that allows building musl without the full openhcl
564            // toolchain, it would require pulling in all the openhcl
565            // toolchain deps...
566            let (pub_pipette_linux_musl, use_pipette_linux_musl) =
567                pipeline.new_typed_artifact(format!("{arch_tag}-linux-musl-pipette"));
568
569            let (pub_tmk_vmm, use_tmk_vmm) =
570                pipeline.new_typed_artifact(format!("{arch_tag}-linux-musl-tmk_vmm"));
571
572            // skim off interesting artifacts required by the VMM tests job
573            match arch {
574                CommonArch::X86_64 => {
575                    vmm_tests_artifacts_windows_x86.use_openhcl_igvm_files =
576                        Some(use_openhcl_igvm.clone());
577                    vmm_tests_artifacts_windows_x86.use_pipette_linux_musl =
578                        Some(use_pipette_linux_musl.clone());
579                    vmm_tests_artifacts_linux_x86.use_pipette_linux_musl =
580                        Some(use_pipette_linux_musl.clone());
581                    vmm_tests_artifacts_linux_x86.use_tmk_vmm = Some(use_tmk_vmm.clone());
582                    vmm_tests_artifacts_windows_x86.use_tmk_vmm_linux_musl =
583                        Some(use_tmk_vmm.clone());
584                }
585                CommonArch::Aarch64 => {
586                    vmm_tests_artifacts_windows_aarch64.use_openhcl_igvm_files =
587                        Some(use_openhcl_igvm.clone());
588                    vmm_tests_artifacts_windows_aarch64.use_pipette_linux_musl =
589                        Some(use_pipette_linux_musl.clone());
590                    vmm_tests_artifacts_windows_aarch64.use_tmk_vmm_linux_musl =
591                        Some(use_tmk_vmm.clone());
592                }
593            }
594            let igvm_recipes = match arch {
595                CommonArch::X86_64 => vec![
596                    OpenhclIgvmRecipe::X64,
597                    OpenhclIgvmRecipe::X64Devkern,
598                    OpenhclIgvmRecipe::X64TestLinuxDirect,
599                    OpenhclIgvmRecipe::X64TestLinuxDirectDevkern,
600                    OpenhclIgvmRecipe::X64Cvm,
601                ],
602                CommonArch::Aarch64 => {
603                    vec![
604                        OpenhclIgvmRecipe::Aarch64,
605                        OpenhclIgvmRecipe::Aarch64Devkern,
606                    ]
607                }
608            };
609
610            let job = pipeline
611                .new_job(
612                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
613                    FlowArch::X86_64,
614                    format!("build openhcl [{arch_tag}-linux]"),
615                )
616                .gh_set_pool(crate::pipelines_shared::gh_pools::default_x86_pool(
617                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
618                ))
619                .dep_on(|ctx| {
620                    let publish_baseline_artifact = pub_openhcl_baseline
621                        .map(|baseline_artifact| ctx.publish_artifact(baseline_artifact));
622
623                    flowey_lib_hvlite::_jobs::build_and_publish_openhcl_igvm_from_recipe::Params {
624                        igvm_files: igvm_recipes
625                            .clone()
626                            .into_iter()
627                            .map(|recipe| OpenhclIgvmBuildParams {
628                                profile: openvmm_hcl_profile,
629                                recipe,
630                                custom_target: Some(CommonTriple::Custom(openhcl_musl_target(
631                                    arch,
632                                ))),
633                            })
634                            .collect(),
635                        artifact_dir_openhcl_igvm: ctx.publish_artifact(pub_openhcl_igvm),
636                        artifact_dir_openhcl_igvm_extras: ctx
637                            .publish_artifact(pub_openhcl_igvm_extras),
638                        artifact_openhcl_verify_size_baseline: publish_baseline_artifact,
639                        done: ctx.new_done_handle(),
640                    }
641                })
642                .dep_on(|ctx| flowey_lib_hvlite::build_pipette::Request {
643                    target: CommonTriple::Common {
644                        arch,
645                        platform: CommonPlatform::LinuxMusl,
646                    },
647                    profile: CommonProfile::from_release(release),
648                    pipette: ctx.publish_typed_artifact(pub_pipette_linux_musl),
649                })
650                .dep_on(|ctx| flowey_lib_hvlite::build_tmk_vmm::Request {
651                    target: CommonTriple::Common {
652                        arch,
653                        platform: CommonPlatform::LinuxMusl,
654                    },
655                    profile: CommonProfile::from_release(release),
656                    unstable_whp: false,
657                    tmk_vmm: ctx.publish_typed_artifact(pub_tmk_vmm),
658                });
659
660            all_jobs.push(job.finish());
661
662            if arch == CommonArch::X86_64 && matches!(config, PipelineConfig::Pr) {
663                let job = pipeline
664                    .new_job(
665                        FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
666                        FlowArch::X86_64,
667                        format!("verify openhcl binary size [{}]", arch_tag),
668                    )
669                    .gh_set_pool(crate::pipelines_shared::gh_pools::default_x86_pool(
670                        FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
671                    ))
672                    .dep_on(
673                        |ctx| flowey_lib_hvlite::_jobs::check_openvmm_hcl_size::Request {
674                            target: CommonTriple::Common {
675                                arch,
676                                platform: CommonPlatform::LinuxMusl,
677                            },
678                            done: ctx.new_done_handle(),
679                            pipeline_name: "openvmm-ci.yaml".into(),
680                        },
681                    )
682                    .finish();
683                all_jobs.push(job);
684            }
685        }
686
687        // Emit clippy + unit-test jobs
688        //
689        // The only reason we bundle clippy and unit-tests together is to avoid
690        // requiring another build agent.
691        struct ClippyUnitTestJobParams<'a> {
692            platform: FlowPlatform,
693            arch: FlowArch,
694            gh_pool: GhRunner,
695            clippy_targets: Option<(&'a str, &'a [(Triple, bool)])>,
696            unit_test_target: Option<(&'a str, Triple)>,
697        }
698
699        for ClippyUnitTestJobParams {
700            platform,
701            arch,
702            gh_pool,
703            clippy_targets,
704            unit_test_target,
705        } in [
706            ClippyUnitTestJobParams {
707                platform: FlowPlatform::Windows,
708                arch: FlowArch::X86_64,
709                gh_pool: crate::pipelines_shared::gh_pools::windows_amd_self_hosted(),
710                clippy_targets: Some((
711                    "windows",
712                    &[
713                        (target_lexicon::triple!("x86_64-pc-windows-msvc"), false),
714                        (target_lexicon::triple!("aarch64-pc-windows-msvc"), false),
715                    ],
716                )),
717                unit_test_target: Some((
718                    "x64-windows",
719                    target_lexicon::triple!("x86_64-pc-windows-msvc"),
720                )),
721            },
722            ClippyUnitTestJobParams {
723                platform: FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
724                arch: FlowArch::X86_64,
725                gh_pool: crate::pipelines_shared::gh_pools::linux_self_hosted(),
726                clippy_targets: Some((
727                    "linux, macos",
728                    &[
729                        (target_lexicon::triple!("x86_64-unknown-linux-gnu"), false),
730                        (target_lexicon::triple!("aarch64-unknown-linux-gnu"), false),
731                        (target_lexicon::triple!("aarch64-apple-darwin"), false),
732                    ],
733                )),
734                unit_test_target: Some((
735                    "x64-linux",
736                    target_lexicon::triple!("x86_64-unknown-linux-gnu"),
737                )),
738            },
739            ClippyUnitTestJobParams {
740                platform: FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
741                arch: FlowArch::X86_64,
742                gh_pool: crate::pipelines_shared::gh_pools::linux_self_hosted(),
743                clippy_targets: Some((
744                    "linux-musl, misc nostd",
745                    &[
746                        (openhcl_musl_target(CommonArch::X86_64), true),
747                        (openhcl_musl_target(CommonArch::Aarch64), true),
748                    ],
749                )),
750                unit_test_target: Some(("x64-linux-musl", openhcl_musl_target(CommonArch::X86_64))),
751            },
752            ClippyUnitTestJobParams {
753                platform: FlowPlatform::Windows,
754                arch: FlowArch::Aarch64,
755                gh_pool: crate::pipelines_shared::gh_pools::windows_arm_self_hosted_baremetal(),
756                clippy_targets: None,
757                unit_test_target: Some((
758                    "aarch64-windows",
759                    target_lexicon::triple!("aarch64-pc-windows-msvc"),
760                )),
761            },
762        ] {
763            let mut job_name = Vec::new();
764            if let Some((label, _)) = &clippy_targets {
765                job_name.push(format!("clippy [{label}]"));
766            }
767            if let Some((label, _)) = &unit_test_target {
768                job_name.push(format!("unit tests [{label}]"));
769            }
770            let job_name = job_name.join(", ");
771
772            let unit_test_target = unit_test_target.map(|(label, target)| {
773                let test_label = format!("{label}-unit-tests");
774                let pub_unit_test_junit_xml = if matches!(backend_hint, PipelineBackendHint::Local)
775                {
776                    Some(pipeline.new_artifact(&test_label).0)
777                } else {
778                    None
779                };
780                (test_label, target, pub_unit_test_junit_xml)
781            });
782
783            let mut clippy_unit_test_job = pipeline
784                .new_job(platform, arch, job_name)
785                .gh_set_pool(gh_pool);
786
787            if let Some((_, targets)) = clippy_targets {
788                for (target, also_check_misc_nostd_crates) in targets {
789                    clippy_unit_test_job = clippy_unit_test_job.dep_on(|ctx| {
790                        flowey_lib_hvlite::_jobs::check_clippy::Request {
791                            target: target.clone(),
792                            profile: CommonProfile::from_release(release),
793                            done: ctx.new_done_handle(),
794                            also_check_misc_nostd_crates: *also_check_misc_nostd_crates,
795                        }
796                    });
797                }
798            }
799
800            if let Some((test_label, target, pub_unit_test_junit_xml)) = unit_test_target {
801                clippy_unit_test_job = clippy_unit_test_job
802                    .dep_on(|ctx| {
803                        flowey_lib_hvlite::_jobs::build_and_run_nextest_unit_tests::Params {
804                            junit_test_label: test_label,
805                            nextest_profile:
806                                flowey_lib_hvlite::run_cargo_nextest_run::NextestProfile::Ci,
807                            fail_job_on_test_fail: true,
808                            target: target.clone(),
809                            profile: CommonProfile::from_release(release),
810                            unstable_panic_abort_tests: None,
811                            artifact_dir: pub_unit_test_junit_xml.map(|x| ctx.publish_artifact(x)),
812                            done: ctx.new_done_handle(),
813                        }
814                    })
815                    .dep_on(
816                        |ctx| flowey_lib_hvlite::_jobs::build_and_run_doc_tests::Params {
817                            target,
818                            profile: CommonProfile::from_release(release),
819                            done: ctx.new_done_handle(),
820                        },
821                    );
822            }
823
824            all_jobs.push(clippy_unit_test_job.finish());
825        }
826
827        let vmm_tests_artifacts_windows_intel_x86 = vmm_tests_artifacts_windows_x86
828            .clone()
829            .finish()
830            .map_err(|missing| {
831                anyhow::anyhow!("missing required windows-intel vmm_tests artifact: {missing}")
832            })?;
833        let vmm_tests_artifacts_windows_intel_tdx_x86 = vmm_tests_artifacts_windows_x86
834            .clone()
835            .finish()
836            .map_err(|missing| {
837                anyhow::anyhow!("missing required windows-tdx vmm_tests artifact: {missing}")
838            })?;
839        let vmm_tests_artifacts_windows_amd_x86 = vmm_tests_artifacts_windows_x86
840            .finish()
841            .map_err(|missing| {
842                anyhow::anyhow!("missing required windows-amd vmm_tests artifact: {missing}")
843            })?;
844        let vmm_tests_artifacts_linux_x86 =
845            vmm_tests_artifacts_linux_x86.finish().map_err(|missing| {
846                anyhow::anyhow!("missing required linux vmm_tests artifact: {missing}")
847            })?;
848        let vmm_tests_artifacts_windows_aarch64 = vmm_tests_artifacts_windows_aarch64
849            .finish()
850            .map_err(|missing| {
851                anyhow::anyhow!("missing required windows-aarch64 vmm_tests artifact: {missing}")
852            })?;
853
854        // Emit VMM tests runner jobs
855        struct VmmTestJobParams<'a> {
856            platform: FlowPlatform,
857            arch: FlowArch,
858            gh_pool: GhRunner,
859            label: &'a str,
860            target: CommonTriple,
861            resolve_vmm_tests_artifacts: vmm_tests_artifact_builders::ResolveVmmTestsDepArtifacts,
862            nextest_filter_expr: String,
863            test_artifacts: Vec<KnownTestArtifacts>,
864        }
865
866        // standard VM-based CI machines should be able to run all tests except
867        // those that require special hardware features (tdx) or need to be run
868        // on a baremetal host (hyper-v vbs doesn't seem to work nested)
869        let standard_filter = "all() & !test(tdx) & !(test(vbs) & test(hyperv))".to_string();
870        let standard_x64_test_artifacts = vec![
871            KnownTestArtifacts::FreeBsd13_2X64Vhd,
872            KnownTestArtifacts::FreeBsd13_2X64Iso,
873            KnownTestArtifacts::Gen1WindowsDataCenterCore2022X64Vhd,
874            KnownTestArtifacts::Gen2WindowsDataCenterCore2022X64Vhd,
875            KnownTestArtifacts::Ubuntu2204ServerX64Vhd,
876            KnownTestArtifacts::VmgsWithBootEntry,
877        ];
878
879        for VmmTestJobParams {
880            platform,
881            arch,
882            gh_pool,
883            label,
884            target,
885            resolve_vmm_tests_artifacts,
886            nextest_filter_expr,
887            test_artifacts,
888        } in [
889            VmmTestJobParams {
890                platform: FlowPlatform::Windows,
891                arch: FlowArch::X86_64,
892                gh_pool: crate::pipelines_shared::gh_pools::windows_intel_self_hosted_largedisk(),
893                label: "x64-windows-intel",
894                target: CommonTriple::X86_64_WINDOWS_MSVC,
895                resolve_vmm_tests_artifacts: vmm_tests_artifacts_windows_intel_x86,
896                nextest_filter_expr: standard_filter.clone(),
897                test_artifacts: standard_x64_test_artifacts.clone(),
898            },
899            VmmTestJobParams {
900                platform: FlowPlatform::Windows,
901                arch: FlowArch::X86_64,
902                gh_pool: crate::pipelines_shared::gh_pools::windows_tdx_self_hosted_baremetal(),
903                label: "x64-windows-intel-tdx",
904                target: CommonTriple::X86_64_WINDOWS_MSVC,
905                resolve_vmm_tests_artifacts: vmm_tests_artifacts_windows_intel_tdx_x86,
906                nextest_filter_expr: "test(tdx) + (test(vbs) & test(hyperv))".to_string(),
907                test_artifacts: vec![KnownTestArtifacts::Gen2WindowsDataCenterCore2025X64Vhd],
908            },
909            VmmTestJobParams {
910                platform: FlowPlatform::Windows,
911                arch: FlowArch::X86_64,
912                gh_pool: crate::pipelines_shared::gh_pools::windows_amd_self_hosted_largedisk(),
913                label: "x64-windows-amd",
914                target: CommonTriple::X86_64_WINDOWS_MSVC,
915                resolve_vmm_tests_artifacts: vmm_tests_artifacts_windows_amd_x86,
916                nextest_filter_expr: standard_filter.clone(),
917                test_artifacts: standard_x64_test_artifacts.clone(),
918            },
919            VmmTestJobParams {
920                platform: FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
921                arch: FlowArch::X86_64,
922                gh_pool: crate::pipelines_shared::gh_pools::linux_self_hosted(),
923                label: "x64-linux",
924                target: CommonTriple::X86_64_LINUX_GNU,
925                resolve_vmm_tests_artifacts: vmm_tests_artifacts_linux_x86,
926                // - No legal way to obtain gen1 pcat blobs on non-msft linux machines
927                nextest_filter_expr: format!("{standard_filter} & !test(pcat_x64)"),
928                test_artifacts: standard_x64_test_artifacts,
929            },
930            VmmTestJobParams {
931                platform: FlowPlatform::Windows,
932                arch: FlowArch::Aarch64,
933                gh_pool: crate::pipelines_shared::gh_pools::windows_arm_self_hosted_baremetal(),
934                label: "aarch64-windows",
935                target: CommonTriple::AARCH64_WINDOWS_MSVC,
936                resolve_vmm_tests_artifacts: vmm_tests_artifacts_windows_aarch64,
937                nextest_filter_expr: "all()".to_string(),
938                test_artifacts: vec![
939                    KnownTestArtifacts::Ubuntu2404ServerAarch64Vhd,
940                    KnownTestArtifacts::Windows11EnterpriseAarch64Vhdx,
941                    KnownTestArtifacts::VmgsWithBootEntry,
942                ],
943            },
944        ] {
945            let test_label = format!("{label}-vmm-tests");
946
947            let pub_vmm_tests_results = if matches!(backend_hint, PipelineBackendHint::Local) {
948                Some(pipeline.new_artifact(&test_label).0)
949            } else {
950                None
951            };
952
953            let use_vmm_tests_archive = match target {
954                CommonTriple::X86_64_WINDOWS_MSVC => &use_vmm_tests_archive_windows_x86,
955                CommonTriple::X86_64_LINUX_GNU => &use_vmm_tests_archive_linux_x86,
956                CommonTriple::AARCH64_WINDOWS_MSVC => &use_vmm_tests_archive_windows_aarch64,
957                _ => unreachable!(),
958            };
959
960            let mut vmm_tests_run_job = pipeline
961                .new_job(platform, arch, format!("run vmm-tests [{label}]"))
962                .gh_set_pool(gh_pool)
963                .dep_on(|ctx| {
964                    flowey_lib_hvlite::_jobs::consume_and_test_nextest_vmm_tests_archive::Params {
965                        junit_test_label: test_label,
966                        nextest_vmm_tests_archive: ctx.use_typed_artifact(use_vmm_tests_archive),
967                        target: target.as_triple(),
968                        nextest_profile:
969                            flowey_lib_hvlite::run_cargo_nextest_run::NextestProfile::Ci,
970                        nextest_filter_expr: Some(nextest_filter_expr),
971                        dep_artifact_dirs: resolve_vmm_tests_artifacts(ctx),
972                        test_artifacts,
973                        fail_job_on_test_fail: true,
974                        artifact_dir: pub_vmm_tests_results.map(|x| ctx.publish_artifact(x)),
975                        done: ctx.new_done_handle(),
976                    }
977                });
978
979            if let Some(vmm_tests_disk_cache_dir) = vmm_tests_disk_cache_dir.clone() {
980                vmm_tests_run_job = vmm_tests_run_job.dep_on(|_| {
981                    flowey_lib_hvlite::download_openvmm_vmm_tests_artifacts::Request::CustomCacheDir(
982                        vmm_tests_disk_cache_dir,
983                    )
984                })
985            }
986
987            all_jobs.push(vmm_tests_run_job.finish());
988        }
989
990        // test the flowey local backend by running cargo xflowey build-igvm on x64
991        {
992            let job = pipeline
993                .new_job(
994                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
995                    FlowArch::X86_64,
996                    "test flowey local backend",
997                )
998                .gh_set_pool(crate::pipelines_shared::gh_pools::default_x86_pool(
999                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
1000                ))
1001                .dep_on(
1002                    |ctx| flowey_lib_hvlite::_jobs::test_local_flowey_build_igvm::Request {
1003                        base_recipe: OpenhclIgvmRecipe::X64,
1004                        done: ctx.new_done_handle(),
1005                    },
1006                )
1007                .finish();
1008            all_jobs.push(job);
1009        }
1010
1011        if matches!(config, PipelineConfig::Pr) {
1012            // Add a job that depends on all others as a workaround for
1013            // https://github.com/orgs/community/discussions/12395.
1014            //
1015            // This workaround then itself requires _another_ workaround, requiring
1016            // the use of `gh_dangerous_override_if`, and some additional custom job
1017            // logic, to deal with https://github.com/actions/runner/issues/2566.
1018            //
1019            // TODO: Add a way for this job to skip flowey setup and become a true
1020            // no-op.
1021            let all_good_job = pipeline
1022                .new_job(
1023                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
1024                    FlowArch::X86_64,
1025                    "openvmm checkin gates",
1026                )
1027                .gh_set_pool(crate::pipelines_shared::gh_pools::default_gh_hosted(
1028                    FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
1029                ))
1030                // always run this job, regardless whether or not any previous jobs failed
1031                .gh_dangerous_override_if("always() && github.event.pull_request.draft == false")
1032                .gh_dangerous_global_env_var("ANY_JOBS_FAILED", "${{ contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'failure') }}")
1033                .dep_on(|ctx| flowey_lib_hvlite::_jobs::all_good_job::Params {
1034                    did_fail_env_var: "ANY_JOBS_FAILED".into(),
1035                    done: ctx.new_done_handle(),
1036                })
1037                .finish();
1038
1039            for job in all_jobs.iter() {
1040                pipeline.non_artifact_dep(&all_good_job, job);
1041            }
1042        }
1043
1044        Ok(pipeline)
1045    }
1046}
1047
1048/// Utility builders which make it easy to "skim off" artifacts required by VMM
1049/// test execution from other pipeline jobs.
1050//
1051// FUTURE: if we end up having a _lot_ of VMM test jobs, this would be the sort
1052// of thing that would really benefit from a derive macro.
1053mod vmm_tests_artifact_builders {
1054    use flowey::pipeline::prelude::*;
1055    use flowey_lib_hvlite::_jobs::consume_and_test_nextest_vmm_tests_archive::VmmTestsDepArtifacts;
1056    use flowey_lib_hvlite::build_guest_test_uefi::GuestTestUefiOutput;
1057    use flowey_lib_hvlite::build_openvmm::OpenvmmOutput;
1058    use flowey_lib_hvlite::build_pipette::PipetteOutput;
1059    use flowey_lib_hvlite::build_tmk_vmm::TmkVmmOutput;
1060    use flowey_lib_hvlite::build_tmks::TmksOutput;
1061
1062    pub type ResolveVmmTestsDepArtifacts =
1063        Box<dyn Fn(&mut PipelineJobCtx<'_>) -> VmmTestsDepArtifacts>;
1064
1065    #[derive(Default)]
1066    pub struct VmmTestsArtifactsBuilderLinuxX86 {
1067        // windows build machine
1068        pub use_pipette_windows: Option<UseTypedArtifact<PipetteOutput>>,
1069        pub use_tmk_vmm: Option<UseTypedArtifact<TmkVmmOutput>>,
1070        // linux build machine
1071        pub use_openvmm: Option<UseTypedArtifact<OpenvmmOutput>>,
1072        pub use_pipette_linux_musl: Option<UseTypedArtifact<PipetteOutput>>,
1073        // any machine
1074        pub use_guest_test_uefi: Option<UseTypedArtifact<GuestTestUefiOutput>>,
1075        pub use_tmks: Option<UseTypedArtifact<TmksOutput>>,
1076    }
1077
1078    impl VmmTestsArtifactsBuilderLinuxX86 {
1079        pub fn finish(self) -> Result<ResolveVmmTestsDepArtifacts, &'static str> {
1080            let VmmTestsArtifactsBuilderLinuxX86 {
1081                use_openvmm,
1082                use_guest_test_uefi,
1083                use_pipette_windows,
1084                use_pipette_linux_musl,
1085                use_tmk_vmm,
1086                use_tmks,
1087            } = self;
1088
1089            let use_guest_test_uefi = use_guest_test_uefi.ok_or("guest_test_uefi")?;
1090            let use_openvmm = use_openvmm.ok_or("openvmm")?;
1091            let use_pipette_linux_musl = use_pipette_linux_musl.ok_or("pipette_linux_musl")?;
1092            let use_pipette_windows = use_pipette_windows.ok_or("pipette_windows")?;
1093            let use_tmk_vmm = use_tmk_vmm.ok_or("tmk_vmm")?;
1094            let use_tmks = use_tmks.ok_or("tmks")?;
1095
1096            Ok(Box::new(move |ctx| VmmTestsDepArtifacts {
1097                openvmm: Some(ctx.use_typed_artifact(&use_openvmm)),
1098                pipette_windows: Some(ctx.use_typed_artifact(&use_pipette_windows)),
1099                pipette_linux_musl: Some(ctx.use_typed_artifact(&use_pipette_linux_musl)),
1100                guest_test_uefi: Some(ctx.use_typed_artifact(&use_guest_test_uefi)),
1101                tmk_vmm: Some(ctx.use_typed_artifact(&use_tmk_vmm)),
1102                tmks: Some(ctx.use_typed_artifact(&use_tmks)),
1103                // not currently required, since OpenHCL tests cannot be run on OpenVMM on linux
1104                artifact_dir_openhcl_igvm_files: None,
1105                tmk_vmm_linux_musl: None,
1106            }))
1107        }
1108    }
1109
1110    #[derive(Default, Clone)]
1111    pub struct VmmTestsArtifactsBuilderWindowsX86 {
1112        // windows build machine
1113        pub use_openvmm: Option<UseTypedArtifact<OpenvmmOutput>>,
1114        pub use_pipette_windows: Option<UseTypedArtifact<PipetteOutput>>,
1115        pub use_tmk_vmm: Option<UseTypedArtifact<TmkVmmOutput>>,
1116        // linux build machine
1117        pub use_openhcl_igvm_files: Option<UseArtifact>,
1118        pub use_pipette_linux_musl: Option<UseTypedArtifact<PipetteOutput>>,
1119        pub use_tmk_vmm_linux_musl: Option<UseTypedArtifact<TmkVmmOutput>>,
1120        // any machine
1121        pub use_guest_test_uefi: Option<UseTypedArtifact<GuestTestUefiOutput>>,
1122        pub use_tmks: Option<UseTypedArtifact<TmksOutput>>,
1123    }
1124
1125    impl VmmTestsArtifactsBuilderWindowsX86 {
1126        pub fn finish(self) -> Result<ResolveVmmTestsDepArtifacts, &'static str> {
1127            let VmmTestsArtifactsBuilderWindowsX86 {
1128                use_openvmm,
1129                use_pipette_windows,
1130                use_pipette_linux_musl,
1131                use_guest_test_uefi,
1132                use_openhcl_igvm_files,
1133                use_tmk_vmm,
1134                use_tmk_vmm_linux_musl,
1135                use_tmks,
1136            } = self;
1137
1138            let use_openvmm = use_openvmm.ok_or("openvmm")?;
1139            let use_pipette_windows = use_pipette_windows.ok_or("pipette_windows")?;
1140            let use_pipette_linux_musl = use_pipette_linux_musl.ok_or("pipette_linux_musl")?;
1141            let use_guest_test_uefi = use_guest_test_uefi.ok_or("guest_test_uefi")?;
1142            let use_openhcl_igvm_files = use_openhcl_igvm_files.ok_or("openhcl_igvm_files")?;
1143            let use_tmk_vmm = use_tmk_vmm.ok_or("tmk_vmm")?;
1144            let use_tmk_vmm_linux_musl = use_tmk_vmm_linux_musl.ok_or("tmk_vmm_linux_musl")?;
1145            let use_tmks = use_tmks.ok_or("tmks")?;
1146
1147            Ok(Box::new(move |ctx| VmmTestsDepArtifacts {
1148                openvmm: Some(ctx.use_typed_artifact(&use_openvmm)),
1149                pipette_windows: Some(ctx.use_typed_artifact(&use_pipette_windows)),
1150                pipette_linux_musl: Some(ctx.use_typed_artifact(&use_pipette_linux_musl)),
1151                guest_test_uefi: Some(ctx.use_typed_artifact(&use_guest_test_uefi)),
1152                artifact_dir_openhcl_igvm_files: Some(ctx.use_artifact(&use_openhcl_igvm_files)),
1153                tmk_vmm: Some(ctx.use_typed_artifact(&use_tmk_vmm)),
1154                tmk_vmm_linux_musl: Some(ctx.use_typed_artifact(&use_tmk_vmm_linux_musl)),
1155                tmks: Some(ctx.use_typed_artifact(&use_tmks)),
1156            }))
1157        }
1158    }
1159
1160    #[derive(Default, Clone)]
1161    pub struct VmmTestsArtifactsBuilderWindowsAarch64 {
1162        // windows build machine
1163        pub use_openvmm: Option<UseTypedArtifact<OpenvmmOutput>>,
1164        pub use_pipette_windows: Option<UseTypedArtifact<PipetteOutput>>,
1165        pub use_tmk_vmm: Option<UseTypedArtifact<TmkVmmOutput>>,
1166        // linux build machine
1167        pub use_openhcl_igvm_files: Option<UseArtifact>,
1168        pub use_pipette_linux_musl: Option<UseTypedArtifact<PipetteOutput>>,
1169        pub use_tmk_vmm_linux_musl: Option<UseTypedArtifact<TmkVmmOutput>>,
1170        // any machine
1171        pub use_guest_test_uefi: Option<UseTypedArtifact<GuestTestUefiOutput>>,
1172        pub use_tmks: Option<UseTypedArtifact<TmksOutput>>,
1173    }
1174
1175    impl VmmTestsArtifactsBuilderWindowsAarch64 {
1176        pub fn finish(self) -> Result<ResolveVmmTestsDepArtifacts, &'static str> {
1177            let VmmTestsArtifactsBuilderWindowsAarch64 {
1178                use_openvmm,
1179                use_pipette_windows,
1180                use_pipette_linux_musl,
1181                use_guest_test_uefi,
1182                use_openhcl_igvm_files,
1183                use_tmk_vmm,
1184                use_tmk_vmm_linux_musl,
1185                use_tmks,
1186            } = self;
1187
1188            let use_openvmm = use_openvmm.ok_or("openvmm")?;
1189            let use_pipette_windows = use_pipette_windows.ok_or("pipette_windows")?;
1190            let use_pipette_linux_musl = use_pipette_linux_musl.ok_or("pipette_linux_musl")?;
1191            let use_guest_test_uefi = use_guest_test_uefi.ok_or("guest_test_uefi")?;
1192            let use_openhcl_igvm_files = use_openhcl_igvm_files.ok_or("openhcl_igvm_files")?;
1193            let use_tmk_vmm = use_tmk_vmm.ok_or("tmk_vmm")?;
1194            let use_tmk_vmm_linux_musl = use_tmk_vmm_linux_musl.ok_or("tmk_vmm_linux_musl")?;
1195            let use_tmks = use_tmks.ok_or("tmks")?;
1196
1197            Ok(Box::new(move |ctx| VmmTestsDepArtifacts {
1198                openvmm: Some(ctx.use_typed_artifact(&use_openvmm)),
1199                pipette_windows: Some(ctx.use_typed_artifact(&use_pipette_windows)),
1200                pipette_linux_musl: Some(ctx.use_typed_artifact(&use_pipette_linux_musl)),
1201                guest_test_uefi: Some(ctx.use_typed_artifact(&use_guest_test_uefi)),
1202                artifact_dir_openhcl_igvm_files: Some(ctx.use_artifact(&use_openhcl_igvm_files)),
1203                tmk_vmm: Some(ctx.use_typed_artifact(&use_tmk_vmm)),
1204                tmk_vmm_linux_musl: Some(ctx.use_typed_artifact(&use_tmk_vmm_linux_musl)),
1205                tmks: Some(ctx.use_typed_artifact(&use_tmks)),
1206            }))
1207        }
1208    }
1209}