Skip to content

Commit 9bdb126

Browse files
authored
fix(compile): address pool review feedback (#541)
1 parent 2499d29 commit 9bdb126

2 files changed

Lines changed: 90 additions & 18 deletions

File tree

src/compile/codemods/0002_pool_object_form.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,20 @@ fn apply_codemod(fm: &mut Mapping, ctx: &CodemodContext) -> Result<bool> {
4545
let key = Value::String("pool".to_string());
4646

4747
let Some(pool_value) = fm.get(&key).cloned() else {
48-
// Pool absent — only inject the legacy default when the
49-
// compiler version is at or above the release that changed
50-
// the implicit default. Older binaries still carry the old
51-
// default in `resolve_pool_block`, so no rewrite is needed.
48+
// Pool absent — only inject the legacy default for 1ES
49+
// targets where the old implicit default was the self-hosted
50+
// pool. Non-1ES (standalone/job/stage) targets now default to
51+
// `vmImage: ubuntu-latest`, which is the desired behaviour
52+
// for new pipelines that omit `pool:`.
5253
if !version_gte(ctx.compiler_version, INTRODUCED_IN) {
5354
return Ok(false);
5455
}
56+
let target = fm
57+
.get(&Value::String("target".to_string()))
58+
.and_then(|v| v.as_str());
59+
if target != Some("1es") {
60+
return Ok(false);
61+
}
5562
let mut mapped = Mapping::new();
5663
mapped.insert(
5764
Value::String("name".to_string()),
@@ -108,8 +115,9 @@ mod tests {
108115
}
109116

110117
#[test]
111-
fn inserts_legacy_default_when_pool_absent_and_version_gte() {
112-
let mut fm: Mapping = serde_yaml::from_str("name: x\ndescription: y").unwrap();
118+
fn inserts_legacy_default_when_pool_absent_1es_and_version_gte() {
119+
let mut fm: Mapping =
120+
serde_yaml::from_str("name: x\ndescription: y\ntarget: 1es").unwrap();
113121
let changed = apply_codemod(&mut fm, &ctx("0.30.0")).expect("apply");
114122
assert!(changed);
115123
assert_eq!(
@@ -119,16 +127,37 @@ mod tests {
119127
}
120128

121129
#[test]
122-
fn noops_when_pool_absent_and_version_below() {
130+
fn noops_when_pool_absent_standalone_and_version_gte() {
131+
// Standalone pipelines without pool should get the new
132+
// vmImage: ubuntu-latest default, not the legacy 1ES pool.
123133
let mut fm: Mapping = serde_yaml::from_str("name: x\ndescription: y").unwrap();
134+
let changed = apply_codemod(&mut fm, &ctx("0.30.0")).expect("apply");
135+
assert!(!changed);
136+
assert!(!fm.contains_key(Value::String("pool".into())));
137+
}
138+
139+
#[test]
140+
fn noops_when_pool_absent_explicit_standalone_and_version_gte() {
141+
let mut fm: Mapping =
142+
serde_yaml::from_str("name: x\ndescription: y\ntarget: standalone").unwrap();
143+
let changed = apply_codemod(&mut fm, &ctx("0.30.0")).expect("apply");
144+
assert!(!changed);
145+
assert!(!fm.contains_key(Value::String("pool".into())));
146+
}
147+
148+
#[test]
149+
fn noops_when_pool_absent_1es_and_version_below() {
150+
let mut fm: Mapping =
151+
serde_yaml::from_str("name: x\ndescription: y\ntarget: 1es").unwrap();
124152
let changed = apply_codemod(&mut fm, &ctx("0.29.0")).expect("apply");
125153
assert!(!changed);
126154
assert!(!fm.contains_key(Value::String("pool".into())));
127155
}
128156

129157
#[test]
130158
fn idempotent_after_inserting_legacy_default() {
131-
let mut fm: Mapping = serde_yaml::from_str("name: x\ndescription: y").unwrap();
159+
let mut fm: Mapping =
160+
serde_yaml::from_str("name: x\ndescription: y\ntarget: 1es").unwrap();
132161
let changed1 = apply_codemod(&mut fm, &ctx("0.30.0")).expect("first apply");
133162
assert!(changed1);
134163
let changed2 = apply_codemod(&mut fm, &ctx("0.30.0")).expect("second apply");

src/compile/common.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,8 @@ fn resolve_pool_block(target: CompileTarget, pool: Option<&PoolConfig>) -> Resul
10551055
),
10561056
(Some(name), None) => Ok(format!("name: {}", name)),
10571057
(None, Some(vm_image)) => Ok(format!("vmImage: {}", vm_image)),
1058+
// `pool: {}` (empty object) — fall back to the
1059+
// Microsoft-hosted default, same as omitting pool.
10581060
(None, None) => Ok(format!("vmImage: {}", DEFAULT_VM_IMAGE_POOL)),
10591061
},
10601062
}
@@ -1815,15 +1817,14 @@ pub fn generate_setup_job(
18151817
let user_steps = steps_parts.join("\n\n");
18161818

18171819
// Build the job YAML with markers for proper indentation
1818-
let mut template = format!(
1819-
r#"- job: Setup
1820+
let mut template = r#"- job: Setup
18201821
displayName: "Setup"
18211822
pool:
1822-
{pool}
1823+
{{ pool }}
18231824
steps:
18241825
- checkout: self
18251826
"#
1826-
);
1827+
.to_string();
18271828

18281829
if !ext_steps_combined.is_empty() {
18291830
template.push_str(" {{ ext_setup_steps }}\n");
@@ -1832,7 +1833,8 @@ pub fn generate_setup_job(
18321833
template.push_str(" {{ user_setup_steps }}\n");
18331834
}
18341835

1835-
let yaml = replace_with_indent(&template, "{{ ext_setup_steps }}", &ext_steps_combined);
1836+
let yaml = replace_with_indent(&template, "{{ pool }}", pool);
1837+
let yaml = replace_with_indent(&yaml, "{{ ext_setup_steps }}", &ext_steps_combined);
18361838
let yaml = replace_with_indent(&yaml, "{{ user_setup_steps }}", &user_steps);
18371839

18381840
Ok(yaml)
@@ -1849,18 +1851,20 @@ pub fn generate_teardown_job(
18491851

18501852
let steps_yaml = format_steps_yaml_indented(teardown_steps, 4);
18511853

1852-
format!(
1854+
let template = format!(
18531855
r#"- job: Teardown
18541856
displayName: "Teardown"
18551857
dependsOn: Execution
18561858
pool:
1857-
{}
1859+
{{{{ pool }}}}
18581860
steps:
18591861
- checkout: self
18601862
{}
18611863
"#,
1862-
pool, steps_yaml
1863-
)
1864+
steps_yaml
1865+
);
1866+
1867+
replace_with_indent(&template, "{{ pool }}", pool)
18641868
}
18651869

18661870
/// Generate prepare steps (inline), including extension steps and user-defined steps.
@@ -2944,7 +2948,7 @@ pub async fn compile_template_target(
29442948
#[cfg(test)]
29452949
mod tests {
29462950
use super::*;
2947-
use crate::compile::types::{McpConfig, McpOptions, Repository};
2951+
use crate::compile::types::{McpConfig, McpOptions, PoolConfigFull, Repository};
29482952
use crate::compile::extensions::{CompileContext, collect_extensions};
29492953
use std::collections::HashMap;
29502954

@@ -6218,6 +6222,33 @@ mod tests {
62186222
assert!(out.contains("echo td"), "out: {out}");
62196223
}
62206224

6225+
#[test]
6226+
fn test_generate_setup_job_multiline_pool_indentation() {
6227+
// 1ES pool resolves to a multi-line string; verify all lines
6228+
// are properly indented under `pool:`.
6229+
let fm: FrontMatter = serde_yaml::from_str("name: t\ndescription: t").unwrap();
6230+
let ctx = CompileContext::for_test(&fm);
6231+
let step: serde_yaml::Value = serde_yaml::from_str("bash: echo setup").unwrap();
6232+
let pool = "name: AZS-1ES-L-MMS-ubuntu-22.04\nos: linux";
6233+
let out = generate_setup_job(&[step], pool, None, None, &[], &ctx).unwrap();
6234+
// Both pool lines must be indented at the same level (4 spaces)
6235+
assert!(
6236+
out.contains(" name: AZS-1ES-L-MMS-ubuntu-22.04\n os: linux"),
6237+
"multi-line pool must be indented correctly:\n{out}"
6238+
);
6239+
}
6240+
6241+
#[test]
6242+
fn test_generate_teardown_job_multiline_pool_indentation() {
6243+
let step: serde_yaml::Value = serde_yaml::from_str("bash: echo td").unwrap();
6244+
let pool = "name: AZS-1ES-L-MMS-ubuntu-22.04\nos: linux";
6245+
let out = generate_teardown_job(&[step], pool);
6246+
assert!(
6247+
out.contains(" name: AZS-1ES-L-MMS-ubuntu-22.04\n os: linux"),
6248+
"multi-line pool must be indented correctly:\n{out}"
6249+
);
6250+
}
6251+
62216252
#[test]
62226253
fn test_resolve_pool_block_non_onees_defaults_to_vm_image() {
62236254
let block = resolve_pool_block(CompileTarget::Standalone, None).expect("pool block");
@@ -6253,6 +6284,18 @@ mod tests {
62536284
assert_eq!(block, "name: CustomPool\nos: windows");
62546285
}
62556286

6287+
#[test]
6288+
fn test_resolve_pool_block_non_onees_empty_object_defaults_to_vm_image() {
6289+
let pool = PoolConfig::Full(PoolConfigFull {
6290+
name: None,
6291+
vm_image: None,
6292+
os: None,
6293+
});
6294+
let block =
6295+
resolve_pool_block(CompileTarget::Standalone, Some(&pool)).expect("pool block");
6296+
assert_eq!(block, "vmImage: ubuntu-latest");
6297+
}
6298+
62566299
#[test]
62576300
fn test_generate_agentic_depends_on_empty_steps() {
62586301
assert!(generate_agentic_depends_on(&[], false, false, &[]).is_empty());

0 commit comments

Comments
 (0)