/// <summary> /// Calculate the next version from a repository. /// </summary> /// <param name="repo">The repo to use.</param> /// <param name="options">The options.</param> /// <param name="log">A log for diagnostics.</param> /// <param name="tagFilter">A filter to ignore tags. When <c>null</c> no filter is used.</param> /// <returns>The version for the state of the repository.</returns> public static async Task <SemVer> FromRepository( IRepoInspector repo, VersionCalculationOptions options, ILogger?log = null, ITagFilter?tagFilter = null) { var(height, lastTagVer) = await HeightCalculator.FromRepository( repo : repo, tagPrefix : options.TagPrefix, queryRemoteTags : options.QueryRemoteTags, log : log, tagFilter : tagFilter); var version = FromTagInfomation(lastTagVer?.Version, options, height); version.BuildMetadata = options.BuildMetadata; if (lastTagVer is not null && options.QueryRemoteTags) { var localTag = (await repo.GetTags(QueryTarget.Local)) .Where(x => x == lastTagVer.Tag); if (!localTag.Any()) { log?.Normal("Local repo missing version tag, fetching."); await repo.FetchTag(lastTagVer.Tag, "origin"); } } return(version); }
/// <summary> /// Append the height to an ordinal for automatic versioning. /// </summary> /// <param name="version">The last version.</param> /// <param name="options">The options to use.</param> /// <param name="height">The height since the tag.</param> /// <exception cref="ArgumentOutOfRangeException">Must be greater than zero.</exception> /// <returns>The bumped version.</returns> public static SemVer Bump(SemVer version, VersionCalculationOptions options, int height) { if (height < 1) { throw new ArgumentOutOfRangeException(nameof(height), height, "Must be greater than zero."); } SemVer ret = version; ret.Prerelease ??= options.DefaultPrereleasePhase; ret.Prerelease += $".{options.PrereleaseBaseHeight + (height - 1)}"; return(ret); }
/// <summary> /// Calculate the next version from a version tag, taking into account the minimum version and auto increment. /// </summary> /// <param name="lastTag">The version of the last tag.</param> /// <param name="options">The options.</param> /// <exception cref="InvalidOperationException">Can only bump by major, minor, or patch (default).</exception> /// <returns>The next version calculated from the input.</returns> public static SemVer NextVersion(SemVer lastTag, VersionCalculationOptions options) { if (options.MinimumVersion > lastTag.DestinedVersion) { return(options.MinimumVersion); } else if (lastTag.Prerelease is not null) { return(lastTag); } else { return options.AutoIncrement switch { VersionPart.Patch => new SemVer(lastTag.Major, lastTag.Minor, lastTag.Patch + 1), VersionPart.Minor => new SemVer(lastTag.Major, lastTag.Minor + 1, 0), VersionPart.Major => new SemVer(lastTag.Major + 1, 0, 0), _ => throw new InvalidOperationException("NextVersion(): Can only bump by major, minor, or patch (default)."), } }; }
/// <summary> /// Calculate the next version from a version tag from the optional last tag and height. /// </summary> /// <param name="lastTag">The version of the last tag.</param> /// <param name="options">The options.</param> /// <param name="height">The height since the last version tag.</param> /// <exception cref="VersionCalculationException">Direct tag's destined version is below the minimum version.</exception> /// <returns>A version from the input parameters.</returns> public static SemVer FromTagInfomation(SemVer?lastTag, VersionCalculationOptions options, int height) { if (lastTag is null) { return(Bump(options.MinimumVersion, options, height)); } bool directTag = height == 0; if (directTag) { if (options.MinimumVersion > lastTag.Value.DestinedVersion) { throw new VersionCalculationException($"Direct tag ({lastTag.Value}) destined version ({lastTag.Value.DestinedVersion}) is below the minimum version ({options.MinimumVersion})."); } return(lastTag.Value); } var nextVersion = NextVersion(lastTag.Value, options); var bumpedVersion = Bump(nextVersion, options, height); return(bumpedVersion); }