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.");
        }
示例#2
0
        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);
            }
        }
示例#3
0
        /// <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);
                }
            }
        }
示例#4
0
        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.");
        }
示例#6
0
        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);
            }
        }
示例#7
0
        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
                {
                }
            }
        }