private void CreateArtifact(string artifactName, string path) { if (string.IsNullOrEmpty(artifactName) || artifactName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) { throw new InvalidOperationException("Artifact Name cannot contain invalid file name characters: " + new string(Path.GetInvalidFileNameChars())); } if (StoredProcs.Releases_GetRelease(this.Context.ApplicationId, this.Context.ReleaseNumber) .Execute().ReleaseDeployables_Extended .Any(rd => rd.Deployable_Id == this.Context.DeployableId && rd.InclusionType_Code == Domains.DeployableInclusionTypes.Referenced)) { this.LogError( "An Artifact cannot be created for this Deployable because the Deployable is Referenced (as opposed to Included) by this Release. " + "To prevent this error, either include this Deployable in the Release or use a Predicate to prevent this action group from being executed."); return; } var fileOps = this.Context.Agent.GetService <IFileOperationsExecuter>(); var zipPath = fileOps.CombinePath(this.Context.TempDirectory, artifactName + ".zip"); this.LogDebug("Preparing directories..."); fileOps.DeleteFiles(new[] { zipPath }); this.ThrowIfCanceledOrTimeoutExpired(); var rootEntry = fileOps.GetDirectoryEntry( new GetDirectoryEntryCommand { Path = path, Recurse = false, IncludeRootPath = false } ).Entry; if ((rootEntry.Files == null || rootEntry.Files.Length == 0) && (rootEntry.SubDirectories == null || rootEntry.SubDirectories.Length == 0)) { this.LogWarning("There are no files to capture in this artifact."); } this.LogDebug("Zipping output..."); this.Context.Agent.GetService <IRemoteZip>().CreateZipFile(path, zipPath); var zipFileEntry = fileOps.GetFileEntry(zipPath); this.ThrowIfCanceledOrTimeoutExpired(); this.LogDebug("Transferring file to artifact library..."); var artifactId = new ArtifactIdentifier(this.Context.ApplicationId, this.Context.ReleaseNumber, this.Context.BuildNumber, this.Context.DeployableId, artifactName); ArtifactBuilder.ImportZip(artifactId, fileOps, zipFileEntry); this.LogDebug("Cleaning up..."); fileOps.DeleteFiles(new[] { zipPath }); this.LogInformation("Artfact captured from TFS."); }
public static async Task <string> DownloadAndImportAsync(IVsoConnectionInfo connectionInfo, ILogger logger, string teamProject, string buildNumber, string buildDefinitionName, ArtifactIdentifier artifactId) { var downloader = new ArtifactDownloader(connectionInfo, logger); using (var artifact = await downloader.DownloadAsync(teamProject, buildNumber, buildDefinitionName, artifactId.ArtifactName).ConfigureAwait(false)) { logger.LogInformation("Downloading artifact file from VSO and importing into BuildMaster artifact library..."); await Artifact.CreateArtifactAsync( applicationId : artifactId.ApplicationId, releaseNumber : artifactId.ReleaseNumber, buildNumber : artifactId.BuildNumber, deployableId : artifactId.DeployableId, executionId : null, artifactName : artifact.Name, artifactData : artifact.Content, overwrite : true ).ConfigureAwait(false); logger.LogInformation($"{artifactId.ArtifactName} artifact imported."); return(artifact.BuildNumber); } }
/// <summary> /// Downloads and imports and artifact from Visual Studio Online. /// </summary> /// <param name="configurer">The configurer.</param> /// <param name="logger">The logger.</param> /// <param name="teamProject">The team project.</param> /// <param name="buildNumber">The build number.</param> /// <param name="artifactId">The artifact identifier.</param> public static string DownloadAndImport(TfsConfigurer configurer, ILogger logger, string teamProject, string buildNumber, string buildDefinitionName, ArtifactIdentifier artifactId) { if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (configurer == null) { throw new ArgumentNullException("A configurer must be configured or selected in order to import a VS online build."); } if (string.IsNullOrEmpty(configurer.BaseUrl)) { throw new InvalidOperationException("The base URL property of the TFS configurer must be set to import a VS online build."); } var api = new TfsRestApi(configurer.BaseUrl, teamProject) { UserName = string.IsNullOrEmpty(configurer.Domain) ? configurer.UserName : string.Format("{0}\\{1}", configurer.Domain, configurer.UserName), Password = configurer.Password }; logger.LogInformation($"Finding last successful build..."); var buildDefinitions = api.GetBuildDefinitions(); var buildDefinition = buildDefinitions.FirstOrDefault(b => b.name == buildDefinitionName); if (buildDefinition == null) { throw new InvalidOperationException($"The build definition {buildDefinitionName} could not be found."); } logger.LogInformation($"Finding {Util.CoalesceStr(buildNumber, "last successful")} build..."); var builds = api.GetBuilds( buildDefinition: buildDefinition.id, buildNumber: InedoLib.Util.NullIf(buildNumber, ""), resultFilter: "succeeded", statusFilter: "completed", top: 2 ); if (builds.Length == 0) { throw new InvalidOperationException($"Could not find build number {buildNumber}. Ensure there is a successful, completed build with this number."); } var build = builds.FirstOrDefault(); string tempFile = Path.GetTempFileName(); try { logger.LogInformation($"Downloading {artifactId.ArtifactName} artifact from VSO..."); logger.LogDebug("Downloading artifact file to: " + tempFile); api.DownloadArtifact(build.id, artifactId.ArtifactName, tempFile); logger.LogInformation("Artifact file downloaded from VSO, importing into BuildMaster artifact library..."); using (var stream = FileEx.Open(tempFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { ArtifactBuilder.ImportZip(artifactId, stream); } logger.LogInformation($"{artifactId.ArtifactName} artifact imported."); return(build.buildNumber); } finally { if (tempFile != null) { FileEx.Delete(tempFile); } } }
public override void Import(IBuildImporterContext context) { var configurer = (TfsConfigurer)this.GetExtensionConfigurer(); this.LogDebug("Searching for build {0} for team project {1} definition {2}...", this.TfsBuildNumber, this.TeamProject, this.BuildDefinition); var tfsBuild = configurer.GetBuildInfo(this.TeamProject, this.BuildDefinition, this.TfsBuildNumber, this.IncludeUnsuccessful); if (tfsBuild == null) { this.LogError("Query did not return any builds."); return; } this.LogInformation("TFS Build Number: {0}", tfsBuild.BuildNumber); if (string.IsNullOrWhiteSpace(tfsBuild.DropLocation)) { this.LogError("TFS configuration error: the selected build definition does not have a drop location specified."); return; } this.LogInformation("Drop location: {0}", tfsBuild.DropLocation); using (var agent = Util.Agents.CreateAgentFromId(configurer.ServerId)) { var fileOps = agent.GetService<IFileOperationsExecuter>(); this.LogDebug("Querying drop location..."); var directoryResult = Util.Files.GetDirectoryEntry( new GetDirectoryEntryCommand { Path = tfsBuild.DropLocation, Recurse = true, IncludeRootPath = true } ).Entry; var matches = Util.Files.Comparison.GetMatches(tfsBuild.DropLocation, directoryResult, new[] { "*" }) .Where(e => !IsSamePath(e.Path, tfsBuild.DropLocation)) .ToList(); if (!matches.Any()) { this.LogWarning("No files were found in the drop folder."); return; } this.LogDebug("Creating {0} artifact...", this.ArtifactName); var artifactId = new ArtifactIdentifier(context.ApplicationId, context.ReleaseNumber, context.BuildNumber, context.DeployableId, this.ArtifactName); using (var artifact = new ArtifactBuilder(artifactId)) { artifact.RootPath = tfsBuild.DropLocation; foreach (var match in matches) artifact.Add(match, fileOps); artifact.Commit(); } } this.LogDebug("Creating $TfsBuildNumber variable..."); StoredProcs.Variables_CreateOrUpdateVariableDefinition( Variable_Name: "TfsBuildNumber", Environment_Id: null, Server_Id: null, ApplicationGroup_Id: null, Application_Id: context.ApplicationId, Deployable_Id: null, Release_Number: context.ReleaseNumber, Build_Number: context.BuildNumber, Execution_Id: null, Value_Text: tfsBuild.BuildNumber, Sensitive_Indicator: YNIndicator.No ).Execute(); }
private void CreateArtifact(string artifactName, string path) { if (string.IsNullOrEmpty(artifactName) || artifactName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) throw new InvalidOperationException("Artifact Name cannot contain invalid file name characters: " + new string(Path.GetInvalidFileNameChars())); if (StoredProcs.Releases_GetRelease(this.Context.ApplicationId, this.Context.ReleaseNumber) .Execute().ReleaseDeployables_Extended .Any(rd => rd.Deployable_Id == this.Context.DeployableId && rd.InclusionType_Code == Domains.DeployableInclusionTypes.Referenced)) { this.LogError( "An Artifact cannot be created for this Deployable because the Deployable is Referenced (as opposed to Included) by this Release. " + "To prevent this error, either include this Deployable in the Release or use a Predicate to prevent this action group from being executed."); return; } var fileOps = this.Context.Agent.GetService<IFileOperationsExecuter>(); var zipPath = fileOps.CombinePath(this.Context.TempDirectory, artifactName + ".zip"); this.LogDebug("Preparing directories..."); fileOps.DeleteFiles(new[] { zipPath }); this.ThrowIfCanceledOrTimeoutExpired(); var rootEntry = fileOps.GetDirectoryEntry( new GetDirectoryEntryCommand { Path = path, Recurse = false, IncludeRootPath = false } ).Entry; if ((rootEntry.Files == null || rootEntry.Files.Length == 0) && (rootEntry.SubDirectories == null || rootEntry.SubDirectories.Length == 0)) this.LogWarning("There are no files to capture in this artifact."); this.LogDebug("Zipping output..."); this.Context.Agent.GetService<IRemoteZip>().CreateZipFile(path, zipPath); var zipFileEntry = fileOps.GetFileEntry(zipPath); this.ThrowIfCanceledOrTimeoutExpired(); this.LogDebug("Transferring file to artifact library..."); var artifactId = new ArtifactIdentifier(this.Context.ApplicationId, this.Context.ReleaseNumber, this.Context.BuildNumber, this.Context.DeployableId, artifactName); ArtifactBuilder.ImportZip(artifactId, fileOps, zipFileEntry); this.LogDebug("Cleaning up..."); fileOps.DeleteFiles(new[] { zipPath }); this.LogInformation("Artfact captured from TFS."); }
public override void Import(IBuildImporterContext context) { var configurer = (TfsConfigurer)this.GetExtensionConfigurer(); this.LogDebug($"Searching for build {this.TfsBuildNumber} for team project {this.TeamProject} definition {this.BuildDefinition}..."); var tfsBuild = configurer.GetBuildInfo(this.TeamProject, this.BuildDefinition, this.TfsBuildNumber, this.IncludeUnsuccessful); if (tfsBuild == null) { this.LogError("Query did not return any builds."); return; } this.LogInformation("TFS Build Number: " + tfsBuild.BuildNumber); if (string.IsNullOrWhiteSpace(tfsBuild.DropLocation)) { this.LogError("TFS configuration error: the selected build definition does not have a drop location specified."); return; } this.LogInformation("Drop location: " + tfsBuild.DropLocation); var agent = configurer.ServerId != null?BuildMasterAgent.Create((int)configurer.ServerId) : BuildMasterAgent.CreateLocalAgent(); using (agent) { var fileOps = agent.GetService <IFileOperationsExecuter>(); this.LogDebug("Querying drop location..."); var directoryResult = fileOps.GetDirectoryEntry( new GetDirectoryEntryCommand { Path = tfsBuild.DropLocation, Recurse = true, IncludeRootPath = true } ); var exception = directoryResult.Exceptions.FirstOrDefault(); if (exception != null) { throw exception; } var matches = Util.Files.Comparison.GetMatches(tfsBuild.DropLocation, directoryResult.Entry, new[] { "*" }) .Where(e => !IsSamePath(e.Path, tfsBuild.DropLocation)) .ToList(); if (!matches.Any()) { this.LogWarning("No files were found in the drop folder."); return; } this.LogDebug($"Creating {this.ArtifactName} artifact..."); var artifactId = new ArtifactIdentifier(context.ApplicationId, context.ReleaseNumber, context.BuildNumber, context.DeployableId, this.ArtifactName); using (var artifact = new ArtifactBuilder(artifactId)) { artifact.RootPath = tfsBuild.DropLocation; foreach (var match in matches) { artifact.Add(match, fileOps); } artifact.Commit(); } } if (this.CreateBuildNumberVariable) { this.LogDebug($"Setting $TfsBuildNumber build variable to {tfsBuild.BuildNumber}..."); DB.Variables_CreateOrUpdateVariableDefinition( Variable_Name: "TfsBuildNumber", Environment_Id: null, ServerRole_Id: null, Server_Id: null, ApplicationGroup_Id: null, Application_Id: context.ApplicationId, Deployable_Id: null, Release_Number: context.ReleaseNumber, Build_Number: context.BuildNumber, Execution_Id: null, Promotion_Id: null, Value_Text: tfsBuild.BuildNumber, Sensitive_Indicator: YNIndicator.No ); this.LogInformation("$TfsBuildNumber build variable set to: " + tfsBuild.BuildNumber); } }
public override void Import(IBuildImporterContext context) { var configurer = (NuGetConfigurer)this.GetExtensionConfigurer(); if (configurer.AlwaysClearNuGetCache) { this.LogDebug("Clearing NuGet cache..."); if (NuGetConfigurer.ClearCache()) { this.LogDebug("Cache cleared!"); } else { this.LogWarning("Error clearing cache; a file may be locked."); } } var nugetExe = configurer != null ? configurer.NuGetExe : null; if (string.IsNullOrEmpty(nugetExe)) { nugetExe = Path.Combine(Path.GetDirectoryName(typeof(NuGetBuildImporter).Assembly.Location), "nuget.exe"); } var packageSource = Util.CoalesceStr(this.PackageSource, configurer != null ? configurer.PackageSource : null); var args = "install \"" + this.PackageId + "\" -ExcludeVersion -NoCache"; if (!string.IsNullOrEmpty(this.PackageVersion)) { args += " -Version \"" + this.PackageVersion + "\""; } if (this.IncludePrerelease) { args += " -Prerelease"; } if (!string.IsNullOrEmpty(packageSource)) { args += " -Source \"" + packageSource + "\""; } var tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); try { Directory.CreateDirectory(tempPath); args += " -OutputDirectory \"" + tempPath + "\""; if (!string.IsNullOrWhiteSpace(this.AdditionalArguments)) { args += " " + this.AdditionalArguments; } this.LogDebug($"Executing {nugetExe} {args}"); this.LogInformation("Executing NuGet..."); using (var process = new LocalProcess(new RemoteProcessStartInfo { FileName = nugetExe, Arguments = args })) { process.OutputDataReceived += this.Process_OutputDataReceived; process.ErrorDataReceived += this.Process_ErrorDataReceived; process.Start(); process.WaitForExit(); if (process.ExitCode != 0) { this.LogError($"NuGet failed with exit code {process.ExitCode}."); return; } } this.LogInformation("NuGet indicated successful package install."); var packageRootPath = Path.Combine(tempPath, this.PackageId); var artifactName = this.PackageId; if (this.CaptureIdAndVersion || this.IncludeVersionInArtifactName) { try { var nupkgPath = Path.Combine(packageRootPath, this.PackageId + ".nupkg"); this.LogDebug($"Attempting to gather metadata from {nupkgPath}..."); var nuspec = NuGetPackage.ReadFromNupkgFile(nupkgPath); var packageId = nuspec.Id; var packageVersion = nuspec.Version.OriginalString; if (this.CaptureIdAndVersion) { this.LogDebug("Setting $ImportedPackageId = " + packageId); SetBuildVariable(context, "ImportedPackageId", packageId); this.LogDebug("Setting $ImportedPackageVersion = " + packageVersion); SetBuildVariable(context, "ImportedPackageVersion", packageVersion); } if (this.IncludeVersionInArtifactName) { artifactName = packageId + "." + packageVersion; } } catch (Exception ex) { this.LogError("Could not read package metadata: " + ex.ToString()); return; } } var rootCapturePath = Path.Combine(packageRootPath, (this.PackageArtifactRoot ?? string.Empty).Replace('/', '\\').TrimStart('/', '\\')); this.LogDebug($"Capturing files in {rootCapturePath}..."); var rootEntry = Util.Files.GetDirectoryEntry( new GetDirectoryEntryCommand { Path = rootCapturePath, IncludeRootPath = true, Recurse = true } ).Entry; using (var agent = BuildMasterAgent.CreateLocalAgent()) { var fileOps = agent.GetService <IFileOperationsExecuter>(); var matches = Util.Files.Comparison.GetMatches(rootCapturePath, rootEntry, new[] { "!\\" + this.PackageId + ".nupkg", "*" }); var artifactId = new ArtifactIdentifier(context.ApplicationId, context.ReleaseNumber, context.BuildNumber, context.DeployableId, artifactName); this.LogInformation($"Creating artifact {artifactName}..."); using (var artifact = new ArtifactBuilder(artifactId)) { artifact.RootPath = rootCapturePath; foreach (var match in matches) { artifact.Add(match, fileOps); } artifact.Commit(); } this.LogInformation("Artifact created."); } } finally { try { DirectoryEx.Delete(tempPath); } catch { } } }