protected override async Task ProcessCommandInternalAsync(
            AgentTaskPluginExecutionContext context,
            CancellationToken token)
        {
            ArgUtil.NotNull(context, nameof(context));
            string artifactName              = context.GetInput(ArtifactEventProperties.ArtifactName, required: false);
            string branchName                = context.GetInput(ArtifactEventProperties.BranchName, required: false);
            string pipelineDefinition        = context.GetInput(ArtifactEventProperties.PipelineDefinition, required: false);
            string sourceRun                 = context.GetInput(ArtifactEventProperties.SourceRun, required: true);
            string pipelineTriggering        = context.GetInput(ArtifactEventProperties.PipelineTriggering, required: false);
            string pipelineVersionToDownload = context.GetInput(ArtifactEventProperties.PipelineVersionToDownload, required: false);
            string targetPath                = context.GetInput(DownloadPath, required: true);
            string environmentBuildId        = context.Variables.GetValueOrDefault(BuildVariables.BuildId)?.Value ?? string.Empty; // BuildID provided by environment.
            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 userSpecifiedpipelineId = context.GetInput(pipelineRunId, required: false);
            string defaultWorkingDirectory = context.Variables.GetValueOrDefault("system.defaultworkingdirectory").Value;

            targetPath = Path.IsPathFullyQualified(targetPath) ? targetPath : Path.GetFullPath(Path.Combine(defaultWorkingDirectory, targetPath));

            bool onPrem = !String.Equals(context.Variables.GetValueOrDefault(WellKnownDistributedTaskVariables.ServerType)?.Value, "Hosted", StringComparison.OrdinalIgnoreCase);

            if (onPrem)
            {
                throw new InvalidOperationException(StringUtil.Loc("OnPremIsNotSupported"));
            }

            if (!PipelineArtifactPathHelper.IsValidArtifactName(artifactName))
            {
                throw new ArgumentException(StringUtil.Loc("ArtifactNameIsNotValid", artifactName));
            }

            string[] minimatchPatterns = itemPattern.Split(
                new[] { "\n" },
                StringSplitOptions.RemoveEmptyEntries
                );

            string[] tagsInput = tags.Split(
                new[] { "," },
                StringSplitOptions.None
                );

            PipelineArtifactServer             server = new PipelineArtifactServer(tracer);
            PipelineArtifactDownloadParameters downloadParameters;

            if (sourceRun == sourceRunCurrent)
            {
                // TODO: use a constant for project id, which is currently defined in Microsoft.VisualStudio.Services.Agent.Constants.Variables.System.TeamProjectId (Ting)
                string projectIdStr = context.Variables.GetValueOrDefault("system.teamProjectId")?.Value;
                if (String.IsNullOrEmpty(projectIdStr))
                {
                    throw new ArgumentNullException("Project ID cannot be null.");
                }
                Guid projectId = Guid.Parse(projectIdStr);
                ArgUtil.NotEmpty(projectId, nameof(projectId));

                int pipelineId = 0;
                if (int.TryParse(environmentBuildId, out pipelineId) && pipelineId != 0)
                {
                    context.Output(StringUtil.Loc("DownloadingFromBuild", pipelineId));
                }
                else
                {
                    string hostType = context.Variables.GetValueOrDefault("system.hosttype")?.Value;
                    if (string.Equals(hostType, "Release", StringComparison.OrdinalIgnoreCase) ||
                        string.Equals(hostType, "DeploymentGroup", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new InvalidOperationException(StringUtil.Loc("BuildIdIsNotAvailable", hostType ?? string.Empty, hostType ?? string.Empty));
                    }
                    else if (!string.Equals(hostType, "Build", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new InvalidOperationException(StringUtil.Loc("CannotDownloadFromCurrentEnvironment", hostType ?? string.Empty));
                    }
                    else
                    {
                        // This should not happen since the build id comes from build environment. But a user may override that so we must be careful.
                        throw new ArgumentException(StringUtil.Loc("BuildIdIsNotValid", environmentBuildId));
                    }
                }

                downloadParameters = new PipelineArtifactDownloadParameters
                {
                    ProjectRetrievalOptions = BuildArtifactRetrievalOptions.RetrieveByProjectId,
                    ProjectId        = projectId,
                    PipelineId       = pipelineId,
                    ArtifactName     = artifactName,
                    TargetDirectory  = targetPath,
                    MinimatchFilters = minimatchPatterns,
                    MinimatchFilterWithArtifactName = true
                };
            }
            else if (sourceRun == sourceRunSpecific)
            {
                if (String.IsNullOrEmpty(projectName))
                {
                    throw new ArgumentNullException("Project Name cannot be null.");
                }
                Guid projectId  = Guid.Parse(projectName);
                int? pipelineId = null;

                bool pipelineTriggeringBool = false;
                if (bool.TryParse(pipelineTriggering, out pipelineTriggeringBool) && pipelineTriggeringBool)
                {
                    string triggeringPipeline = context.Variables.GetValueOrDefault("build.triggeredBy.buildId")?.Value;

                    if (!string.IsNullOrEmpty(triggeringPipeline))
                    {
                        pipelineId = int.Parse(triggeringPipeline);
                    }
                }

                if (!pipelineId.HasValue)
                {
                    if (pipelineVersionToDownload == pipelineVersionToDownloadLatest)
                    {
                        pipelineId = await this.GetPipelineIdAsync(context, pipelineDefinition, pipelineVersionToDownload, projectName, tagsInput);
                    }
                    else if (pipelineVersionToDownload == pipelineVersionToDownloadSpecific)
                    {
                        pipelineId = Int32.Parse(userSpecifiedpipelineId);
                    }
                    else if (pipelineVersionToDownload == pipelineVersionToDownloadLatestFromBranch)
                    {
                        pipelineId = await this.GetPipelineIdAsync(context, pipelineDefinition, pipelineVersionToDownload, projectName, tagsInput, branchName);
                    }
                    else
                    {
                        throw new InvalidOperationException("Unreachable code!");
                    }
                }

                context.Output(StringUtil.Loc("DownloadingFromBuild", pipelineId));

                downloadParameters = new PipelineArtifactDownloadParameters
                {
                    ProjectRetrievalOptions = BuildArtifactRetrievalOptions.RetrieveByProjectName,
                    ProjectName             = projectName,
                    ProjectId        = projectId,
                    PipelineId       = pipelineId.Value,
                    ArtifactName     = artifactName,
                    TargetDirectory  = targetPath,
                    MinimatchFilters = minimatchPatterns,
                    MinimatchFilterWithArtifactName = true
                };
            }
            else
            {
                throw new InvalidOperationException($"Build type '{sourceRun}' is not recognized.");
            }

            string fullPath = this.CreateDirectoryIfDoesntExist(targetPath);

            DownloadOptions downloadOptions;

            if (string.IsNullOrEmpty(downloadParameters.ArtifactName))
            {
                downloadOptions = DownloadOptions.MultiDownload;
            }
            else
            {
                downloadOptions = DownloadOptions.SingleDownload;
            }

            context.Output(StringUtil.Loc("DownloadArtifactTo", targetPath));
            await server.DownloadAsyncV2(context, downloadParameters, downloadOptions, token);

            context.Output(StringUtil.Loc("DownloadArtifactFinished"));
        }
        protected override async Task ProcessCommandInternalAsync(
            AgentTaskPluginExecutionContext context,
            CancellationToken token)
        {
            string artifactName = context.GetInput(ArtifactEventProperties.ArtifactName, required: false);

            if (string.IsNullOrEmpty(artifactName))
            {
                context.Output($"Artifact name was not inserted for publishing.");
            }
            else
            {
                context.Output($"Artifact name input: {artifactName}");
            }
            string targetPath   = context.GetInput(TargetPath, required: true);
            string artifactType = context.GetInput(ArtifactEventProperties.ArtifactType, required: false);

            artifactType = string.IsNullOrEmpty(artifactType) ? pipelineType : artifactType.ToLower();

            string defaultWorkingDirectory = context.Variables.GetValueOrDefault("system.defaultworkingdirectory").Value;

            bool onPrem = !String.Equals(context.Variables.GetValueOrDefault(WellKnownDistributedTaskVariables.ServerType)?.Value, "Hosted", StringComparison.OrdinalIgnoreCase);

            if (onPrem)
            {
                throw new InvalidOperationException(StringUtil.Loc("OnPremIsNotSupported"));
            }

            targetPath = Path.IsPathFullyQualified(targetPath) ? targetPath : Path.GetFullPath(Path.Combine(defaultWorkingDirectory, targetPath));

            // Project ID
            var  teamProjectId = context.Variables.GetValueOrDefault(BuildVariables.TeamProjectId)?.Value;
            Guid projectId     = teamProjectId != null ? new Guid(teamProjectId) : Guid.Empty;

            ArgUtil.NotEmpty(projectId, nameof(projectId));

            // Build ID
            string buildIdStr = context.Variables.GetValueOrDefault(BuildVariables.BuildId)?.Value ?? string.Empty;

            if (!int.TryParse(buildIdStr, out int buildId))
            {
                // This should not happen since the build id comes from build environment. But a user may override that so we must be careful.
                throw new ArgumentException(StringUtil.Loc("BuildIdIsNotValid", buildIdStr));
            }

            if (artifactType == pipelineType)
            {
                string hostType = context.Variables.GetValueOrDefault(WellKnownDistributedTaskVariables.HostType)?.Value;
                if (!string.Equals(hostType, "Build", StringComparison.OrdinalIgnoreCase))
                {
                    throw new InvalidOperationException(
                              StringUtil.Loc("CannotUploadFromCurrentEnvironment", hostType ?? string.Empty));
                }

                if (String.IsNullOrWhiteSpace(artifactName))
                {
                    string jobIdentifier           = context.Variables.GetValueOrDefault(WellKnownDistributedTaskVariables.JobIdentifier).Value;
                    var    normalizedJobIdentifier = NormalizeJobIdentifier(jobIdentifier);
                    artifactName = normalizedJobIdentifier;
                }

                if (!PipelineArtifactPathHelper.IsValidArtifactName(artifactName))
                {
                    throw new ArgumentException(StringUtil.Loc("ArtifactNameIsNotValid", artifactName));
                }

                string fullPath = Path.GetFullPath(targetPath);
                bool   isFile   = File.Exists(fullPath);
                bool   isDir    = Directory.Exists(fullPath);
                if (!isFile && !isDir)
                {
                    // if local path is neither file nor folder
                    throw new FileNotFoundException(StringUtil.Loc("PathDoesNotExist", targetPath));
                }

                // Upload to VSTS BlobStore, and associate the artifact with the build.
                context.Output(StringUtil.Loc("UploadingPipelineArtifact", fullPath, buildId));
                PipelineArtifactServer server = new PipelineArtifactServer(tracer);
                await server.UploadAsync(context, projectId, buildId, artifactName, fullPath, token);

                context.Output(StringUtil.Loc("UploadArtifactFinished"));
            }
            else if (artifactType == fileShareType)
            {
                string fileSharePath = context.GetInput(ArtifactEventProperties.FileSharePath, required: true);

                fileSharePath = Path.IsPathFullyQualified(fileSharePath) ? fileSharePath : Path.GetFullPath(Path.Combine(defaultWorkingDirectory, fileSharePath));

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    FilePathServer server = new FilePathServer();
                    await server.UploadAsync(context, projectId, buildId, artifactName, targetPath, fileSharePath, token);
                }
                else
                {
                    // file share artifacts are not currently supported on OSX/Linux.
                    throw new InvalidOperationException(StringUtil.Loc("FileShareOperatingSystemNotSupported"));
                }
            }
        }
Beispiel #3
0
        protected override async Task ProcessCommandInternalAsync(
            AgentTaskPluginExecutionContext context,
            CancellationToken token)
        {
            string artifactName            = context.GetInput(ArtifactEventProperties.ArtifactName, required: false);
            string targetPath              = context.GetInput(TargetPath, required: true);
            string defaultWorkingDirectory = context.Variables.GetValueOrDefault("system.defaultworkingdirectory").Value;

            targetPath = Path.IsPathFullyQualified(targetPath) ? targetPath : Path.GetFullPath(Path.Combine(defaultWorkingDirectory, targetPath));

            string hostType = context.Variables.GetValueOrDefault(WellKnownDistributedTaskVariables.HostType)?.Value;

            if (!string.Equals(hostType, "Build", StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException(
                          StringUtil.Loc("CannotUploadFromCurrentEnvironment", hostType ?? string.Empty));
            }

            if (String.IsNullOrWhiteSpace(artifactName))
            {
                string jobIdentifier           = context.Variables.GetValueOrDefault(WellKnownDistributedTaskVariables.JobIdentifier).Value;
                var    normalizedJobIdentifier = NormalizeJobIdentifier(jobIdentifier);
                artifactName = normalizedJobIdentifier;
            }

            if (!PipelineArtifactPathHelper.IsValidArtifactName(artifactName))
            {
                throw new ArgumentException(StringUtil.Loc("ArtifactNameIsNotValid", artifactName));
            }

            // Project ID
            Guid projectId = new Guid(context.Variables.GetValueOrDefault(BuildVariables.TeamProjectId)?.Value ?? Guid.Empty.ToString());

            ArgUtil.NotEmpty(projectId, nameof(projectId));

            // Build ID
            string buildIdStr = context.Variables.GetValueOrDefault(BuildVariables.BuildId)?.Value ?? string.Empty;

            if (!int.TryParse(buildIdStr, out int buildId))
            {
                // This should not happen since the build id comes from build environment. But a user may override that so we must be careful.
                throw new ArgumentException(StringUtil.Loc("BuildIdIsNotValid", buildIdStr));
            }

            string fullPath = Path.GetFullPath(targetPath);
            bool   isFile   = File.Exists(fullPath);
            bool   isDir    = Directory.Exists(fullPath);

            if (!isFile && !isDir)
            {
                // if local path is neither file nor folder
                throw new FileNotFoundException(StringUtil.Loc("PathDoesNotExist", targetPath));
            }

            // Upload to VSTS BlobStore, and associate the artifact with the build.
            context.Output(StringUtil.Loc("UploadingPipelineArtifact", fullPath, buildId));
            PipelineArtifactServer server = new PipelineArtifactServer();
            await server.UploadAsync(context, projectId, buildId, artifactName, fullPath, token);

            context.Output(StringUtil.Loc("UploadArtifactFinished"));
        }
Beispiel #4
0
        protected override async Task ProcessCommandInternalAsync(
            AgentTaskPluginExecutionContext context,
            CancellationToken token)
        {
            ArgUtil.NotNull(context, nameof(context));
            string artifactName              = context.GetInput(ArtifactEventProperties.ArtifactName, required: false);
            string branchName                = context.GetInput(ArtifactEventProperties.BranchName, required: false);
            string pipelineDefinition        = context.GetInput(ArtifactEventProperties.PipelineDefinition, required: false);
            string sourceRun                 = context.GetInput(ArtifactEventProperties.SourceRun, required: true);
            string pipelineTriggering        = context.GetInput(ArtifactEventProperties.PipelineTriggering, required: false);
            string pipelineVersionToDownload = context.GetInput(ArtifactEventProperties.PipelineVersionToDownload, required: false);
            string targetPath                = context.GetInput(DownloadPath, required: true);
            string environmentBuildId        = context.Variables.GetValueOrDefault(BuildVariables.BuildId)?.Value ?? string.Empty; // BuildID provided by environment.
            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 allowCanceledBuilds           = context.GetInput(ArtifactEventProperties.AllowCanceledBuilds, required: false);
            string userSpecifiedRunId            = context.GetInput(RunId, required: false);
            string defaultWorkingDirectory       = context.Variables.GetValueOrDefault("system.defaultworkingdirectory").Value;

            targetPath = Path.IsPathFullyQualified(targetPath) ? targetPath : Path.GetFullPath(Path.Combine(defaultWorkingDirectory, targetPath));
            context.Debug($"TargetPath: {targetPath}");

            bool onPrem = !String.Equals(context.Variables.GetValueOrDefault(WellKnownDistributedTaskVariables.ServerType)?.Value, "Hosted", StringComparison.OrdinalIgnoreCase);

            if (onPrem)
            {
                throw new InvalidOperationException(StringUtil.Loc("OnPremIsNotSupported"));
            }

            if (!PipelineArtifactPathHelper.IsValidArtifactName(artifactName))
            {
                throw new ArgumentException(StringUtil.Loc("ArtifactNameIsNotValid", artifactName));
            }
            context.Debug($"ArtifactName: {artifactName}");

            string[] minimatchPatterns = itemPattern.Split(
                new[] { "\n" },
                StringSplitOptions.RemoveEmptyEntries
                );

            string[] tagsInput = tags.Split(
                new[] { "," },
                StringSplitOptions.None
                );

            if (!bool.TryParse(allowPartiallySucceededBuilds, out var allowPartiallySucceededBuildsBool))
            {
                allowPartiallySucceededBuildsBool = false;
            }
            if (!bool.TryParse(allowFailedBuilds, out var allowFailedBuildsBool))
            {
                allowFailedBuildsBool = false;
            }
            if (!bool.TryParse(allowCanceledBuilds, out var allowCanceledBuildsBool))
            {
                allowCanceledBuildsBool = false;
            }
            var resultFilter = GetResultFilter(allowPartiallySucceededBuildsBool, allowFailedBuildsBool, allowCanceledBuildsBool);

            context.Debug($"BuildResult: {resultFilter.ToString()}");

            PipelineArtifactServer     server = new PipelineArtifactServer(tracer);
            ArtifactDownloadParameters downloadParameters;

            if (sourceRun == sourceRunCurrent)
            {
                context.Debug("Run: CurrentRun");
                // TODO: use a constant for project id, which is currently defined in Microsoft.VisualStudio.Services.Agent.Constants.Variables.System.TeamProjectId (Ting)
                string projectIdStr = context.Variables.GetValueOrDefault("system.teamProjectId")?.Value;
                if (String.IsNullOrEmpty(projectIdStr))
                {
                    throw new ArgumentNullException(StringUtil.Loc("CannotBeNullOrEmpty"), "Project ID");
                }

                Guid projectId = Guid.Parse(projectIdStr);
                ArgUtil.NotEmpty(projectId, nameof(projectId));
                context.Debug($"ProjectId: {projectId.ToString()}");

                int pipelineId = 0;
                if (int.TryParse(environmentBuildId, out pipelineId) && pipelineId != 0)
                {
                    OutputBuildInfo(context, pipelineId);
                }
                else
                {
                    string hostType = context.Variables.GetValueOrDefault("system.hosttype")?.Value;
                    if (string.Equals(hostType, "Release", StringComparison.OrdinalIgnoreCase) ||
                        string.Equals(hostType, "DeploymentGroup", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new InvalidOperationException(StringUtil.Loc("BuildIdIsNotAvailable", hostType ?? string.Empty, hostType ?? string.Empty));
                    }
                    else if (!string.Equals(hostType, "Build", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new InvalidOperationException(StringUtil.Loc("CannotDownloadFromCurrentEnvironment", hostType ?? string.Empty));
                    }
                    else
                    {
                        // This should not happen since the build id comes from build environment. But a user may override that so we must be careful.
                        throw new ArgumentException(StringUtil.Loc("BuildIdIsNotValid", environmentBuildId));
                    }
                }

                downloadParameters = new ArtifactDownloadParameters
                {
                    ProjectRetrievalOptions = BuildArtifactRetrievalOptions.RetrieveByProjectId,
                    ProjectId        = projectId,
                    PipelineId       = pipelineId,
                    ArtifactName     = artifactName,
                    TargetDirectory  = targetPath,
                    MinimatchFilters = minimatchPatterns,
                    MinimatchFilterWithArtifactName = true
                };
            }
            else if (sourceRun == sourceRunSpecific)
            {
                context.Debug("Run: Specific");
                if (String.IsNullOrEmpty(projectName))
                {
                    throw new ArgumentNullException(StringUtil.Loc("CannotBeNullOrEmpty"), "Project Name");
                }
                Guid projectId;
                bool isProjGuid = Guid.TryParse(projectName, out projectId);
                if (!isProjGuid)
                {
                    projectId = await GetProjectIdAsync(context, projectName);
                }
                context.Debug($"ProjectId: {projectId.ToString()}");
                // Set the default pipelineId to 0, which is an invalid build id and it has to be reassigned to a valid build id.
                int pipelineId = 0;

                bool pipelineTriggeringBool;
                if (bool.TryParse(pipelineTriggering, out pipelineTriggeringBool) && pipelineTriggeringBool)
                {
                    context.Debug("TrigerringPipeline: true");
                    string hostType           = context.Variables.GetValueOrDefault("system.hostType").Value;
                    string triggeringPipeline = null;
                    if (!string.IsNullOrWhiteSpace(hostType) && !hostType.Equals("build", StringComparison.OrdinalIgnoreCase)) // RM env.
                    {
                        context.Debug("Environment: Release");
                        var releaseAlias          = context.Variables.GetValueOrDefault("release.triggeringartifact.alias")?.Value;
                        var definitionIdTriggered = context.Variables.GetValueOrDefault("release.artifacts." + releaseAlias ?? string.Empty + ".definitionId")?.Value;
                        if (!string.IsNullOrWhiteSpace(definitionIdTriggered) && definitionIdTriggered.Equals(pipelineDefinition, StringComparison.OrdinalIgnoreCase))
                        {
                            triggeringPipeline = context.Variables.GetValueOrDefault("release.artifacts." + releaseAlias ?? string.Empty + ".buildId")?.Value;
                            context.Debug($"TrigerringPipeline: {triggeringPipeline}");
                        }
                    }
                    else
                    {
                        context.Debug("Environment: Build");
                        var definitionIdTriggered = context.Variables.GetValueOrDefault("build.triggeredBy.definitionId")?.Value;
                        if (!string.IsNullOrWhiteSpace(definitionIdTriggered) && definitionIdTriggered.Equals(pipelineDefinition, StringComparison.OrdinalIgnoreCase))
                        {
                            triggeringPipeline = context.Variables.GetValueOrDefault("build.triggeredBy.buildId")?.Value;
                            context.Debug($"TrigerringPipeline: {triggeringPipeline}");
                        }
                    }

                    if (!string.IsNullOrWhiteSpace(triggeringPipeline))
                    {
                        pipelineId = int.Parse(triggeringPipeline);
                    }
                    context.Debug($"PipelineId from trigerringBuild: {pipelineId}");
                }

                if (pipelineId == 0)
                {
                    context.Debug($"PipelineVersionToDownload: {pipelineVersionToDownload}");
                    if (pipelineVersionToDownload == pipelineVersionToDownloadLatest)
                    {
                        pipelineId = await this.GetPipelineIdAsync(context, pipelineDefinition, pipelineVersionToDownload, projectId.ToString(), tagsInput, resultFilter, null, cancellationToken : token);
                    }
                    else if (pipelineVersionToDownload == pipelineVersionToDownloadSpecific)
                    {
                        bool isPipelineIdNum = Int32.TryParse(userSpecifiedRunId, out pipelineId);
                        if (!isPipelineIdNum)
                        {
                            throw new ArgumentException(StringUtil.Loc("RunIDNotValid", userSpecifiedRunId));
                        }
                    }
                    else if (pipelineVersionToDownload == pipelineVersionToDownloadLatestFromBranch)
                    {
                        pipelineId = await this.GetPipelineIdAsync(context, pipelineDefinition, pipelineVersionToDownload, projectId.ToString(), tagsInput, resultFilter, branchName, cancellationToken : token);
                    }
                    else
                    {
                        throw new InvalidOperationException("Unreachable code!");
                    }
                    context.Debug($"PipelineId from non-trigerringBuild: {pipelineId}");
                }

                OutputBuildInfo(context, pipelineId);

                downloadParameters = new ArtifactDownloadParameters
                {
                    ProjectRetrievalOptions = BuildArtifactRetrievalOptions.RetrieveByProjectName,
                    ProjectName             = projectName,
                    ProjectId        = projectId,
                    PipelineId       = pipelineId,
                    ArtifactName     = artifactName,
                    TargetDirectory  = targetPath,
                    MinimatchFilters = minimatchPatterns,
                    MinimatchFilterWithArtifactName = true
                };
            }
            else
            {
                throw new InvalidOperationException($"Build type '{sourceRun}' is not recognized.");
            }

            string fullPath = this.CreateDirectoryIfDoesntExist(targetPath);

            DownloadOptions downloadOptions;

            if (string.IsNullOrEmpty(downloadParameters.ArtifactName))
            {
                downloadOptions = DownloadOptions.MultiDownload;
            }
            else
            {
                downloadOptions = DownloadOptions.SingleDownload;
            }

            context.Output(StringUtil.Loc("DownloadArtifactTo", targetPath));
            await server.DownloadAsyncV2(context, downloadParameters, downloadOptions, token);

            context.Output(StringUtil.Loc("DownloadArtifactFinished"));
        }