/// <summary> /// Full constructor. Used by <see cref="TryParse(string, bool)"/> and methods like <see cref="GetDirectSuccessors(bool, ReleaseTagVersion)"/>. /// </summary> /// <param name="tag">Original text version. Can be null: the <see cref="ReleaseTagFormat.Normalized"/> is automatically used to compute <see cref="OriginalTagText"/>.</param> /// <param name="major">Major (between 0 and 99999).</param> /// <param name="minor">Minor (between 0 and 99999).</param> /// <param name="patch">Patch (between 0 and 9999).</param> /// <param name="preReleaseName">Not null (empty for release). Can be any string [a-z]*.</param> /// <param name="preReleaseNameIdx">The index in StandardPreReleaseNames.</param> /// <param name="preReleaseNumber">Number between 0 (for release or first prerelease) and 99.</param> /// <param name="preReleaseFix">Number between 0 (not a fix, first actual fix starts at 1) and 99.</param> /// <param name="kind">One of the <see cref="ReleaseTagKind"/> value. Must be coherent with the other parameters.</param> ReleaseTagVersion(string tag, int major, int minor, int patch, string preReleaseName, int preReleaseNameIdx, int preReleaseNumber, int preReleaseFix, ReleaseTagKind kind) { Debug.Assert(_standardNames.Length == MaxPreReleaseNameIdx + 1); Debug.Assert(major >= 0 && major <= MaxMajor); Debug.Assert(minor >= 0 && minor <= MaxMinor); Debug.Assert(patch >= 0 && patch <= MaxPatch); Debug.Assert(preReleaseName != null); Debug.Assert(Regex.IsMatch(preReleaseName, "[a-z]*", RegexOptions.CultureInvariant)); Debug.Assert(preReleaseNameIdx >= -1); Debug.Assert((preReleaseName.Length == 0 && preReleaseNameIdx == -1) || (preReleaseName.Length > 0 && preReleaseNameIdx >= 0 && preReleaseNameIdx <= MaxPreReleaseNameIdx)); Debug.Assert(preReleaseNumber >= 0 && preReleaseNumber <= MaxPreReleaseNumber); Debug.Assert(PreReleasePatch >= 0 && PreReleasePatch <= MaxPreReleaseNumber); Debug.Assert(kind != ReleaseTagKind.Malformed); Major = major; Minor = minor; Patch = patch; PreReleaseNameFromTag = preReleaseName; PreReleaseNameIdx = preReleaseNameIdx; PreReleaseNumber = preReleaseNumber; PreReleasePatch = preReleaseFix; Kind = kind; Marker = kind.ToStringMarker(); OriginalTagText = tag ?? ToString(); // Debug.Assert(((Kind & ReleaseTagKind.PreRelease) != 0) == IsPreRelease); _orderedVersion = new SOrderedVersion() { Number = ComputeOrderedVersion(major, minor, patch, preReleaseNameIdx, preReleaseNumber, preReleaseFix) }; DefinitionStrength = ComputeDefinitionStrength(); }
/// <summary> /// Obtains the marker as a string. <see cref="string.Empty"/> if this is nor marked. /// </summary> /// <param name="this">This <see cref="ReleaseTagKind"/>.</param> /// <param name="prefixPlus">Optionally removes the '+' build meta separator.</param> /// <returns>A string with the marker if any.</returns> public static string ToStringMarker(this ReleaseTagKind @this, bool prefixPlus = true) { if ((@this & ReleaseTagKind.MarkedInvalid) != 0) { return(prefixPlus ? "+invalid" : "invalid"); } return(string.Empty); }
/// <summary> /// Returns true if this tag is marked with <see cref="ReleaseTagKind.MarkedInvalid"/>. /// </summary> /// <param name="this"></param> /// <returns>True if MarkedInvalid.</returns> public static bool IsMarkedInvalid(this ReleaseTagKind @this) { return((@this & ReleaseTagKind.MarkedInvalid) != 0); }
/// <summary> /// Attempts to parse a string like "4.0.0", "1.0-5-alpha.0", "1.0-5-rc.12.87". /// Initial 'v' (or 'V') is optional (GitHub convention). /// Numbers can not start with a 0 (except if it is 0). /// The pre release name (alpha, beta, gamma, ..., rc) must be any number of a-z (all lower case, no digit nor underscore). /// The pre release name can be followed by ".0" or a greater number (not greater than <see cref="MaxPreReleaseNumber"/>). /// Returns a ReleaseTagVersion where <see cref="ReleaseTagVersion.IsValid"/> is false if the string is not valid: <see cref="ParseErrorMessage"/> /// gives more information. /// </summary> /// <param name="s">String to parse.</param> /// <param name="analyseInvalidTag"> /// True to analyse an invalid string for a more precise error: /// if the tag looks like a release tag, the <see cref="ParseErrorMessage"/> will describe the issue. /// </param> /// <returns>Resulting version (can be invalid).</returns> public static ReleaseTagVersion TryParse(string s, bool analyseInvalidTag = false) { if (s == null) { throw new ArgumentNullException(); } Match m = _regexStrict.Match(s); if (!m.Success) { if (analyseInvalidTag) { m = _regexApprox.Match(s); if (m.Success) { return(new ReleaseTagVersion(s, true, SyntaxErrorHelper(s, m))); } } return(new ReleaseTagVersion(s, false, _noTagParseErrorMessage)); } string sMajor = m.Groups[1].Value; string sMinor = m.Groups[2].Value; string sPatch = m.Groups[3].Value; int major, minor, patch; if (!Int32.TryParse(sMajor, out major) || major > MaxMajor) { return(new ReleaseTagVersion(s, true, string.Format("Incorrect Major version. Must not be greater than {0}.", MaxMajor))); } if (!Int32.TryParse(sMinor, out minor) || minor > MaxMinor) { return(new ReleaseTagVersion(s, true, string.Format("Incorrect Minor version. Must not be greater than {0}.", MaxMinor))); } if (!Int32.TryParse(sPatch, out patch) || patch > MaxPatch) { return(new ReleaseTagVersion(s, true, string.Format("Incorrect Patch version. Must not be greater than {0}.", MaxPatch))); } string sPRName = m.Groups[4].Value; string sPRNum = m.Groups[5].Value; string sPRFix = m.Groups[6].Value; string sBuldMetaData = m.Groups[7].Value; int prNameIdx = GetPreReleaseNameIdx(sPRName); int prNum = 0; int prFix = 0; if (prNameIdx >= 0) { if (sPRFix.Length > 0) { prFix = Int32.Parse(sPRFix); } if (sPRNum.Length > 0) { prNum = Int32.Parse(sPRNum); } if (prFix == 0 && prNum == 0 && sPRNum.Length > 0) { return(new ReleaseTagVersion(s, true, string.Format("Incorrect '.0' Release Number version. 0 can appear only to fix the first pre release (ie. '.0.F' where F is between 1 and {0}).", MaxPreReleaseFix))); } } ReleaseTagKind kind = prNameIdx >= 0 ? ReleaseTagKind.PreRelease : ReleaseTagKind.OfficialRelease; if (sBuldMetaData.Length > 0) { kind |= ReleaseTagKind.MarkedInvalid; } return(new ReleaseTagVersion(s, major, minor, patch, sPRName, prNameIdx, prNum, prFix, kind)); }