Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 5 additions & 2 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
- 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`)
- Added `--target-api-url` as an optional arg to the `add-team-to-repo` command
- **ado2gh**: Improved `rewire-pipeline` command to gracefully handle disabled repositories and pipelines with clear warnings instead of errors
- **ado2gh**: Fixed 404 errors when checking branch policies for classic pipelines with prefixed repository names
- **ado2gh**: Fixed 400 errors when running `rewire-pipeline --dry-run` on disabled pipelines
- **ado2gh**: Fixed misleading success messages when pipeline rewiring was skipped
- **ado2gh**: Fixed monitor timeout minutes to only display when --dry-run mode is enabled, reducing confusion during regular pipeline rewiring operations
2 changes: 1 addition & 1 deletion src/Octoshift/Commands/CommandArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public abstract class CommandArgs
public virtual void Validate(OctoLogger log)
{ }

public void Log(OctoLogger log)
public virtual void Log(OctoLogger log)
{
if (log is null)
{
Expand Down
12 changes: 12 additions & 0 deletions src/Octoshift/Services/AdoApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,18 @@ public virtual async Task ShareServiceConnection(string adoOrg, string adoTeamPr
return (defaultBranch, clean, checkoutSubmodules, triggers);
}

public virtual async Task<bool> IsPipelineEnabled(string org, string teamProject, int pipelineId)
{
var url = $"{_adoBaseUrl}/{org.EscapeDataString()}/{teamProject.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";

var response = await _client.GetAsync(url);
var data = JObject.Parse(response);

// Check the queueStatus field - it can be "enabled", "disabled", or "paused"
var queueStatus = (string)data["queueStatus"];
return string.IsNullOrEmpty(queueStatus) || queueStatus.Equals("enabled", StringComparison.OrdinalIgnoreCase);
}

public virtual async Task<string> GetBoardsGithubRepoId(string org, string teamProject, string teamProjectId, string endpointId, string githubOrg, string githubRepo)
{
var url = $"{_adoBaseUrl}/{org.EscapeDataString()}/_apis/Contribution/HierarchyQuery?api-version=5.0-preview.1";
Expand Down
177 changes: 112 additions & 65 deletions src/Octoshift/Services/AdoPipelineTriggerService.cs

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/Octoshift/Services/PipelineTestService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ public async Task<PipelineTestResult> TestPipeline(PipelineTestArgs args)
args.PipelineId = pipelineId;
}

// Check if pipeline is disabled before attempting to queue a build
var isEnabled = await _adoApi.IsPipelineEnabled(args.AdoOrg, args.AdoTeamProject, args.PipelineId.Value);
if (!isEnabled)
{
_log.LogWarning($"Pipeline '{args.PipelineName}' (ID: {args.PipelineId.Value}) is disabled. Skipping pipeline test.");
testResult.ErrorMessage = "Pipeline is disabled";
testResult.EndTime = DateTime.UtcNow;
return testResult;
}

// Get original repository information for restoration
(originalRepoName, _, originalDefaultBranch, originalClean, originalCheckoutSubmodules) =
await _adoApi.GetPipelineRepository(args.AdoOrg, args.AdoTeamProject, args.PipelineId.Value);
Expand Down
75 changes: 75 additions & 0 deletions src/OctoshiftCLI.Tests/Octoshift/Services/AdoApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,81 @@ public async Task GetPipeline_Should_Return_Pipeline()
Triggers.Should().NotBeNull();
}

[Fact]
public async Task IsPipelineEnabled_Should_Return_True_For_Enabled_Pipeline()
{
var pipelineId = 826263;

var endpoint = $"https://dev.azure.com/{ADO_ORG.EscapeDataString()}/{ADO_TEAM_PROJECT.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";
var response = new
{
id = pipelineId,
queueStatus = "enabled"
};

_mockAdoClient.Setup(x => x.GetAsync(endpoint).Result).Returns(response.ToJson());

var result = await sut.IsPipelineEnabled(ADO_ORG, ADO_TEAM_PROJECT, pipelineId);

result.Should().BeTrue();
}

[Fact]
public async Task IsPipelineEnabled_Should_Return_False_For_Disabled_Pipeline()
{
var pipelineId = 826263;

var endpoint = $"https://dev.azure.com/{ADO_ORG.EscapeDataString()}/{ADO_TEAM_PROJECT.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";
var response = new
{
id = pipelineId,
queueStatus = "disabled"
};

_mockAdoClient.Setup(x => x.GetAsync(endpoint).Result).Returns(response.ToJson());

var result = await sut.IsPipelineEnabled(ADO_ORG, ADO_TEAM_PROJECT, pipelineId);

result.Should().BeFalse();
}

[Fact]
public async Task IsPipelineEnabled_Should_Return_False_For_Paused_Pipeline()
{
var pipelineId = 826263;

var endpoint = $"https://dev.azure.com/{ADO_ORG.EscapeDataString()}/{ADO_TEAM_PROJECT.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";
var response = new
{
id = pipelineId,
queueStatus = "paused"
};

_mockAdoClient.Setup(x => x.GetAsync(endpoint).Result).Returns(response.ToJson());

var result = await sut.IsPipelineEnabled(ADO_ORG, ADO_TEAM_PROJECT, pipelineId);

result.Should().BeFalse();
}

[Fact]
public async Task IsPipelineEnabled_Should_Return_True_For_Missing_QueueStatus()
{
var pipelineId = 826263;

var endpoint = $"https://dev.azure.com/{ADO_ORG.EscapeDataString()}/{ADO_TEAM_PROJECT.EscapeDataString()}/_apis/build/definitions/{pipelineId}?api-version=6.0";
var response = new
{
id = pipelineId
};

_mockAdoClient.Setup(x => x.GetAsync(endpoint).Result).Returns(response.ToJson());

var result = await sut.IsPipelineEnabled(ADO_ORG, ADO_TEAM_PROJECT, pipelineId);

result.Should().BeTrue();
}

[Fact]
public async Task GetBoardsGithubRepoId_Should_Return_RepoId()
{
Expand Down
Loading
Loading