Skip to content

Commit 8029980

Browse files
fix(configure): accept bare org name for --org (#579)
Previously, �do-aw configure --org myorg would build malformed ADO API URLs because the value was used verbatim as the organization URL. When no usable ADO git remote is present (e.g. when the pipeline source lives in GitHub but runs in Azure DevOps), this made --definition-ids unusable without forcing users to pass the full https://dev.azure.com/myorg URL. Add a ormalize_org_url helper that: - prefixes the canonical https://dev.azure.com/ host when a bare org name is passed - rewrites the legacy {org}.visualstudio.com form to dev.azure.com/{org}`n- trims whitespace and trailing slashes Apply it in both branches of esolve_ado_context (override-on-ADO-remote and explicit-no-remote), update the --org CLI help text and docs/cli.md, and add unit tests covering bare names, full URLs, trailing slashes, legacy hosts, and whitespace. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b841998 commit 8029980

3 files changed

Lines changed: 78 additions & 4 deletions

File tree

docs/cli.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Global flags (apply to all subcommands): `--verbose, -v` (enable info-level logg
3737

3838
- `configure` - Detect agentic pipelines in a local repository and update the `GITHUB_TOKEN` pipeline variable on their Azure DevOps build definitions
3939
- `--token <token>` / `GITHUB_TOKEN` env var - The new GITHUB_TOKEN value (prompted if omitted)
40-
- `--org <url>` - Override: Azure DevOps organization URL (inferred from git remote by default)
40+
- `--org <url>` - Override: Azure DevOps organization URL (e.g. `https://dev.azure.com/myorg`) or just the org name (e.g. `myorg`, auto-prefixed to the canonical URL). Inferred from git remote by default.
4141
- `--project <name>` - Override: Azure DevOps project name (inferred from git remote by default)
4242
- `--pat <pat>` / `AZURE_DEVOPS_EXT_PAT` env var - PAT for ADO API authentication (prompted if omitted)
4343
- `--path <path>` - Path to the repository root (defaults to current directory)

src/configure.rs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,33 @@ async fn resolve_auth(pat: Option<&str>) -> Result<AdoAuth> {
652652
}
653653
}
654654

655+
/// Normalize a `--org` value to a full ADO organization URL.
656+
///
657+
/// Users commonly pass just the org name (e.g. `myorg`) instead of the full
658+
/// URL (`https://dev.azure.com/myorg`). Accept both forms by prefixing the
659+
/// canonical `https://dev.azure.com/` host when the input has no scheme.
660+
///
661+
/// Also accepts the legacy `{org}.visualstudio.com` form and rewrites it to
662+
/// the modern `dev.azure.com/{org}` form for consistency with `parse_ado_remote`.
663+
pub fn normalize_org_url(org: &str) -> String {
664+
let trimmed = org.trim().trim_end_matches('/');
665+
666+
// Bare org name: no scheme, no dots — assume it's just the org.
667+
if !trimmed.contains("://") && !trimmed.contains('/') && !trimmed.contains('.') {
668+
return format!("https://dev.azure.com/{}", trimmed);
669+
}
670+
671+
// Legacy `https://{org}.visualstudio.com` → `https://dev.azure.com/{org}`.
672+
if let Ok(url) = url::Url::parse(trimmed)
673+
&& let Some(host) = url.host_str()
674+
&& let Some(org) = host.strip_suffix(".visualstudio.com")
675+
{
676+
return format!("https://dev.azure.com/{}", org);
677+
}
678+
679+
trimmed.to_string()
680+
}
681+
655682
/// Resolves the ADO context from the git remote (best-effort) with CLI overrides.
656683
/// Falls back to explicit `--org`/`--project` when the remote is absent or non-ADO.
657684
async fn resolve_ado_context(
@@ -677,7 +704,7 @@ async fn resolve_ado_context(
677704
// Git remote parsed — apply overrides
678705
(Some(mut ctx), org, project) => {
679706
if let Some(org) = org {
680-
ctx.org_url = org.to_string();
707+
ctx.org_url = normalize_org_url(org);
681708
}
682709
if let Some(project) = project {
683710
ctx.project = project.to_string();
@@ -688,7 +715,7 @@ async fn resolve_ado_context(
688715
(None, Some(org), Some(project)) => {
689716
info!("No ADO git remote; using --org and --project");
690717
Ok(AdoContext {
691-
org_url: org.to_string(),
718+
org_url: normalize_org_url(org),
692719
project: project.to_string(),
693720
repo_name: String::new(),
694721
})
@@ -922,6 +949,52 @@ mod tests {
922949
assert!(parse_ado_remote("not-a-url").is_err());
923950
}
924951

952+
// ==================== Org URL normalization ====================
953+
954+
#[test]
955+
fn normalize_org_url_accepts_bare_name() {
956+
assert_eq!(
957+
normalize_org_url("myorg"),
958+
"https://dev.azure.com/myorg"
959+
);
960+
}
961+
962+
#[test]
963+
fn normalize_org_url_preserves_full_url() {
964+
assert_eq!(
965+
normalize_org_url("https://dev.azure.com/myorg"),
966+
"https://dev.azure.com/myorg"
967+
);
968+
}
969+
970+
#[test]
971+
fn normalize_org_url_strips_trailing_slash() {
972+
assert_eq!(
973+
normalize_org_url("https://dev.azure.com/myorg/"),
974+
"https://dev.azure.com/myorg"
975+
);
976+
}
977+
978+
#[test]
979+
fn normalize_org_url_rewrites_legacy_visualstudio() {
980+
assert_eq!(
981+
normalize_org_url("https://myorg.visualstudio.com"),
982+
"https://dev.azure.com/myorg"
983+
);
984+
assert_eq!(
985+
normalize_org_url("https://myorg.visualstudio.com/"),
986+
"https://dev.azure.com/myorg"
987+
);
988+
}
989+
990+
#[test]
991+
fn normalize_org_url_trims_whitespace() {
992+
assert_eq!(
993+
normalize_org_url(" myorg "),
994+
"https://dev.azure.com/myorg"
995+
);
996+
}
997+
925998
// ==================== Fuzzy name matching ====================
926999

9271000
fn make_def(id: u64, name: &str) -> DefinitionSummary {

src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ enum Commands {
118118
/// The new GITHUB_TOKEN value (defaults to GITHUB_TOKEN env var; prompted if omitted)
119119
#[arg(long, env = "GITHUB_TOKEN")]
120120
token: Option<String>,
121-
/// Override: Azure DevOps organization URL (inferred from git remote by default)
121+
/// Override: Azure DevOps organization (URL like `https://dev.azure.com/myorg`,
122+
/// or just the org name `myorg`). Inferred from git remote by default.
122123
#[arg(long)]
123124
org: Option<String>,
124125
/// Override: Azure DevOps project name (inferred from git remote by default)

0 commit comments

Comments
 (0)