Пример #1
0
        /// <inheritdoc />
        public IEnumerable <SemanticVersion> GetVersionTagsOnBranch(IBranchHead branch, string tagPrefixRegex)
        {
            if (_semanticVersionTagsOnBranchCache.ContainsKey(branch))
            {
                Logger.WriteDebug($"Cache hit for version tags on branch '{branch.Name}");
                return(_semanticVersionTagsOnBranchCache[branch]);
            }

            using (Logger.IndentLog($"Getting version tags from branch '{branch.Name}'."))
            {
                var builder = new HgLogQueryBuilder();
                var tags    = _repository
                              .Log(builder.TaggedBranchCommits(branch.Name))
                              .SelectMany(commit => commit.Tags)
                              .ToList();

                var versionTags = tags
                                  .SelectMany(tag =>
                {
                    if (SemanticVersion.TryParse(tag, tagPrefixRegex, out var semver))
                    {
                        return new[] { semver }
                    }
                    ;

                    return(Enumerable.Empty <SemanticVersion>());
                })
                                  .ToList();

                _semanticVersionTagsOnBranchCache.Add(branch, versionTags);
                return(versionTags);
            }
        }
Пример #2
0
        /// <inheritdoc />
        public ICommit FindMergeBase(IBranchHead branch, IBranchHead otherBranch)
        {
            var key = Tuple.Create(branch, otherBranch);

            if (_mergeBaseCache.ContainsKey(key))
            {
                Logger.WriteDebug($"Cache hit for merge base between '{branch.Name}' and '{otherBranch.Name}'.");
                return(_mergeBaseCache[key].MergeBase);
            }

            using (Logger.IndentLog($"Finding merge base between '{branch.Name}' and '{otherBranch.Name}'."))
            {
                var select        = new HgLogQueryBuilder();
                var findMergeBase = _repository
                                    .Log(select.CommonAncestorOf(
                                             select.ByBranch(branch.Name),
                                             select.ByBranch(branch.Name)))
                                    .FirstOrDefault();

                // Store in cache.
                _mergeBaseCache.Add(key, new MergeBaseData(branch, otherBranch, _repository, findMergeBase));

                Logger.WriteInfo($"Merge base of {branch.Name}' and '{otherBranch.Name} is {findMergeBase}");
                return(findMergeBase);
            }
        }
Пример #3
0
 public MergeBaseData(IBranchHead branch, IBranchHead otherBranch, IRepository repository, ICommit mergeBase)
 {
     Branch      = branch;
     OtherBranch = otherBranch;
     Repository  = repository;
     MergeBase   = mergeBase;
 }
