diff --git a/releaseNote.md b/releaseNote.md index fa4e99f5ef..5d3359b40d 100644 --- a/releaseNote.md +++ b/releaseNote.md @@ -8,6 +8,7 @@ - Add an option to reduce checkout verbosity (#2547) - Make tarring default for Pipeline Caching and modifying Display to Info from Warning for Save Cache (#2535) - A customer reported an issue of a NPE when initializing secret masker (#2633) +- Add support of minimumBuildStatus property (#2560) ## Bugs - Use DirectorySeparatorChar in git path (#2492) diff --git a/src/Agent.Plugins/PipelineArtifact/PipelineArtifactPluginV2.cs b/src/Agent.Plugins/PipelineArtifact/PipelineArtifactPluginV2.cs index 8558d6eb11..f11a12298f 100644 --- a/src/Agent.Plugins/PipelineArtifact/PipelineArtifactPluginV2.cs +++ b/src/Agent.Plugins/PipelineArtifact/PipelineArtifactPluginV2.cs @@ -46,12 +46,14 @@ protected static class ArtifactEventProperties public static readonly string PipelineVersionToDownload = "runVersion"; public static readonly string BranchName = "runBranch"; public static readonly string Tags = "tags"; + public static readonly string AllowPartiallySucceededBuilds = "allowPartiallySucceededBuilds"; + public static readonly string AllowFailedBuilds = "allowFailedBuilds"; public static readonly string ArtifactName = "artifact"; public static readonly string ItemPattern = "patterns"; } } - // Can be invoked from a build run or a release run should a build be set as the artifact. + // Can be invoked from a build run or a release run should a build be set as the artifact. public class DownloadPipelineArtifactTaskV2_0_0 : PipelineArtifactTaskPluginBaseV2 { // Same as https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/DownloadPipelineArtifactV1/task.json @@ -78,6 +80,8 @@ protected override async Task ProcessCommandInternalAsync( string itemPattern = context.GetInput(ArtifactEventProperties.ItemPattern, required: false); string projectName = context.GetInput(ArtifactEventProperties.Project, required: false); string tags = context.GetInput(ArtifactEventProperties.Tags, required: false); + string allowPartiallySucceededBuilds = context.GetInput(ArtifactEventProperties.AllowPartiallySucceededBuilds, required: false); + string allowFailedBuilds = context.GetInput(ArtifactEventProperties.AllowFailedBuilds, required: false); string userSpecifiedpipelineId = context.GetInput(pipelineRunId, required: false); string defaultWorkingDirectory = context.Variables.GetValueOrDefault("system.defaultworkingdirectory").Value; @@ -104,6 +108,16 @@ protected override async Task ProcessCommandInternalAsync( StringSplitOptions.None ); + if (!bool.TryParse(allowPartiallySucceededBuilds, out var allowPartiallySucceededBuildsBool)) + { + allowPartiallySucceededBuildsBool = false; + } + if (!bool.TryParse(allowFailedBuilds, out var allowFailedBuildsBool)) + { + allowFailedBuildsBool = false; + } + var resultFilter = GetResultFilter(allowPartiallySucceededBuildsBool, allowFailedBuildsBool); + PipelineArtifactServer server = new PipelineArtifactServer(tracer); PipelineArtifactDownloadParameters downloadParameters; @@ -177,7 +191,7 @@ protected override async Task ProcessCommandInternalAsync( { if (pipelineVersionToDownload == pipelineVersionToDownloadLatest) { - pipelineId = await this.GetPipelineIdAsync(context, pipelineDefinition, pipelineVersionToDownload, projectName, tagsInput); + pipelineId = await this.GetPipelineIdAsync(context, pipelineDefinition, pipelineVersionToDownload, projectName, tagsInput, resultFilter, null, cancellationToken: token); } else if (pipelineVersionToDownload == pipelineVersionToDownloadSpecific) { @@ -185,7 +199,7 @@ protected override async Task ProcessCommandInternalAsync( } else if (pipelineVersionToDownload == pipelineVersionToDownloadLatestFromBranch) { - pipelineId = await this.GetPipelineIdAsync(context, pipelineDefinition, pipelineVersionToDownload, projectName, tagsInput, branchName); + pipelineId = await this.GetPipelineIdAsync(context, pipelineDefinition, pipelineVersionToDownload, projectName, tagsInput, resultFilter, branchName, cancellationToken: token); } else { @@ -245,19 +259,31 @@ private string CreateDirectoryIfDoesntExist(string targetPath) return fullPath; } - private async Task GetPipelineIdAsync(AgentTaskPluginExecutionContext context, string pipelineDefinition, string pipelineVersionToDownload, string project, string[] tagFilters, string branchName = null) + private async Task GetPipelineIdAsync(AgentTaskPluginExecutionContext context, string pipelineDefinition, string pipelineVersionToDownload, string project, string[] tagFilters, BuildResult resultFilter = BuildResult.Succeeded, string branchName = null, CancellationToken cancellationToken = default(CancellationToken)) { - var definitions = new List() { Int32.Parse(pipelineDefinition) }; + if(String.IsNullOrWhiteSpace(pipelineDefinition)) + { + throw new InvalidOperationException("Pipeline definition cannot be null or empty"); + } + VssConnection connection = context.VssConnection; BuildHttpClient buildHttpClient = connection.GetClient(); + + var isDefinitionNum = Int32.TryParse(pipelineDefinition, out int definition); + if(!isDefinitionNum) + { + definition = (await buildHttpClient.GetDefinitionsAsync(new System.Guid(project), pipelineDefinition, cancellationToken: cancellationToken)).FirstOrDefault().Id; + } + var definitions = new List() { definition }; + List list; if (pipelineVersionToDownload == "latest") { - list = await buildHttpClient.GetBuildsAsync(project, definitions, tagFilters: tagFilters, queryOrder: BuildQueryOrder.FinishTimeDescending, resultFilter: BuildResult.Succeeded); + list = await buildHttpClient.GetBuildsAsync(project, definitions, tagFilters: tagFilters, queryOrder: BuildQueryOrder.FinishTimeDescending, resultFilter: resultFilter); } else if (pipelineVersionToDownload == "latestFromBranch") { - list = await buildHttpClient.GetBuildsAsync(project, definitions, branchName: branchName, tagFilters: tagFilters, queryOrder: BuildQueryOrder.FinishTimeDescending, resultFilter: BuildResult.Succeeded); + list = await buildHttpClient.GetBuildsAsync(project, definitions, branchName: branchName, tagFilters: tagFilters, queryOrder: BuildQueryOrder.FinishTimeDescending, resultFilter: resultFilter); } else { @@ -273,5 +299,22 @@ private async Task GetPipelineIdAsync(AgentTaskPluginExecutionContext conte throw new ArgumentException("No builds currently exist in the build definition supplied."); } } + + private BuildResult GetResultFilter(bool allowPartiallySucceededBuilds, bool allowFailedBuilds) + { + var result = BuildResult.Succeeded; + + if (allowPartiallySucceededBuilds) + { + result |= BuildResult.PartiallySucceeded; + } + + if (allowFailedBuilds) + { + result |= BuildResult.Failed; + } + + return result; + } } } \ No newline at end of file