public override void Log(ILogMessage message) { switch (message.Level) { case LogLevel.Verbose: _logger.Detailed(message.Message); break; case LogLevel.Debug: _logger.Detailed(message.Message); break; case LogLevel.Information: _logger.Detailed(message.Message); break; case LogLevel.Minimal: _logger.Normal(message.Message); break; case LogLevel.Warning: _logger.Normal(message.Message); break; case LogLevel.Error: _logger.Error(message.Message); break; default: throw new ArgumentOutOfRangeException($"Invalid log level {message.Level}"); } }
public async Task Invoke(FileInfo file, NuGetSources sources) { _logger.Normal($"Nuget restore on {file.DirectoryName} {file.Name}"); if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { _logger.Normal("Cannot run NuGet.exe file restore as OS Platform is not Windows"); return; } var nuget = NuGetPath.FindExecutable(); if (string.IsNullOrWhiteSpace(nuget)) { _logger.Normal("Cannot find NuGet exe for solution restore"); return; } var sourcesCommandLine = sources.CommandLine("-Source"); var arguments = $"restore {file.Name} {sourcesCommandLine}"; _logger.Detailed($"{nuget} {arguments}"); var processOutput = await _externalProcess.Run(file.DirectoryName, nuget, arguments, ensureSuccess : false); if (processOutput.Success) { _logger.Detailed($"Nuget restore on {file.Name} complete"); } else { _logger.Detailed($"Nuget restore failed on {file.DirectoryName} {file.Name}:\n{processOutput.Output}\n{processOutput.ErrorOutput}"); } }
public IEnumerable <PackageUpdateSet> Sort(IReadOnlyCollection <PackageUpdateSet> input) { if (input.Count < 2) { return(input); } _data = input .Select(p => MakeNode(p, input)) .ToList(); if (!_data.Any(i => i.Dependencies.Any())) { _logger.Detailed("No dependencies between packages being updated, no need to sort on this"); return(input); } foreach (var item in _data) { if (item.Mark == Mark.None) { Visit(item); } } if (_cycleFound) { return(input); } ReportSort(input.ToList(), _sortedList); return(_sortedList); }
private async Task <T> GetResourceOrEmpty <T>(string url, [CallerMemberName] string caller = null) { _logger.Detailed($"Getting from BitBucketLocal url {url}"); var response = await _client.GetAsync(url); return(await HandleResponse <T>(response, caller)); }
public void Report( OutputDestination destination, OutputFormat format, string reportName, string fileName, IReadOnlyCollection <PackageUpdateSet> updates) { if (updates == null) { throw new ArgumentNullException(nameof(updates)); } var destinationDesc = destination == OutputDestination.File ? $" File '{fileName}'" : destination.ToString(); _logger.Detailed($"Output report named {reportName}, is {format} to {destinationDesc}"); using (var writer = MakeReportWriter(destination, fileName)) { var reporter = MakeReporter(format, writer); reporter.Write(reportName, updates); } _logger.Detailed($"Wrote report for {updates.Count} updates"); }
private async Task<T> PostResource<T>(string url, HttpContent content, bool previewApi = false, [CallerMemberName] string caller = null) { var fullUrl = BuildAzureDevOpsUri(url, previewApi); _logger.Detailed($"{caller}: Requesting {fullUrl}"); var response = await _client.PostAsync(fullUrl, content); return await HandleResponse<T>(response, caller); }
public async Task <ProcessOutput> Run(string workingDirectory, string command, string arguments, bool ensureSuccess) { return(await Task.Run(() => { _logger.Detailed($"In path {workingDirectory}, running command: {command} {arguments}"); System.Diagnostics.Process process; outputData = new StringBuilder(); errorData = new StringBuilder(); try { var processInfo = MakeProcessStartInfo(workingDirectory, command, arguments); process = System.Diagnostics.Process.Start(processInfo); } catch (Exception ex) { _logger.Error($"External command failed:{command} {arguments}", ex); if (ensureSuccess) { throw; } var message = $"Error starting external process for {command}: {ex.GetType().Name} {ex.Message}"; return new ProcessOutput(string.Empty, message, 1); } if (process == null) { throw new NuKeeperException($"Could not start external process for {command}"); } process.OutputDataReceived += (outSender, outArgs) => outputData.AppendLine(outArgs.Data); process.ErrorDataReceived += (errSender, errArgs) => errorData.AppendLine(errArgs.Data); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); var exitCode = process.ExitCode; string textOut = outputData.ToString(); string errorOut = errorData.ToString(); if (exitCode != 0) { var message = $"Command {command} failed with exit code: {exitCode}\n\n{textOut}\n\n{errorOut}"; _logger.Detailed(message); if (ensureSuccess) { throw new NuKeeperException(message); } } return new ProcessOutput(textOut, errorOut, exitCode); })); }
public async Task Clone(Uri pullEndpoint, string branchName) { _logger.Normal($"Git clone {pullEndpoint}, branch {branchName ?? "default"}, to {WorkingFolder.FullPath}"); var branchparam = branchName == null ? "" : $" -b {branchName}"; await StartGitProcess($"clone{branchparam} {CreateCredentialsUri(pullEndpoint, _gitCredentials)} .", true); // Clone into current folder _logger.Detailed("Git clone complete"); }
private async Task <T> GetResource <T>(string url, Func <HttpStatusCode, Result <T> > customErrorHandling = null, [CallerMemberName] string caller = null) { var fullUrl = new Uri(url, UriKind.Relative); _logger.Detailed($"{caller}: Requesting {fullUrl}"); var response = await _client.GetAsync(fullUrl); return(await HandleResponse(response, customErrorHandling, caller)); }
private async Task <T> GetResourceOrEmpty <T>(string url) { _logger.Detailed($"Getting from BitBucket url {url}"); var response = await _client.GetAsync(url); var responseBody = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { _logger.Detailed($"Response {response.StatusCode} is not success, body:\n{responseBody}"); return(default);
public async Task <ProcessOutput> Run(string workingDirectory, string command, string arguments, bool ensureSuccess) { _logger.Detailed($"In path {workingDirectory}, running command: {command} {arguments}"); System.Diagnostics.Process process; try { var processInfo = MakeProcessStartInfo(workingDirectory, command, arguments); process = System.Diagnostics.Process.Start(processInfo); } catch (Exception ex) { _logger.Error($"External command failed:{command} {arguments}", ex); if (ensureSuccess) { throw; } var message = $"Error starting external process for {command}: {ex.GetType().Name} {ex.Message}"; return(new ProcessOutput(string.Empty, message, 1)); } if (process == null) { throw new NuKeeperException($"Could not start external process for {command}"); } var outputs = await Task.WhenAll( process.StandardOutput.ReadToEndAsync(), process.StandardError.ReadToEndAsync() ); var textOut = outputs[0]; var errorOut = outputs[1]; process.WaitForExit(); var exitCode = process.ExitCode; if (exitCode != 0) { var message = $"Command {command} failed with exit code: {exitCode}\n\n{textOut}\n\n{errorOut}"; _logger.Detailed(message); if (ensureSuccess) { throw new NuKeeperException(message); } } return(new ProcessOutput(textOut, errorOut, exitCode)); }
public NuGetSources ReadNugetSources(IFolder workingFolder) { var settings = Settings.LoadDefaultSettings(workingFolder.FullPath); foreach (var file in settings.GetConfigFilePaths()) { _logger.Detailed($"Reading file {file} for package sources"); } var enabledSources = SettingsUtility.GetEnabledSources(settings).ToList(); return(ReadFromFile(enabledSources)); }
public NuGetSources ReadNugetSources(IFolder workingFolder) { var settings = Settings.LoadDefaultSettings(workingFolder.FullPath); foreach (var file in settings.Priority) { _logger.Detailed($"Reading file {Path.Combine(file.Root, file.FileName)} for package sources"); } var enabledSources = SettingsUtility.GetEnabledSources(settings).ToList(); return(ReadFromFile(enabledSources)); }
private string FindLocalNuget() { var appDir = AppDomain.CurrentDomain.BaseDirectory; var fullPath = Path.Combine(appDir, "NuGet.exe"); if (File.Exists(fullPath)) { _logger.Detailed("Found NuGet.exe: " + fullPath); return(fullPath); } return(string.Empty); }
public async Task Invoke(FileInfo file, NuGetSources sources) { _logger.Normal($"Nuget restore on {file.DirectoryName} {file.Name}"); var nuget = _nuGetPath.Executable; if (string.IsNullOrWhiteSpace(nuget)) { _logger.Normal("Cannot find NuGet.exe for solution restore"); return; } var sourcesCommandLine = sources.CommandLine("-Source"); var restoreCommand = $"restore {file.Name} {sourcesCommandLine} -NonInteractive"; ProcessOutput processOutput; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (await _monoExecutor.CanRun()) { processOutput = await _monoExecutor.Run(file.DirectoryName, nuget, restoreCommand, ensureSuccess : false); } else { _logger.Error("Cannot run NuGet.exe. It requires either Windows OS Platform or Mono installation"); return; } } else { processOutput = await _externalProcess.Run(file.DirectoryName, nuget, restoreCommand, ensureSuccess : false); } if (processOutput.Success) { _logger.Detailed($"Nuget restore on {file.Name} complete"); } else { _logger.Detailed( $"Nuget restore failed on {file.DirectoryName} {file.Name}:\n{processOutput.Output}\n{processOutput.ErrorOutput}"); } }
public void TryDelete() { _logger.Detailed($"Attempting delete of folder {_root.FullName}"); try { DeleteDirectoryInternal(_root.FullName); _logger.Detailed($"Deleted folder {_root.FullName}"); } catch (Exception ex) { _logger.Detailed($"Folder delete failed: {ex.GetType().Name} {ex.Message}"); } }
public async Task <bool> RepositoryBranchExists(string projectName, string repositoryName, string branchName) { var branches = await _client.GetGitRepositoryBranches(projectName, repositoryName); var count = branches.Count(x => x.DisplayId.Equals(branchName, StringComparison.OrdinalIgnoreCase)); if (count > 0) { _logger.Detailed($"Branch found for {projectName} / {repositoryName} / {branchName}"); return(true); } _logger.Detailed($"No branch found for {projectName} / {repositoryName} / {branchName}"); return(false); }
public async Task<bool> RepositoryBranchExists(string projectName, string repositoryName, string branchName) { var repos = await _client.GetGitRepositories(projectName); var repo = repos.Single(x => x.name.Equals(repositoryName, StringComparison.OrdinalIgnoreCase)); var refs = await _client.GetRepositoryRefs(projectName, repo.id); var count = refs.Count(x => x.name.EndsWith(branchName, StringComparison.OrdinalIgnoreCase)); if (count > 0) { _logger.Detailed($"Branch found for {projectName} / {repositoryName} / {branchName}"); return true; } _logger.Detailed($"No branch found for {projectName} / {repositoryName} / {branchName}"); return false; }
public async Task <int> Run(SettingsContainer settings) { var github = _githubCreator.Create(settings); var repositoryDiscovery = _repositoryDiscoveryCreator.Create(settings); var repositoryEngine = _repositoryEngineCreator.Create(settings); _logger.Detailed($"{Now()}: Started"); _folderFactory.DeleteExistingTempDirs(); var githubUser = await github.GetCurrentUser(); var gitCreds = new UsernamePasswordCredentials { Username = githubUser.Login, Password = settings.GithubAuthSettings.Token }; var userIdentity = GetUserIdentity(githubUser); var repositories = await repositoryDiscovery.GetRepositories(); var reposUpdated = 0; foreach (var repository in repositories) { if (reposUpdated >= settings.UserSettings.MaxRepositoriesChanged) { _logger.Detailed($"Reached max of {reposUpdated} repositories changed"); break; } var updatesInThisRepo = await repositoryEngine.Run(repository, gitCreds, userIdentity); if (updatesInThisRepo > 0) { reposUpdated++; } } if (reposUpdated > 1) { _logger.Detailed($"{reposUpdated} repositories were updated"); } _logger.Detailed($"Done at {Now()}"); return(reposUpdated); }
public async Task Update(PackageUpdateSet updateSet, NuGetSources sources) { if (updateSet == null) { throw new ArgumentNullException(nameof(updateSet)); } var sortedUpdates = Sort(updateSet.CurrentPackages); _logger.Detailed($"Updating '{updateSet.SelectedId}' to {updateSet.SelectedVersion} in {sortedUpdates.Count} projects"); var updateTasks = sortedUpdates.ToList().Select(current => { return(Task.Factory.StartNew(async() => { var updateCommands = GetUpdateCommands(current.Path.PackageReferenceType); foreach (var updateCommand in updateCommands) { await updateCommand.Invoke(current, updateSet.SelectedVersion, updateSet.Selected.Source, sources); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)); }); await Task.WhenAll(updateTasks); }
private async Task UpdateNuspec(FileStream fileContents, NuGetVersion newVersion, PackageInProject currentPackage) { var xml = XDocument.Load(fileContents); var packagesNode = xml.Element("package")?.Element("metadata")?.Element("dependencies"); if (packagesNode == null) { return; } var packageNodeList = packagesNode.Elements() .Where(x => x.Name == "dependency" && x.Attributes("id") .Any(a => a.Value == currentPackage.Id)); foreach (var dependencyToUpdate in packageNodeList) { _logger.Detailed($"Updating nuspec depenencies: {currentPackage.Id} in path {currentPackage.Path.FullName}"); dependencyToUpdate.Attribute("version").Value = newVersion.ToString(); } fileContents.Seek(0, SeekOrigin.Begin); await xml.SaveAsync(fileContents, SaveOptions.None, CancellationToken.None); }
private void UpdateFile(Stream fileContents, NuGetVersion newVersion, PackageInProject currentPackage, XDocument xml) { var packagesNode = xml.Element("Project")?.Elements("ItemGroup"); if (packagesNode == null) { return; } var packageNodeList = packagesNode.Elements("PackageReference") .Where(x => (x.Attributes("Include").Any(a => a.Value.Equals(currentPackage.Id, StringComparison.InvariantCultureIgnoreCase)) || x.Attributes("Update").Any(a => a.Value.Equals(currentPackage.Id, StringComparison.InvariantCultureIgnoreCase)))); foreach (var dependencyToUpdate in packageNodeList) { _logger.Detailed( $"Updating directory-level dependencies: {currentPackage.Id} in path {currentPackage.Path.FullName}"); var attribute = dependencyToUpdate.Attribute("Version"); if (attribute != null) { attribute.Value = newVersion.ToString(); } else { dependencyToUpdate.Element("Version").Value = newVersion.ToString(); } } xml.Save(fileContents); }
public async Task ApplyAnUpdate( IReadOnlyCollection <PackageUpdateSet> updates, NuGetSources sources) { if (!updates.Any()) { return; } var filtered = await _selection .Filter(updates, p => Task.FromResult(true)); if (!filtered.Any()) { _logger.Detailed("All updates were filtered out"); return; } var candidate = filtered.First(); var reporter = new ConsoleReporter(); _logger.Minimal("Updating " + reporter.Describe(candidate)); await _updateRunner.Update(candidate, sources); }
public void Report(string name, IReadOnlyCollection <PackageUpdateSet> updates) { using (var writer = _reportStreamSource.GetStream(name)) { _logger.Detailed($"writing {updates.Count} lines to report"); WriteHeading(writer); foreach (var update in updates) { WriteLine(writer, update); } writer.Close(); _logger.Detailed("Report written"); } }
public async Task <bool> ContainsDotNetProjects(RepositorySettings repository) { const string dotNetCodeFiles = "\"packages.config\" OR \".csproj\" OR \".fsproj\" OR \".vbproj\""; var repos = new List <SearchRepo> { new SearchRepo(repository.RepositoryOwner, repository.RepositoryName) }; var searchCodeRequest = new SearchCodeRequest(dotNetCodeFiles, repos) { PerPage = 1 }; try { var result = await _collaborationFactory.CollaborationPlatform.Search(searchCodeRequest); if (result.TotalCount <= 0) { _logger.Detailed( $"Repository {repository.RepositoryOwner}/{repository.RepositoryName} contains no .NET code on the default branch, skipping."); return(false); } return(true); } catch (Exception ex) { _logger.Error("Repository search failed.", ex); } return(true); }
public async Task ApplyUpdates( IReadOnlyCollection <PackageUpdateSet> updates, IFolder workingFolder, NuGetSources sources, SettingsContainer settings) { if (settings == null) { throw new ArgumentNullException(nameof(settings)); } if (!updates.Any()) { return; } var filtered = _selection .Filter(updates, settings.PackageFilters); if (!filtered.Any()) { _logger.Detailed("All updates were filtered out"); return; } await ApplyUpdates(filtered, workingFolder, sources); }
private async Task <int> MakeUpdatePullRequests( IGitDriver git, RepositoryData repository, NuGetSources sources, SettingsContainer settings, IReadOnlyCollection <PackageUpdateSet> updates) { _logger.Normal(UpdatesLogger.OldVersionsToBeUpdated(updates)); git.Checkout(repository.DefaultBranch); // branch var branchName = BranchNamer.MakeName(updates); _logger.Detailed($"Using branch name: '{branchName}'"); git.CheckoutNewBranch(branchName); foreach (var updateSet in updates) { await _updateRunner.Update(updateSet, sources); var commitMessage = CommitWording.MakeCommitMessage(updateSet); git.Commit(commitMessage); } git.Push("nukeeper_push", branchName); var title = CommitWording.MakePullRequestTitle(updates); var body = CommitWording.MakeCommitDetails(updates); await _gitHub.CreatePullRequest(repository, title, body, branchName, settings.SourceControlServerSettings.Labels); git.Checkout(repository.DefaultBranch); return(updates.Count); }
public void Report(PackageLookupResult lookupResult) { var highestVersion = lookupResult.Major?.Identity?.Version; if (highestVersion == null) { return; } var allowing = lookupResult.AllowedChange == VersionChange.Major ? string.Empty : $" Allowing {lookupResult.AllowedChange} version updates."; var highestMatchVersion = lookupResult.Selected()?.Identity?.Version; var packageId = lookupResult.Major.Identity.Id; if (highestMatchVersion == null) { _logger.Normal($"Package {packageId} version {highestVersion} is available but is not allowed.{allowing}"); return; } if (highestVersion > highestMatchVersion) { _logger.Normal($"Selected update of package {packageId} to version {highestMatchVersion}, but version {highestVersion} is also available.{allowing}"); } else { _logger.Detailed($"Selected update of package {packageId} to highest version, {highestMatchVersion}.{allowing}"); } }
public IEnumerable <T> Sort( IReadOnlyCollection <SortItemData <T> > inputMap) { if (inputMap == null) { throw new ArgumentNullException(nameof(inputMap)); } var inputItems = inputMap .Select(i => i.Item) .ToList(); if (inputMap.Count < 2) { return(inputItems); } if (!inputMap.Any(i => i.Dependencies.Any())) { _logger.Detailed("No dependencies between items, no need to sort on dependencies"); return(inputItems); } _data = inputMap.ToList(); return(DoSortVisits(inputItems)); }
public async Task <bool> ContainsDotNetProjects(RepositorySettings repository) { var request = new SearchCodeRequest("\"packages.config\" OR \".csproj\" OR \".fsproj\" OR \".vbproj\"") { Repos = new RepositoryCollection { { repository.RepositoryOwner, repository.RepositoryName } }, In = new [] { CodeInQualifier.Path }, PerPage = 1 }; try { var result = await _gitHubClient.Search(request); if (result.TotalCount <= 0) { _logger.Detailed( $"Repository {repository.RepositoryOwner}/{repository.RepositoryName} contains no .NET code on the default branch, skipping."); return(false); } } catch (Exception ex) { _logger.Error("GitHub Repository search failed.", ex); } return(true); }