internal RepositoryVersions( IEnumerable<TagCommit> collected, StringBuilder errors, ReleaseTagVersion startingVersionForCSemVer, bool checkCompactExistingVersions ) { Debug.Assert( collected.All( c => c.ThisTag != null ) ); _versions = collected.OrderBy( t => t.ThisTag ).ToList(); if( _versions.Count > 0 ) { var first = _versions[0].ThisTag; if( checkCompactExistingVersions && startingVersionForCSemVer == null && !first.IsDirectPredecessor( null ) ) { errors.AppendFormat( "First existing version is '{0}' (on '{1}'). One or more previous versions are missing.", first, _versions[0].CommitSha ) .AppendLine(); } for( int i = 0; i < _versions.Count - 1; ++i ) { var prev = _versions[i].ThisTag; var next = _versions[i + 1].ThisTag; if( next.Equals( prev ) ) { errors.AppendFormat( "Version '{0}' is defined on '{1}' and '{2}'.", prev, _versions[i].CommitSha, _versions[i + 1].CommitSha ) .AppendLine(); } else if( checkCompactExistingVersions && !next.IsDirectPredecessor( prev ) ) { errors.AppendFormat( "Missing one or more version(s) between '{0}' and '{1}'.", prev, next ) .AppendLine(); } } } }
internal CIReleaseInfo( ReleaseTagVersion ciBaseTag, int ciBaseDepth, string ciBuildVersion, string ciBuildVersionNuGet ) { BaseTag = ciBaseTag; Depth = ciBaseDepth; BuildVersion = ciBuildVersion; BuildVersionNuGet = ciBuildVersionNuGet; }
public TagCommit( Commit c, ReleaseTagVersion first ) { Debug.Assert( c != null && first != null && first.IsValid ); _commitSha = c.Sha; _contentSha = c.Tree.Sha; _thisTag = first; }
internal static CIReleaseInfo Create(Commit commit, CIBranchVersionMode ciVersionMode, string ciBuildName, StringBuilder errors, CommitVersionInfo info) { var actualBaseTag = info.PreviousMaxTag; ReleaseTagVersion ciBaseTag = actualBaseTag ?? ReleaseTagVersion.VeryFirstVersion; string ciBuildVersionNuGet = null, ciBuildVersion = null; // If there is no base release found, we fall back to ZeroTimedBased mode. if (ciVersionMode == CIBranchVersionMode.ZeroTimed || actualBaseTag == null) { DateTime timeRelease = commit.Committer.When.ToUniversalTime().UtcDateTime; ciBuildVersion = CreateSemVerZeroTimed(ciBuildName, timeRelease, actualBaseTag?.ToString()); ciBuildVersionNuGet = CreateNuGetZeroTimed(ciBuildName, timeRelease); } else { Debug.Assert(ciVersionMode == CIBranchVersionMode.LastReleaseBased && actualBaseTag != null); CIBuildDescriptor ci = new CIBuildDescriptor { BranchName = ciBuildName, BuildIndex = info.PreviousMaxCommitDepth }; if (!ci.IsValidForNuGetV2) { errors.AppendLine("Due to NuGet V2 limitation, the branch name must not be longer than 8 characters. "); errors.Append("Adds a VersionName attribute to the branch element in RepositoryInfo.xml with a shorter name: ") .AppendFormat(@"<Branch Name=""{0}"" VersionName=""{1}"" ... />.", ci.BranchName, ci.BranchName.Substring(0, 8)) .AppendLine(); } else { ciBuildVersion = actualBaseTag.ToString(ReleaseTagFormat.SemVer, ci); ciBuildVersionNuGet = actualBaseTag.ToString(ReleaseTagFormat.NuGetPackage, ci); } } Debug.Assert(ciBuildVersion == null || errors.Length == 0); return(ciBuildVersion != null ? new CIReleaseInfo(ciBaseTag, info.PreviousMaxCommitDepth, ciBuildVersion, ciBuildVersionNuGet) : null); }
internal CIReleaseInfo(ReleaseTagVersion ciBaseTag, int ciBaseDepth, string ciBuildVersion, string ciBuildVersionNuGet) { BaseTag = ciBaseTag; Depth = ciBaseDepth; BuildVersion = ciBuildVersion; BuildVersionNuGet = ciBuildVersionNuGet; }
public TagCommit(Commit c, ReleaseTagVersion first) { Debug.Assert(c != null && first != null && first.IsValid); _commitSha = c.Sha; _contentSha = c.Tree.Sha; _thisTag = first; }
/// <summary> /// Relies only on <see cref="OrderedVersion"/>. /// </summary> /// <param name="other">Other release tag (can be null).</param> /// <returns>A signed number indicating the relative values of this instance and <paramref name="other"/>.</returns> public int CompareTo(ReleaseTagVersion other) { if (other == null) { return(1); } return(_orderedVersion.Number.CompareTo(other._orderedVersion.Number)); }
/// <summary> /// Tags are equal it their <see cref="OrderedVersion"/> are equals. /// No other members are used for equality and comparison. /// </summary> /// <param name="other">Other release tag.</param> /// <returns>True if they have the same OrderedVersion.</returns> public bool Equals(ReleaseTagVersion other) { if (other == null) { return(false); } return(_orderedVersion.Number == other._orderedVersion.Number); }
void SetNumericalVersionValues(ReleaseTagVersion t, bool isCIBuild) { Major = t.Major; Minor = t.Minor; Patch = t.Patch; PreReleaseName = t.PreReleaseName; PreReleaseNumber = t.PreReleaseNumber; PreReleaseFix = t.PreReleasePatch; FileVersion = t.ToStringFileVersion(isCIBuild); OrderedVersion = t.OrderedVersion; }
/// <summary> /// Computes the final release tag: +invalid hides any other version tags. /// If multiple versions exist on this commit, an error is raised. /// </summary> /// <param name="errors">Errors collector.</param> /// <returns>False it this tag is invalid.</returns> public bool CloseCollect(StringBuilder errors) { var t = DoCloseCollect(errors); if (t != null && t.IsValid) { _thisTag = t; return(true); } _thisTag = null; return(false); }
public void AddCollectedTag( ReleaseTagVersion t ) { Debug.Assert( t != null ); if( t.Equals( _thisTag ) ) { if( t.DefinitionStrength > _thisTag.DefinitionStrength ) _thisTag = t; } else { if( _extraCollectedTags == null ) _extraCollectedTags = new List<ReleaseTagVersion>(); _extraCollectedTags.Add( t ); } }
static IReadOnlyList<ReleaseTagVersion> BuildFirstPossibleVersions() { var versions = new ReleaseTagVersion[3 * 9]; long v = 1L; int i = 0; while( i < 3 * 9 ) { versions[i++] = new ReleaseTagVersion( v, true ); if( (i % 18) == 0 ) v += MulMajor - MulMinor - MulPatch + 1; else if( (i % 9) == 0 ) v += MulMinor - MulPatch + 1; else v += MulName; } return versions; }
/// <summary> /// Tags are equal it their <see cref="OrderedVersion"/> are equals. /// No other members are used for equality and comparison. /// </summary> /// <param name="obj">Other release tag.</param> /// <returns>True if obj is a tag that has the same OrderedVersion as this.</returns> public override bool Equals(object obj) { if (obj == null) { return(false); } ReleaseTagVersion other = obj as ReleaseTagVersion; if (other == null) { throw new ArgumentException(); } return(Equals(other)); }
void RegisterOneTag(StringBuilder errors, Commit c, string tagName, Func <Commit, ReleaseTagParsingMode> analyseInvalidTagSyntax, ref bool startingVersionForCSemVerFound) { ReleaseTagParsingMode mode = analyseInvalidTagSyntax == null ? ReleaseTagParsingMode.IgnoreMalformedTag : analyseInvalidTagSyntax(c); ReleaseTagVersion v = ReleaseTagVersion.TryParse(tagName, mode == ReleaseTagParsingMode.RaiseErrorOnMalformedTag); if (v.IsMalformed) { // Parsing in strict mode can result in malformed tag. We can not assume that here: // Debug.Assert( mode == ReleaseTagParsingMode.RaiseErrorOnMalformedTag ); if (mode == ReleaseTagParsingMode.RaiseErrorOnMalformedTag) { errors.AppendFormat("Malformed {0} on commit '{1}'.", v.ParseErrorMessage, c.Sha).AppendLine(); } return; } if (v.IsValid) { if (_startingVersionForCSemVer != null) { int cmp = _startingVersionForCSemVer.CompareTo(v); if (cmp == 0) { startingVersionForCSemVerFound = true; } else if (cmp > 0) { // This version is smaller than the StartingVersionForCSemVer: // we ignore it. return; } } if (mode == ReleaseTagParsingMode.RaiseErrorOnMalformedTagAndNonStandardPreReleaseName && v.IsPreRelease && !v.IsPreReleaseNameStandard) { errors.AppendFormat("Invalid PreRelease name in '{0}' on commit '{1}'.", v.OriginalTagText, c.Sha).AppendLine(); return; } TagCommit tagCommit; if (_collector.TryGetValue(c.Sha, out tagCommit)) { tagCommit.AddCollectedTag(v); } else { _collector.Add(c.Sha, tagCommit = new TagCommit(c, v)); } } }
public void AddCollectedTag(ReleaseTagVersion t) { Debug.Assert(t != null); if (t.Equals(_thisTag)) { if (t.DefinitionStrength > _thisTag.DefinitionStrength) { _thisTag = t; } } else { if (_extraCollectedTags == null) { _extraCollectedTags = new List <ReleaseTagVersion>(); } _extraCollectedTags.Add(t); } }
void ComputePossibleVersions() { var allVersions = _tagCollector.ExistingVersions.Versions; // Special case: there is no existing versions (other than this that is skipped if it exists) but // there is a startingVersionForCSemVer, every commit may be the first one. if (_tagCollector.StartingVersionForCSemVer != null && (allVersions.Count == 0 || (allVersions.Count == 1 && ThisTag != null))) { _possibleVersionsStrict = _possibleVersions = new[] { _tagCollector.StartingVersionForCSemVer }; } else { var versions = allVersions.Where(c => c != _thisCommit); List <ReleaseTagVersion> possible = new List <ReleaseTagVersion>(); List <ReleaseTagVersion> possibleStrict = new List <ReleaseTagVersion>(); foreach (ReleaseTagVersion b in GetBaseVersions()) { // The base version b can be null here: a null version tag correctly generates // the very first possible versions (and the comparison operators handle null). var nextReleased = versions.FirstOrDefault(c => c.ThisTag > b); var successors = ReleaseTagVersion.GetDirectSuccessors(false, b); foreach (var v in successors.Where(v => v > _tagCollector.StartingVersionForCSemVer && (nextReleased == null || v < nextReleased.ThisTag))) { if (!possible.Contains(v)) { possible.Add(v); if (nextReleased == null || v.IsPatch) { possibleStrict.Add(v); } } } } _possibleVersions = possible; _possibleVersionsStrict = possibleStrict; } }
/// <summary> /// Initializes a new <see cref="TagCollector"/>. /// Errors may be appended to the collector that can be syntaxic errors or multiple different versions applied to the same commit point. /// </summary> /// <param name="errors">A collector of errors. One line per error.</param> /// <param name="repo">The Git repository.</param> /// <param name="startingVersionForCSemVer">Vesion tags lower than this version will be ignored.</param> /// <param name="analyseInvalidTagSyntax"> /// Optional function that drives the behavior regarding malformed tags of commits. /// When null, <see cref="ReleaseTagParsingMode.IgnoreMalformedTag">IgnoreMalformedTag</see> is used for all tags. /// </param> /// <param name="OverriddenTags">Optional commits with associated tags that are applied as if they exist in the repository.</param> /// <param name="checkValidExistingVersions"> /// When true, existing versions are checked: one of the valid first version must exist and exisitng versions /// must be compact. /// </param> public TagCollector( StringBuilder errors, Repository repo, string startingVersionForCSemVer = null, Func <Commit, ReleaseTagParsingMode> analyseInvalidTagSyntax = null, IEnumerable <KeyValuePair <string, IReadOnlyList <string> > > OverriddenTags = null, bool checkValidExistingVersions = false) { Debug.Assert(errors != null && repo != null); _collector = new Dictionary <string, TagCommit>(); _versionsCache = new Dictionary <string, CommitVersionInfo>(); if (startingVersionForCSemVer != null) { _startingVersionForCSemVer = ReleaseTagVersion.TryParse(startingVersionForCSemVer, true); if (!_startingVersionForCSemVer.IsValid) { errors.Append("Invalid StartingVersionForCSemVer. ").Append(_startingVersionForCSemVer.ParseErrorMessage).AppendLine(); return; } } // Register all tags. RegisterAllTags(errors, repo, analyseInvalidTagSyntax, OverriddenTags); // Resolves multiple tags on the same commit. CloseCollect(errors); // Sorts TagCommit, optionally checking the existing versions. _repoVersions = new RepositoryVersions(_collector.Values, errors, _startingVersionForCSemVer, checkValidExistingVersions); // Register content. if (errors.Length == 0) { foreach (var tc in _repoVersions.TagCommits) { RegisterContent(tc); } } }
/// <summary> /// Initializes a new <see cref="TagCollector"/>. /// Errors may be appended to the collector that can be syntaxic errors or multiple different versions applied to the same commit point. /// </summary> /// <param name="errors">A collector of errors. One line per error.</param> /// <param name="repo">The Git repository.</param> /// <param name="startingVersionForCSemVer">Vesion tags lower than this version will be ignored.</param> /// <param name="analyseInvalidTagSyntax"> /// Optional function that drives the behavior regarding malformed tags of commits. /// When null, <see cref="ReleaseTagParsingMode.IgnoreMalformedTag">IgnoreMalformedTag</see> is used for all tags. /// </param> /// <param name="OverriddenTags">Optional commits with associated tags that are applied as if they exist in the repository.</param> /// <param name="checkValidExistingVersions"> /// When true, existing versions are checked: one of the valid first version must exist and exisitng versions /// must be compact. /// </param> public TagCollector( StringBuilder errors, Repository repo, string startingVersionForCSemVer = null, Func<Commit, ReleaseTagParsingMode> analyseInvalidTagSyntax = null, IEnumerable<KeyValuePair<string, IReadOnlyList<string>>> OverriddenTags = null, bool checkValidExistingVersions = false ) { Debug.Assert( errors != null && repo != null ); _collector = new Dictionary<string, TagCommit>(); _versionsCache = new Dictionary<string, CommitVersionInfo>(); if( startingVersionForCSemVer != null ) { _startingVersionForCSemVer = ReleaseTagVersion.TryParse( startingVersionForCSemVer, true ); if( !_startingVersionForCSemVer.IsValid ) { errors.Append( "Invalid StartingVersionForCSemVer. " ).Append( _startingVersionForCSemVer.ParseErrorMessage ).AppendLine(); return; } } // Register all tags. RegisterAllTags( errors, repo, analyseInvalidTagSyntax, OverriddenTags ); // Resolves multiple tags on the same commit. CloseCollect( errors ); // Sorts TagCommit, optionally checking the existing versions. _repoVersions = new RepositoryVersions( _collector.Values, errors, _startingVersionForCSemVer, checkValidExistingVersions ); // Register content. if( errors.Length == 0 ) { foreach( var tc in _repoVersions.TagCommits ) { RegisterContent( tc ); } } }
static IReadOnlyList <ReleaseTagVersion> BuildFirstPossibleVersions() { var versions = new ReleaseTagVersion[3 * 9]; long v = 1L; int i = 0; while (i < 3 * 9) { versions[i++] = new ReleaseTagVersion(v, true); if ((i % 18) == 0) { v += MulMajor - MulMinor - MulPatch + 1; } else if ((i % 9) == 0) { v += MulMinor - MulPatch + 1; } else { v += MulName; } } return(versions); }
/// <summary> /// Standard TryParse pattern that returns a boolean rather than the resulting <see cref="ReleaseTagVersion"/>. See <see cref="TryParse(string,bool)"/>. /// </summary> /// <param name="s">String to parse.</param> /// <param name="v">Resulting version.</param> /// <returns>True on success, false otherwise.</returns> public static bool TryParse(string s, out ReleaseTagVersion v) { v = TryParse(s, analyseInvalidTag: false); return(v.IsValid); }
void SetNumericalVersionValues( ReleaseTagVersion t, bool isCIBuild ) { Major = t.Major; Minor = t.Minor; Patch = t.Patch; PreReleaseName = t.PreReleaseName; PreReleaseNumber = t.PreReleaseNumber; PreReleaseFix = t.PreReleasePatch; FileVersion = t.ToStringFileVersion( isCIBuild ); OrderedVersion = t.OrderedVersion; }
/// <summary> /// Tags are equal it their <see cref="OrderedVersion"/> are equals. /// No other members are used for equality and comparison. /// </summary> /// <param name="other">Other release tag.</param> /// <returns>True if they have the same OrderedVersion.</returns> public bool Equals( ReleaseTagVersion other ) { if( other == null ) return false; return _orderedVersion.Number == other._orderedVersion.Number; }
/// <summary> /// Relies only on <see cref="OrderedVersion"/>. /// </summary> /// <param name="other">Other release tag (can be null).</param> /// <returns>A signed number indicating the relative values of this instance and <paramref name="other"/>.</returns> public int CompareTo( ReleaseTagVersion other ) { if( other == null ) return 1; return _orderedVersion.Number.CompareTo( other._orderedVersion.Number ); }
/// <summary> /// Standard TryParse pattern that returns a boolean rather than the resulting <see cref="ReleaseTagVersion"/>. See <see cref="TryParse(string,bool)"/>. /// </summary> /// <param name="s">String to parse.</param> /// <param name="v">Resulting version.</param> /// <returns>True on success, false otherwise.</returns> public static bool TryParse( string s, out ReleaseTagVersion v ) { v = TryParse( s, analyseInvalidTag: false ); return v.IsValid; }
/// <summary> /// Computes the final release tag: +invalid hides any other version tags. /// If multiple versions exist on this commit, an error is raised. /// </summary> /// <param name="errors">Errors collector.</param> /// <returns>False it this tag is invalid.</returns> public bool CloseCollect( StringBuilder errors ) { var t = DoCloseCollect( errors ); if( t != null && t.IsValid ) { _thisTag = t; return true; } _thisTag = null; return false; }
RepositoryInfo( Repository r, RepositoryInfoOptions options, string gitSolutionDir ) : this() { if( options == null ) options = new RepositoryInfoOptions(); Options = options; if( r == null ) RepositoryError = "No Git repository."; else { Debug.Assert( gitSolutionDir != null && gitSolutionDir[gitSolutionDir.Length-1] == Path.DirectorySeparatorChar ); GitSolutionDirectory = gitSolutionDir; Commit commit; CIBranchVersionMode ciVersionMode; string ciBuildName; RepositoryError = TryFindCommit( options, r, out commit, out ciVersionMode, out ciBuildName ); Debug.Assert( (ciVersionMode != CIBranchVersionMode.None) == (ciBuildName != null) ); if( commit != null ) { CommitSha = commit.Sha; CommitDateUtc = commit.Author.When.ToUniversalTime().DateTime; IsDirtyExplanations = ComputeIsDirty( r, commit, options ); if( !IsDirty || options.IgnoreDirtyWorkingFolder ) { StringBuilder errors = new StringBuilder(); TagCollector collector = new TagCollector( errors, r, options.StartingVersionForCSemVer, c => c.Sha == CommitSha ? ReleaseTagParsingMode.RaiseErrorOnMalformedTag : ReleaseTagParsingMode.IgnoreMalformedTag, options.OverriddenTags ); if( errors.Length == 0 ) { CommitVersionInfo info = collector.GetVersionInfo( commit ); ExistingVersions = collector.ExistingVersions.TagCommits; PossibleVersions = info.PossibleVersions; PossibleVersionsStrict = info.PossibleVersionsStrict; PreviousRelease = info.PreviousCommit; PreviousMaxRelease = info.PreviousMaxCommit; if( info.ThisCommit != null ) { bool strictMode = options.PossibleVersionsMode.IsStrict(); var possibleSet = strictMode ? info.PossibleVersionsStrict : info.PossibleVersions; if( possibleSet.Contains( info.ThisCommit.ThisTag ) ) { ValidReleaseTag = info.ThisCommit.ThisTag; } else { ReleaseTagIsNotPossibleError = true; errors.Append( "Release tag '" ) .Append( info.ThisCommit.ThisTag.OriginalTagText ) .Append( "' is not valid here. Valid tags are: " ) .Append( string.Join( ", ", possibleSet ) ) .AppendLine(); if( strictMode && info.PossibleVersions.Contains( info.ThisCommit.ThisTag )) { if( options.PossibleVersionsMode == PossibleVersionsMode.Default ) { errors.Append( "Consider setting <PossibleVersionsMode>AllSuccessors</PossibleVersionsMode> in RepositoryInfo.xml to allow this version." ); } else { errors.Append( "Current <PossibleVersionsMode>Restricted</PossibleVersionsMode> in RepositoryInfo.xml forbids this version." ); } } } } else { if( ciBuildName != null ) { CIRelease = CIReleaseInfo.Create( commit, ciVersionMode, ciBuildName, errors, info ); } } } if( errors.Length > 0 ) SetError( errors, out ReleaseTagErrorLines, out ReleaseTagErrorText ); } } } }
internal RepositoryVersions(IEnumerable <TagCommit> collected, StringBuilder errors, ReleaseTagVersion startingVersionForCSemVer, bool checkCompactExistingVersions) { Debug.Assert(collected.All(c => c.ThisTag != null)); _versions = collected.OrderBy(t => t.ThisTag).ToList(); if (_versions.Count > 0) { var first = _versions[0].ThisTag; if (checkCompactExistingVersions && startingVersionForCSemVer == null && !first.IsDirectPredecessor(null)) { errors.AppendFormat("First existing version is '{0}' (on '{1}'). One or more previous versions are missing.", first, _versions[0].CommitSha) .AppendLine(); } for (int i = 0; i < _versions.Count - 1; ++i) { var prev = _versions[i].ThisTag; var next = _versions[i + 1].ThisTag; if (next.Equals(prev)) { errors.AppendFormat("Version '{0}' is defined on '{1}' and '{2}'.", prev, _versions[i].CommitSha, _versions[i + 1].CommitSha) .AppendLine(); } else if (checkCompactExistingVersions && !next.IsDirectPredecessor(prev)) { errors.AppendFormat("Missing one or more version(s) between '{0}' and '{1}'.", prev, next) .AppendLine(); } } } }
RepositoryInfo(Repository r, RepositoryInfoOptions options, string gitSolutionDir) : this() { if (options == null) { options = new RepositoryInfoOptions(); } Options = options; if (r == null) { RepositoryError = "No Git repository."; } else { Debug.Assert(gitSolutionDir != null && gitSolutionDir[gitSolutionDir.Length - 1] == Path.DirectorySeparatorChar); GitSolutionDirectory = gitSolutionDir; Commit commit; CIBranchVersionMode ciVersionMode; string ciBuildName; RepositoryError = TryFindCommit(options, r, out commit, out ciVersionMode, out ciBuildName); Debug.Assert((ciVersionMode != CIBranchVersionMode.None) == (ciBuildName != null)); if (commit != null) { CommitSha = commit.Sha; CommitDateUtc = commit.Author.When.ToUniversalTime().DateTime; IsDirtyExplanations = ComputeIsDirty(r, commit, options); if (!IsDirty || options.IgnoreDirtyWorkingFolder) { StringBuilder errors = new StringBuilder(); TagCollector collector = new TagCollector(errors, r, options.StartingVersionForCSemVer, c => c.Sha == CommitSha ? ReleaseTagParsingMode.RaiseErrorOnMalformedTag : ReleaseTagParsingMode.IgnoreMalformedTag, options.OverriddenTags); if (errors.Length == 0) { CommitVersionInfo info = collector.GetVersionInfo(commit); ExistingVersions = collector.ExistingVersions.TagCommits; PossibleVersions = info.PossibleVersions; PossibleVersionsStrict = info.PossibleVersionsStrict; PreviousRelease = info.PreviousCommit; PreviousMaxRelease = info.PreviousMaxCommit; if (info.ThisCommit != null) { bool strictMode = options.PossibleVersionsMode.IsStrict(); var possibleSet = strictMode ? info.PossibleVersionsStrict : info.PossibleVersions; if (possibleSet.Contains(info.ThisCommit.ThisTag)) { ValidReleaseTag = info.ThisCommit.ThisTag; } else { ReleaseTagIsNotPossibleError = true; errors.Append("Release tag '") .Append(info.ThisCommit.ThisTag.OriginalTagText) .Append("' is not valid here. Valid tags are: ") .Append(string.Join(", ", possibleSet)) .AppendLine(); if (strictMode && info.PossibleVersions.Contains(info.ThisCommit.ThisTag)) { if (options.PossibleVersionsMode == PossibleVersionsMode.Default) { errors.Append("Consider setting <PossibleVersionsMode>AllSuccessors</PossibleVersionsMode> in RepositoryInfo.xml to allow this version."); } else { errors.Append("Current <PossibleVersionsMode>Restricted</PossibleVersionsMode> in RepositoryInfo.xml forbids this version."); } } } } else { if (ciBuildName != null) { CIRelease = CIReleaseInfo.Create(commit, ciVersionMode, ciBuildName, errors, info); } } } if (errors.Length > 0) { SetError(errors, out ReleaseTagErrorLines, out ReleaseTagErrorText); } } } } }