Пример #1
0
        public async Task <string> CloneIfNotExistLocally(string remoteUrl, string localRepository, bool isPrivateRepository)
        {
            if (Directory.Exists(localRepository) && Repository.IsValid(localRepository))
            {
                return(localRepository);
            }

            var cloneOption = new CloneOptions()
            {
                OnTransferProgress = CloneTransferProgressHandler
            };

            if (isPrivateRepository)
            {
                cloneOption.CredentialsProvider = (url, user, cred) => _gitCredential;
            }

            try
            {
                return(await Task.Run(() => Repository.Clone(remoteUrl, localRepository, cloneOption)));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                return("");
            }
        }
        public void Pull(Octokit.Repository rep)
        {
            string reppath = Path.Combine(_account.TempRepPath, rep.Name);

            if (!Repository.IsValid(reppath))
            {
                Repository.Clone(rep.CloneUrl, reppath);
                using (var repo = new Repository(reppath))
                {
                    var upstream = repo.Network.Remotes.Add("upstream", rep.Parent.CloneUrl);
                    Commands.Fetch(repo, "upstream", new List <string>()
                    {
                    }, new FetchOptions(), null);
                    Branch upstreamMaster = repo.Branches["upstream/master"];
                    Branch localMaster    = repo.Branches["master"];
                    repo.Branches.Update(localMaster, b => b.TrackedBranch = upstreamMaster.CanonicalName);
                    var sign = new LibGit2Sharp.Signature(_account.UserName, _account.Email, new DateTimeOffset(DateTime.Now));
                    Commands.Pull(repo, sign, new PullOptions());
                }
            }
            else
            {
                using (var repo = new Repository(reppath))
                {
                    var branchMaster = repo.Branches["master"];

                    Commands.Checkout(repo, branchMaster);
                    var sign = new LibGit2Sharp.Signature(_account.UserName, _account.Email, new DateTimeOffset(DateTime.Now));
                    Commands.Pull(repo, sign, new PullOptions());
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Handles a webhook event created by github
        /// </summary>
        // TODO: Find use for the webhookEvent parameter
        public void HandleEvent(GithubWebhookEvent webhookEvent)
        {
            if (!this.IsCloned)
            {
                this.Logger?.Debug(
                    "Cloning repository to {@path}", this.ClonePath.FullName
                    );
                Repository.Clone(this.RepositoryUrl, this.ClonePath.FullName);
                this._repository = new Repository(this.ClonePath.FullName);
                return;
            }

            var signature = new Signature(
                "Jay", "*****@*****.**", DateTimeOffset.Now
                );

            var pullOptions = new PullOptions();
            var mergeResult = Commands.Pull(
                this._repository, signature, pullOptions
                );

            // This shouldn't really happen since the repo on the server should not be edited directly
            if (mergeResult.Status == MergeStatus.Conflicts)
            {
                this.Logger?.Error(
                    "Pull operation resulted in a merge conflict"
                    );
            }
        }
Пример #4
0
        bool CloneCore(CommonRepository repository)
        {
            var co = new CloneOptions();

            co.CredentialsProvider = (_url, _user, _cred) => new UsernamePasswordCredentials {
                Username = "******", Password = "******"
            };
            co.BranchName = $"20{repository.Version}";
            var result = Repository.Clone("http://gitserver/XPF/VisualTests.git", repository.Path, co);

            return(Directory.Exists(result));
        }
Пример #5
0
        public void Clone(Uri pullEndpoint)
        {
            _logger.Normal($"Git clone {pullEndpoint} to {WorkingFolder.FullPath}");

            Repository.Clone(pullEndpoint.AbsoluteUri, WorkingFolder.FullPath,
                             new CloneOptions
            {
                CredentialsProvider = UsernamePasswordCredentials,
                OnTransferProgress  = OnTransferProgress
            });

            _logger.Detailed("Git clone complete");
        }
Пример #6
0
        public void Clone(Uri pullEndpoint, string branchName)
        {
            _logger.Normal($"Git clone {pullEndpoint}, branch {branchName ?? "default"}, to {WorkingFolder.FullPath}");

            Repository.Clone(pullEndpoint.AbsoluteUri, WorkingFolder.FullPath,
                             new CloneOptions
            {
                CredentialsProvider = UsernamePasswordCredentials,
                OnTransferProgress  = OnTransferProgress,
                BranchName          = branchName
            });

            _logger.Detailed("Git clone complete");
        }
Пример #7
0
        public static void Clone(string url, string branchName, string path)
        {
            CloneOptions option = new CloneOptions
            {
                CredentialsProvider = (_url, _user, _cred) => Token,
                BranchName          = branchName
            };

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            GitRepo.Clone(url, path, option);
        }
Пример #8
0
        private async Task SetupSrcRepo()
        {
            if (!Directory.Exists("srcRepo"))
            {
                Logger.Info("Cloning source repository... ", false);

                Directory.CreateDirectory("srcRepo");
                await Task.Run(() => GitRepository.Clone(_ghSrc.CloneUrl, "srcRepo",
                                                         new CloneOptions {
                    CredentialsProvider = GitCredentials
                }));

                Console.WriteLine("Done.");
            }
        }
        public RepositoryProcessor(Uri repositoryUrl, UsernamePasswordCredentials credentials)
        {
            _repositoryUrl = repositoryUrl;
            _credentials   = credentials;

            Console.WriteLine($"Cloning {_repositoryUrl}");

            _clonePath = Path.Combine(".", _repositoryUrl.ToString().Split("/").Last(x => !string.IsNullOrWhiteSpace(x)));
            var repoPath = Repository.Clone(
                _repositoryUrl.ToString(),
                _clonePath,
                new CloneOptions {
                CredentialsProvider = (x, y, z) => _credentials
            });

            _repository = new Repository(repoPath);
            _baseBranch = _repository.Branches[_repository.Head.FriendlyName];
        }
Пример #10
0
        private static async Task Clone(
            IEnumerable <Organization> organizations,
            string clonePath,
            string userName,
            string pat)
        {
            var credentials  = new NetworkCredential(userName, pat);
            var cloneOptions = new CloneOptions
            {
                Checkout            = true,
                CredentialsProvider = (url, user, cred) => new SecureUsernamePasswordCredentials
                {
                    Username = credentials.UserName,
                    Password = credentials.SecurePassword
                }
            };

            foreach (var organization in organizations)
            {
                foreach (var project in organization.Projects)
                {
                    foreach (var repository in project.Repositories)
                    {
                        var path     = Path.Combine(clonePath, repository.Name);
                        var repoRoot = Repository.Discover(path);

                        // don't crash when there is no repo to this path, return empty changes
                        if (repoRoot != null)
                        {
                            Console.WriteLine($"Repo {repository.Name} already exists! Continue with other.");
                            continue;
                        }

                        Console.WriteLine($"Cloning {repository.Name} repository!");
                        Directory.CreateDirectory(path);
                        await Task.Run(() => Repository.Clone(
                                           $"https://{Uri.EscapeUriString(organization.Name)}@dev.azure.com/{Uri.EscapeUriString(organization.Name)}/" +
                                           $"{Uri.EscapeUriString(project.Name)}/_git/{Uri.EscapeUriString(repository.Name)}",
                                           path,
                                           cloneOptions));
                    }
                }
            }
        }
Пример #11
0
        private async void btnRun_Click(object sender, EventArgs e)
        {
            var userName = tbUserName.Text;

            if (string.IsNullOrEmpty(userName))
            {
                return;
            }
            if (Directory.Exists("repos") == false)
            {
                Directory.CreateDirectory("repos");
            }
            var github       = new GitHubClient(new ProductHeaderValue("GitHubBackTester"));
            var repositories = await github.Repository.GetAllForUser(userName);

            foreach (var githubRepository in repositories)
            {
                var path = Path.Combine("repos", githubRepository.Name);
                Repository.Clone(githubRepository.HtmlUrl, path);
            }
        }
Пример #12
0
        private string GetLocalRepoFolder(Models.Repository repo, string personalAccessKey)
        {
            var    checkOutFolder = GetLocalFolder(repo);
            string logMessage     = "";

            if (Repository.IsValid(checkOutFolder) == false)
            {
                checkOutFolder = Repository.Clone(repo.CloneUrl, checkOutFolder, getCloneOptions(personalAccessKey));
            }
            else
            {
                using (var tmpRepo = new Repository(checkOutFolder))
                {
                    var remote   = tmpRepo.Network.Remotes["origin"];
                    var refSpecs = remote.FetchRefSpecs.Select(x => x.Specification);

                    Commands.Fetch(tmpRepo, remote.Name, refSpecs, getFetchOptions(personalAccessKey), logMessage);
                }
            }

            return(checkOutFolder);
        }
Пример #13
0
        /// <summary>
        /// Ensure that the repository exists on disk and its origin remote points to the correct url
        /// </summary>
        /// <param name="repo"></param>
        private void EnsureRepository(List <RepositoryInfo> repos)
        {
            foreach (var repo in repos)
            {
                var repoPath = repo.Path;
                s_logger.Info($"Verifying repository {repo} at {repo.Path}");
                if (!Directory.Exists(repoPath) || !Repository.IsValid(repoPath))
                {
                    if (Directory.Exists(repoPath))
                    {
                        Directory.Delete(repoPath, true);
                    }

                    s_logger.Info($"Cloning the repo from {repo.CloneUrl}");
                    Repository.Clone(repo.CloneUrl, repoPath);
                }
                using (var repository = new Repository(repoPath))
                {
                    var remote = repository.Network.Remotes["origin"];
                    if (remote == null)
                    {
                        repository.Network.Remotes.Add("origin", repo.CloneUrl);
                    }
                    else if (remote.Url != repo.CloneUrl)
                    {
                        repository.Network.Remotes.Update("origin", u => u.Url = repo.CloneUrl);
                    }
                    var master = repository.Branches["master"] ?? repository.CreateBranch("master");
                    repository.Branches.Update(master, b => b.Remote = "origin", b => b.UpstreamBranch = "refs/heads/master");

                    remote = repository.Network.Remotes["upstream"];
                    if (remote == null)
                    {
                        repository.Network.Remotes.Add("upstream", @"https://github.com/" + repo.UpstreamOwner + @"/" + repo.Name + ".git");
                    }
                }
            }
        }
Пример #14
0
        public override int Execute(UpdateSettings settings, ILookup <string, string> remaining)
        {
            // Get the user.
            var client = new GitHubClient(new ProductHeaderValue("Cake-Addin-Updater"))
            {
                Credentials = new Octokit.Credentials(settings.Token)
            };

            // Validate the provided version.
            if (!System.Version.TryParse(settings.Version, out var _))
            {
                _log.Error("The provided version is not valid.");
                return(1);
            }

            // Get the root.
            var root = settings.WorkingDirectory ?? new DirectoryPath(".");

            root = root.MakeAbsolute(_environment);

            // Get the user.
            var user      = client.User.Get(settings.User).Result;
            var userEmail = GetUserEmail(client);

            // Get the repository parts.
            var info = GetRepositoryInfo(settings);

            // Does the directory contains anything?
            var path = CreateRepositoryDirectory(root, info);

            if (_filesystem.Directory.GetFiles(path, "*.*", SearchScope.Current).Any() ||
                _filesystem.Directory.GetDirectories(path, "*.*", SearchScope.Current).Any())
            {
                _log.Error($"Repository '{path}' already exist on disk.");
                _log.Write("Remove it and try again.");
                return(1);
            }

            // Fork the repository.
            var repository = ForkRepository(client, info);

            if (string.IsNullOrWhiteSpace(repository?.Name))
            {
                _log.Error("Could not fork repository.");
                return(1);
            }

            // Get the default branch.
            var defaultBranch = repository.DefaultBranch;

            if (string.IsNullOrWhiteSpace(defaultBranch))
            {
                _log.Error("Could not get default branch for repository.");
                return(1);
            }

            // Clone the repository at the specified path.
            _log.Write("Cloning repository...");
            GitRepository.Clone($"https://github.com/{settings.User}/{repository.Name}", path.FullPath, new CloneOptions
            {
                Checkout = true
            });

            using (var gitRepository = new GitRepository(path.FullPath))
            {
                // Create a new branch in the repository.
                _log.Write("Creating branch...");
                gitRepository.CreateBranch($"feature/cake-{settings.Version}");
                _log.Write("Checking out branch...");
                GitCommands.Checkout(gitRepository, $"feature/cake-{settings.Version}");

                // Update all package references in project.
                var processed = _processor.Process(root, path, settings.Version);
                if (processed == 0)
                {
                    _log.Error("Nothing was updated. Probably a newer repository.");
                    return(1);
                }

                // Commit?
                if (settings.Commit)
                {
                    _log.Write("Staging changes...");
                    GitCommands.Stage(gitRepository, "*");

                    var status = gitRepository.RetrieveStatus();
                    if (status.Any())
                    {
                        _log.Write("Committing changes...");
                        var author = new GitSignature(user.Name, userEmail, DateTime.Now);
                        gitRepository.Commit($"Updated to Cake {settings.Version}.", author, author);

                        // Push?
                        if (settings.Push)
                        {
                            // Build everything first.
                            if (!BuildProject(path))
                            {
                                return(1);
                            }

                            // Push the commit.
                            if (!Push(settings, path))
                            {
                                return(1);
                            }

                            // Create a pull request?
                            if (settings.OpenPullRequest)
                            {
                                CreatePullRequest(client, settings, info);
                            }
                        }
                    }
                    else
                    {
                        _log.Error("No changes in repository. Already updated?");
                    }
                }
            }

            return(0);
        }
Пример #15
0
        /// <summary>
        /// Adds the standard .NET targets to the build.
        /// </summary>
        /// <param name="build">The build to which to add targets.</param>
        /// <param name="settings">The build settings.</param>
        public static void AddDotNetTargets(this BuildApp build, DotNetBuildSettings?settings = null)
        {
            settings ??= new DotNetBuildSettings();

            var buildOptions        = settings.BuildOptions ?? (settings.BuildOptions = new DotNetBuildOptions());
            var configurationOption = buildOptions.ConfigurationOption ?? (buildOptions.ConfigurationOption =
                                                                               build.AddOption("-c|--configuration <name>", "The configuration to build (default Release)", "Release"));
            var platformOption = buildOptions.PlatformOption ?? (buildOptions.PlatformOption =
                                                                     build.AddOption("-p|--platform <name>", "The solution platform to build"));
            var versionSuffixOption = buildOptions.VersionSuffixOption ?? (buildOptions.VersionSuffixOption =
                                                                               build.AddOption("--version-suffix <suffix>", "Generates a prerelease package"));
            var nugetOutputOption = buildOptions.NuGetOutputOption ?? (buildOptions.NuGetOutputOption =
                                                                           build.AddOption("--nuget-output <path>", "Directory for generated package (default release)", "release"));
            var triggerOption = buildOptions.TriggerOption ?? (buildOptions.TriggerOption =
                                                                   build.AddOption("--trigger <name>", "The git branch or tag that triggered the build"));
            var buildNumberOption = buildOptions.BuildNumberOption ?? (buildOptions.BuildNumberOption =
                                                                           build.AddOption("--build-number <number>", "The automated build number"));
            var noTestFlag = buildOptions.NoTestFlag ?? (buildOptions.NoTestFlag =
                                                             build.AddFlag("--no-test", "Skip the unit tests"));

            var solutionName    = settings.SolutionName;
            var nugetSource     = settings.NuGetSource ?? "https://api.nuget.org/v3/index.json";
            var msbuildSettings = settings.MSBuildSettings;

            var dotNetTools           = settings.DotNetTools ?? new DotNetTools(Path.Combine("tools", "bin"));
            var xmlDocMarkdownVersion = settings.DocsSettings?.ToolVersion ?? "2.0.1";

            var    packagePaths          = new List <string>();
            string?trigger               = null;
            var    ignoreIfAlreadyPushed = false;

            build.Target("clean")
            .Describe("Deletes all build output")
            .Does(() =>
            {
                var findDirectoriesToDelete = settings.CleanSettings?.FindDirectoriesToDelete ?? (() => FindDirectories("{src,tests}/**/{bin,obj}", "tools/XmlDocTarget/{bin,obj}"));
                foreach (var directoryToDelete in findDirectoriesToDelete())
                {
                    deleteDirectory(directoryToDelete);
                }

                var extraProperties = getExtraProperties("clean");
                if (msbuildSettings == null)
                {
                    RunDotNet(new[] { "clean", solutionName, "-c", configurationOption.Value, getPlatformArg(), "--verbosity", "normal", getMaxCpuCountArg() }.Concat(extraProperties));
                }
                else
                {
                    runMSBuild(new[] { solutionName, "-t:Clean", $"-p:Configuration={configurationOption.Value}", getPlatformArg(), "-v:normal", getMaxCpuCountArg() }.Concat(extraProperties));
                }
            });

            build.Target("restore")
            .Describe("Restores NuGet packages")
            .Does(() =>
            {
                var extraProperties = getExtraProperties("restore");
                if (msbuildSettings == null)
                {
                    RunDotNet(new[] { "restore", solutionName, getPlatformArg(), "--verbosity", "normal", getMaxCpuCountArg() }.Concat(extraProperties));
                }
                else
                {
                    runMSBuild(new[] { solutionName, "-t:Restore", $"-p:Configuration={configurationOption.Value}", getPlatformArg(), "-v:normal", getMaxCpuCountArg() }.Concat(extraProperties));
                }
            });

            build.Target("build")
            .DependsOn("restore")
            .Describe("Builds the solution")
            .Does(() =>
            {
                var buildNumberArg = buildNumberOption.Value == null ? null : $"-p:BuildNumber={buildNumberOption.Value}";

                var extraProperties = getExtraProperties("build");
                if (msbuildSettings == null)
                {
                    RunDotNet(new[] { "build", solutionName, "-c", configurationOption.Value, getPlatformArg(), buildNumberArg, "--no-restore", "--verbosity", "normal", getMaxCpuCountArg() }.Concat(extraProperties));
                }
                else
                {
                    runMSBuild(new[] { solutionName, $"-p:Configuration={configurationOption.Value}", getPlatformArg(), buildNumberArg, "-v:normal", getMaxCpuCountArg() }.Concat(extraProperties));
                }
            });

            build.Target("test")
            .DependsOn("build")
            .Describe("Runs the unit tests")
            .Does(() =>
            {
                if (noTestFlag.Value)
                {
                    Console.WriteLine("Skipping unit tests due to --no-test.");
                }
                else
                {
                    var extraProperties    = getExtraProperties("test").ToList();
                    var findTestAssemblies = settings.TestSettings?.FindTestAssemblies;
                    if (findTestAssemblies != null)
                    {
                        foreach (var testAssembly in findTestAssemblies())
                        {
                            if (settings.TestSettings?.RunTests != null)
                            {
                                settings.TestSettings.RunTests(testAssembly);
                            }
                            else
                            {
                                RunDotNet(new AppRunnerSettings {
                                    Arguments = new[] { "vstest", Path.GetFileName(testAssembly) }.Concat(extraProperties), WorkingDirectory = Path.GetDirectoryName(testAssembly)
                                });
                            }
                        }
                    }
                    else
                    {
                        var testProjects = new List <string?>();

                        var findTestProjects = settings.TestSettings?.FindProjects;
                        if (findTestProjects != null)
                        {
                            testProjects.AddRange(findTestProjects());
                        }
                        else
                        {
                            testProjects.Add(solutionName);
                        }

                        foreach (var testProject in testProjects)
                        {
                            if (settings.TestSettings?.RunTests != null)
                            {
                                settings.TestSettings.RunTests(testProject);
                            }
                            else
                            {
                                RunDotNet(new[] { "test", testProject, "-c", configurationOption.Value, getPlatformArg(), "--no-build", getMaxCpuCountArg() }.Concat(extraProperties));
                            }
                        }
                    }
                }
            });

            build.Target("package")
            .DependsOn("clean", "test")
            .Describe("Builds NuGet packages")
            .Does(() =>
            {
                trigger = triggerOption.Value;

                if (trigger == "detect")
                {
                    using var repository = new Repository(".");
                    var headSha          = repository.Head.Tip.Sha;
                    var autoTrigger      = GetBestTriggerFromTags(repository.Tags.Where(x => x.Target.Sha == headSha).Select(x => x.FriendlyName).ToList());
                    if (autoTrigger != null)
                    {
                        trigger = autoTrigger;
                        ignoreIfAlreadyPushed = true;
                        Console.WriteLine($"Detected trigger: {trigger}");
                    }
                }

                var versionSuffix = versionSuffixOption.Value;
                if (versionSuffix == null && trigger != null)
                {
                    versionSuffix = GetVersionFromTrigger(trigger) is string triggerVersion ? SplitVersion(triggerVersion).Suffix : null;
                }

                var nugetOutputPath = Path.GetFullPath(nugetOutputOption.Value);
                var tempOutputPath  = Path.Combine(nugetOutputPath, $"temp_{Guid.NewGuid():N}");

                var packageProjects = new List <string?>();

                var findPackageProjects = settings.PackageSettings?.FindProjects;
                if (findPackageProjects != null)
                {
                    packageProjects.AddRange(findPackageProjects());
                }
                else
                {
                    packageProjects.Add(solutionName);
                }

                var extraProperties = getExtraProperties("package").ToList();
                foreach (var packageProject in packageProjects)
                {
                    if (msbuildSettings == null)
                    {
                        RunDotNet(new[]
                        {
                            "pack", packageProject,
                            "-c", configurationOption.Value,
                            getPlatformArg(),
                            "--no-build",
                            "--output", tempOutputPath,
                            versionSuffix != null ? "--version-suffix" : null, versionSuffix,
                            getMaxCpuCountArg()
                        }.Concat(extraProperties));
                    }
                    else
                    {
                        runMSBuild(new[]
                        {
                            packageProject, "-t:Pack",
                            $"-p:Configuration={configurationOption.Value}",
                            getPlatformArg(),
                            "-p:NoBuild=true",
                            $"-p:PackageOutputPath={tempOutputPath}",
                            versionSuffix != null ? $"-p:VersionSuffix={versionSuffix}" : null,
                            "-v:normal",
                            getMaxCpuCountArg()
                        }.Concat(extraProperties));
                    }
                }

                var tempPackagePaths = FindFilesFrom(tempOutputPath, "*.nupkg");
                foreach (var tempPackagePath in tempPackagePaths)
                {
                    var packagePath = Path.Combine(nugetOutputPath, Path.GetFileName(tempPackagePath) ?? throw new InvalidOperationException());
                    if (File.Exists(packagePath))
                    {
                        File.Delete(packagePath);
                    }
                    File.Move(tempPackagePath, packagePath);
                    packagePaths.Add(packagePath);
                }
                deleteDirectory(tempOutputPath);

                if (packagePaths.Count == 0)
                {
                    throw new ApplicationException("No NuGet packages created.");
                }
            });

            build.Target("publish")
            .Describe("Publishes NuGet packages and documentation")
            .DependsOn("package")
            .Does(() =>
            {
                if (packagePaths.Count == 0)
                {
                    throw new ApplicationException("No NuGet packages found.");
                }

                if (trigger == null)
                {
                    throw new ApplicationException("--trigger option required.");
                }

                var triggerParts          = trigger.Split('-');
                var publishTrigger        = triggerParts.Length >= 2 && triggerParts[0] == "publish" ? triggerParts[1] : null;
                var shouldPublishPackages = publishTrigger == "package" || publishTrigger == "packages" || publishTrigger == "all";
                var shouldPublishDocs     = publishTrigger == "docs" || publishTrigger == "all";

                var triggerVersion = GetVersionFromTrigger(trigger);
                if (triggerVersion != null)
                {
                    var mismatches = packagePaths.Where(x => GetPackageInfo(x).Version != triggerVersion).ToList();
                    if (mismatches.Count != 0)
                    {
                        throw new ApplicationException($"Trigger '{trigger}' doesn't match package version: {string.Join(", ", mismatches.Select(Path.GetFileName))}");
                    }

                    shouldPublishPackages = true;
                    shouldPublishDocs     = triggerVersion.IndexOf('-') == -1;
                }

                if (shouldPublishPackages || shouldPublishDocs)
                {
                    var docsSettings      = settings.DocsSettings;
                    var shouldPushDocs    = false;
                    string?cloneDirectory = null;
                    string?repoDirectory  = null;
                    string?gitBranchName  = null;

                    Credentials provideCredentials(string url, string usernameFromUrl, SupportedCredentialTypes types) =>
                    new UsernamePasswordCredentials
                    {
                        Username = docsSettings?.GitLogin?.Username ?? throw new ApplicationException("GitLogin has a null Username."),
                        Password = docsSettings?.GitLogin?.Password ?? throw new ApplicationException("GitLogin has a null Password."),
                    };

                    if (shouldPublishDocs && docsSettings != null)
                    {
                        if (docsSettings.GitLogin == null || docsSettings.GitAuthor == null)
                        {
                            throw new ApplicationException("GitLogin and GitAuthor must be set on DocsSettings.");
                        }

                        var gitRepositoryUrl = docsSettings.GitRepositoryUrl;
                        gitBranchName        = docsSettings.GitBranchName;

                        if (gitRepositoryUrl != null)
                        {
                            cloneDirectory = "docs_repo_" + Path.GetRandomFileName();
                            Repository.Clone(sourceUrl: gitRepositoryUrl, workdirPath: cloneDirectory,
                                             options: new CloneOptions {
                                BranchName = gitBranchName, CredentialsProvider = provideCredentials
                            });
                            repoDirectory = cloneDirectory;
                        }
                        else
                        {
                            repoDirectory = ".";
                        }

                        using var repository = new Repository(repoDirectory);
                        if (gitRepositoryUrl != null)
                        {
                            if (gitBranchName == null)
                            {
                                gitBranchName = repository.Head.FriendlyName;
                            }
                        }
                        else if (gitBranchName != null)
                        {
                            if (gitBranchName != repository.Head.FriendlyName)
                            {
                                var branch = repository.Branches[gitBranchName] ?? repository.CreateBranch(gitBranchName);
                                Commands.Checkout(repository, branch);
                            }
                        }
                        else
                        {
                            var branch = repository.Branches.FirstOrDefault(x => x.IsCurrentRepositoryHead);
                            if (branch == null)
                            {
                                var autoBranchName = Environment.GetEnvironmentVariable("APPVEYOR_REPO_BRANCH");
                                if (autoBranchName != null)
                                {
                                    branch = repository.Branches[autoBranchName] ?? repository.CreateBranch(autoBranchName);
                                }
                                else
                                {
                                    branch = repository.Branches.FirstOrDefault(x => x.Tip.Sha == repository.Head.Tip.Sha);
                                }
                                if (branch != null)
                                {
                                    Commands.Checkout(repository, branch);
                                }
                            }
                            if (branch == null)
                            {
                                throw new ArgumentException("Could not determine repository branch for publishing docs.");
                            }
                            gitBranchName = branch.FriendlyName;
                        }

                        var projectHasDocs = docsSettings.ProjectHasDocs ?? (_ => true);
                        foreach (var projectName in packagePaths.Select(x => GetPackageInfo(x).Name).Where(projectHasDocs))
                        {
                            string findAssembly(string name) =>
                            FindFiles($"tools/XmlDocTarget/bin/**/{name}.dll").OrderByDescending(File.GetLastWriteTime).FirstOrDefault() ??
                            FindFiles($"src/{name}/bin/**/{name}.dll").OrderByDescending(File.GetLastWriteTime).FirstOrDefault();

                            var assemblyPaths = new List <string>();
                            if (docsSettings.FindAssemblies != null)
                            {
                                assemblyPaths.AddRange(docsSettings.FindAssemblies(projectName));
                            }
                            else
                            {
                                var assemblyPath = (docsSettings.FindAssembly ?? findAssembly)(projectName);
                                if (assemblyPath != null)
                                {
                                    assemblyPaths.Add(assemblyPath);
                                }
                            }

                            if (assemblyPaths.Count != 0)
                            {
                                foreach (var assemblyPath in assemblyPaths)
                                {
                                    RunApp(dotNetTools.GetToolPath($"xmldocmd/{xmlDocMarkdownVersion}"), assemblyPath,
                                           Path.Combine(repoDirectory, docsSettings.TargetDirectory ?? "docs"),
                                           "--source", $"{docsSettings.SourceCodeUrl}/{projectName}", "--newline", "lf", "--clean");
                                }
                            }
                            else
                            {
                                Console.WriteLine($"Documentation not generated for {projectName}; assembly not found.");
                            }
                        }

                        shouldPushDocs = repository.RetrieveStatus().IsDirty;
                    }

                    if (shouldPublishPackages)
                    {
                        var nugetApiKey = settings.NuGetApiKey;
                        if (string.IsNullOrEmpty(nugetApiKey))
                        {
                            throw new ApplicationException("NuGetApiKey required to publish.");
                        }

                        if (ignoreIfAlreadyPushed)
                        {
                            var nugetSettings            = NuGet.Configuration.Settings.LoadDefaultSettings(root: null);
                            var packageSourceProvider    = new PackageSourceProvider(nugetSettings);
                            var sourceRepositoryProvider = new SourceRepositoryProvider(packageSourceProvider, NuGet.Protocol.Core.Types.Repository.Provider.GetCoreV3());
                            using var sourceCacheContext = new SourceCacheContext();
                            var nugetRepositories        = sourceRepositoryProvider.GetRepositories()
                                                           .Select(x => x.GetResourceAsync <DependencyInfoResource>().GetAwaiter().GetResult())
                                                           .ToList();

                            foreach (var packagePath in packagePaths.ToList())
                            {
                                var packageInfo = GetPackageInfo(packagePath);
                                var package     = new PackageIdentity(packageInfo.Name, NuGetVersion.Parse(packageInfo.Version));

                                foreach (var nugetRepository in nugetRepositories)
                                {
                                    var dependencyInfo = nugetRepository.ResolvePackage(package, NuGetFramework.AnyFramework,
                                                                                        sourceCacheContext, NullLogger.Instance, CancellationToken.None).GetAwaiter().GetResult();
                                    if (dependencyInfo != null)
                                    {
                                        Console.WriteLine($"Package already pushed: {packageInfo.Name} {packageInfo.Version}");
                                        packagePaths.Remove(packagePath);
                                        break;
                                    }
                                }
                            }
                        }

                        foreach (var packagePath in packagePaths)
                        {
                            RunDotNet("nuget", "push", packagePath, "--source", nugetSource, "--api-key", nugetApiKey);
                        }
                    }

                    if (shouldPushDocs)
                    {
                        using var repository = new Repository(repoDirectory);
                        Console.WriteLine("Publishing documentation changes.");
                        Commands.Stage(repository, "*");
                        var author = new Signature(docsSettings !.GitAuthor !.Name, docsSettings !.GitAuthor !.Email, DateTimeOffset.Now);
                        repository.Commit("Documentation updated.", author, author, new CommitOptions());
                        repository.Network.Push(repository.Network.Remotes["origin"],
                                                $"refs/heads/{gitBranchName}", new PushOptions {
                            CredentialsProvider = provideCredentials
                        });
                    }

                    if (cloneDirectory != null)
                    {
                        // delete the cloned directory
                        foreach (var fileInfo in FindFiles(cloneDirectory, "**").Select(x => new FileInfo(x)).Where(x => x.IsReadOnly))
                        {
                            fileInfo.IsReadOnly = false;
                        }
                        deleteDirectory(cloneDirectory);
                    }
                }
                else
                {
                    Console.WriteLine("To publish to NuGet, push this tag: v" + GetPackageInfo(packagePaths[0]).Version);
                }
            });

            string?getPlatformArg()
            {
                var platformValue = platformOption?.Value ?? settings?.SolutionPlatform;

                return(platformValue == null ? null : $"-p:Platform={platformValue}");
            }

            string?getMaxCpuCountArg()
            {
                if (settings !.MaxCpuCount != null)
                {
                    return($"-maxcpucount:{settings.MaxCpuCount}");
                }
Пример #16
0
        private static async Task <int> Main(string[] args)
        {
            var initialColour = Console.ForegroundColor;
            var path          = args.Length == 0 ? "./output/" : args[0];

            try
            {
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
            }
            catch (Exception ex)
            {
                WriteLines(ConsoleColor.Red, "Invalid output path specified:", ex.ToString());
                return(1);
            }

            var configuration = new Configuration();

            try
            {
                new ConfigurationBuilder().AddJsonFile(args.Length == 2 ? args[1] : "appsettings.json").Build().Bind(configuration);
                if (string.IsNullOrWhiteSpace(configuration.ApiKey))
                {
                    throw new ArgumentException($"No {nameof(configuration.ApiKey)} specified.", nameof(configuration.ApiKey));
                }

                if (string.IsNullOrWhiteSpace(configuration.User))
                {
                    throw new ArgumentException($"No {nameof(configuration.User)} specified.", nameof(configuration.User));
                }

                if (configuration.ApiPath is null)
                {
                    throw new ArgumentNullException(nameof(configuration.ApiPath), $"No {nameof(configuration.ApiPath)} specified.");
                }
            }
            catch (Exception ex)
            {
                WriteLines(ConsoleColor.Red, "Invalid appsettings.json file:", ex.ToString());
                return(1);
            }

            var client = new GitHubClient(new Connection(
                                              new ProductHeaderValue(configuration.User),
                                              configuration.ApiPath,
                                              new InMemoryCredentialStore(new Credentials(configuration.ApiKey))));

            IReadOnlyDictionary <string, string> repositories;

            try
            {
                var repositoryList = await client.Repository.GetAllForCurrent();

                repositoryList = string.IsNullOrWhiteSpace(configuration.GetRepositortiesForOrganization) ?
                                 repositoryList.Where(r => r.Owner.Login == configuration.User).ToArray() :
                                 repositoryList.Where(r => r.Owner.Login == configuration.GetRepositortiesForOrganization).ToArray();

                switch (configuration.Archived)
                {
                case Configuration.ArchiveState.NoArchivedRepositories:
                    repositoryList = repositoryList.Where(r => !r.Archived).ToArray();
                    break;

                case Configuration.ArchiveState.OnlyArchivedRepositories:
                    repositoryList = repositoryList.Where(r => r.Archived).ToArray();
                    break;
                }

                switch (configuration.Forked)
                {
                case Configuration.ForkState.NoForkedRepositories:
                    repositoryList = repositoryList.Where(r => !r.Fork).ToArray();
                    break;

                case Configuration.ForkState.OnlyForkedRepositories:
                    repositoryList = repositoryList.Where(r => r.Fork).ToArray();
                    break;
                }

                repositories = repositoryList.ToDictionary(r => r.FullName, r => r.CloneUrl);
            }
            catch (Exception ex)
            {
                WriteLines(ConsoleColor.Red, $"Failed to get repositories for {(string.IsNullOrWhiteSpace(configuration.GetRepositortiesForOrganization) ? configuration.User : configuration.GetRepositortiesForOrganization)}.", ex.Message);
                return(1);
            }

            if (repositories.Count == 0)
            {
                WriteLines(ConsoleColor.Red, "No repositories found.");
                return(1);
            }

            WriteLines(ConsoleColor.Green, $"Found the following {repositories.Count} repositories:", string.Join(Environment.NewLine, repositories.Keys.Select(r => $"    - {r}")), string.Empty);
            LibGit2Sharp.Credentials CredentialsProvider(string _, string __, SupportedCredentialTypes ___) => new UsernamePasswordCredentials
            {
                Username = configuration.ApiKey,
                Password = string.Empty,
            };

            var issues = new Dictionary <string, string>();

            Parallel.ForEach(repositories, r =>
            {
                var(name, url) = r;
                WriteLines(initialColour, $"Checking whether {name} has already been cloned.");
                try
                {
                    var repoPath = Path.Combine(path, name);
                    if (Directory.Exists(Path.Combine(repoPath, ".git")))
                    {
                        WriteLines(initialColour, $"{name} has been cloned; fetching to get the latest changes.");
                        var repository = new Repository(repoPath);
                        Commands.Fetch(
                            repository,
                            "origin",
                            repository.Refs.Select(r => r.CanonicalName),
                            new FetchOptions {
                            CredentialsProvider = CredentialsProvider
                        },
                            null);
                        WriteLines(ConsoleColor.Green, $"{name} was updated successfully.");
                    }
                    else
                    {
                        WriteLines(initialColour, $"{name} has not been cloned; cloning into new folder.");
                        Repository.Clone(
                            url,
                            repoPath,
                            new CloneOptions {
                            CredentialsProvider = CredentialsProvider
                        });
                        WriteLines(ConsoleColor.Green, $"{name} was cloned successfully.");
                    }
                }
                catch (Exception ex)
                {
                    WriteLines(ConsoleColor.Red, $"Failed to clone or update {name}:", ex.ToString());
                    issues[name] = ex.ToString();
                }
            });

            if (issues.Count == 0)
            {
                return(0);
            }

            WriteLines(ConsoleColor.Red, string.Empty, "The following repositories had issues:", string.Join(Environment.NewLine, issues.Select(i => $"{i.Key}: {i.Value}{Environment.NewLine}")));
            return(1);
        }
Пример #17
0
        /// <summary>
        /// Adds the standard .NET targets to the build.
        /// </summary>
        /// <param name="build">The build to which to add targets.</param>
        /// <param name="settings">The build settings.</param>
        public static void AddDotNetTargets(this BuildApp build, DotNetBuildSettings?settings = null)
        {
            settings ??= new DotNetBuildSettings();

            var buildOptions        = settings.BuildOptions ?? (settings.BuildOptions = new DotNetBuildOptions());
            var configurationOption = buildOptions.ConfigurationOption ?? (buildOptions.ConfigurationOption =
                                                                               build.AddOption("-c|--configuration <name>", "The configuration to build (default Release)", "Release"));
            var platformOption = buildOptions.PlatformOption ?? (buildOptions.PlatformOption =
                                                                     build.AddOption("-p|--platform <name>", "The solution platform to build"));
            var verbosityOption = buildOptions.VerbosityOption ?? (buildOptions.VerbosityOption =
                                                                       build.AddOption("-v|--verbosity <level>", "The build verbosity (q[uiet], m[inimal], n[ormal], d[etailed])"));
            var versionSuffixOption = buildOptions.VersionSuffixOption ?? (buildOptions.VersionSuffixOption =
                                                                               build.AddOption("--version-suffix <suffix>", "Generates a prerelease package"));
            var nugetOutputOption = buildOptions.NuGetOutputOption ?? (buildOptions.NuGetOutputOption =
                                                                           build.AddOption("--nuget-output <path>", "Directory for generated package (default release)", "release"));
            var triggerOption = buildOptions.TriggerOption ?? (buildOptions.TriggerOption =
                                                                   build.AddOption("--trigger <name>", "The git branch or tag that triggered the build"));
            var buildNumberOption = buildOptions.BuildNumberOption ?? (buildOptions.BuildNumberOption =
                                                                           build.AddOption("--build-number <number>", "The automated build number"));
            var noTestFlag = buildOptions.NoTestFlag ?? (buildOptions.NoTestFlag =
                                                             build.AddFlag("--no-test", "Skip the unit tests"));

            var solutionName    = settings.SolutionName;
            var nugetSource     = settings.NuGetSource ?? "https://api.nuget.org/v3/index.json";
            var msbuildSettings = settings.MSBuildSettings;

            var    packagePaths          = new List <string>();
            string?trigger               = null;
            var    ignoreIfAlreadyPushed = false;

            build.Target("clean")
            .Describe("Deletes all build output")
            .Does(() =>
            {
                var findDirectoriesToDelete = settings.CleanSettings?.FindDirectoriesToDelete ??
                                              (() => FindDirectories("{src,tests,tools}/**/{bin,obj}").Except(FindDirectories("tools/bin")).ToList());
                foreach (var directoryToDelete in findDirectoriesToDelete())
                {
                    DeleteDirectory(directoryToDelete);
                }

                var verbosity       = GetVerbosity();
                var extraProperties = GetExtraProperties("clean");
                if (msbuildSettings == null)
                {
                    RunDotNet(new[] { "clean", solutionName, "-c", configurationOption.Value, GetPlatformArg(), "--verbosity", verbosity, GetMaxCpuCountArg() }.Concat(extraProperties));
                }
                else
                {
                    MSBuild(new[] { solutionName, "-t:Clean", $"-p:Configuration={configurationOption.Value}", GetPlatformArg(), $"-v:{verbosity}", GetMaxCpuCountArg() }.Concat(extraProperties));
                }
            });

            build.Target("restore")
            .Describe("Restores NuGet packages")
            .Does(() =>
            {
                var verbosity       = GetVerbosity();
                var extraProperties = GetExtraProperties("restore");
                if (msbuildSettings == null)
                {
                    RunDotNet(new[] { "restore", solutionName, GetPlatformArg(), "--verbosity", verbosity, GetMaxCpuCountArg() }.Concat(extraProperties));
                }
                else
                {
                    MSBuild(new[] { solutionName, "-t:Restore", $"-p:Configuration={configurationOption.Value}", GetPlatformArg(), $"-v:{verbosity}", GetMaxCpuCountArg() }.Concat(extraProperties));
                }

                if (DotNetLocalTool.Any())
                {
                    RunDotNet("tool", "restore");
                }
            });

            build.Target("build")
            .DependsOn("restore")
            .Describe("Builds the solution")
            .Does(() =>
            {
                var buildNumberArg = GetBuildNumberArg();

                var verbosity       = GetVerbosity();
                var extraProperties = GetExtraProperties("build");
                if (msbuildSettings == null)
                {
                    RunDotNet(new[] { "build", solutionName, "-c", configurationOption.Value, GetPlatformArg(), buildNumberArg, "--no-restore", "--verbosity", verbosity, GetMaxCpuCountArg() }.Concat(extraProperties));
                }
                else
                {
                    MSBuild(new[] { solutionName, $"-p:Configuration={configurationOption.Value}", GetPlatformArg(), buildNumberArg, $"-v:{verbosity}", GetMaxCpuCountArg() }.Concat(extraProperties));
                }
            });

            build.Target("test")
            .DependsOn("build")
            .Describe("Runs the unit tests")
            .Does(() =>
            {
                if (noTestFlag.Value)
                {
                    Console.WriteLine("Skipping unit tests due to --no-test.");
                }
                else
                {
                    var extraProperties    = GetExtraProperties("test").ToList();
                    var findTestAssemblies = settings.TestSettings?.FindTestAssemblies;
                    if (findTestAssemblies != null)
                    {
                        foreach (var testAssembly in findTestAssemblies())
                        {
                            if (settings.TestSettings?.RunTests != null)
                            {
                                settings.TestSettings.RunTests(testAssembly);
                            }
                            else
                            {
                                RunDotNet(new AppRunnerSettings {
                                    Arguments = new[] { "vstest", Path.GetFileName(testAssembly) }.Concat(extraProperties), WorkingDirectory = Path.GetDirectoryName(testAssembly)
                                });
                            }
                        }
                    }
                    else
                    {
                        var testProjects = new List <string?>();

                        var findTestProjects = settings.TestSettings?.FindProjects;
                        if (findTestProjects != null)
                        {
                            testProjects.AddRange(findTestProjects());
                        }
                        else
                        {
                            testProjects.Add(solutionName);
                        }

                        foreach (var testProject in testProjects)
                        {
                            if (settings.TestSettings?.RunTests != null)
                            {
                                settings.TestSettings.RunTests(testProject);
                            }
                            else
                            {
                                RunDotNet(new[] { "test", testProject, "-c", configurationOption.Value, GetPlatformArg(), "--no-build", GetMaxCpuCountArg() }.Concat(extraProperties));
                            }
                        }
                    }
                }
            });

            build.Target("package")
            .DependsOn("clean", "test")
            .Describe("Builds NuGet packages")
            .Does(() =>
            {
                trigger = triggerOption.Value;

                if (trigger == "detect")
                {
                    using var repository = new Repository(".");
                    var headSha          = repository.Head.Tip.Sha;
                    var autoTrigger      = GetBestTriggerFromTags(repository.Tags.Where(x => x.Target.Sha == headSha).Select(x => x.FriendlyName).ToList());
                    if (autoTrigger != null)
                    {
                        trigger = autoTrigger;
                        ignoreIfAlreadyPushed = true;
                        Console.WriteLine($"Detected trigger: {trigger}");
                    }
                }

                var versionSuffix = versionSuffixOption.Value;
                if (versionSuffix == null && trigger != null)
                {
                    versionSuffix = GetVersionFromTrigger(trigger) is string triggerVersion ? SplitVersion(triggerVersion).Suffix : null;
                }

                var nugetOutputPath = Path.GetFullPath(nugetOutputOption.Value !);
                var tempOutputPath  = Path.Combine(nugetOutputPath, Path.GetRandomFileName());

                var packageProjects = new List <string?>();

                var findPackageProjects = settings.PackageSettings?.FindProjects;
                if (findPackageProjects != null)
                {
                    packageProjects.AddRange(findPackageProjects());
                }
                else
                {
                    packageProjects.Add(solutionName);
                }

                var extraProperties = GetExtraProperties("package").ToList();
                foreach (var packageProject in packageProjects)
                {
                    if (msbuildSettings == null)
                    {
                        RunDotNet(new[]
                        {
                            "pack", packageProject,
                            "-c", configurationOption.Value,
                            GetPlatformArg(),
                            "--no-build",
                            "--output", tempOutputPath,
                            versionSuffix != null ? "--version-suffix" : null, versionSuffix,
                            GetMaxCpuCountArg(),
                        }.Concat(extraProperties));
                    }
                    else
                    {
                        MSBuild(new[]
                        {
                            packageProject, "-t:Pack",
                            $"-p:Configuration={configurationOption.Value}",
                            GetPlatformArg(),
                            "-p:NoBuild=true",
                            $"-p:PackageOutputPath={tempOutputPath}",
                            versionSuffix != null ? $"-p:VersionSuffix={versionSuffix}" : null,
                            $"-v:{GetVerbosity()}",
                            GetMaxCpuCountArg(),
                        }.Concat(extraProperties));
                    }
                }

                var tempPackagePaths = FindFilesFrom(tempOutputPath, "*.nupkg");
                foreach (var tempPackagePath in tempPackagePaths)
                {
                    var packagePath = Path.Combine(nugetOutputPath, Path.GetFileName(tempPackagePath) ?? throw new InvalidOperationException());
                    if (File.Exists(packagePath))
                    {
                        File.Delete(packagePath);
                    }
                    File.Move(tempPackagePath, packagePath);
                    packagePaths.Add(packagePath);
                    Console.WriteLine($"NuGet package: {packagePath}");
                }
                DeleteDirectory(tempOutputPath);

                if (packagePaths.Count == 0)
                {
                    throw new BuildException("No NuGet packages created.");
                }
            });

            build.Target("publish")
            .Describe("Publishes NuGet packages and documentation")
            .DependsOn("package")
            .Does(() =>
            {
                if (packagePaths.Count == 0)
                {
                    throw new BuildException("No NuGet packages found.");
                }

                if (trigger is null)
                {
                    if (packagePaths.Any(x => GetPackageInfo(x).Version == "0.0.0"))
                    {
                        Console.WriteLine("Not publishing package with version 0.0.0. Change package version to publish.");
                        return;
                    }

                    trigger = "publish-all";
                }

                var triggerParts          = trigger.Split('-');
                var publishTrigger        = triggerParts.Length >= 2 && triggerParts[0] == "publish" ? triggerParts[1] : null;
                var shouldPublishPackages = publishTrigger == "package" || publishTrigger == "packages" || publishTrigger == "all";
                var shouldPublishDocs     = publishTrigger == "docs" || publishTrigger == "all";
                var shouldSkipDuplicates  = publishTrigger == "all";

                var triggerVersion = GetVersionFromTrigger(trigger);
                if (triggerVersion != null)
                {
                    var mismatches = packagePaths.Where(x => GetPackageInfo(x).Version != triggerVersion).ToList();
                    if (mismatches.Count != 0)
                    {
                        throw new BuildException($"Trigger '{trigger}' doesn't match package version: {string.Join(", ", mismatches.Select(Path.GetFileName))}");
                    }

                    shouldPublishPackages = true;
                    shouldPublishDocs     = triggerVersion.IndexOf('-') == -1;
                }

                if (shouldPublishPackages || shouldPublishDocs)
                {
                    var docsSettings      = settings.DocsSettings;
                    var shouldPushDocs    = false;
                    string?cloneDirectory = null;
                    string?repoDirectory  = null;
                    string?gitBranchName  = null;

                    if (shouldPublishDocs && docsSettings != null)
                    {
                        if (docsSettings.GitLogin == null || docsSettings.GitAuthor == null)
                        {
                            throw new BuildException("GitLogin and GitAuthor must be set on DocsSettings.");
                        }

                        var gitRepositoryUrl = docsSettings.GitRepositoryUrl;
                        gitBranchName        = docsSettings.GitBranchName;

                        if (gitRepositoryUrl != null)
                        {
                            cloneDirectory = "docs_repo_" + Path.GetRandomFileName();
                            Repository.Clone(sourceUrl: gitRepositoryUrl, workdirPath: cloneDirectory,
                                             options: new CloneOptions {
                                BranchName = gitBranchName, CredentialsProvider = ProvideCredentials
                            });
                            repoDirectory = cloneDirectory;
                        }
                        else
                        {
                            repoDirectory = ".";
                        }

                        using var repository = new Repository(repoDirectory);
                        if (gitRepositoryUrl != null)
                        {
                            gitBranchName ??= repository.Head.FriendlyName;
                        }
                        else if (gitBranchName != null)
                        {
                            if (gitBranchName != repository.Head.FriendlyName)
                            {
                                var branch = repository.Branches[gitBranchName] ?? repository.CreateBranch(gitBranchName);
                                Commands.Checkout(repository, branch);
                            }
                        }
                        else
                        {
                            var branch = repository.Branches.FirstOrDefault(x => x.IsCurrentRepositoryHead);
                            if (branch == null)
                            {
                                var autoBranchName = Environment.GetEnvironmentVariable("APPVEYOR_REPO_BRANCH");

                                if (autoBranchName == null)
                                {
                                    var gitRef          = Environment.GetEnvironmentVariable("GITHUB_REF");
                                    const string prefix = "refs/heads/";
                                    if (gitRef != null && gitRef.StartsWith(prefix, StringComparison.Ordinal))
                                    {
                                        autoBranchName = gitRef.Substring(prefix.Length);
                                    }
                                }

                                if (autoBranchName != null)
                                {
                                    branch = repository.Branches[autoBranchName] ?? repository.CreateBranch(autoBranchName);
                                }
                                else
                                {
                                    branch = repository.Branches.FirstOrDefault(x => x.Tip.Sha == repository.Head.Tip.Sha);
                                }

                                if (branch != null)
                                {
                                    Commands.Checkout(repository, branch);
                                }
                            }
                            if (branch == null)
                            {
                                throw new BuildException("Could not determine repository branch for publishing docs.");
                            }
                            gitBranchName = branch.FriendlyName;
                        }

                        var docsPath = Path.Combine(repoDirectory, docsSettings.TargetDirectory ?? "docs");

                        string?xmlDocGenPath = null;
                        var xmlDocGenProject = FindFiles("tools/XmlDocGen/XmlDocGen.csproj").FirstOrDefault();
                        if (xmlDocGenProject != null)
                        {
                            RunDotNet("publish", xmlDocGenProject, "--output", Path.Combine("tools", "bin", "XmlDocGen"), "--nologo", "--verbosity", "quiet");
                            xmlDocGenPath = Path.Combine("tools", "bin", "XmlDocGen", "XmlDocGen.dll");
                        }

                        var projectHasDocs = docsSettings.ProjectHasDocs ?? (_ => true);
                        foreach (var projectName in packagePaths.Select(x => GetPackageInfo(x).Name).Where(projectHasDocs))
                        {
                            if (xmlDocGenPath != null)
                            {
                                RunDotNet(new[] { xmlDocGenPath }.Concat(GetXmlDocArgs(projectName)));
                            }
                            else
                            {
                                var assemblyPaths = new List <string>();
                                if (docsSettings.FindAssemblies != null)
                                {
                                    assemblyPaths.AddRange(docsSettings.FindAssemblies(projectName));
                                }
                                else
                                {
                                    var assemblyPath = (docsSettings.FindAssembly ?? FindAssembly)(projectName);
                                    if (assemblyPath != null)
                                    {
                                        assemblyPaths.Add(assemblyPath);
                                    }
                                }

                                if (assemblyPaths.Count != 0)
                                {
                                    if (DotNetLocalTool.TryCreate("xmldocmd") is DotNetLocalTool xmldocmd)
                                    {
                                        foreach (var assemblyPath in assemblyPaths)
                                        {
                                            xmldocmd.Run(GetXmlDocArgs(assemblyPath));
                                        }
                                    }
                                    else
                                    {
                                        var dotNetTools           = settings.DotNetTools ?? new DotNetTools(Path.Combine("tools", "bin"));
                                        var xmlDocMarkdownVersion = settings.DocsSettings?.ToolVersion ?? "2.0.1";

                                        foreach (var assemblyPath in assemblyPaths)
                                        {
                                            RunApp(dotNetTools.GetToolPath($"xmldocmd/{xmlDocMarkdownVersion}"), GetXmlDocArgs(assemblyPath));
                                        }
                                    }
                                }
                                else
                                {
                                    Console.WriteLine($"Documentation not generated for {projectName}; assembly not found.");
                                }