public async Task DownloadMultipleArtifactsAsync(PipelineArtifactDownloadParameters downloadParameters, IEnumerable <BuildArtifact> buildArtifacts, CancellationToken cancellationToken) { DedupManifestArtifactClient dedupManifestClient = DedupManifestArtifactClientFactory.CreateDedupManifestClient( this.context, this.connection, cancellationToken, out BlobStoreClientTelemetry clientTelemetry); using (clientTelemetry) { var artifactNameAndManifestIds = buildArtifacts.ToDictionary( keySelector: (a) => a.Name, // keys should be unique, if not something is really wrong elementSelector: (a) => DedupIdentifier.Create(a.Resource.Data)); // 2) download to the target path var options = DownloadDedupManifestArtifactOptions.CreateWithMultiManifestIds( artifactNameAndManifestIds, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters, minimatchFilterWithArtifactName: downloadParameters.MinimatchFilterWithArtifactName); PipelineArtifactActionRecord downloadRecord = clientTelemetry.CreateRecord <PipelineArtifactActionRecord>((level, uri, type) => new PipelineArtifactActionRecord(level, uri, type, nameof(DownloadMultipleArtifactsAsync), this.context)); await clientTelemetry.MeasureActionAsync( record : downloadRecord, actionAsync : async() => { await dedupManifestClient.DownloadAsync(options, cancellationToken); }); // Send results to CustomerIntelligence this.context.PublishTelemetry(area: PipelineArtifactConstants.AzurePipelinesAgent, feature: PipelineArtifactConstants.PipelineArtifact, record: downloadRecord); } }
public async Task DownloadSingleArtifactAsync(PipelineArtifactDownloadParameters downloadParameters, BuildArtifact buildArtifact, CancellationToken cancellationToken) { DedupManifestArtifactClient dedupManifestClient = DedupManifestArtifactClientFactory.CreateDedupManifestClient( this.context, this.connection, cancellationToken, out BlobStoreClientTelemetry clientTelemetry); using (clientTelemetry) { var manifestId = DedupIdentifier.Create(buildArtifact.Resource.Data); var options = DownloadDedupManifestArtifactOptions.CreateWithManifestId( manifestId, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters); PipelineArtifactActionRecord downloadRecord = clientTelemetry.CreateRecord <PipelineArtifactActionRecord>((level, uri, type) => new PipelineArtifactActionRecord(level, uri, type, nameof(DownloadMultipleArtifactsAsync), this.context)); await clientTelemetry.MeasureActionAsync( record : downloadRecord, actionAsync : async() => { await dedupManifestClient.DownloadAsync(options, cancellationToken); }); // Send results to CustomerIntelligence this.context.PublishTelemetry(area: PipelineArtifactConstants.AzurePipelinesAgent, feature: PipelineArtifactConstants.PipelineArtifact, record: downloadRecord); } }
public async Task DownloadMultipleArtifactsAsync(PipelineArtifactDownloadParameters downloadParameters, IEnumerable <BuildArtifact> buildArtifacts, CancellationToken cancellationToken) { foreach (var buildArtifact in buildArtifacts) { var downloadRootPath = Path.Combine(buildArtifact.Resource.Data, buildArtifact.Name); var minimatchPatterns = downloadParameters.MinimatchFilters.Select(pattern => Path.Combine(buildArtifact.Resource.Data, pattern)); await this.CopyFileShareAsync(downloadRootPath, Path.Combine(downloadParameters.TargetDirectory, buildArtifact.Name), minimatchPatterns, cancellationToken); } }
public async Task DownloadSingleArtifactAsync(PipelineArtifactDownloadParameters downloadParameters, BuildArtifact buildArtifact, CancellationToken cancellationToken) { var manifestId = DedupIdentifier.Create(buildArtifact.Resource.Data); var options = DownloadDedupManifestArtifactOptions.CreateWithManifestId( manifestId, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters); await dedupManifestArtifactClient.DownloadAsync(options, cancellationToken); }
public async Task DownloadMultipleArtifactsAsync(PipelineArtifactDownloadParameters downloadParameters, IEnumerable <BuildArtifact> buildArtifacts, CancellationToken cancellationToken) { var artifactNameAndManifestIds = buildArtifacts.ToDictionary( keySelector: (a) => a.Name, // keys should be unique, if not something is really wrong elementSelector: (a) => DedupIdentifier.Create(a.Resource.Data)); // 2) download to the target path var options = DownloadPipelineArtifactOptions.CreateWithMultiManifestIds( artifactNameAndManifestIds, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters); await buildDropManager.DownloadAsync(options, cancellationToken); }
private async Task <FileShareDownloadResult> DownloadArtifactsAsync(PipelineArtifactDownloadParameters downloadParameters, IEnumerable <BuildArtifact> buildArtifacts, CancellationToken cancellationToken) { var records = new List <ArtifactRecord>(); long totalContentSize = 0; int totalFileCount = 0; foreach (var buildArtifact in buildArtifacts) { var downloadRootPath = Path.Combine(buildArtifact.Resource.Data, buildArtifact.Name); var minimatchPatterns = downloadParameters.MinimatchFilters.Select(pattern => Path.Combine(buildArtifact.Resource.Data, pattern)); var record = await this.DownloadFileShareArtifactAsync(downloadRootPath, Path.Combine(downloadParameters.TargetDirectory, buildArtifact.Name), defaultParallelCount, cancellationToken, minimatchPatterns); totalContentSize += record.ContentSize; totalFileCount += record.FileCount; records.Add(record); } return(new FileShareDownloadResult(records, totalFileCount, totalContentSize)); }
// Download pipeline artifact from Azure DevOps BlobStore service through DedupManifestArtifactClient to a target path // Old V0 function internal Task DownloadAsync( AgentTaskPluginExecutionContext context, Guid projectId, int pipelineId, string artifactName, string targetDir, CancellationToken cancellationToken) { var downloadParameters = new PipelineArtifactDownloadParameters { ProjectRetrievalOptions = BuildArtifactRetrievalOptions.RetrieveByProjectId, ProjectId = projectId, PipelineId = pipelineId, ArtifactName = artifactName, TargetDirectory = targetDir }; return(this.DownloadAsync(context, downloadParameters, DownloadOptions.SingleDownload, cancellationToken)); }
public async Task DownloadMultipleArtifactsAsync(PipelineArtifactDownloadParameters downloadParameters, IEnumerable <BuildArtifact> buildArtifacts, CancellationToken cancellationToken, AgentTaskPluginExecutionContext context) { var(dedupManifestClient, clientTelemetry) = await DedupManifestArtifactClientFactory.Instance.CreateDedupManifestClientAsync( this.context, this.connection, cancellationToken); using (clientTelemetry) { var artifactNameAndManifestIds = buildArtifacts.ToDictionary( keySelector: (a) => a.Name, // keys should be unique, if not something is really wrong elementSelector: (a) => DedupIdentifier.Create(a.Resource.Data)); // 2) download to the target path var options = DownloadDedupManifestArtifactOptions.CreateWithMultiManifestIds( artifactNameAndManifestIds, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters, minimatchFilterWithArtifactName: downloadParameters.MinimatchFilterWithArtifactName); PipelineArtifactActionRecord downloadRecord = clientTelemetry.CreateRecord <PipelineArtifactActionRecord>((level, uri, type) => new PipelineArtifactActionRecord(level, uri, type, nameof(DownloadMultipleArtifactsAsync), this.context)); await clientTelemetry.MeasureActionAsync( record : downloadRecord, actionAsync : async() => { await AsyncHttpRetryHelper.InvokeVoidAsync( async() => { await dedupManifestClient.DownloadAsync(options, cancellationToken); }, maxRetries: 3, tracer: tracer, canRetryDelegate: e => true, context: nameof(DownloadMultipleArtifactsAsync), cancellationToken: cancellationToken, continueOnCapturedContext: false); }); // Send results to CustomerIntelligence this.context.PublishTelemetry(area: PipelineArtifactConstants.AzurePipelinesAgent, feature: PipelineArtifactConstants.PipelineArtifact, record: downloadRecord); } }
public async Task DownloadMultipleArtifactsAsync(PipelineArtifactDownloadParameters downloadParameters, IEnumerable <BuildArtifact> buildArtifacts, CancellationToken cancellationToken, AgentTaskPluginExecutionContext context) { context.Warning(StringUtil.Loc("DownloadArtifactWarning", "UNC")); var(dedupManifestClient, clientTelemetry) = await this.factory.CreateDedupManifestClientAsync(context, connection, cancellationToken); using (clientTelemetry) { FileShareActionRecord downloadRecord = clientTelemetry.CreateRecord <FileShareActionRecord>((level, uri, type) => new FileShareActionRecord(level, uri, type, nameof(DownloadArtifactsAsync), context)); await clientTelemetry.MeasureActionAsync( record : downloadRecord, actionAsync : async() => { return(await DownloadArtifactsAsync(downloadParameters, buildArtifacts, cancellationToken)); } ); // Send results to CustomerIntelligence context.PublishTelemetry(area: PipelineArtifactConstants.AzurePipelinesAgent, feature: PipelineArtifactConstants.PipelineArtifact, record: downloadRecord); } }
public async Task DownloadMultipleArtifactsAsync(PipelineArtifactDownloadParameters downloadParameters, IEnumerable <BuildArtifact> buildArtifacts, CancellationToken cancellationToken) { BlobStoreClientTelemetry clientTelemetry; DedupManifestArtifactClient dedupManifestClient = this.factory.CreateDedupManifestClient(context, connection, cancellationToken, out clientTelemetry); using (clientTelemetry) { FileShareActionRecord downloadRecord = clientTelemetry.CreateRecord <FileShareActionRecord>((level, uri, type) => new FileShareActionRecord(level, uri, type, nameof(DownloadArtifactsAsync), context)); await clientTelemetry.MeasureActionAsync( record : downloadRecord, actionAsync : async() => { return(await DownloadArtifactsAsync(downloadParameters, buildArtifacts, cancellationToken)); } ); // Send results to CustomerIntelligence context.PublishTelemetry(area: PipelineArtifactConstants.AzurePipelinesAgent, feature: PipelineArtifactConstants.PipelineArtifact, record: downloadRecord); } }
public async Task DownloadSingleArtifactAsync(PipelineArtifactDownloadParameters downloadParameters, BuildArtifact buildArtifact, CancellationToken cancellationToken, AgentTaskPluginExecutionContext context) { var(dedupManifestClient, clientTelemetry) = await DedupManifestArtifactClientFactory.Instance.CreateDedupManifestClientAsync( this.context, this.connection, cancellationToken); using (clientTelemetry) { var manifestId = DedupIdentifier.Create(buildArtifact.Resource.Data); var options = DownloadDedupManifestArtifactOptions.CreateWithManifestId( manifestId, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters); PipelineArtifactActionRecord downloadRecord = clientTelemetry.CreateRecord <PipelineArtifactActionRecord>((level, uri, type) => new PipelineArtifactActionRecord(level, uri, type, nameof(DownloadMultipleArtifactsAsync), this.context)); await clientTelemetry.MeasureActionAsync( record : downloadRecord, actionAsync : async() => { await AsyncHttpRetryHelper.InvokeVoidAsync( async() => { await dedupManifestClient.DownloadAsync(options, cancellationToken); }, maxRetries: 3, tracer: tracer, canRetryDelegate: e => true, context: nameof(DownloadSingleArtifactAsync), cancellationToken: cancellationToken, continueOnCapturedContext: false); }); // Send results to CustomerIntelligence this.context.PublishTelemetry(area: PipelineArtifactConstants.AzurePipelinesAgent, feature: PipelineArtifactConstants.PipelineArtifact, record: downloadRecord); } }
// Download with minimatch patterns, V1. internal async Task DownloadAsync( AgentTaskPluginExecutionContext context, PipelineArtifactDownloadParameters downloadParameters, DownloadOptions downloadOptions, CancellationToken cancellationToken) { VssConnection connection = context.VssConnection; BlobStoreClientTelemetry clientTelemetry; DedupManifestArtifactClient dedupManifestClient = DedupManifestArtifactClientFactory.CreateDedupManifestClient(context, connection, out clientTelemetry); BuildServer buildHelper = new BuildServer(connection); using (clientTelemetry) { // download all pipeline artifacts if artifact name is missing if (downloadOptions == DownloadOptions.MultiDownload) { List <BuildArtifact> artifacts; if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectId) { artifacts = await buildHelper.GetArtifactsAsync(downloadParameters.ProjectId, downloadParameters.PipelineId, cancellationToken); } else if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectName) { if (string.IsNullOrEmpty(downloadParameters.ProjectName)) { throw new InvalidOperationException("Project name can't be empty when trying to fetch build artifacts!"); } else { artifacts = await buildHelper.GetArtifactsWithProjectNameAsync(downloadParameters.ProjectName, downloadParameters.PipelineId, cancellationToken); } } else { throw new InvalidOperationException($"Invalid {nameof(downloadParameters.ProjectRetrievalOptions)}!"); } IEnumerable <BuildArtifact> pipelineArtifacts = artifacts.Where(a => a.Resource.Type == PipelineArtifactConstants.PipelineArtifact); if (pipelineArtifacts.Count() == 0) { throw new ArgumentException("Could not find any pipeline artifacts in the build."); } else { context.Output(StringUtil.Loc("DownloadingMultiplePipelineArtifacts", pipelineArtifacts.Count())); var artifactNameAndManifestIds = pipelineArtifacts.ToDictionary( keySelector: (a) => a.Name, // keys should be unique, if not something is really wrong elementSelector: (a) => DedupIdentifier.Create(a.Resource.Data)); // 2) download to the target path var options = DownloadPipelineArtifactOptions.CreateWithMultiManifestIds( artifactNameAndManifestIds, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters); PipelineArtifactActionRecord downloadRecord = clientTelemetry.CreateRecord <PipelineArtifactActionRecord>((level, uri, type) => new PipelineArtifactActionRecord(level, uri, type, nameof(DownloadAsync), context)); await clientTelemetry.MeasureActionAsync( record : downloadRecord, actionAsync : async() => { await dedupManifestClient.DownloadAsync(options, cancellationToken); }); // Send results to CustomerIntelligence context.PublishTelemetry(area: PipelineArtifactConstants.AzurePipelinesAgent, feature: PipelineArtifactConstants.PipelineArtifact, record: downloadRecord); } } else if (downloadOptions == DownloadOptions.SingleDownload) { // 1) get manifest id from artifact data BuildArtifact buildArtifact; if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectId) { buildArtifact = await buildHelper.GetArtifact(downloadParameters.ProjectId, downloadParameters.PipelineId, downloadParameters.ArtifactName, cancellationToken); } else if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectName) { if (string.IsNullOrEmpty(downloadParameters.ProjectName)) { throw new InvalidOperationException("Project name can't be empty when trying to fetch build artifacts!"); } else { buildArtifact = await buildHelper.GetArtifactWithProjectNameAsync(downloadParameters.ProjectName, downloadParameters.PipelineId, downloadParameters.ArtifactName, cancellationToken); } } else { throw new InvalidOperationException($"Invalid {nameof(downloadParameters.ProjectRetrievalOptions)}!"); } var manifestId = DedupIdentifier.Create(buildArtifact.Resource.Data); var options = DownloadPipelineArtifactOptions.CreateWithManifestId( manifestId, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters); PipelineArtifactActionRecord downloadRecord = clientTelemetry.CreateRecord <PipelineArtifactActionRecord>((level, uri, type) => new PipelineArtifactActionRecord(level, uri, type, nameof(DownloadAsync), context)); await clientTelemetry.MeasureActionAsync( record : downloadRecord, actionAsync : async() => { await dedupManifestClient.DownloadAsync(options, cancellationToken); }); // Send results to CustomerIntelligence context.PublishTelemetry(area: PipelineArtifactConstants.AzurePipelinesAgent, feature: PipelineArtifactConstants.PipelineArtifact, record: downloadRecord); } else { throw new InvalidOperationException($"Invalid {nameof(downloadOptions)}!"); } } }
// Download for version 2. This decision was made because version 1 is sealed and we didn't want to break any existing customers. internal async Task DownloadAsyncV2( AgentTaskPluginExecutionContext context, PipelineArtifactDownloadParameters downloadParameters, DownloadOptions downloadOptions, CancellationToken cancellationToken) { VssConnection connection = context.VssConnection; BuildServer buildHelper = new BuildServer(connection); // download all pipeline artifacts if artifact name is missing if (downloadOptions == DownloadOptions.MultiDownload) { List <BuildArtifact> artifacts; if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectId) { artifacts = await buildHelper.GetArtifactsAsync(downloadParameters.ProjectId, downloadParameters.PipelineId, cancellationToken); } else if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectName) { if (string.IsNullOrEmpty(downloadParameters.ProjectName)) { throw new InvalidOperationException("Project name can't be empty when trying to fetch build artifacts!"); } else { artifacts = await buildHelper.GetArtifactsWithProjectNameAsync(downloadParameters.ProjectName, downloadParameters.PipelineId, cancellationToken); } } else { throw new InvalidOperationException($"Invalid {nameof(downloadParameters.ProjectRetrievalOptions)}!"); } IEnumerable <BuildArtifact> buildArtifacts = artifacts.Where(a => a.Resource.Type == PipelineArtifactConstants.Container); IEnumerable <BuildArtifact> pipelineArtifacts = artifacts.Where(a => a.Resource.Type == PipelineArtifactConstants.PipelineArtifact); if (buildArtifacts.Any()) { FileContainerProvider provider = new FileContainerProvider(connection, this.CreateTracer(context)); await provider.DownloadMultipleArtifactsAsync(downloadParameters, buildArtifacts, cancellationToken); } if (pipelineArtifacts.Any()) { PipelineArtifactProvider provider = new PipelineArtifactProvider(context, connection, this.CreateTracer(context)); await provider.DownloadMultipleArtifactsAsync(downloadParameters, pipelineArtifacts, cancellationToken); } } else if (downloadOptions == DownloadOptions.SingleDownload) { // 1) get manifest id from artifact data BuildArtifact buildArtifact; if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectId) { buildArtifact = await buildHelper.GetArtifact(downloadParameters.ProjectId, downloadParameters.PipelineId, downloadParameters.ArtifactName, cancellationToken); } else if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectName) { if (string.IsNullOrEmpty(downloadParameters.ProjectName)) { throw new InvalidOperationException("Project name can't be empty when trying to fetch build artifacts!"); } else { buildArtifact = await buildHelper.GetArtifactWithProjectNameAsync(downloadParameters.ProjectName, downloadParameters.PipelineId, downloadParameters.ArtifactName, cancellationToken); } } else { throw new InvalidOperationException($"Invalid {nameof(downloadParameters.ProjectRetrievalOptions)}!"); } ArtifactProviderFactory factory = new ArtifactProviderFactory(context, connection, this.CreateTracer(context)); IArtifactProvider provider = factory.GetProvider(buildArtifact); await provider.DownloadSingleArtifactAsync(downloadParameters, buildArtifact, cancellationToken); } else { throw new InvalidOperationException($"Invalid {nameof(downloadOptions)}!"); } }
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")); }
// Download with minimatch patterns. internal async Task DownloadAsync( AgentTaskPluginExecutionContext context, PipelineArtifactDownloadParameters downloadParameters, CancellationToken cancellationToken) { VssConnection connection = context.VssConnection; var buildDropManager = this.CreateBulidDropManager(context, connection); BuildServer buildHelper = new BuildServer(connection); // download all pipeline artifacts if artifact name is missing if (string.IsNullOrEmpty(downloadParameters.ArtifactName)) { List <BuildArtifact> artifacts = await buildHelper.GetArtifactsAsync(downloadParameters.ProjectId, downloadParameters.BuildId, cancellationToken); IEnumerable <BuildArtifact> pipelineArtifacts = artifacts.Where(a => a.Resource.Type == PipelineArtifactTypeName); if (pipelineArtifacts.Count() == 0) { throw new ArgumentException("Could not find any pipeline artifacts in the build."); } else { context.Output(StringUtil.Loc("DownloadingMultiplePipelineArtifacts", pipelineArtifacts.Count())); foreach (BuildArtifact pipelineArtifact in pipelineArtifacts) { // each pipeline artifact will have its own subroot to avoid file collisions string pipelineArtifactRootPath = Path.Combine(downloadParameters.TargetDirectory, pipelineArtifact.Name); await DownloadPipelineArtifact( buildDropManager, pipelineArtifact, pipelineArtifactRootPath, downloadParameters.MinimatchFilters, cancellationToken); } } } else { // 1) get manifest id from artifact data BuildArtifact buildArtifact; if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectId) { buildArtifact = await buildHelper.GetArtifact(downloadParameters.ProjectId, downloadParameters.BuildId, downloadParameters.ArtifactName, cancellationToken); } else if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectName) { if (string.IsNullOrEmpty(downloadParameters.ProjectName)) { throw new InvalidOperationException("Project name can't be empty when trying to fetch build artifacts!"); } else { buildArtifact = await buildHelper.GetArtifactWithProjectNameAsync(downloadParameters.ProjectName, downloadParameters.BuildId, downloadParameters.ArtifactName, cancellationToken); } } else { throw new InvalidOperationException("Unreachable code!"); } await DownloadPipelineArtifact( buildDropManager, buildArtifact, downloadParameters.TargetDirectory, downloadParameters.MinimatchFilters, cancellationToken); } }
protected override async Task ProcessCommandInternalAsync( AgentTaskPluginExecutionContext context, CancellationToken token) { ArgUtil.NotNull(context, nameof(context)); string artifactName = this.GetArtifactName(context); string branchName = context.GetInput(ArtifactEventProperties.BranchName, required: false); string buildPipelineDefinition = context.GetInput(ArtifactEventProperties.BuildPipelineDefinition, required: false); string buildType = context.GetInput(ArtifactEventProperties.BuildType, required: true); string buildTriggering = context.GetInput(ArtifactEventProperties.BuildTriggering, required: false); string buildVersionToDownload = context.GetInput(ArtifactEventProperties.BuildVersionToDownload, required: false); string downloadPath = context.GetInput(ArtifactEventProperties.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 userSpecifiedBuildId = context.GetInput(ArtifactEventProperties.BuildId, required: false); string[] minimatchPatterns = itemPattern.Split( new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries ); string[] tagsInput = tags.Split( new[] { "," }, StringSplitOptions.None ); PipelineArtifactServer server = new PipelineArtifactServer(); PipelineArtifactDownloadParameters downloadParameters; if (buildType == buildTypeCurrent) { // 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 buildId = 0; if (int.TryParse(environmentBuildId, out buildId) && buildId != 0) { context.Output(StringUtil.Loc("DownloadingFromBuild", buildId)); } 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)); } 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, BuildId = buildId, ArtifactName = artifactName, TargetDirectory = downloadPath, MinimatchFilters = minimatchPatterns }; } else if (buildType == buildTypeSpecific) { int buildId; if (buildVersionToDownload == buildVersionToDownloadLatest) { buildId = await this.GetBuildIdAsync(context, buildPipelineDefinition, buildVersionToDownload, projectName, tagsInput); } else if (buildVersionToDownload == buildVersionToDownloadSpecific) { buildId = Int32.Parse(userSpecifiedBuildId); } else if (buildVersionToDownload == buildVersionToDownloadLatestFromBranch) { buildId = await this.GetBuildIdAsync(context, buildPipelineDefinition, buildVersionToDownload, projectName, tagsInput, branchName); } else { throw new InvalidOperationException("Unreachable code!"); } downloadParameters = new PipelineArtifactDownloadParameters { ProjectRetrievalOptions = BuildArtifactRetrievalOptions.RetrieveByProjectName, ProjectName = projectName, BuildId = buildId, ArtifactName = artifactName, TargetDirectory = downloadPath, MinimatchFilters = minimatchPatterns }; } else { throw new InvalidOperationException($"Build type '{buildType}' is not recognized."); } string fullPath = this.CreateDirectoryIfDoesntExist(downloadPath); DownloadOptions downloadOptions; if (string.IsNullOrEmpty(downloadParameters.ArtifactName)) { downloadOptions = DownloadOptions.MultiDownload; } else { downloadOptions = DownloadOptions.SingleDownload; } context.Output(StringUtil.Loc("DownloadArtifactTo", downloadPath)); await server.DownloadAsync(context, downloadParameters, downloadOptions, token); context.Output(StringUtil.Loc("DownloadArtifactFinished")); }
public async Task DownloadSingleArtifactAsync(PipelineArtifactDownloadParameters downloadParameters, BuildArtifact buildArtifact, CancellationToken cancellationToken) { await DownloadMultipleArtifactsAsync(downloadParameters, new List <BuildArtifact> { buildArtifact }, cancellationToken); }
public async Task DownloadMultipleArtifactsAsync(PipelineArtifactDownloadParameters downloadParameters, IEnumerable <BuildArtifact> buildArtifacts, CancellationToken cancellationToken) { await this.DownloadFileContainersAsync(downloadParameters.ProjectId, buildArtifacts, downloadParameters.TargetDirectory, downloadParameters.MinimatchFilters, cancellationToken); }
public async Task DownloadSingleArtifactAsync(PipelineArtifactDownloadParameters downloadParameters, BuildArtifact buildArtifact, CancellationToken cancellationToken) { await this.DownloadFileContainerAsync(downloadParameters.ProjectId, buildArtifact, downloadParameters.TargetDirectory, downloadParameters.MinimatchFilters, cancellationToken); }
public async Task DownloadMultipleArtifactsAsync(PipelineArtifactDownloadParameters downloadParameters, IEnumerable <BuildArtifact> buildArtifacts, CancellationToken cancellationToken, AgentTaskPluginExecutionContext context) { context.Warning(StringUtil.Loc("DownloadArtifactWarning", "Build Artifact")); await this.DownloadFileContainersAsync(downloadParameters.ProjectId, buildArtifacts, downloadParameters.TargetDirectory, downloadParameters.MinimatchFilters, cancellationToken); }
public async Task DownloadSingleArtifactAsync(PipelineArtifactDownloadParameters downloadParameters, BuildArtifact buildArtifact, CancellationToken cancellationToken, AgentTaskPluginExecutionContext context) { await DownloadMultipleArtifactsAsync(downloadParameters, new List <BuildArtifact> { buildArtifact }, cancellationToken, context); }
// Download with minimatch patterns. internal async Task DownloadAsync( AgentTaskPluginExecutionContext context, PipelineArtifactDownloadParameters downloadParameters, DownloadOptions downloadOptions, CancellationToken cancellationToken) { VssConnection connection = context.VssConnection; var buildDropManager = this.CreateBulidDropManager(context, connection); BuildServer buildHelper = new BuildServer(connection); // download all pipeline artifacts if artifact name is missing if (downloadOptions == DownloadOptions.MultiDownload) { List <BuildArtifact> artifacts; if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectId) { artifacts = await buildHelper.GetArtifactsAsync(downloadParameters.ProjectId, downloadParameters.PipelineId, cancellationToken); } else if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectName) { if (string.IsNullOrEmpty(downloadParameters.ProjectName)) { throw new InvalidOperationException("Project name can't be empty when trying to fetch build artifacts!"); } else { artifacts = await buildHelper.GetArtifactsWithProjectNameAsync(downloadParameters.ProjectName, downloadParameters.PipelineId, cancellationToken); } } else { throw new InvalidOperationException("Unreachable code!"); } IEnumerable <BuildArtifact> pipelineArtifacts = artifacts.Where(a => a.Resource.Type == PipelineArtifactTypeName); if (pipelineArtifacts.Count() == 0) { throw new ArgumentException("Could not find any pipeline artifacts in the build."); } else { context.Output(StringUtil.Loc("DownloadingMultiplePipelineArtifacts", pipelineArtifacts.Count())); var artifactNameAndManifestIds = pipelineArtifacts.ToDictionary( keySelector: (a) => a.Name, // keys should be unique, if not something is really wrong elementSelector: (a) => DedupIdentifier.Create(a.Resource.Data)); // 2) download to the target path var options = DownloadPipelineArtifactOptions.CreateWithMultiManifestIds( artifactNameAndManifestIds, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters); await buildDropManager.DownloadAsync(options, cancellationToken); } } else if (downloadOptions == DownloadOptions.SingleDownload) { // 1) get manifest id from artifact data BuildArtifact buildArtifact; if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectId) { buildArtifact = await buildHelper.GetArtifact(downloadParameters.ProjectId, downloadParameters.PipelineId, downloadParameters.ArtifactName, cancellationToken); } else if (downloadParameters.ProjectRetrievalOptions == BuildArtifactRetrievalOptions.RetrieveByProjectName) { if (string.IsNullOrEmpty(downloadParameters.ProjectName)) { throw new InvalidOperationException("Project name can't be empty when trying to fetch build artifacts!"); } else { buildArtifact = await buildHelper.GetArtifactWithProjectNameAsync(downloadParameters.ProjectName, downloadParameters.PipelineId, downloadParameters.ArtifactName, cancellationToken); } } else { throw new InvalidOperationException("Unreachable code!"); } var manifestId = DedupIdentifier.Create(buildArtifact.Resource.Data); var options = DownloadPipelineArtifactOptions.CreateWithManifestId( manifestId, downloadParameters.TargetDirectory, proxyUri: null, minimatchPatterns: downloadParameters.MinimatchFilters); await buildDropManager.DownloadAsync(options, cancellationToken); } else { throw new InvalidOperationException("Unreachable code!"); } }