Skip to content

Commit 5cdb5ce

Browse files
jamesadevineCopilot
andcommitted
fix: extract normalize_ado_yaml_path helper and update docs
- Extract YAML path normalization into a named helper function so tests exercise the same code path as production (not duplicated logic) - Normalize separators before trimming leading slash (handles backslash paths) - Add backslash normalization test - Add legacy SSH format to parse_ado_remote doc comment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f5316ca commit 5cdb5ce

1 file changed

Lines changed: 27 additions & 28 deletions

File tree

src/configure.rs

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub struct AdoContext {
3232
/// - HTTPS: `https://dev.azure.com/{org}/{project}/_git/{repo}`
3333
/// - HTTPS (legacy): `https://{org}.visualstudio.com/{project}/_git/{repo}`
3434
/// - SSH: `git@ssh.dev.azure.com:v3/{org}/{project}/{repo}`
35+
/// - SSH (legacy): `git@vs-ssh.visualstudio.com:v3/{org}/{project}/{repo}`
3536
pub fn parse_ado_remote(remote_url: &str) -> Result<AdoContext> {
3637
let url = remote_url.trim();
3738

@@ -269,6 +270,15 @@ fn fuzzy_match_by_name(agent_name: &str, definitions: &[DefinitionSummary]) -> F
269270
}
270271
}
271272

273+
/// Normalize an ADO YAML filename for comparison with local paths.
274+
///
275+
/// ADO's Build Definitions API stores `yamlFilename` with a leading `/`
276+
/// (e.g., `/.azdo/pipelines/agent.yml`) and may use backslashes on Windows.
277+
/// This strips the leading `/` and normalizes separators to forward slashes.
278+
fn normalize_ado_yaml_path(path: &str) -> String {
279+
path.replace('\\', "/").trim_start_matches('/').to_string()
280+
}
281+
272282
/// Match detected pipeline YAML files to ADO pipeline definitions.
273283
///
274284
/// Strategy:
@@ -301,10 +311,7 @@ async fn match_definitions(
301311
d.process
302312
.as_ref()
303313
.and_then(|p| p.yaml_filename.as_ref())
304-
.is_some_and(|f| {
305-
let f_normalized = f.trim_start_matches('/').replace('\\', "/");
306-
f_normalized == yaml_path_normalized
307-
})
314+
.is_some_and(|f| normalize_ado_yaml_path(f) == yaml_path_normalized)
308315
});
309316

310317
if let Some(def) = path_match {
@@ -699,35 +706,27 @@ mod tests {
699706
#[test]
700707
fn test_yaml_path_match_strips_leading_slash() {
701708
// ADO stores yamlFilename with a leading '/'
702-
let def = make_def_with_yaml(1, "My Pipeline", "/.azdo/pipelines/agent.yml");
703-
let local_path = ".azdo/pipelines/agent.yml";
704-
let f_normalized = def
705-
.process
706-
.as_ref()
707-
.unwrap()
708-
.yaml_filename
709-
.as_ref()
710-
.unwrap()
711-
.trim_start_matches('/')
712-
.replace('\\', "/");
713-
assert_eq!(f_normalized, local_path);
709+
assert_eq!(
710+
normalize_ado_yaml_path("/.azdo/pipelines/agent.yml"),
711+
".azdo/pipelines/agent.yml"
712+
);
714713
}
715714

716715
#[test]
717716
fn test_yaml_path_match_without_leading_slash() {
718717
// Some ADO instances may store without leading '/'
719-
let def = make_def_with_yaml(1, "My Pipeline", ".azdo/pipelines/agent.yml");
720-
let local_path = ".azdo/pipelines/agent.yml";
721-
let f_normalized = def
722-
.process
723-
.as_ref()
724-
.unwrap()
725-
.yaml_filename
726-
.as_ref()
727-
.unwrap()
728-
.trim_start_matches('/')
729-
.replace('\\', "/");
730-
assert_eq!(f_normalized, local_path);
718+
assert_eq!(
719+
normalize_ado_yaml_path(".azdo/pipelines/agent.yml"),
720+
".azdo/pipelines/agent.yml"
721+
);
722+
}
723+
724+
#[test]
725+
fn test_yaml_path_match_backslash_normalization() {
726+
assert_eq!(
727+
normalize_ado_yaml_path("\\.azdo\\pipelines\\agent.yml"),
728+
".azdo/pipelines/agent.yml"
729+
);
731730
}
732731

733732
#[test]

0 commit comments

Comments
 (0)