Пример #4
0
        /// <inheritdoc />
        public ICommit FindCommitWasBranchedFrom(IBranchHead branch, params IBranchHead[] excludedBranches)
        {
            if (branch == null)
            {
                throw new ArgumentNullException(nameof(branch));
            }

            using (Logger.IndentLog($"Finding branch source of '{branch.Name}'"))
            {
                var builder          = new HgLogQueryBuilder();
                var possibleBranches = _repository
                                       .Log(builder.ByBranch(branch.Name)
                                            .Limit(1)
                                            .Parents()
                                            .Except(excludedBranches.Select(b => b.Name).ToArray()))
                                       .ToList();

                if (possibleBranches.Count > 1)
                {
                    var first = possibleBranches.First();
                    Logger.WriteInfo(
                        $"Multiple source branches have been found, picking the first one ({first.Branch}).\n" +
                        "This may result in incorrect commit counting.\nOptions were:\n " +
                        string.Join(", ", possibleBranches.Select(b => b.Branch)));

                    return(first);
                }

                return(possibleBranches.SingleOrDefault());
            }
        }
        /// <summary>
        /// Gets the <see cref="BranchConfig"/> for the current commit.
        /// </summary>
        public static BranchConfig GetBranchConfiguration(HgVersionContext context, IBranchHead targetBranch,
                                                          IList <IBranchHead> excludedInheritBranches = null)
        {
            var matchingBranches = context.FullConfiguration.GetConfigForBranch(targetBranch.Name);

            if (matchingBranches == null)
            {
                Logger.WriteInfo(
                    $"No branch configuration found for branch '{targetBranch.Name}', "
                    + "falling back to default configuration");

                matchingBranches = new BranchConfig {
                    Name = string.Empty
                };
                HgConfigurationProvider.ApplyBranchDefaults(context.FullConfiguration, matchingBranches, "",
                                                            new List <string>());
            }

            return(matchingBranches.Increment == IncrementStrategyType.Inherit
                ? InheritBranchConfiguration(context, targetBranch, matchingBranches, excludedInheritBranches)
                : matchingBranches);
        }
        /// <inheritdoc />
        public IEnumerable <SemanticVersion> GetVersionTagsOnBranch(IBranchHead branch, string tagPrefixRegex)
        {
            if (_semanticVersionTagsOnBranchCache.ContainsKey(branch))
            {
                Logger.WriteDebug($"Cache hit for version tags on branch '{branch.Name}");
                return(_semanticVersionTagsOnBranchCache[branch]);
            }

            using (Logger.IndentLog($"Getting version tags from branch '{branch.Name}'."))
            {
                var tags = _repository
                           .Log(select =>
                                select.Intersect(
                                    select.TaggedWithVersion(tagPrefixRegex),
                                    select.ByBranch(branch.Name)
                                    )
                                .Last(_configuration.TaggedCommitsLimit.GetValueOrDefault())
                                )
                           .SelectMany(commit => commit.Tags)
                           .ToList();

                var versionTags = tags
                                  .SelectMany(tag =>
                {
                    if (SemanticVersion.TryParse(tag.Name, tagPrefixRegex, out var semver))
                    {
                        return new[] { semver }
                    }
                    ;

                    return(Enumerable.Empty <SemanticVersion>());
                })
                                  .ToList();

                _semanticVersionTagsOnBranchCache.Add(branch, versionTags);
                return(versionTags);
            }
        }
        static BranchConfig InheritBranchConfiguration(HgVersionContext context, IBranchHead targetBranch,
                                                       BranchConfig branchConfiguration, IList <IBranchHead> excludedInheritBranches)
        {
            var repository = context.Repository;
            var config     = context.FullConfiguration;

            using (Logger.IndentLog("Attempting to inherit branch configuration from parent branch"))
            {
                var excludedBranches = new[] { targetBranch };
                // Check if we are a merge commit. If so likely we are a pull request
                var parentCount = repository.Parents(context.CurrentCommit).Count();
                if (parentCount == 2)
                {
                    excludedBranches = CalculateWhenMultipleParents(repository, context.CurrentCommit, ref targetBranch,
                                                                    excludedBranches);
                }

                if (excludedInheritBranches == null)
                {
                    excludedInheritBranches = repository.Branches()
                                              .Where(b =>
                    {
                        var branchConfig = config.GetConfigForBranch(b.Name);

                        return(branchConfig != null && branchConfig.Increment == IncrementStrategyType.Inherit);
                    })
                                              .ToList();
                }

                // Add new excluded branches.
                foreach (var excludedBranch in excludedBranches.Except(excludedInheritBranches))
                {
                    excludedInheritBranches.Add(excludedBranch);
                }

                var branchesToEvaluate = repository
                                         .Branches()
                                         .Except(excludedInheritBranches)
                                         .ToList();

                var branchPoint = context.RepositoryMetadataProvider
                                  .FindCommitWasBranchedFrom(targetBranch, excludedInheritBranches.ToArray());

                var possibleParents = CalculatePossibleParents(context, branchPoint, branchesToEvaluate);

                Logger.WriteInfo("Found possible parent branches: " +
                                 string.Join(", ", possibleParents.Select(p => p.Name)));

                if (possibleParents.Count == 1)
                {
                    var branchConfig = GetBranchConfiguration(context, possibleParents[0], excludedInheritBranches);
                    return(new BranchConfig(branchConfiguration)
                    {
                        Increment = branchConfig.Increment,
                        PreventIncrementOfMergedBranchVersion = branchConfig.PreventIncrementOfMergedBranchVersion,
                        // If we are inheriting from develop then we should behave like develop
                        TracksReleaseBranches = branchConfig.TracksReleaseBranches
                    });
                }

                // If we fail to inherit it is probably because the branch has been merged and we can't do much. So we will fall back to develop's config
                // if develop exists and default if not
                string errorMessage;
                if (possibleParents.Count == 0)
                {
                    errorMessage = "Failed to inherit Increment branch configuration, no branches found.";
                }
                else
                {
                    errorMessage = "Failed to inherit Increment branch configuration, ended up with: " +
                                   string.Join(", ", possibleParents.Select(p => p.Name));
                }

                var developBranchRegex = config.Branches[HgConfigurationProvider.DevelopBranchKey].Regex;
                var defaultBranchRegex = config.Branches[HgConfigurationProvider.DefaultBranchKey].Regex;

                var chosenBranch = repository.Branches()
                                   .FirstOrDefault(b =>
                                                   Regex.IsMatch(b.Name, developBranchRegex, RegexOptions.IgnoreCase) ||
                                                   Regex.IsMatch(b.Name, defaultBranchRegex, RegexOptions.IgnoreCase));

                if (chosenBranch == null)
                {
                    // TODO We should call the build server to generate this exception, each build server works differently
                    // for fetch issues and we could give better warnings.
                    throw new InvalidOperationException(
                              $"Could not find a '{HgConfigurationProvider.DevelopBranchKey}' or "
                              + $"'{HgConfigurationProvider.DefaultBranchKey}' branch, neither locally nor remotely.");
                }

                var branchName = chosenBranch.Name;
                Logger.WriteWarning(errorMessage + Environment.NewLine + Environment.NewLine + "Falling back to " +
                                    branchName + " branch config");

                // To prevent infinite loops, make sure that a new branch was chosen.
                if (Equals(targetBranch, chosenBranch))
                {
                    Logger.WriteWarning(
                        "Fallback branch wants to inherit Increment branch configuration from itself. "
                        + "Using patch increment instead.");

                    return(new BranchConfig(branchConfiguration)
                    {
                        Increment = IncrementStrategyType.Patch
                    });
                }

                var inheritingBranchConfig = GetBranchConfiguration(context, chosenBranch, excludedInheritBranches);
                return(new BranchConfig(branchConfiguration)
                {
                    Increment = inheritingBranchConfig.Increment,
                    PreventIncrementOfMergedBranchVersion =
                        inheritingBranchConfig.PreventIncrementOfMergedBranchVersion,
                    // If we are inheriting from develop then we should behave like develop
                    TracksReleaseBranches = inheritingBranchConfig.TracksReleaseBranches
                });
            }
        }
        static IBranchHead[] CalculateWhenMultipleParents(IRepository repository, ICommit currentCommit, ref IBranchHead currentBranch, IBranchHead[] excludedBranches)
        {
            var parents = repository
                          .Parents(currentCommit)
                          .ToArray();

            var branches = repository.Branches()
                           .Where(b => Equals(b.Commit, parents[1]))
                           .ToList();

            if (branches.Count == 1)
            {
                var branch = branches[0];
                excludedBranches = new[]
                {
                    currentBranch,
                    branch
                };
                currentBranch = branch;
            }
            else if (branches.Count > 1)
            {
                currentBranch = branches.FirstOrDefault(b => b.Name == HgConfigurationProvider.DefaultBranchKey) ?? branches.First();
            }
            else
            {
                var possibleTargetBranches = repository.Branches()
                                             .Where(b => Equals(b.Commit, parents[0]))
                                             .ToList();

                if (possibleTargetBranches.Count > 1)
                {
                    currentBranch = possibleTargetBranches.FirstOrDefault(b => b.Name == HgConfigurationProvider.DefaultBranchKey) ??
                                    possibleTargetBranches.First();
                }
                else
                {
                    currentBranch = possibleTargetBranches.FirstOrDefault() ?? currentBranch;
                }
            }

            Logger.WriteInfo("HEAD is merge commit, this is likely a pull request using "
                             + $"{currentBranch.Name} as base");

            return(excludedBranches);
        }
Пример #9
0
 /// <summary>
 /// todo: add summary
 /// </summary>
 public static IEnumerable <ICommit> Commits(this IBranchHead branch, IVersionContext context) =>
 context.Repository.Log(select => select.ByBranch(branch.Name));
Пример #10
0
 /// <summary>
 /// todo: add summary
 /// </summary>
 public static IEnumerable <ICommit> CommitsPriorToThan(this IBranchHead branch, IVersionContext context, DateTimeOffset olderThan) =>
 branch.Commits(context).SkipWhile(c => c.When > olderThan);