Skip to content
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
3a064d5
initial work
Oct 6, 2025
b215a0c
fixes
Oct 6, 2025
92d4904
Add support for force published artifacts
Oct 6, 2025
233acfa
test out new force publish artifact step
Oct 6, 2025
ccbe79d
regen yaml
Oct 6, 2025
33381cf
Try new job
Oct 6, 2025
c46f87f
condense
Oct 6, 2025
e7826ba
Merge branch 'main' into add-verify-tests-step
Oct 6, 2025
693630a
Try a successful vmm_tests run
Oct 6, 2025
2c2795d
update pipeline files
Oct 7, 2025
6be7aa0
.
Oct 7, 2025
689dd30
fix typo
Oct 7, 2025
922d587
Prepare for review
Oct 7, 2025
51f8bb8
print debug logs
Oct 7, 2025
cb736c0
Handle both dirs and files gracefully
Oct 7, 2025
d1348e7
Remove logging statements
Oct 7, 2025
4c0d383
.
Oct 7, 2025
2962333
Proper refactor of publish_test_result.rs
Oct 7, 2025
3fa2e2e
More cleanup
Oct 7, 2025
044179e
Merge branch 'main' into add-verify-tests-step
Oct 8, 2025
e944546
Add file extension
Oct 8, 2025
2cd9f9d
Fix local vmm_tests
Oct 8, 2025
fcb1ed5
Scope changes in YAML
Oct 9, 2025
d522230
Address feedback
Oct 10, 2025
b4595ac
.
Oct 10, 2025
717272c
.
Oct 13, 2025
de175cb
Trim unnecessary optionals
Oct 13, 2025
2185870
Merge branch 'main' into add-verify-tests-step
Oct 14, 2025
4b8f415
Feedback
Oct 15, 2025
130e31e
Update comments and make the run_cargo_nextest_list command configurable
Oct 15, 2025
eea6cc1
Revert this change
Oct 15, 2025
2e1d8e2
Revert "Revert this change"
Oct 15, 2025
20e6604
.
Oct 15, 2025
98bfa23
Revert "."
Oct 17, 2025
2c1eccb
Merge branch 'main' into add-verify-tests-step
Oct 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,526 changes: 945 additions & 581 deletions .github/workflows/openvmm-ci.yaml

Large diffs are not rendered by default.

1,526 changes: 945 additions & 581 deletions .github/workflows/openvmm-pr-release.yaml

Large diffs are not rendered by default.

