// TODO I think we need to take a fresh approach to this.. it's getting really complex with heaps of edge cases private BranchConfig InheritBranchConfiguration(Branch targetBranch, BranchConfig branchConfiguration, Commit currentCommit, Config configuration, IList <Branch> excludedInheritBranches) { using (log.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 = currentCommit.Parents.Count(); if (parentCount == 2) { excludedBranches = CalculateWhenMultipleParents(currentCommit, ref targetBranch, excludedBranches); } excludedInheritBranches ??= repositoryMetadataProvider.GetExcludedInheritBranches(configuration); // Add new excluded branches. foreach (var excludedBranch in excludedBranches.ExcludingBranches(excludedInheritBranches)) { excludedInheritBranches.Add(excludedBranch); } var branchesToEvaluate = repositoryMetadataProvider.ExcludingBranches(excludedInheritBranches).ToList(); var branchPoint = repositoryMetadataProvider .FindCommitBranchWasBranchedFrom(targetBranch, configuration, excludedInheritBranches.ToArray()); List <Branch> possibleParents; if (branchPoint == BranchCommit.Empty) { possibleParents = repositoryMetadataProvider.GetBranchesContainingCommit(targetBranch.Tip, branchesToEvaluate) // 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 = repositoryMetadataProvider.GetBranchesContainingCommit(branchPoint.Commit, branchesToEvaluate).ToList(); if (branches.Count > 1) { var currentTipBranches = repositoryMetadataProvider.GetBranchesContainingCommit(currentCommit, branchesToEvaluate).ToList(); possibleParents = branches.Except(currentTipBranches).ToList(); } else { possibleParents = branches; } } log.Info("Found possible parent branches: " + string.Join(", ", possibleParents.Select(p => p.FriendlyName))); if (possibleParents.Count == 1) { var branchConfig = GetBranchConfiguration(possibleParents[0], currentCommit, configuration, 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 var errorMessage = possibleParents.Count == 0 ? "Failed to inherit Increment branch configuration, no branches found." : "Failed to inherit Increment branch configuration, ended up with: " + string.Join(", ", possibleParents.Select(p => p.FriendlyName)); var chosenBranch = repositoryMetadataProvider.GetChosenBranch(configuration); 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; log.Warning(errorMessage + System.Environment.NewLine + "Falling back to " + branchName + " branch config"); // To prevent infinite loops, make sure that a new branch was chosen. if (targetBranch.IsSameBranch(chosenBranch)) { var developOrMasterConfig = ChooseMasterOrDevelopIncrementStrategyIfTheChosenBranchIsOneOfThem( chosenBranch, branchConfiguration, configuration); if (developOrMasterConfig != null) { return(developOrMasterConfig); } log.Warning("Fallback branch wants to inherit Increment branch configuration from itself. Using patch increment instead."); return(new BranchConfig(branchConfiguration) { Increment = IncrementStrategy.Patch }); } var inheritingBranchConfig = GetBranchConfiguration(chosenBranch, currentCommit, configuration, excludedInheritBranches); var configIncrement = inheritingBranchConfig.Increment; if (inheritingBranchConfig.Name.IsEquivalentTo(FallbackConfigName) && configIncrement == IncrementStrategy.Inherit) { log.Warning("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 }); } }
private static Config CreateDefaultConfiguration() { var config = new Config { AssemblyVersioningScheme = AssemblyVersioningScheme.MajorMinorPatch, AssemblyFileVersioningScheme = AssemblyFileVersioningScheme.MajorMinorPatch, TagPrefix = Config.DefaultTagPrefix, VersioningMode = VersioningMode.ContinuousDelivery, ContinuousDeploymentFallbackTag = "ci", MajorVersionBumpMessage = IncrementStrategyFinder.DefaultMajorPattern, MinorVersionBumpMessage = IncrementStrategyFinder.DefaultMinorPattern, PatchVersionBumpMessage = IncrementStrategyFinder.DefaultPatchPattern, NoBumpMessage = IncrementStrategyFinder.DefaultNoBumpPattern, CommitMessageIncrementing = CommitMessageIncrementMode.Enabled, LegacySemVerPadding = 4, BuildMetaDataPadding = 4, CommitsSinceVersionSourcePadding = 4, CommitDateFormat = "yyyy-MM-dd", UpdateBuildNumber = true, TagPreReleaseWeight = DefaultTagPreReleaseWeight }; AddBranchConfig(Config.DevelopBranchKey, new BranchConfig { Regex = Config.DevelopBranchRegex, SourceBranches = new HashSet <string>(), Tag = "alpha", Increment = IncrementStrategy.Minor, TrackMergeTarget = true, TracksReleaseBranches = true, PreReleaseWeight = 0, }); AddBranchConfig(Config.MasterBranchKey, new BranchConfig { Regex = Config.MasterBranchRegex, SourceBranches = new HashSet <string> { Config.DevelopBranchKey, Config.ReleaseBranchKey }, Tag = string.Empty, PreventIncrementOfMergedBranchVersion = true, Increment = IncrementStrategy.Patch, IsMainline = true, PreReleaseWeight = 55000, }); AddBranchConfig(Config.ReleaseBranchKey, new BranchConfig { Regex = Config.ReleaseBranchRegex, SourceBranches = new HashSet <string> { Config.DevelopBranchKey, Config.MasterBranchKey, Config.SupportBranchKey, Config.ReleaseBranchKey }, Tag = "beta", PreventIncrementOfMergedBranchVersion = true, Increment = IncrementStrategy.None, IsReleaseBranch = true, PreReleaseWeight = 30000, }); AddBranchConfig(Config.FeatureBranchKey, new BranchConfig { Regex = Config.FeatureBranchRegex, SourceBranches = new HashSet <string> { Config.DevelopBranchKey, Config.MasterBranchKey, Config.ReleaseBranchKey, Config.FeatureBranchKey, Config.SupportBranchKey, Config.HotfixBranchKey }, Increment = IncrementStrategy.Inherit, PreReleaseWeight = 30000, }); AddBranchConfig(Config.PullRequestBranchKey, new BranchConfig { Regex = Config.PullRequestRegex, SourceBranches = new HashSet <string> { Config.DevelopBranchKey, Config.MasterBranchKey, Config.ReleaseBranchKey, Config.FeatureBranchKey, Config.SupportBranchKey, Config.HotfixBranchKey }, Tag = "PullRequest", TagNumberPattern = @"[/-](?<number>\d+)", Increment = IncrementStrategy.Inherit, PreReleaseWeight = 30000, }); AddBranchConfig(Config.HotfixBranchKey, new BranchConfig { Regex = Config.HotfixBranchRegex, SourceBranches = new HashSet <string> { Config.DevelopBranchKey, Config.MasterBranchKey, Config.SupportBranchKey }, Tag = "beta", Increment = IncrementStrategy.Patch, PreReleaseWeight = 30000, }); AddBranchConfig(Config.SupportBranchKey, new BranchConfig { Regex = Config.SupportBranchRegex, SourceBranches = new HashSet <string> { Config.MasterBranchKey }, Tag = string.Empty, PreventIncrementOfMergedBranchVersion = true, Increment = IncrementStrategy.Patch, IsMainline = true, PreReleaseWeight = 55000, }); return(config); void AddBranchConfig(string name, BranchConfig overrides) { config.Branches[name] = BranchConfig.CreateDefaultBranchConfig(name).Apply(overrides); } }
private static BranchConfig ChooseMasterOrDevelopIncrementStrategyIfTheChosenBranchIsOneOfThem(Branch chosenBranch, BranchConfig branchConfiguration, Config config) { BranchConfig masterOrDevelopConfig = null; var developBranchRegex = config.Branches[Config.DevelopBranchKey].Regex; var masterBranchRegex = config.Branches[Config.MasterBranchKey].Regex; if (Regex.IsMatch(chosenBranch.FriendlyName, developBranchRegex, RegexOptions.IgnoreCase)) { // Normally we would not expect this to happen but for safety we add a check if (config.Branches[Config.DevelopBranchKey].Increment != IncrementStrategy.Inherit) { masterOrDevelopConfig = new BranchConfig(branchConfiguration) { Increment = config.Branches[Config.DevelopBranchKey].Increment }; } } else if (Regex.IsMatch(chosenBranch.FriendlyName, masterBranchRegex, RegexOptions.IgnoreCase)) { // Normally we would not expect this to happen but for safety we add a check if (config.Branches[Config.MasterBranchKey].Increment != IncrementStrategy.Inherit) { masterOrDevelopConfig = new BranchConfig(branchConfiguration) { Increment = config.Branches[Config.DevelopBranchKey].Increment }; } } return(masterOrDevelopConfig); }
public static EffectiveConfiguration CalculateEffectiveConfiguration(this Config configuration, BranchConfig currentBranchConfig) { var name = currentBranchConfig.Name; if (!currentBranchConfig.VersioningMode.HasValue) { throw new Exception($"Configuration value for 'Versioning mode' for branch {name} has no value. (this should not happen, please report an issue)"); } if (!currentBranchConfig.Increment.HasValue) { throw new Exception($"Configuration value for 'Increment' for branch {name} has no value. (this should not happen, please report an issue)"); } if (!currentBranchConfig.PreventIncrementOfMergedBranchVersion.HasValue) { throw new Exception($"Configuration value for 'PreventIncrementOfMergedBranchVersion' for branch {name} has no value. (this should not happen, please report an issue)"); } if (!currentBranchConfig.TrackMergeTarget.HasValue) { throw new Exception($"Configuration value for 'TrackMergeTarget' for branch {name} has no value. (this should not happen, please report an issue)"); } if (!currentBranchConfig.TracksReleaseBranches.HasValue) { throw new Exception($"Configuration value for 'TracksReleaseBranches' for branch {name} has no value. (this should not happen, please report an issue)"); } if (!currentBranchConfig.IsReleaseBranch.HasValue) { throw new Exception($"Configuration value for 'IsReleaseBranch' for branch {name} has no value. (this should not happen, please report an issue)"); } if (!configuration.AssemblyVersioningScheme.HasValue) { throw new Exception("Configuration value for 'AssemblyVersioningScheme' has no value. (this should not happen, please report an issue)"); } if (!configuration.AssemblyFileVersioningScheme.HasValue) { throw new Exception("Configuration value for 'AssemblyFileVersioningScheme' has no value. (this should not happen, please report an issue)"); } if (!configuration.CommitMessageIncrementing.HasValue) { throw new Exception("Configuration value for 'CommitMessageIncrementing' has no value. (this should not happen, please report an issue)"); } if (!configuration.LegacySemVerPadding.HasValue) { throw new Exception("Configuration value for 'LegacySemVerPadding' has no value. (this should not happen, please report an issue)"); } if (!configuration.BuildMetaDataPadding.HasValue) { throw new Exception("Configuration value for 'BuildMetaDataPadding' has no value. (this should not happen, please report an issue)"); } if (!configuration.CommitsSinceVersionSourcePadding.HasValue) { throw new Exception("Configuration value for 'CommitsSinceVersionSourcePadding' has no value. (this should not happen, please report an issue)"); } var versioningMode = currentBranchConfig.VersioningMode.Value; var tag = currentBranchConfig.Tag; var tagNumberPattern = currentBranchConfig.TagNumberPattern; var incrementStrategy = currentBranchConfig.Increment.Value; var preventIncrementForMergedBranchVersion = currentBranchConfig.PreventIncrementOfMergedBranchVersion.Value; var trackMergeTarget = currentBranchConfig.TrackMergeTarget.Value; var preReleaseWeight = currentBranchConfig.PreReleaseWeight ?? 0; var nextVersion = configuration.NextVersion; var assemblyVersioningScheme = configuration.AssemblyVersioningScheme.Value; var assemblyFileVersioningScheme = configuration.AssemblyFileVersioningScheme.Value; var assemblyInformationalFormat = configuration.AssemblyInformationalFormat; var assemblyVersioningFormat = configuration.AssemblyVersioningFormat; var assemblyFileVersioningFormat = configuration.AssemblyFileVersioningFormat; var gitTagPrefix = configuration.TagPrefix; var majorMessage = configuration.MajorVersionBumpMessage; var minorMessage = configuration.MinorVersionBumpMessage; var patchMessage = configuration.PatchVersionBumpMessage; var noBumpMessage = configuration.NoBumpMessage; var commitDateFormat = configuration.CommitDateFormat; var commitMessageVersionBump = currentBranchConfig.CommitMessageIncrementing ?? configuration.CommitMessageIncrementing.Value; return(new EffectiveConfiguration( assemblyVersioningScheme, assemblyFileVersioningScheme, assemblyInformationalFormat, assemblyVersioningFormat, assemblyFileVersioningFormat, versioningMode, gitTagPrefix, tag, nextVersion, incrementStrategy, currentBranchConfig.Regex, preventIncrementForMergedBranchVersion, tagNumberPattern, configuration.ContinuousDeploymentFallbackTag, trackMergeTarget, majorMessage, minorMessage, patchMessage, noBumpMessage, commitMessageVersionBump, configuration.LegacySemVerPadding.Value, configuration.BuildMetaDataPadding.Value, configuration.CommitsSinceVersionSourcePadding.Value, configuration.Ignore.ToFilters(), currentBranchConfig.TracksReleaseBranches.Value, currentBranchConfig.IsReleaseBranch.Value, commitDateFormat, preReleaseWeight)); }