Cmdlets/src/XpandPwsh.Cmdlets/Nuget/Update-NugetProjectVersion.cs
using System;
using System.IO; using System.Linq; using System.Management.Automation; using System.Reactive.Linq; using System.Reactive.Subjects; using System.Reactive.Threading.Tasks; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using XpandPwsh.CmdLets; using XpandPwsh.Cmdlets.GitHub; namespace XpandPwsh.Cmdlets.Nuget{ [CmdletBinding(SupportsShouldProcess = true)] [Cmdlet(VerbsData.Update,"NugetProjectVersion",SupportsShouldProcess = true)] [CmdLetTag(CmdLetTag.Nuget,CmdLetTag.Reactive,CmdLetTag.RX)][PublicAPI] public class UpdateNugetProjectVersion:GitHubCmdlet,IParameter{ [Parameter(Mandatory = true)] public string Repository{ get; set; } [Parameter(Mandatory = true)] public string Branch{ get; set; } [Parameter(Mandatory = true)] public string SourcePath{ get; set; } [Parameter(Mandatory = true)] public string ExcludeFilter{ get; set; } [Parameter(Mandatory=true)] public PSObject[] Packages{ get; set; } [Parameter(Mandatory=true)] public DateTimeOffset CommitsSince{ get; set; } protected override async Task ProcessRecordAsync(){ var commits = GitHubClient.Commits(Organization, Repository, CommitsSince, Branch).Replay().RefCount(); if (!commits.ToEnumerable().Any()){ WriteVerbose("No commits found"); return; } await commits.WriteVerboseObject(this,commit => commit.Commit.Message); var changedPackages = ExistingPackages(this).ToObservable() .WriteVerboseObject(this,_ => $"Existing: {_.name}, {_.nextVersion} ") .SelectMany(tuple => commits.SelectMany(commit => commit.Files).Where(file => file.Filename.Contains(tuple.directory.Name)).Select(_=>tuple)).Distinct() .Replay().RefCount(); WriteVerbose("ChangedPackages:"); var valueTuple = await changedPackages.WriteVerboseObject(this,_ => $"Changed: {_.name}, {_.nextVersion} ").LastOrDefaultAsync(); if (valueTuple == default){ return; } var subject = new Subject<string>(); subject.WriteObject(this).Subscribe(); var synchronizationContext = SynchronizationContext.Current; await changedPackages.SelectMany(tuple => GitHubClient.Repository .GetForOrg(Organization, Repository) // .SelectMany(_ => CreateTagReference(this, GitHubClient, _, tuple, subject,synchronizationContext)) .Select(tag => tuple)) .ObserveOn(synchronizationContext) .Select(UpdateAssemblyInfo) .HandleErrors(this) .WriteObject(this) .ToTask(); } private string UpdateAssemblyInfo((string name, string nextVersion, DirectoryInfo directory) info){ if (ShouldProcess($"Update {info.name} to version {info.nextVersion}")){ var directoryName = info.directory.FullName; var path = $@"{directoryName}\Properties\AssemblyInfo.cs"; var text = File.ReadAllText(path); text = Regex.Replace(text, @"Version\(""([^""]*)", $"Version(\"{info.nextVersion}"); File.WriteAllText(path, text); WriteVerbose($"{info.name} version raised to {info.nextVersion} "); return info.name; } return default; } // private IObservable<Reference> CreateTagReference(IParameter parameter, GitHubClient appClient, // Repository repository, (string name, string nextVersion, DirectoryInfo directory) tuple, // IObserver<string> observer, SynchronizationContext synchronizationContext){ // observer.OnNext($"Lookup {tuple.name} heads"); // return appClient.Git.Reference.Get(repository.Id, $"heads/{parameter.Branch}") // .ToObservable() // .ObserveOn(synchronizationContext) // .SelectMany(reference => { // var tag = $"{tuple.directory.Name}_{tuple.nextVersion}"; // var description = $"Creating {tag} tag on repo {repository.Name}"; // if (ShouldProcess(description)){ // observer.OnNext(description); // return appClient.Git.Reference.Create(repository.Id,new NewReference($@"refs/tags/{tag}",reference.Object.Sha)) // .ToObservable().Catch<Reference, ApiValidationException>(ex => // ex.ApiError.Message=="Reference already exists"? Observable.Return<Reference>(null): Observable.Throw<Reference>(ex)); // } // // return Observable.Return(default(Reference)); // // }); // } private (string name, string nextVersion, DirectoryInfo directory)[] ExistingPackages(IParameter parameter){ var packageArgs = parameter.Packages.Select(_ => (name: $"{_.Properties["Id"].Value}", nextVersion: $"{_.Properties["nextVersion"].Value}", directory: (DirectoryInfo) null)).ToArray(); var existingPackages = Directory.GetFiles(parameter.SourcePath, "*.csproj", SearchOption.AllDirectories) .Where(s => !s.ToLower().Contains(ExcludeFilter.ToLower())) .Where(s => packageArgs.Select(_ => _.name).Any(s.Contains)).ToArray() .Select(s => { var valueTuple = packageArgs.First(_ => _.name == Path.GetFileNameWithoutExtension(s)); valueTuple.directory = new DirectoryInfo($"{Path.GetDirectoryName(s)}"); return valueTuple; }).ToArray(); return existingPackages; } } [PublicAPI] public interface IParameter{ PSObject[] Packages{ get; set; } string Owner{ get; set; } string Organization{ get; set; } string Repository{ get; set; } string Branch{ get; set; } string Pass{ get; set; } string SourcePath{ get; set; } } } |