public static bool IsHotfix(this Branch branch) { return(branch.Name.StartsWith("hotfix-") || branch.Name.StartsWith("hotfix/")); }
public static bool IsPullRequest(this Branch branch) { return(branch.CanonicalName.Contains("/pull/") || branch.CanonicalName.Contains("/pull-requests/")); }
public static bool IsSupport(this Branch branch) { return(branch.Name.ToLower().StartsWith("support-") || branch.Name.StartsWith("support/")); }
public static bool IsDevelop(this Branch branch) { return(branch.Name == "develop"); }
public static bool IsMaster(this Branch branch) { return(branch.Name == "master"); }
public static IEnumerable <Commit> CommitsPriorToThan(this Branch branch, DateTimeOffset olderThan) { return(branch.Commits.SkipWhile(c => c.When() > olderThan)); }
public static KeyValuePair <string, BranchConfig> GetBranchConfiguration(Commit currentCommit, IRepository repository, bool onlyEvaluateTrackedBranches, Config config, Branch currentBranch, IList <Branch> excludedInheritBranches = null) { var matchingBranches = config.Branches.Where(b => Regex.IsMatch(currentBranch.Name, "^" + b.Key, RegexOptions.IgnoreCase)).ToArray(); if (matchingBranches.Length == 0) { return(new KeyValuePair <string, BranchConfig>(string.Empty, new BranchConfig())); } if (matchingBranches.Length == 1) { var keyValuePair = matchingBranches[0]; var branchConfiguration = keyValuePair.Value; if (branchConfiguration.Increment == IncrementStrategy.Inherit) { return(InheritBranchConfiguration(onlyEvaluateTrackedBranches, repository, currentCommit, currentBranch, keyValuePair, branchConfiguration, config, excludedInheritBranches)); } return(keyValuePair); } const string format = "Multiple branch configurations match the current branch branchName of '{0}'. Matching configurations: '{1}'"; throw new Exception(string.Format(format, currentBranch.Name, string.Join(", ", matchingBranches.Select(b => b.Key)))); }
static Branch[] CalculateWhenMultipleParents(IRepository repository, Commit currentCommit, ref Branch currentBranch, Branch[] excludedBranches) { var parents = currentCommit.Parents.ToArray(); var branches = repository.Branches.Where(b => !b.IsRemote && b.Tip == 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.FriendlyName == "master") ?? branches.First(); } else { var possibleTargetBranches = repository.Branches.Where(b => !b.IsRemote && b.Tip == parents[0]).ToList(); if (possibleTargetBranches.Count > 1) { currentBranch = possibleTargetBranches.FirstOrDefault(b => b.FriendlyName == "master") ?? possibleTargetBranches.First(); } else { currentBranch = possibleTargetBranches.FirstOrDefault() ?? currentBranch; } } Logger.WriteInfo("HEAD is merge commit, this is likely a pull request using " + currentBranch.FriendlyName + " as base"); return(excludedBranches); }
// TODO I think we need to take a fresh approach to this.. it's getting really complex with heaps of edge cases static BranchConfig InheritBranchConfiguration(GitVersionContext context, Branch targetBranch, BranchConfig branchConfiguration, IList <Branch> 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 = context.CurrentCommit.Parents.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.NameWithoutRemote()); return(branchConfig == null || branchConfig.Increment == IncrementStrategy.Inherit); }).ToList(); } // Add new excluded branches. foreach (var excludedBranch in excludedBranches.ExcludingBranches(excludedInheritBranches)) { excludedInheritBranches.Add(excludedBranch); } var branchesToEvaluate = repository.Branches.ExcludingBranches(excludedInheritBranches).ToList(); var branchPoint = context.RepositoryMetadataProvider .FindCommitBranchWasBranchedFrom(targetBranch, excludedInheritBranches.ToArray()); List <Branch> possibleParents; if (branchPoint == BranchCommit.Empty) { possibleParents = context.RepositoryMetadataProvider.GetBranchesContainingCommit(targetBranch.Tip, branchesToEvaluate, true) // It fails to inherit Increment branch configuration if more than 1 parent; // therefore no point to get more than 2 parents .Take(2) .ToList(); } else { var branches = context.RepositoryMetadataProvider .GetBranchesContainingCommit(branchPoint.Commit, branchesToEvaluate, true).ToList(); if (branches.Count > 1) { var currentTipBranches = context.RepositoryMetadataProvider .GetBranchesContainingCommit(context.CurrentCommit, branchesToEvaluate, true).ToList(); possibleParents = branches.Except(currentTipBranches).ToList(); } else { possibleParents = branches; } } Logger.WriteInfo("Found possible parent branches: " + string.Join(", ", possibleParents.Select(p => p.FriendlyName))); if (possibleParents.Count == 1) { var branchConfig = GetBranchConfiguration(context, possibleParents[0], excludedInheritBranches); // If we have resolved a fallback config we should not return that we have got config if (branchConfig.Name != FallbackConfigName) { 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 master 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.FriendlyName)); } var developBranchRegex = config.Branches[ConfigurationProvider.DevelopBranchKey].Regex; var masterBranchRegex = config.Branches[ConfigurationProvider.MasterBranchKey].Regex; var chosenBranch = repository.Branches.FirstOrDefault(b => Regex.IsMatch(b.FriendlyName, developBranchRegex, RegexOptions.IgnoreCase) || Regex.IsMatch(b.FriendlyName, masterBranchRegex, 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 'develop' or 'master' branch, neither locally nor remotely."); } var branchName = chosenBranch.FriendlyName; 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 (targetBranch.IsSameBranch(chosenBranch)) { BranchConfig developOrMasterConfig = ChooseMasterOrDevelopIncrementStrategyIfTheChosenBranchIsOneOfThem( chosenBranch, branchConfiguration, config); if (developOrMasterConfig != null) { return(developOrMasterConfig); } else { Logger.WriteWarning("Fallback branch wants to inherit Increment branch configuration from itself. Using patch increment instead."); return(new BranchConfig(branchConfiguration) { Increment = IncrementStrategy.Patch }); } } var inheritingBranchConfig = GetBranchConfiguration(context, chosenBranch, excludedInheritBranches); var configIncrement = inheritingBranchConfig.Increment; if (inheritingBranchConfig.Name == FallbackConfigName && configIncrement == IncrementStrategy.Inherit) { Logger.WriteWarning("Fallback config inherits by default, dropping to patch increment"); configIncrement = IncrementStrategy.Patch; } return(new BranchConfig(branchConfiguration) { Increment = configIncrement, PreventIncrementOfMergedBranchVersion = inheritingBranchConfig.PreventIncrementOfMergedBranchVersion, // If we are inheriting from develop then we should behave like develop TracksReleaseBranches = inheritingBranchConfig.TracksReleaseBranches }); } }
static KeyValuePair <string, BranchConfig> InheritBranchConfiguration(bool onlyEvaluateTrackedBranches, IRepository repository, Commit currentCommit, Branch currentBranch, KeyValuePair <string, BranchConfig> keyValuePair, BranchConfig branchConfiguration, Config config, IList <Branch> excludedInheritBranches) { using (Logger.IndentLog("Attempting to inherit branch configuration from parent branch")) { var excludedBranches = new[] { currentBranch }; // Check if we are a merge commit. If so likely we are a pull request var parentCount = currentCommit.Parents.Count(); if (parentCount == 2) { excludedBranches = CalculateWhenMultipleParents(repository, currentCommit, ref currentBranch, excludedBranches); } if (excludedInheritBranches == null) { excludedInheritBranches = repository.Branches.Where(b => { var branchConfig = LookupBranchConfiguration(config, b); // NOTE: if length is 0 we couldn't find the configuration for the branch e.g. "origin/master" // NOTE: if the length is greater than 1 we cannot decide which merge strategy to pick return((branchConfig.Length != 1) || (branchConfig.Length == 1 && branchConfig[0].Value.Increment == IncrementStrategy.Inherit)); }).ToList(); } excludedBranches.ToList().ForEach(excludedInheritBranches.Add); var branchesToEvaluate = repository.Branches.Except(excludedInheritBranches).ToList(); var branchPoint = currentBranch.FindCommitBranchWasBranchedFrom(repository, excludedInheritBranches.ToArray()); List <Branch> possibleParents; if (branchPoint == null) { possibleParents = currentCommit.GetBranchesContainingCommit(repository, branchesToEvaluate, true) // It fails to inherit Increment branch configuration if more than 1 parent; // therefore no point to get more than 2 parents .Take(2) .ToList(); } else { var branches = branchPoint.GetBranchesContainingCommit(repository, branchesToEvaluate, true).ToList(); if (branches.Count > 1) { var currentTipBranches = currentCommit.GetBranchesContainingCommit(repository, branchesToEvaluate, true).ToList(); possibleParents = branches.Except(currentTipBranches).ToList(); } else { possibleParents = branches; } } Logger.WriteInfo("Found possible parent branches: " + string.Join(", ", possibleParents.Select(p => p.FriendlyName))); if (possibleParents.Count == 1) { var branchConfig = GetBranchConfiguration(currentCommit, repository, onlyEvaluateTrackedBranches, config, possibleParents[0], excludedInheritBranches).Value; return(new KeyValuePair <string, BranchConfig>( keyValuePair.Key, new BranchConfig(branchConfiguration) { Increment = branchConfig.Increment, PreventIncrementOfMergedBranchVersion = branchConfig.PreventIncrementOfMergedBranchVersion, // If we are inheriting from develop then we should behave like develop IsDevelop = branchConfig.IsDevelop })); } // 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 master 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.FriendlyName)); } var chosenBranch = repository.Branches.FirstOrDefault(b => Regex.IsMatch(b.FriendlyName, "^develop", RegexOptions.IgnoreCase) || Regex.IsMatch(b.FriendlyName, "master$", RegexOptions.IgnoreCase)); if (chosenBranch == null) { throw new InvalidOperationException("Could not find a 'develop' or 'master' branch, neither locally nor remotely."); } var branchName = chosenBranch.FriendlyName; Logger.WriteWarning(errorMessage + Environment.NewLine + Environment.NewLine + "Falling back to " + branchName + " branch config"); var inheritingBranchConfig = GetBranchConfiguration(currentCommit, repository, onlyEvaluateTrackedBranches, config, chosenBranch).Value; return(new KeyValuePair <string, BranchConfig>( keyValuePair.Key, new BranchConfig(branchConfiguration) { Increment = inheritingBranchConfig.Increment, PreventIncrementOfMergedBranchVersion = inheritingBranchConfig.PreventIncrementOfMergedBranchVersion, // If we are inheriting from develop then we should behave like develop IsDevelop = inheritingBranchConfig.IsDevelop })); } }
public BranchCommit(Commit commit, Branch branch) : this() { Branch = branch; Commit = commit; }
static KeyValuePair <string, BranchConfig>[] LookupBranchConfiguration([NotNull] Config config, [NotNull] Branch currentBranch) { if (config == null) { throw new ArgumentNullException("config"); } if (currentBranch == null) { throw new ArgumentNullException("currentBranch"); } return(config.Branches.Where(b => Regex.IsMatch(currentBranch.FriendlyName, "^" + b.Key, RegexOptions.IgnoreCase)).ToArray()); }
public static KeyValuePair <string, BranchConfig> GetBranchConfiguration(Commit currentCommit, IRepository repository, bool onlyEvaluateTrackedBranches, Config config, Branch currentBranch, IList <Branch> excludedInheritBranches = null) { var matchingBranches = LookupBranchConfiguration(config, currentBranch); if (matchingBranches.Length == 0) { var branchConfig = new BranchConfig(); ConfigurationProvider.ApplyBranchDefaults(config, branchConfig); return(new KeyValuePair <string, BranchConfig>(string.Empty, branchConfig)); } if (matchingBranches.Length == 1) { var keyValuePair = matchingBranches[0]; var branchConfiguration = keyValuePair.Value; if (branchConfiguration.Increment == IncrementStrategy.Inherit) { return(InheritBranchConfiguration(onlyEvaluateTrackedBranches, repository, currentCommit, currentBranch, keyValuePair, branchConfiguration, config, excludedInheritBranches)); } return(keyValuePair); } const string format = "Multiple branch configurations match the current branch branchName of '{0}'. Matching configurations: '{1}'"; throw new Exception(string.Format(format, currentBranch.FriendlyName, string.Join(", ", matchingBranches.Select(b => b.Key)))); }
static KeyValuePair <string, BranchConfig> InheritBranchConfiguration(bool onlyEvaluateTrackedBranches, IRepository repository, Commit currentCommit, Branch currentBranch, KeyValuePair <string, BranchConfig> keyValuePair, BranchConfig branchConfiguration, Config config, IList <Branch> excludedInheritBranches) { Logger.WriteInfo("Attempting to inherit branch configuration from parent branch"); var excludedBranches = new [] { currentBranch }; // Check if we are a merge commit. If so likely we are a pull request var parentCount = currentCommit.Parents.Count(); if (parentCount == 2) { var parents = currentCommit.Parents.ToArray(); var branch = repository.Branches.SingleOrDefault(b => !b.IsRemote && b.Tip == parents[1]); if (branch != null) { excludedBranches = new[] { currentBranch, branch }; currentBranch = branch; } else { var possibleTargetBranches = repository.Branches.Where(b => !b.IsRemote && b.Tip == parents[0]).ToList(); if (possibleTargetBranches.Count() > 1) { currentBranch = possibleTargetBranches.FirstOrDefault(b => b.Name == "master") ?? possibleTargetBranches.First(); } else { currentBranch = possibleTargetBranches.FirstOrDefault() ?? currentBranch; } } Logger.WriteInfo("HEAD is merge commit, this is likely a pull request using " + currentBranch.Name + " as base"); } if (excludedInheritBranches == null) { excludedInheritBranches = new List <Branch>(); } excludedBranches.ToList().ForEach(excludedInheritBranches.Add); var branchPoint = currentBranch.FindCommitBranchWasBranchedFrom(repository, onlyEvaluateTrackedBranches, excludedInheritBranches.ToArray()); List <Branch> possibleParents; if (branchPoint.Sha == currentCommit.Sha) { possibleParents = currentCommit.GetBranchesContainingCommit(repository, true).Except(excludedInheritBranches).ToList(); } else { var branches = branchPoint.GetBranchesContainingCommit(repository, true).Except(excludedInheritBranches).ToList(); var currentTipBranches = currentCommit.GetBranchesContainingCommit(repository, true).Except(excludedInheritBranches).ToList(); possibleParents = branches .Except(currentTipBranches) .ToList(); } Logger.WriteInfo("Found possible parent branches: " + string.Join(", ", possibleParents.Select(p => p.Name))); // If it comes down to master and something, master is always first so we pick other branch if (possibleParents.Count == 2 && possibleParents.Any(p => p.Name == "master")) { possibleParents.Remove(possibleParents.Single(p => p.Name == "master")); } if (possibleParents.Count == 1) { var branchConfig = GetBranchConfiguration(currentCommit, repository, onlyEvaluateTrackedBranches, config, possibleParents[0], excludedInheritBranches).Value; return(new KeyValuePair <string, BranchConfig>( keyValuePair.Key, new BranchConfig(branchConfiguration) { Increment = branchConfig.Increment, PreventIncrementOfMergedBranchVersion = branchConfig.PreventIncrementOfMergedBranchVersion })); } // 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 master 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 hasDevelop = repository.Branches["develop"] != null; var branchName = hasDevelop ? "develop" : "master"; Logger.WriteWarning(errorMessage + Environment.NewLine + Environment.NewLine + "Falling back to " + branchName + " branch config"); var value = GetBranchConfiguration(currentCommit, repository, onlyEvaluateTrackedBranches, config, repository.Branches[branchName]).Value; return(new KeyValuePair <string, BranchConfig>( keyValuePair.Key, new BranchConfig(branchConfiguration) { Increment = value.Increment, PreventIncrementOfMergedBranchVersion = value.PreventIncrementOfMergedBranchVersion })); }
public static string NameWithoutRemote(this Branch branch) { return(branch.IsRemote ? branch.FriendlyName.Substring(branch.FriendlyName.IndexOf("/", StringComparison.Ordinal) + 1) : branch.FriendlyName); }
/// <summary> /// Find the merge base of the two branches, i.e. the best common ancestor of the two branches' tips. /// </summary> public Commit FindMergeBase(Branch branch, Branch otherBranch) { var key = Tuple.Create(branch, otherBranch); if (mergeBaseCache.ContainsKey(key)) { Logger.WriteDebug($"Cache hit for merge base between '{branch.FriendlyName}' and '{otherBranch.FriendlyName}'."); return(mergeBaseCache[key].MergeBase); } using (Logger.IndentLog($"Finding merge base between '{branch.FriendlyName}' and '{otherBranch.FriendlyName}'.")) { // Otherbranch tip is a forward merge var commitToFindCommonBase = otherBranch.Tip; var commit = branch.Tip; if (otherBranch.Tip.Parents.Contains(commit)) { commitToFindCommonBase = otherBranch.Tip.Parents.First(); } var findMergeBase = Repository.ObjectDatabase.FindMergeBase(commit, commitToFindCommonBase); if (findMergeBase != null) { Logger.WriteInfo($"Found merge base of {findMergeBase.Sha}"); // We do not want to include merge base commits which got forward merged into the other branch Commit forwardMerge; do { // Now make sure that the merge base is not a forward merge forwardMerge = Repository.Commits .QueryBy(new CommitFilter { IncludeReachableFrom = commitToFindCommonBase, ExcludeReachableFrom = findMergeBase }) .FirstOrDefault(c => c.Parents.Contains(findMergeBase)); if (forwardMerge != null) { // TODO Fix the logging up in this section var second = forwardMerge.Parents.First(); Logger.WriteDebug("Second " + second.Sha); var mergeBase = Repository.ObjectDatabase.FindMergeBase(commit, second); if (mergeBase == null) { Logger.WriteWarning("Could not find mergbase for " + commit); } else { Logger.WriteDebug("New Merge base " + mergeBase.Sha); } if (mergeBase == findMergeBase) { Logger.WriteDebug("Breaking"); break; } findMergeBase = mergeBase; commitToFindCommonBase = second; Logger.WriteInfo($"Merge base was due to a forward merge, next merge base is {findMergeBase}"); } } while (forwardMerge != null); } // Store in cache. mergeBaseCache.Add(key, new MergeBaseData(branch, otherBranch, Repository, findMergeBase)); Logger.WriteInfo($"Merge base of {branch.FriendlyName}' and '{otherBranch.FriendlyName} is {findMergeBase}"); return(findMergeBase); } }
public static string NameWithoutOrigin(this Branch branch) { return(branch.IsRemote && branch.FriendlyName.StartsWith("origin/") ? branch.FriendlyName.Substring("origin/".Length) : branch.FriendlyName); }
public static bool IsRelease(this Branch branch) { return(branch.Name.StartsWith("release-") || branch.Name.StartsWith("release/")); }
public static bool IsDetachedHead(this Branch branch) { return(branch.CanonicalName.Equals("(no branch)", StringComparison.OrdinalIgnoreCase)); }
public MergeResult Merge(Branch branch, Signature merger, MergeOptions options) { return(repositoryInstance.Merge(branch, merger, options)); }