|
|
@ -1,15 +1,21 @@ |
|
|
using Microsoft.DotNet.ProjectModel; |
|
|
// <copyright file="Program.cs" company="James Jackson-South">
|
|
|
using System; |
|
|
// Copyright (c) James Jackson-South and contributors.
|
|
|
using System.IO; |
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
using System.Linq; |
|
|
// </copyright>
|
|
|
using NuGet.Versioning; |
|
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
|
using LibGit2Sharp; |
|
|
|
|
|
using Newtonsoft.Json; |
|
|
|
|
|
using System.Text; |
|
|
|
|
|
|
|
|
|
|
|
namespace ConsoleApplication |
|
|
namespace ConsoleApplication |
|
|
{ |
|
|
{ |
|
|
|
|
|
using System; |
|
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
|
using System.IO; |
|
|
|
|
|
using System.Linq; |
|
|
|
|
|
using System.Text; |
|
|
|
|
|
|
|
|
|
|
|
using LibGit2Sharp; |
|
|
|
|
|
using Microsoft.DotNet.ProjectModel; |
|
|
|
|
|
using Newtonsoft.Json; |
|
|
|
|
|
using NuGet.Versioning; |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// This updates the version numbers for all the projects in the src folder.
|
|
|
/// This updates the version numbers for all the projects in the src folder.
|
|
|
/// The version number it will geneate is dependent on if this is a build from master or a branch/PR
|
|
|
/// The version number it will geneate is dependent on if this is a build from master or a branch/PR
|
|
|
@ -24,7 +30,8 @@ namespace ConsoleApplication |
|
|
/// We take the version number specified in project.json, append a tag for the branch/PR (so we can determin how each package was built)
|
|
|
/// We take the version number specified in project.json, append a tag for the branch/PR (so we can determin how each package was built)
|
|
|
/// append number of commits effecting the project.
|
|
|
/// append number of commits effecting the project.
|
|
|
///
|
|
|
///
|
|
|
/// Examples
|
|
|
/// </summary>
|
|
|
|
|
|
/// <example>
|
|
|
/// for PR#123 and project.json version 2.0.1 and we have had 30 commits affecting the project
|
|
|
/// for PR#123 and project.json version 2.0.1 and we have had 30 commits affecting the project
|
|
|
/// we would end up with version number 2.0.1-PR124-00030
|
|
|
/// we would end up with version number 2.0.1-PR124-00030
|
|
|
///
|
|
|
///
|
|
|
@ -42,26 +49,32 @@ namespace ConsoleApplication |
|
|
///
|
|
|
///
|
|
|
/// for `master` project.json version 2.0.1-alpha1 and we have had 1 commits affecting the project
|
|
|
/// for `master` project.json version 2.0.1-alpha1 and we have had 1 commits affecting the project
|
|
|
/// we would end up with version number 2.0.1-alpha1
|
|
|
/// we would end up with version number 2.0.1-alpha1
|
|
|
/// </summary>
|
|
|
/// </example>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// TODO Add the option for using this to update the version numbers in a project and its dependent references.
|
|
|
|
|
|
/// </remarks>
|
|
|
public class Program |
|
|
public class Program |
|
|
{ |
|
|
{ |
|
|
const string fallbackTag = "CI"; |
|
|
private const string FallbackTag = "CI"; |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Main entry point.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="args">The arguments.</param>
|
|
|
public static void Main(string[] args) |
|
|
public static void Main(string[] args) |
|
|
{ |
|
|
{ |
|
|
// TODO add options to updating the version number for indirvidual projects
|
|
|
|
|
|
|
|
|
|
|
|
var resetmode = args.Contains("reset"); |
|
|
var resetmode = args.Contains("reset"); |
|
|
|
|
|
|
|
|
// find the project root where glbal.json lives
|
|
|
// Find the project root where glbal.json lives
|
|
|
var root = ProjectRootResolver.ResolveRootDirectory("."); |
|
|
var root = ProjectRootResolver.ResolveRootDirectory("."); |
|
|
//lets find the repo
|
|
|
|
|
|
|
|
|
// Lets find the repo
|
|
|
var repo = new LibGit2Sharp.Repository(root); |
|
|
var repo = new LibGit2Sharp.Repository(root); |
|
|
|
|
|
|
|
|
//lets find all the project.json files in the src folder (don't care about versioning `tests`)
|
|
|
// Lets find all the project.json files in the src folder (don't care about versioning `tests`)
|
|
|
var projectFiles = Directory.EnumerateFiles(Path.Combine(root, "src"), Project.FileName, SearchOption.AllDirectories); |
|
|
var projectFiles = Directory.EnumerateFiles(Path.Combine(root, "src"), Project.FileName, SearchOption.AllDirectories); |
|
|
|
|
|
|
|
|
//open them and convert them to source projects
|
|
|
// Open them and convert them to source projects
|
|
|
var projects = projectFiles.Select(x => ProjectReader.GetProject(x)) |
|
|
var projects = projectFiles.Select(x => ProjectReader.GetProject(x)) |
|
|
.Select(x => new SourceProject(x, repo.Info.WorkingDirectory)) |
|
|
.Select(x => new SourceProject(x, repo.Info.WorkingDirectory)) |
|
|
.ToList(); |
|
|
.ToList(); |
|
|
@ -100,9 +113,8 @@ namespace ConsoleApplication |
|
|
{ |
|
|
{ |
|
|
foreach (var p in projects) |
|
|
foreach (var p in projects) |
|
|
{ |
|
|
{ |
|
|
//TODO force update of all dependent projects to point to the newest build.
|
|
|
// TODO force update of all dependent projects to point to the newest build.
|
|
|
|
|
|
// we skip the build number and standard CI prefix on first commits
|
|
|
//we skip the build number and standard CI prefix on first commits
|
|
|
|
|
|
var newVersion = p.FinalVersionNumber; |
|
|
var newVersion = p.FinalVersionNumber; |
|
|
|
|
|
|
|
|
// create a backup file so we can rollback later without breaking formatting
|
|
|
// create a backup file so we can rollback later without breaking formatting
|
|
|
@ -164,7 +176,7 @@ namespace ConsoleApplication |
|
|
File.Delete("build-inner.bak"); |
|
|
File.Delete("build-inner.bak"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
//revert the project.json change be reverting it but skipp all the git stuff as its not needed
|
|
|
// revert the project.json change be reverting it but skipp all the git stuff as its not needed
|
|
|
foreach (var p in projects) |
|
|
foreach (var p in projects) |
|
|
{ |
|
|
{ |
|
|
if (File.Exists($"{p.FullProjectFilePath}.bak")) |
|
|
if (File.Exists($"{p.FullProjectFilePath}.bak")) |
|
|
@ -175,62 +187,145 @@ namespace ConsoleApplication |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Project level logic
|
|
|
|
|
|
/// </summary>
|
|
|
public class SourceProject |
|
|
public class SourceProject |
|
|
{ |
|
|
{ |
|
|
private readonly IEnumerable<string> dependencies; |
|
|
private readonly IEnumerable<string> dependencies; |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Initializes a new instance of the <see cref="SourceProject"/> class.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="project">The project.</param>
|
|
|
|
|
|
/// <param name="root">The root.</param>
|
|
|
|
|
|
public SourceProject(Project project, string root) |
|
|
|
|
|
{ |
|
|
|
|
|
this.Name = project.Name; |
|
|
|
|
|
this.ProjectDirectory = project.ProjectDirectory.Substring(root.Length); |
|
|
|
|
|
this.ProjectFilePath = project.ProjectFilePath.Substring(root.Length); |
|
|
|
|
|
this.FullProjectFilePath = project.ProjectFilePath; |
|
|
|
|
|
this.Version = project.Version; |
|
|
|
|
|
this.dependencies = project.Dependencies.Select(x => x.Name); |
|
|
|
|
|
this.FinalVersionNumber = this.Version.ToFullString(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the project directory.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <value>
|
|
|
|
|
|
/// The project directory.
|
|
|
|
|
|
/// </value>
|
|
|
public string ProjectDirectory { get; } |
|
|
public string ProjectDirectory { get; } |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the version.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <value>
|
|
|
|
|
|
/// The version.
|
|
|
|
|
|
/// </value>
|
|
|
public NuGetVersion Version { get; } |
|
|
public NuGetVersion Version { get; } |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the dependent projects.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <value>
|
|
|
|
|
|
/// The dependent projects.
|
|
|
|
|
|
/// </value>
|
|
|
public List<SourceProject> DependentProjects { get; private set; } |
|
|
public List<SourceProject> DependentProjects { get; private set; } |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the name.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <value>
|
|
|
|
|
|
/// The name.
|
|
|
|
|
|
/// </value>
|
|
|
public string Name { get; private set; } |
|
|
public string Name { get; private set; } |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the project file path.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <value>
|
|
|
|
|
|
/// The project file path.
|
|
|
|
|
|
/// </value>
|
|
|
public string ProjectFilePath { get; private set; } |
|
|
public string ProjectFilePath { get; private set; } |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the commit count since version change.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <value>
|
|
|
|
|
|
/// The commit count since version change.
|
|
|
|
|
|
/// </value>
|
|
|
public int CommitCountSinceVersionChange { get; private set; } = 0; |
|
|
public int CommitCountSinceVersionChange { get; private set; } = 0; |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the full project file path.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <value>
|
|
|
|
|
|
/// The full project file path.
|
|
|
|
|
|
/// </value>
|
|
|
public string FullProjectFilePath { get; private set; } |
|
|
public string FullProjectFilePath { get; private set; } |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the final version number.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <value>
|
|
|
|
|
|
/// The final version number.
|
|
|
|
|
|
/// </value>
|
|
|
public string FinalVersionNumber { get; private set; } |
|
|
public string FinalVersionNumber { get; private set; } |
|
|
|
|
|
|
|
|
public SourceProject(Project project, string root) |
|
|
/// <summary>
|
|
|
|
|
|
/// Populates the dependencies.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="projects">The projects.</param>
|
|
|
|
|
|
public void PopulateDependencies(IEnumerable<SourceProject> projects) |
|
|
{ |
|
|
{ |
|
|
this.Name = project.Name; |
|
|
this.DependentProjects = projects.Where(x => this.dependencies.Contains(x.Name)).ToList(); |
|
|
this.ProjectDirectory = project.ProjectDirectory.Substring(root.Length); |
|
|
|
|
|
this.ProjectFilePath = project.ProjectFilePath.Substring(root.Length); |
|
|
|
|
|
this.FullProjectFilePath = project.ProjectFilePath; |
|
|
|
|
|
this.Version = project.Version; |
|
|
|
|
|
this.dependencies = project.Dependencies.Select(x => x.Name); |
|
|
|
|
|
this.FinalVersionNumber = Version.ToFullString(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public void PopulateDependencies(IEnumerable<SourceProject> projects) |
|
|
/// <summary>
|
|
|
|
|
|
/// Calculates the version.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="repo">The repo.</param>
|
|
|
|
|
|
/// <param name="branch">The branch.</param>
|
|
|
|
|
|
internal void CalculateVersion(Repository repo, string branch) |
|
|
{ |
|
|
{ |
|
|
DependentProjects = projects.Where(x => dependencies.Contains(x.Name)).ToList(); |
|
|
foreach (var c in repo.Commits) |
|
|
|
|
|
{ |
|
|
|
|
|
if (!this.ApplyCommit(c, repo)) |
|
|
|
|
|
{ |
|
|
|
|
|
// we have finished lets populate the final version number
|
|
|
|
|
|
this.FinalVersionNumber = this.CalculateVersionNumber(branch); |
|
|
|
|
|
|
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private bool MatchPath(string path) |
|
|
private bool MatchPath(string path) |
|
|
{ |
|
|
{ |
|
|
if(path.StartsWith(this.ProjectDirectory, StringComparison.OrdinalIgnoreCase)) |
|
|
if (path.StartsWith(this.ProjectDirectory, StringComparison.OrdinalIgnoreCase)) |
|
|
{ |
|
|
{ |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (DependentProjects.Any()) |
|
|
if (this.DependentProjects.Any()) |
|
|
{ |
|
|
{ |
|
|
return DependentProjects.Any(x => x.MatchPath(path)); |
|
|
return this.DependentProjects.Any(x => x.MatchPath(path)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private bool ApplyCommitInternal(Commit commit, TreeChanges changes, Repository repo) |
|
|
private bool ApplyCommitInternal(Commit commit, TreeChanges changes, Repository repo) |
|
|
{ |
|
|
{ |
|
|
CommitCountSinceVersionChange++; |
|
|
this.CommitCountSinceVersionChange++; |
|
|
|
|
|
|
|
|
//return false if this is a version number root
|
|
|
// return false if this is a version number root
|
|
|
var projectFileChange = changes.Where(x => x.Path?.Equals(this.ProjectFilePath, StringComparison.OrdinalIgnoreCase) == true).FirstOrDefault(); |
|
|
var projectFileChange = changes.Where(x => x.Path?.Equals(this.ProjectFilePath, StringComparison.OrdinalIgnoreCase) == true).FirstOrDefault(); |
|
|
if(projectFileChange != null) |
|
|
if (projectFileChange != null) |
|
|
{ |
|
|
{ |
|
|
if(projectFileChange.Status == ChangeKind.Added) |
|
|
if (projectFileChange.Status == ChangeKind.Added) |
|
|
{ |
|
|
{ |
|
|
// the version must have been set here
|
|
|
// the version must have been set here
|
|
|
return false; |
|
|
return false; |
|
|
@ -241,9 +336,9 @@ namespace ConsoleApplication |
|
|
using (var s = blob.GetContentStream()) |
|
|
using (var s = blob.GetContentStream()) |
|
|
{ |
|
|
{ |
|
|
var project = new ProjectReader().ReadProject(s, this.Name, this.FullProjectFilePath, null); |
|
|
var project = new ProjectReader().ReadProject(s, this.Name, this.FullProjectFilePath, null); |
|
|
if(project.Version != this.Version) |
|
|
if (project.Version != this.Version) |
|
|
{ |
|
|
{ |
|
|
//version changed
|
|
|
// version changed
|
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -256,21 +351,6 @@ namespace ConsoleApplication |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
internal void CalculateVersion(Repository repo, string branch) |
|
|
|
|
|
{ |
|
|
|
|
|
foreach(var c in repo.Commits) |
|
|
|
|
|
{ |
|
|
|
|
|
if(!ApplyCommit(c, repo)) |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
//we have finished lets populate the final version number
|
|
|
|
|
|
this.FinalVersionNumber = CalculateVersionNumber(branch); |
|
|
|
|
|
|
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private bool ApplyCommit(Commit commit, Repository repo) |
|
|
private bool ApplyCommit(Commit commit, Repository repo) |
|
|
{ |
|
|
{ |
|
|
foreach (var parent in commit.Parents) |
|
|
foreach (var parent in commit.Parents) |
|
|
@ -281,17 +361,17 @@ namespace ConsoleApplication |
|
|
{ |
|
|
{ |
|
|
if (!string.IsNullOrWhiteSpace(change.OldPath)) |
|
|
if (!string.IsNullOrWhiteSpace(change.OldPath)) |
|
|
{ |
|
|
{ |
|
|
if (MatchPath(change.OldPath)) |
|
|
if (this.MatchPath(change.OldPath)) |
|
|
{ |
|
|
{ |
|
|
return ApplyCommitInternal(commit, changes, repo); |
|
|
return this.ApplyCommitInternal(commit, changes, repo); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(change.Path)) |
|
|
if (!string.IsNullOrWhiteSpace(change.Path)) |
|
|
{ |
|
|
{ |
|
|
if (MatchPath(change.Path)) |
|
|
if (this.MatchPath(change.Path)) |
|
|
{ |
|
|
{ |
|
|
return ApplyCommitInternal(commit, changes, repo); |
|
|
return this.ApplyCommitInternal(commit, changes, repo); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -304,11 +384,12 @@ namespace ConsoleApplication |
|
|
{ |
|
|
{ |
|
|
var version = this.Version.ToFullString(); |
|
|
var version = this.Version.ToFullString(); |
|
|
|
|
|
|
|
|
if (this.CommitCountSinceVersionChange == 1 && branch == "master") //master only
|
|
|
// master only
|
|
|
|
|
|
if (this.CommitCountSinceVersionChange == 1 && branch == "master") |
|
|
{ |
|
|
{ |
|
|
if (this.Version.IsPrerelease) |
|
|
if (this.Version.IsPrerelease) |
|
|
{ |
|
|
{ |
|
|
//prerelease always needs the build counter just not on a branch name
|
|
|
// prerelease always needs the build counter just not on a branch name
|
|
|
return $"{version}-{this.CommitCountSinceVersionChange:00000}"; |
|
|
return $"{version}-{this.CommitCountSinceVersionChange:00000}"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -316,7 +397,7 @@ namespace ConsoleApplication |
|
|
return version; |
|
|
return version; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var rootSpecialVersion = ""; |
|
|
var rootSpecialVersion = string.Empty; |
|
|
|
|
|
|
|
|
if (this.Version.IsPrerelease) |
|
|
if (this.Version.IsPrerelease) |
|
|
{ |
|
|
{ |
|
|
@ -331,10 +412,11 @@ namespace ConsoleApplication |
|
|
{ |
|
|
{ |
|
|
if (!this.Version.IsPrerelease) |
|
|
if (!this.Version.IsPrerelease) |
|
|
{ |
|
|
{ |
|
|
branch = fallbackTag; |
|
|
branch = FallbackTag; |
|
|
}else |
|
|
} |
|
|
|
|
|
else |
|
|
{ |
|
|
{ |
|
|
branch = ""; |
|
|
branch = string.Empty; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -342,6 +424,7 @@ namespace ConsoleApplication |
|
|
{ |
|
|
{ |
|
|
rootSpecialVersion = "-" + rootSpecialVersion; |
|
|
rootSpecialVersion = "-" + rootSpecialVersion; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (branch.Length > 0) |
|
|
if (branch.Length > 0) |
|
|
{ |
|
|
{ |
|
|
branch = "-" + branch; |
|
|
branch = "-" + branch; |
|
|
@ -351,7 +434,7 @@ namespace ConsoleApplication |
|
|
maxLength -= rootSpecialVersion.Length; // this is a required tag
|
|
|
maxLength -= rootSpecialVersion.Length; // this is a required tag
|
|
|
maxLength -= 7; // for the counter and dashes
|
|
|
maxLength -= 7; // for the counter and dashes
|
|
|
|
|
|
|
|
|
if(branch.Length > maxLength) |
|
|
if (branch.Length > maxLength) |
|
|
{ |
|
|
{ |
|
|
branch = branch.Substring(0, maxLength); |
|
|
branch = branch.Substring(0, maxLength); |
|
|
} |
|
|
} |
|
|
|