/// <summary> /// Creates a new implementation version from a a string. /// </summary> /// <param name="value">The string containing the version information.</param> /// <exception cref="FormatException"><paramref name="value"/> is not a valid version string.</exception> public ImplementationVersion(string value) { if (string.IsNullOrEmpty(value)) { throw new FormatException(Resources.MustStartWithDottedList); } if (ModelUtils.ContainsTemplateVariables(value)) { _verbatimString = value; return; } var parts = value.Split('-'); // Ensure the first part is a dotted list if (!VersionDottedList.IsValid(parts[0])) { throw new FormatException(Resources.MustStartWithDottedList); } FirstPart = new VersionDottedList(parts[0]); // Iterate through all additional parts var additionalParts = new VersionPart[parts.Length - 1]; for (int i = 1; i < parts.Length; i++) { additionalParts[i - 1] = new VersionPart(parts[i]); } AdditionalParts = additionalParts; }
private static int GetVersionPart(string version, VersionPart part) { if (string.IsNullOrWhiteSpace(version)) { return(0); } var versionParts = version.Split('.', StringSplitOptions.RemoveEmptyEntries); var versionPart = string.Empty; if (versionParts.Length != 2) { return(0); } else if (part == VersionPart.Major) { versionPart = versionParts[0]; } else if (part == VersionPart.Minor) { versionPart = versionParts[1]; } if (int.TryParse(versionPart, out var intVersion)) { return(intVersion); } return(0); }
public void Add_Version_Test(string version, int value, VersionPart versionPart, string expectedVersion) { var nugetVersion = NuGet.Versioning.NuGetVersion.Parse(version); var expected = NuGet.Versioning.NuGetVersion.Parse(expectedVersion); var result = nugetVersion.Add(value, versionPart); Assert.Equal(expected, result); }
private static Lens <Project, int> VersionLens(VersionPart versionPart) { return(versionPart switch { VersionPart.Major => lens(Project.version, Version.major), VersionPart.Minor => lens(Project.version, Version.minor), VersionPart.Patch => lens(Project.version, Version.patch), _ => lens(Project.version, Version.major) });
public static NuGetVersion Add(this NuGetVersion version, int value, VersionPart versionPart) { return(new NuGetVersion( version.Major + (versionPart == VersionPart.Major ? value : 0), version.Minor + (versionPart == VersionPart.Minor ? value : 0), version.Patch + (versionPart == VersionPart.Patch ? value : 0), version.Revision + (versionPart == VersionPart.Revision ? value : 0), version.ReleaseLabels, version.Metadata)); }
public static Version GetVersion(this Repository repo, string tagPrefix, VersionPart autoIncrement, ILogger log) { var commit = repo.Commits.FirstOrDefault(); if (commit == default) { var version = new Version(); log.Info($"No commits found. Using default version {version}."); return(version); } var tagsAndVersions = repo.Tags .Select(tag => (tag, Version.ParseOrDefault(tag.FriendlyName, tagPrefix))) .OrderBy(tagAndVersion => tagAndVersion.Item2) .ThenBy(tagsAndVersion => tagsAndVersion.tag.FriendlyName) .ToList(); var commitsChecked = new HashSet <string>(); var count = 0; var height = 0; var candidates = new List <Candidate>(); var commitsToCheck = new Stack <(Commit, int, Commit)>(); Commit previousCommit = default; if (log.IsTraceEnabled) { log.Trace($"Starting at commit {commit.ShortSha()} (height {height})..."); } while (true) { var parentCount = 0; if (commitsChecked.Add(commit.Sha)) { ++count; var commitTagsAndVersions = tagsAndVersions.Where(tagAndVersion => tagAndVersion.tag.Target.Sha == commit.Sha).ToList(); var foundVersion = false; foreach (var(tag, commitVersion) in commitTagsAndVersions) { var candidate = new Candidate { Commit = commit, Height = height, Tag = tag.FriendlyName, Version = commitVersion, }; foundVersion = foundVersion || candidate.Version != default; if (log.IsTraceEnabled) { log.Trace($"Found {(candidate.Version == default ? "non-" : default)}version tag {candidate}.");
public static void RtmVersionIncrement(string tag, VersionPart autoIncrement, string expectedVersion, string path, Version actualVersion) { $"Given a git repository with a commit in {path = MethodBase.GetCurrentMethod().GetTestDirectory(autoIncrement)}" .x(() => EnsureEmptyRepositoryAndCommit(path)); $"And the commit is tagged '{tag}'" .x(() => Tag(path, tag)); "And another commit" .x(() => Commit(path)); $"When the version is determined using auto-increment '{autoIncrement}'" .x(() => actualVersion = Versioner.GetVersion(path, default, default, default, autoIncrement, default, default));
public void NextVersion(string versionStr, VersionPart part, string expectedNextStr) { var version = SemVer.Parse(versionStr); var expectedNext = SemVer.Parse(expectedNextStr); var opts = new VersionCalculationOptions() { AutoIncrement = part, }; var actualNext = VersionCalculator.NextVersion(version, opts); actualNext.Should().Be(expectedNext); }
public static void RtmVersionIncrement(string tag, VersionPart autoIncrement, string expectedVersion, string path, Repository repo, Version actualVersion) { $"Given a git repository with a commit in '{path = GetScenarioDirectory($"rtm-auto-increment-{tag}")}'" .x(c => repo = EnsureEmptyRepositoryAndCommit(path).Using(c)); $"And the commit is tagged '{tag}'" .x(() => repo.ApplyTag(tag)); $"And another commit" .x(() => Commit(path)); $"When the version is determined using auto-increment '{autoIncrement}'" .x(() => actualVersion = Versioner.GetVersion(path, default, default, default, autoIncrement, default, new TestLogger()));
private static Version GetVersion(string workDir, string tagPrefix, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log) { if (!Repository.TryCreateRepo(workDir, out var repo, log)) { var version = new Version(defaultPreReleasePhase); log.Warn(1001, $"'{workDir}' is not a valid Git working directory. Using default version {version}."); return(version); } return(repo.GetVersion(tagPrefix, autoIncrement, defaultPreReleasePhase, log)); }
public static async Task RtmVersionIncrement(string tag, VersionPart autoIncrement, string expectedVersion) { // arrange var path = MethodBase.GetCurrentMethod().GetTestDirectory((tag, autoIncrement)); await EnsureEmptyRepositoryAndCommit(path); await Tag(path, tag); await Commit(path); // act var actualVersion = Versioner.GetVersion(path, "", MajorMinor.Zero, "", autoIncrement, "", NullLogger.Instance); // assert Assert.Equal(expectedVersion, actualVersion.ToString()); }
private static Version GetVersion(string repoOrWorkDir, string tagPrefix, VersionPart autoIncrement, ILogger log) { if (!RepositoryEx.TryCreateRepo(repoOrWorkDir, out var repo)) { var version = new Version(); log.Warn(1001, $"'{repoOrWorkDir}' is not a valid repository or working directory. Using default version {version}."); return(version); } try { return(repo.GetVersion(tagPrefix, autoIncrement, log)); } finally { repo.Dispose(); } }
private static Version GetVersion(string workDir, string tagPrefix, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log) { if (!Git.IsWorkingDirectory(workDir, log)) { var version = new Version(defaultPreReleasePhase); _ = log.IsWarnEnabled && log.Warn(1001, $"'{workDir}' is not a valid Git working directory. Using default version {version}."); return(version); } if (!Git.TryGetHead(workDir, out var head, log)) { var version = new Version(defaultPreReleasePhase); _ = log.IsInfoEnabled && log.Info($"No commits found. Using default version {version}."); return(version); } var tags = Git.GetTags(workDir, log); var orderedCandidates = GetCandidates(head, tags, tagPrefix, defaultPreReleasePhase, log) .OrderBy(candidate => candidate.Version) .ThenByDescending(candidate => candidate.Index).ToList(); var tagWidth = log.IsDebugEnabled ? orderedCandidates.Max(candidate => candidate.Tag.Length) : 0; var versionWidth = log.IsDebugEnabled ? orderedCandidates.Max(candidate => candidate.Version.ToString().Length) : 0; var heightWidth = log.IsDebugEnabled ? orderedCandidates.Max(candidate => candidate.Height).ToString(CultureInfo.CurrentCulture).Length : 0; if (log.IsDebugEnabled) { foreach (var candidate in orderedCandidates.Take(orderedCandidates.Count - 1)) { _ = log.Debug($"Ignoring {candidate.ToString(tagWidth, versionWidth, heightWidth)}."); } } var selectedCandidate = orderedCandidates.Last(); _ = string.IsNullOrEmpty(selectedCandidate.Tag) && log.IsInfoEnabled && log.Info($"No commit found with a valid SemVer 2.0 version{(string.IsNullOrEmpty(tagPrefix) ? "" : $" prefixed with '{tagPrefix}'")}. Using default version {selectedCandidate.Version}.");
public override string ToString() { var sb = new StringBuilder(); if (!NamePart.IsEmpty()) { sb.Append(NamePart); } if (!VersionPart.IsEmpty()) { if (!NamePart.IsEmpty()) { sb.Append("-"); } sb.Append(VersionPart); if (!PreReleasePart.IsEmpty()) { sb.Append("-").Append(PreReleasePart); } } return(sb.ToString()); }
/// <summary> /// Increases the version at the given <paramref name="part"/>. /// </summary> /// <param name="part">The part.</param> /// <returns></returns> public void IncreaseVersion(VersionPart part) { ParseFromString(Version, out int major, out int minor, out int revision, out int build); switch (part) { case VersionPart.Major: if (major != int.MaxValue && major != -1) { major++; } break; case VersionPart.Minor: if (minor != int.MaxValue && minor != -1) { minor++; } break; case VersionPart.Revision: if (revision != int.MaxValue && revision != -1) { revision++; } break; case VersionPart.Build: if (build != int.MaxValue && build != -1) { build++; } break; } Version = ToString(major, minor, revision, build); }
public static Version GetVersion(string workDir, string tagPrefix, MajorMinor minMajorMinor, string buildMeta, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log) { log = log ?? new NullLogger(); defaultPreReleasePhase = string.IsNullOrEmpty(defaultPreReleasePhase) ? "alpha" : defaultPreReleasePhase; var version = GetVersion(workDir, tagPrefix, autoIncrement, defaultPreReleasePhase, log).AddBuildMetadata(buildMeta); var calculatedVersion = version.Satisfying(minMajorMinor, defaultPreReleasePhase); if (calculatedVersion != version) { log.Info($"Bumping version to {calculatedVersion} to satisfy minimum major minor {minMajorMinor}."); } else { if (minMajorMinor != null) { log.Debug($"The calculated version {calculatedVersion} satisfies the minimum major minor {minMajorMinor}."); } } log.Info($"Calculated version {calculatedVersion}."); return(calculatedVersion); }
public static Project VersionOperator(Project project, VersionPart part, Func <int, int> operation) { var lens = VersionLens(part); return(lens.Set(operation(lens.Get(project)), project)); }
public Version GetVersion(string tagPrefix, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log) { var commit = this.head; if (commit == null) { var version = new Version(defaultPreReleasePhase); log.Info($"No commits found. Using default version {version}."); return(version); } var tagsAndVersions = this.tags .Select(tag => (tag, Version.ParseOrDefault(tag.Name, tagPrefix))) .OrderBy(tagAndVersion => tagAndVersion.Item2) .ThenBy(tagsAndVersion => tagsAndVersion.tag.Name) .ToList(); var commitsChecked = new HashSet <string>(); var count = 0; var height = 0; var candidates = new List <Candidate>(); var commitsToCheck = new Stack <(Commit, int, Commit)>(); Commit previousCommit = null; if (log.IsTraceEnabled) { log.Trace($"Starting at commit {commit.ShortSha} (height {height})..."); } while (true) { var parentCount = 0; if (commitsChecked.Add(commit.Sha)) { ++count; var commitTagsAndVersions = tagsAndVersions.Where(tagAndVersion => tagAndVersion.tag.Sha == commit.Sha).ToList(); var foundVersion = false; foreach (var(tag, commitVersion) in commitTagsAndVersions) { var candidate = new Candidate { Commit = commit, Height = height, Tag = tag.Name, Version = commitVersion, }; foundVersion = foundVersion || candidate.Version != null; if (log.IsTraceEnabled) { log.Trace($"Found {(candidate.Version == null ? "non-" : null)}version tag {candidate}."); } candidates.Add(candidate); } if (!foundVersion) { if (log.IsTraceEnabled) { var parentIndex = 0; Commit firstParent = null; foreach (var parent in commit.Parents) { switch (parentIndex) { case 0: firstParent = parent; break; case 1: log.Trace($"History diverges from {commit.ShortSha} (height {height}) to:"); log.Trace($"- {firstParent.ShortSha} (height {height + 1})"); goto default; default: log.Trace($"- {parent.ShortSha} (height {height + 1})"); break; } ++parentIndex; parentCount = parentIndex; } } foreach (var parent in ((IEnumerable <Commit>)commit.Parents).Reverse()) { commitsToCheck.Push((parent, height + 1, commit)); } if (commitsToCheck.Count == 0 || commitsToCheck.Peek().Item2 <= height) { var candidate = new Candidate { Commit = commit, Height = height, Tag = null, Version = new Version(defaultPreReleasePhase), }; if (log.IsTraceEnabled) { log.Trace($"Found root commit {candidate}."); } candidates.Add(candidate); } } } else { if (log.IsTraceEnabled) { log.Trace($"History converges from {previousCommit.ShortSha} (height {height - 1}) back to previously seen commit {commit.ShortSha} (height {height}). Abandoning path."); } } if (commitsToCheck.Count == 0) { break; } if (log.IsTraceEnabled) { previousCommit = commit; } var oldHeight = height; Commit child; (commit, height, child) = commitsToCheck.Pop(); if (log.IsTraceEnabled) { if (parentCount > 1) { log.Trace($"Following path from {child.ShortSha} (height {height - 1}) through first parent {commit.ShortSha} (height {height})..."); } else if (height <= oldHeight) { if (commitsToCheck.Any() && commitsToCheck.Peek().Item2 == height) { log.Trace($"Backtracking to {child.ShortSha} (height {height - 1}) and following path through next parent {commit.ShortSha} (height {height})..."); } else { log.Trace($"Backtracking to {child.ShortSha} (height {height - 1}) and following path through last parent {commit.ShortSha} (height {height})..."); } } } } log.Debug($"{count:N0} commits checked."); var orderedCandidates = candidates.OrderBy(candidate => candidate.Version).ToList(); var tagWidth = log.IsDebugEnabled ? orderedCandidates.Max(candidate => candidate.Tag?.Length ?? 2) : 0; var versionWidth = log.IsDebugEnabled ? orderedCandidates.Max(candidate => candidate.Version?.ToString().Length ?? 4) : 0; var heightWidth = log.IsDebugEnabled ? orderedCandidates.Max(candidate => candidate.Height).ToString().Length : 0; if (log.IsDebugEnabled) { foreach (var candidate in orderedCandidates.Take(orderedCandidates.Count - 1)) { log.Debug($"Ignoring {candidate.ToString(tagWidth, versionWidth, heightWidth)}."); } } var selectedCandidate = orderedCandidates.Last(); if (selectedCandidate.Tag == null) { log.Info($"No commit found with a valid SemVer 2.0 version{(tagPrefix == null ? null : $" prefixed with '{tagPrefix}'")}. Using default version {selectedCandidate.Version}.");
public override VersionPart PartToCascadeBump(VersionPart partBumpedOnDependency) { return partBumpedOnDependency; }
public DecrementProjectsCommand(string slnPath, IReadOnlyList <string> projectNames, VersionPart version) { SlnPath = slnPath; ProjectNames = projectNames; Version = version; }
private static bool BumpUp(ILogger logger, IVersionable component, VersionPart partToBump) { var componentName = component.Name; Version currentVersion = component.CurrentVersion; Version newVersion = currentVersion.Bump(partToBump); if (component.SetNewVersion(logger, newVersion)) { logger.Info("Bumped component '{0}' version from {1} to {2}", componentName, currentVersion.ToString(), newVersion.ToString()); return true; } logger.Error("Could not bump component '{0}' version to {1}", componentName, newVersion.ToString()); return false; }
private bool BumpVersion(ILogger logger, IVersionable component, VersionPart partToBump, string packagesOutputDirectory, bool noBuild) { var componentsToRebuild = new List<IProject>(); logger.Info("Bumping versions. Affected version part: {0} number", partToBump); using (logger.Block) { if (!BumpUp(logger, component, partToBump)) return false; foreach (IComponent dependentComponent in component.DependentComponents) { if (dependentComponent is IVersionable) { var versionableComponent = (IVersionable)dependentComponent; if (BumpUp(logger, versionableComponent, versionableComponent.PartToCascadeBump(partToBump))) if (dependentComponent is IProject) componentsToRebuild.Add((IProject)dependentComponent); } } } if (noBuild) return true; logger.Info("Rebuilding bumped components"); return BuildHelper.BuildChain(logger, component, packagesOutputDirectory, componentsToRebuild); }
private string UpdateAssemblyFile(ISourceControl sourceControl, VersionPart versionPart, Match match, string fileAssemblySetting, string newFile, ref bool isCheckout) { if (match.Success) { if (!isCheckout) { sourceControl.Checkout(fileAssemblySetting); isCheckout = true; } do { var group = match.Groups[((int) versionPart) + 1]; int value = int.Parse(@group.Value); newFile = newFile.Substring(0, @group.Index) + (value + 1) + newFile.Substring(@group.Index + @group.Length); match = match.NextMatch(); } while (match.Success); } return newFile; }
public static Version GetVersion(string workDir, string tagPrefix, MajorMinor minMajorMinor, string buildMeta, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log) { log = log ?? throw new ArgumentNullException(nameof(log)); defaultPreReleasePhase = string.IsNullOrEmpty(defaultPreReleasePhase) ? "alpha" : defaultPreReleasePhase; var version = GetVersion(workDir, tagPrefix, autoIncrement, defaultPreReleasePhase, log).AddBuildMetadata(buildMeta); var calculatedVersion = version.Satisfying(minMajorMinor, defaultPreReleasePhase); _ = calculatedVersion != version ? log.IsInfoEnabled && log.Info($"Bumping version to {calculatedVersion} to satisfy minimum major minor {minMajorMinor}.") : log.IsDebugEnabled && log.Debug($"The calculated version {calculatedVersion} satisfies the minimum major minor {minMajorMinor}."); _ = log.IsInfoEnabled && log.Info($"Calculated version {calculatedVersion}."); return(calculatedVersion); }
public static string GetValidValues(this VersionPart versionPart) => "major, minor, or patch (default)";
private static bool TryParse(string workDirOption, string minMajorMinorOption, string verbosityOption, string autoIncrementOption, out string workDir, out MajorMinor minMajorMinor, out Verbosity verbosity, out VersionPart autoIncrement) { workDir = "."; minMajorMinor = null; verbosity = default; autoIncrement = default; if (!string.IsNullOrEmpty(workDirOption) && !Directory.Exists(workDir = workDirOption)) { Logger.ErrorWorkDirDoesNotExist(workDirOption); return(false); } if (!string.IsNullOrEmpty(minMajorMinorOption) && !MajorMinor.TryParse(minMajorMinorOption, out minMajorMinor)) { Logger.ErrorInvalidMinMajorMinor(minMajorMinorOption); return(false); } if (!string.IsNullOrEmpty(verbosityOption) && !VerbosityMap.TryMap(verbosityOption, out verbosity)) { Logger.ErrorInvalidVerbosity(verbosityOption); return(false); } if (!string.IsNullOrEmpty(autoIncrementOption) && !Enum.TryParse(autoIncrementOption, true, out autoIncrement)) { Logger.ErrorInvalidAutoIncrement(autoIncrementOption); return(false); } return(true); }
public static Version GetVersion(string workDir, string tagPrefix, MajorMinor minMajorMinor, string buildMeta, VersionPart autoIncrement, string defaultPreReleasePhase, ILogger log, bool ignoreHeight = false) { log = log ?? throw new ArgumentNullException(nameof(log)); defaultPreReleasePhase = string.IsNullOrEmpty(defaultPreReleasePhase) ? "alpha" : defaultPreReleasePhase; var(version, height) = GetVersion(workDir, tagPrefix, defaultPreReleasePhase, log); _ = height.HasValue && ignoreHeight && log.IsDebugEnabled && log.Debug("Ignoring height."); version = !height.HasValue || ignoreHeight ? version : version.WithHeight(height.Value, autoIncrement, defaultPreReleasePhase); version = version.AddBuildMetadata(buildMeta); var calculatedVersion = version.Satisfying(minMajorMinor, defaultPreReleasePhase); _ = calculatedVersion != version ? log.IsInfoEnabled && log.Info($"Bumping version to {calculatedVersion} to satisfy minimum major minor {minMajorMinor}.") : log.IsDebugEnabled && log.Debug($"The calculated version {calculatedVersion} satisfies the minimum major minor {minMajorMinor}."); _ = log.IsInfoEnabled && log.Info($"Calculated version {calculatedVersion}."); return(calculatedVersion); }
public static Version GetVersion(string repoOrWorkDir, string tagPrefix, MajorMinor minMajorMinor, string buildMeta, VersionPart autoIncrement, ILogger log) { var version = GetVersion(repoOrWorkDir, tagPrefix, autoIncrement, log).AddBuildMetadata(buildMeta); var calculatedVersion = version.Satisfying(minMajorMinor); if (calculatedVersion != version) { log.Info($"Bumping version to {calculatedVersion} to satisfy minimum major minor {minMajorMinor}."); } else { if (minMajorMinor != default) { log.Debug($"The calculated version {calculatedVersion} satisfies the minimum major minor {minMajorMinor}."); } } log.Info($"Calculated version {calculatedVersion}."); return(calculatedVersion); }
public virtual VersionPart PartToCascadeBump(VersionPart partBumpedOnDependency) { return UsesNUnit || (ComponentType == "Library" && !_isWeb) ? partBumpedOnDependency : VersionPart.Revision; }