Skip to content

Commit 25dd045

Browse files
committed
Merge PR #1465: Improve rewire-pipeline error handling for disabled repos/pipelines
2 parents ce47d4b + 9ea32af commit 25dd045

File tree

13 files changed

+569
-100
lines changed

13 files changed

+569
-100
lines changed

RELEASENOTES.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
- Added validation to detect and return clear error messages when a URL is provided instead of a name for organization, repository, or enterprise arguments (e.g., `--github-org`, `--github-target-org`, `--source-repo`, `--github-target-enterprise`)
2-
- Added `--target-api-url` as an optional arg to the `add-team-to-repo` command
1+
- **ado2gh**: Improved `rewire-pipeline` command to gracefully handle disabled repositories and pipelines with clear warnings instead of errors
2+
- **ado2gh**: Fixed 404 errors when checking branch policies for classic pipelines with prefixed repository names
3+
- **ado2gh**: Fixed 400 errors when running `rewire-pipeline --dry-run` on disabled pipelines
4+
- **ado2gh**: Fixed misleading success messages when pipeline rewiring was skipped
5+
- **ado2gh**: Fixed monitor timeout minutes to only display when --dry-run mode is enabled, reducing confusion during regular pipeline rewiring operations

src/Octoshift/Commands/CommandArgs.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public abstract class CommandArgs
1313
public virtual void Validate(OctoLogger log)
1414
{ }
1515

16-
public void Log(OctoLogger log)
16+
public virtual void Log(OctoLogger log)
1717
{
1818
if (log is null)
1919
{

src/Octoshift/Services/AdoApi.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,18 @@ public virtual async Task ShareServiceConnection(string adoOrg, string adoTeamPr
562562
return (defaultBranch, clean, checkoutSubmodules, triggers);
563563
}
564564

565+
public virtual async Task<bool> IsPipelineEnabled(string org, string teamProject, int pipelineId)
566+
{
567+
var url = $"{_adoBaseUrl}/{org.EscapeDataString()}/{teamProject.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";
568+
569+
var response = await _client.GetAsync(url);
570+
var data = JObject.Parse(response);
571+
572+
// Check the queueStatus field - it can be "enabled", "disabled", or "paused"
573+
var queueStatus = (string)data["queueStatus"];
574+
return string.IsNullOrEmpty(queueStatus) || queueStatus.Equals("enabled", StringComparison.OrdinalIgnoreCase);
575+
}
576+
565577
public virtual async Task<string> GetBoardsGithubRepoId(string org, string teamProject, string teamProjectId, string endpointId, string githubOrg, string githubRepo)
566578
{
567579
var url = $"{_adoBaseUrl}/{org.EscapeDataString()}/_apis/Contribution/HierarchyQuery?api-version=5.0-preview.1";

src/Octoshift/Services/AdoPipelineTriggerService.cs

Lines changed: 125 additions & 65 deletions
Large diffs are not rendered by default.

src/Octoshift/Services/PipelineTestService.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ public async Task<PipelineTestResult> TestPipeline(PipelineTestArgs args)
5959
args.PipelineId = pipelineId;
6060
}
6161

62+
// Check if pipeline is disabled before attempting to queue a build
63+
var isEnabled = await _adoApi.IsPipelineEnabled(args.AdoOrg, args.AdoTeamProject, args.PipelineId.Value);
64+
if (!isEnabled)
65+
{
66+
_log.LogWarning($"Pipeline '{args.PipelineName}' (ID: {args.PipelineId.Value}) is disabled. Skipping pipeline test.");
67+
testResult.ErrorMessage = "Pipeline is disabled";
68+
testResult.EndTime = DateTime.UtcNow;
69+
return testResult;
70+
}
71+
6272
// Get original repository information for restoration
6373
(originalRepoName, _, originalDefaultBranch, originalClean, originalCheckoutSubmodules) =
6474
await _adoApi.GetPipelineRepository(args.AdoOrg, args.AdoTeamProject, args.PipelineId.Value);

src/OctoshiftCLI.Tests/Octoshift/Services/AdoApiTests.cs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,81 @@ public async Task GetPipeline_Should_Return_Pipeline()
985985
Triggers.Should().NotBeNull();
986986
}
987987

988+
[Fact]
989+
public async Task IsPipelineEnabled_Should_Return_True_For_Enabled_Pipeline()
990+
{
991+
var pipelineId = 826263;
992+
993+
var endpoint = $"https://dev.azure.com/{ADO_ORG.EscapeDataString()}/{ADO_TEAM_PROJECT.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";
994+
var response = new
995+
{
996+
id = pipelineId,
997+
queueStatus = "enabled"
998+
};
999+
1000+
_mockAdoClient.Setup(x => x.GetAsync(endpoint).Result).Returns(response.ToJson());
1001+
1002+
var result = await sut.IsPipelineEnabled(ADO_ORG, ADO_TEAM_PROJECT, pipelineId);
1003+
1004+
result.Should().BeTrue();
1005+
}
1006+
1007+
[Fact]
1008+
public async Task IsPipelineEnabled_Should_Return_False_For_Disabled_Pipeline()
1009+
{
1010+
var pipelineId = 826263;
1011+
1012+
var endpoint = $"https://dev.azure.com/{ADO_ORG.EscapeDataString()}/{ADO_TEAM_PROJECT.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";
1013+
var response = new
1014+
{
1015+
id = pipelineId,
1016+
queueStatus = "disabled"
1017+
};
1018+
1019+
_mockAdoClient.Setup(x => x.GetAsync(endpoint).Result).Returns(response.ToJson());
1020+
1021+
var result = await sut.IsPipelineEnabled(ADO_ORG, ADO_TEAM_PROJECT, pipelineId);
1022+
1023+
result.Should().BeFalse();
1024+
}
1025+
1026+
[Fact]
1027+
public async Task IsPipelineEnabled_Should_Return_False_For_Paused_Pipeline()
1028+
{
1029+
var pipelineId = 826263;
1030+
1031+
var endpoint = $"https://dev.azure.com/{ADO_ORG.EscapeDataString()}/{ADO_TEAM_PROJECT.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";
1032+
var response = new
1033+
{
1034+
id = pipelineId,
1035+
queueStatus = "paused"
1036+
};
1037+
1038+
_mockAdoClient.Setup(x => x.GetAsync(endpoint).Result).Returns(response.ToJson());
1039+
1040+
var result = await sut.IsPipelineEnabled(ADO_ORG, ADO_TEAM_PROJECT, pipelineId);
1041+
1042+
result.Should().BeFalse();
1043+
}
1044+
1045+
[Fact]
1046+
public async Task IsPipelineEnabled_Should_Return_True_For_Missing_QueueStatus()
1047+
{
1048+
var pipelineId = 826263;
1049+
1050+
var endpoint = $"https://dev.azure.com/{ADO_ORG.EscapeDataString()}/{ADO_TEAM_PROJECT.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";
1051+
var response = new
1052+
{
1053+
id = pipelineId
1054+
};
1055+
1056+
_mockAdoClient.Setup(x => x.GetAsync(endpoint).Result).Returns(response.ToJson());
1057+
1058+
var result = await sut.IsPipelineEnabled(ADO_ORG, ADO_TEAM_PROJECT, pipelineId);
1059+
1060+
result.Should().BeTrue();
1061+
}
1062+
9881063
[Fact]
9891064
public async Task GetBoardsGithubRepoId_Should_Return_RepoId()
9901065
{

0 commit comments

Comments
 (0)