1,541 changes: 953 additions & 588 deletions .github/workflows/openvmm-pr.yaml

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,7 @@ dependencies = [
"fs-err",
"igvmfilegen_config",
"log",
"quick-xml",
"serde",
"serde_json",
"target-lexicon",
Expand Down Expand Up @@ -5990,6 +5991,15 @@ dependencies = [
"syn 2.0.106",
]

[[package]]
name = "quick-xml"
version = "0.38.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89"
dependencies = [
"memchr",
]

[[package]]
name = "quote"
version = "1.0.40"
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ proc-macro2 = "1.0"
prost = "0.11"
prost-build = "0.11"
prost-types = "0.11"
quick-xml = "0.38.3"
quote = "1.0"
range_map_vec = "0.2.0"
rayon = "1.5"
Expand Down
20 changes: 17 additions & 3 deletions flowey/flowey_cli/src/pipeline_resolver/ado_yaml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ pub fn ado_yaml(
for ResolvedJobArtifact {
flowey_var: _,
name,
..
} in artifacts_used
{
ado_steps.push({
Expand Down Expand Up @@ -310,7 +311,10 @@ EOF

// next, emit ado steps to create dirs for artifacts which will be
// published
for ResolvedJobArtifact { flowey_var, name } in artifacts_published {
for ResolvedJobArtifact {
flowey_var, name, ..
} in artifacts_published
{
writeln!(
flowey_bootstrap_bash,
r#"mkdir -p "$(AgentTempDirNormal)/publish_artifacts/{name}""#
Expand All @@ -324,7 +328,10 @@ EOF

// lastly, emit ado steps that report the dirs for any artifacts which
// are used by this job
for ResolvedJobArtifact { flowey_var, name } in artifacts_used {
for ResolvedJobArtifact {
flowey_var, name, ..
} in artifacts_used
{
// do NOT use ADO macro syntax $(...), since this is in the same
// bootstrap block as where those ADO vars get defined, meaning it's
// not available yet!
Expand Down Expand Up @@ -425,17 +432,24 @@ EOF
for ResolvedJobArtifact {
flowey_var: _,
name,
force_upload,
} in artifacts_published
{
ado_steps.push({
let map: serde_yaml::Mapping = serde_yaml::from_str(&format!(
let mut map: serde_yaml::Mapping = serde_yaml::from_str(&format!(
r#"
publish: $(FLOWEY_TEMP_DIR)/publish_artifacts/{name}
displayName: '🌼📦 Publish {name}'
artifact: {name}
"#
))
.unwrap();
if *force_upload {
map.insert(
"condition".into(),
serde_yaml::Value::String("always()".into()),
);
}
map.into()
});
}
Expand Down
10 changes: 8 additions & 2 deletions flowey/flowey_cli/src/pipeline_resolver/direct_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,10 @@ fn direct_run_do_work(
serde_json::to_string(&persist_dir).unwrap().into(),
);

for ResolvedJobArtifact { flowey_var, name } in artifacts_published {
for ResolvedJobArtifact {
flowey_var, name, ..
} in artifacts_published
{
let path = out_dir.join("artifacts").join(name);
fs_err::create_dir_all(&path)?;

Expand All @@ -291,7 +294,10 @@ fn direct_run_do_work(
}
fs_err::create_dir_all(out_dir.join(".job_artifacts"))?;

for ResolvedJobArtifact { flowey_var, name } in artifacts_used {
for ResolvedJobArtifact {
flowey_var, name, ..
} in artifacts_used
{
let path = out_dir.join(".job_artifacts").join(name);
fs_err::create_dir_all(&path)?;
copy_dir_all(out_dir.join("artifacts").join(name), &path)?;
Expand Down
19 changes: 14 additions & 5 deletions flowey/flowey_cli/src/pipeline_resolver/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub struct ResolvedPipeline {
pub struct ResolvedJobArtifact {
pub flowey_var: String,
pub name: String,
pub force_upload: bool,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -112,6 +113,7 @@ pub fn resolve_pipeline(pipeline: Pipeline) -> anyhow::Result<ResolvedPipeline>
name,
published_by_job,
used_by_jobs,
force_published: _,
} in &artifacts
{
let no_existing = m
Expand Down Expand Up @@ -183,11 +185,16 @@ pub fn resolve_pipeline(pipeline: Pipeline) -> anyhow::Result<ResolvedPipeline>

let artifacts_published: Vec<_> = artifacts_published
.into_iter()
.map(|a| ResolvedJobArtifact {
flowey_var: flowey_core::pipeline::internal::consistent_artifact_runtime_var_name(
&a, false,
),
name: a,
.map(|a| {
let artifact_meta = artifacts.iter().find(|meta| meta.name == a).unwrap();
ResolvedJobArtifact {
flowey_var:
flowey_core::pipeline::internal::consistent_artifact_runtime_var_name(
&a, false,
),
name: a,
force_upload: artifact_meta.force_published,
}
})
.collect();
let artifacts_used: Vec<_> = artifacts_used
Expand All @@ -197,6 +204,7 @@ pub fn resolve_pipeline(pipeline: Pipeline) -> anyhow::Result<ResolvedPipeline>
&a, true,
),
name: a,
force_upload: false,
})
.collect();
let parameters_used: Vec<_> = parameters_used
Expand Down Expand Up @@ -245,6 +253,7 @@ pub fn resolve_pipeline(pipeline: Pipeline) -> anyhow::Result<ResolvedPipeline>
name: _,
published_by_job,
used_by_jobs,
force_published: _,
} in artifacts
{
let published_idx = job_graph_idx[published_by_job.expect("checked in loop above")];
Expand Down
16 changes: 13 additions & 3 deletions flowey/flowey_cli/src/pipeline_resolver/github_yaml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,10 @@ EOF

// next, emit GitHub steps to create dirs for artifacts which will be
// published
for ResolvedJobArtifact { flowey_var, name } in artifacts_published {
for ResolvedJobArtifact {
flowey_var, name, ..
} in artifacts_published
{
writeln!(
flowey_bootstrap_bash,
r#"mkdir -p "$AgentTempDirNormal/publish_artifacts/{name}""#
Expand All @@ -392,7 +395,10 @@ EOF

// lastly, emit GitHub steps that report the dirs for any artifacts which
// are used by this job
for ResolvedJobArtifact { flowey_var, name } in artifacts_used {
for ResolvedJobArtifact {
flowey_var, name, ..
} in artifacts_used
{
let var_db_inject_cmd = bootstrap_bash_var_db_inject(flowey_var, true);
match platform.kind() {
FlowPlatformKind::Windows => {
Expand Down Expand Up @@ -430,10 +436,11 @@ EOF
for ResolvedJobArtifact {
flowey_var: _,
name,
force_upload,
} in artifacts_published
{
gh_steps.push({
let map: serde_yaml::Mapping = serde_yaml::from_str(&format!(
let mut map: serde_yaml::Mapping = serde_yaml::from_str(&format!(
r#"
name: 🌼📦 Publish {name}
uses: actions/upload-artifact@v4
Expand All @@ -444,6 +451,9 @@ EOF
"#
))
.unwrap();
if *force_upload {
map.insert("if".into(), serde_yaml::Value::String("always()".into()));
}
map.into()
});
}
Expand Down
26 changes: 26 additions & 0 deletions flowey/flowey_core/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ impl Pipeline {
name: owned_name,
published_by_job: None,
used_by_jobs: BTreeSet::new(),
force_published: false,
});

(PublishArtifact { idx }, UseArtifact { idx })
Expand All @@ -658,6 +659,30 @@ impl Pipeline {
)
}

/// Mark an artifact to be force published, meaning it will be published
/// even if the job fails.
///
/// This is useful for artifacts that contain diagnostic information or logs
/// that are needed to debug failures.
#[track_caller]
pub fn force_publish_artifact(&mut self, artifact: &PublishArtifact) -> &mut Self {
self.artifacts[artifact.idx].force_published = true;
self
}

/// Mark a typed artifact to be force published, meaning it will be published
/// even if the job fails.
///
/// This is useful for artifacts that contain diagnostic information or logs
/// that are needed to debug failures.
#[track_caller]
pub fn force_publish_typed_artifact<T: Artifact>(
&mut self,
artifact: &PublishTypedArtifact<T>,
) -> &mut Self {
self.force_publish_artifact(&artifact.0)
}

/// (ADO only) Set the pipeline-level name.
///
/// <https://learn.microsoft.com/en-us/azure/devops/pipelines/process/run-number?view=azure-devops&tabs=yaml>
Expand Down Expand Up @@ -1330,6 +1355,7 @@ pub mod internal {
pub name: String,
pub published_by_job: Option<usize>,
pub used_by_jobs: BTreeSet<usize>,
pub force_published: bool,
}

#[derive(Debug)]
Expand Down
65 changes: 59 additions & 6 deletions flowey/flowey_hvlite/src/pipelines/checkin_gates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,8 @@ impl IntoPipeline for CheckinGatesCli {
KnownTestArtifacts::Ubuntu2404ServerX64Vhd,
];

let mut vmm_tests_results_artifacts = vec![];

for VmmTestJobParams {
platform,
arch,
Expand Down Expand Up @@ -1010,11 +1012,22 @@ impl IntoPipeline for CheckinGatesCli {
] {
let test_label = format!("{label}-vmm-tests");

let pub_vmm_tests_results = if matches!(backend_hint, PipelineBackendHint::Local) {
Some(pipeline.new_artifact(&test_label).0)
} else {
None
};
let (pub_vmm_tests_results_full, _) =
pipeline.new_artifact(format!("{label}-vmm-tests-results"));

let (pub_vmm_tests_junit_xml, use_vmm_tests_junit_xml) =
pipeline.new_artifact(format!("{label}-vmm-tests-results-junit-xml"));
let (pub_vmm_tests_nextest_list_json, use_vmm_tests_nextest_list_json) =
pipeline.new_artifact(format!("{label}-vmm-tests-results-nextest-list-json"));

pipeline.force_publish_artifact(&pub_vmm_tests_results_full);
pipeline.force_publish_artifact(&pub_vmm_tests_junit_xml);
pipeline.force_publish_artifact(&pub_vmm_tests_nextest_list_json);

vmm_tests_results_artifacts.push((
label.to_string(),
(use_vmm_tests_junit_xml, use_vmm_tests_nextest_list_json),
));

let use_vmm_tests_archive = match target {
CommonTriple::X86_64_WINDOWS_MSVC => &use_vmm_tests_archive_windows_x86,
Expand All @@ -1037,7 +1050,16 @@ impl IntoPipeline for CheckinGatesCli {
dep_artifact_dirs: resolve_vmm_tests_artifacts(ctx),
test_artifacts,
fail_job_on_test_fail: true,
artifact_dir: pub_vmm_tests_results.map(|x| ctx.publish_artifact(x)),
artifact_dirs:
flowey_lib_common::publish_test_results::VmmTestResultsArtifacts {
junit_xml: Some(ctx.publish_artifact(pub_vmm_tests_junit_xml)),
nextest_list_json: Some(
ctx.publish_artifact(pub_vmm_tests_nextest_list_json),
),
test_results_full: Some(
ctx.publish_artifact(pub_vmm_tests_results_full),
),
},
needs_prep_run,
done: ctx.new_done_handle(),
}
Expand All @@ -1059,6 +1081,37 @@ impl IntoPipeline for CheckinGatesCli {
}
}

{
let job = pipeline
.new_job(
FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
FlowArch::X86_64,
"verify all tests run at least once",
)
.gh_set_pool(crate::pipelines_shared::gh_pools::default_x86_pool(
FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu),
))
.dep_on(
|ctx| flowey_lib_hvlite::_jobs::verify_all_tests_run::Request {
test_artifacts: vmm_tests_results_artifacts
.iter()
.map(|elem| {
(
elem.0.clone(),
flowey_lib_hvlite::_jobs::verify_all_tests_run::VmmTestResultsArtifacts {
junit_xml: ctx.use_artifact(&elem.1.0),
nextest_list_json: ctx.use_artifact(&elem.1.1),
},
)
})
.collect(),
done: ctx.new_done_handle(),
},
)
.finish();
all_jobs.push(job);
}

// test the flowey local backend by running cargo xflowey build-igvm on x64
{
let job = pipeline
Expand Down
Loading