diff --git a/src/Commands/GitFlow.cs b/src/Commands/GitFlow.cs index e4fab235..18f51359 100644 --- a/src/Commands/GitFlow.cs +++ b/src/Commands/GitFlow.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Text; using Avalonia.Threading; @@ -8,34 +7,6 @@ namespace SourceGit.Commands { public static class GitFlow { - public class BranchDetectResult - { - public bool IsGitFlowBranch { get; set; } = false; - public string Type { get; set; } = string.Empty; - public string Prefix { get; set; } = string.Empty; - } - - public static bool IsEnabled(string repo, List branches) - { - var localBrancheNames = new HashSet(); - foreach (var branch in branches) - { - if (branch.IsLocal) - localBrancheNames.Add(branch.Name); - } - - var config = new Config(repo).ListAll(); - if (!config.TryGetValue("gitflow.branch.master", out string master) || !localBrancheNames.Contains(master)) - return false; - - if (!config.TryGetValue("gitflow.branch.develop", out string develop) || !localBrancheNames.Contains(develop)) - return false; - - return config.ContainsKey("gitflow.prefix.feature") && - config.ContainsKey("gitflow.prefix.release") && - config.ContainsKey("gitflow.prefix.hotfix"); - } - public static bool Init(string repo, List branches, string master, string develop, string feature, string release, string hotfix, string version, Models.ICommandLog log) { var current = branches.Find(x => x.IsCurrent); @@ -66,90 +37,53 @@ namespace SourceGit.Commands return init.Exec(); } - public static string GetPrefix(string repo, string type) + public static bool Start(string repo, Models.GitFlowBranchType type, string name, Models.ICommandLog log) { - return new Config(repo).Get($"gitflow.prefix.{type}"); - } - - public static BranchDetectResult DetectType(string repo, List branches, string branch) - { - var rs = new BranchDetectResult(); - var localBrancheNames = new HashSet(); - foreach (var b in branches) - { - if (b.IsLocal) - localBrancheNames.Add(b.Name); - } - - var config = new Config(repo).ListAll(); - if (!config.TryGetValue("gitflow.branch.master", out string master) || !localBrancheNames.Contains(master)) - return rs; - - if (!config.TryGetValue("gitflow.branch.develop", out string develop) || !localBrancheNames.Contains(develop)) - return rs; - - if (!config.TryGetValue("gitflow.prefix.feature", out var feature) || - !config.TryGetValue("gitflow.prefix.release", out var release) || - !config.TryGetValue("gitflow.prefix.hotfix", out var hotfix)) - return rs; - - if (branch.StartsWith(feature, StringComparison.Ordinal)) - { - rs.IsGitFlowBranch = true; - rs.Type = "feature"; - rs.Prefix = feature; - } - else if (branch.StartsWith(release, StringComparison.Ordinal)) - { - rs.IsGitFlowBranch = true; - rs.Type = "release"; - rs.Prefix = release; - } - else if (branch.StartsWith(hotfix, StringComparison.Ordinal)) - { - rs.IsGitFlowBranch = true; - rs.Type = "hotfix"; - rs.Prefix = hotfix; - } - - return rs; - } - - public static bool Start(string repo, string type, string name, Models.ICommandLog log) - { - if (!SUPPORTED_BRANCH_TYPES.Contains(type)) - { - Dispatcher.UIThread.Post(() => - { - App.RaiseException(repo, "Bad branch type!!!"); - }); - - return false; - } - var start = new Command(); start.WorkingDirectory = repo; start.Context = repo; - start.Args = $"flow {type} start {name}"; + + switch (type) + { + case Models.GitFlowBranchType.Feature: + start.Args = $"flow feature start {name}"; + break; + case Models.GitFlowBranchType.Release: + start.Args = $"flow release start {name}"; + break; + case Models.GitFlowBranchType.Hotfix: + start.Args = $"flow hotfix start {name}"; + break; + default: + Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, "Bad git-flow branch type!!!")); + return false; + } + start.Log = log; return start.Exec(); } - public static bool Finish(string repo, string type, string name, bool squash, bool push, bool keepBranch, Models.ICommandLog log) + public static bool Finish(string repo, Models.GitFlowBranchType type, string name, bool squash, bool push, bool keepBranch, Models.ICommandLog log) { - if (!SUPPORTED_BRANCH_TYPES.Contains(type)) - { - Dispatcher.UIThread.Post(() => - { - App.RaiseException(repo, "Bad branch type!!!"); - }); - - return false; - } - var builder = new StringBuilder(); builder.Append("flow "); - builder.Append(type); + + switch (type) + { + case Models.GitFlowBranchType.Feature: + builder.Append("feature"); + break; + case Models.GitFlowBranchType.Release: + builder.Append("release"); + break; + case Models.GitFlowBranchType.Hotfix: + builder.Append("hotfix"); + break; + default: + Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, "Bad git-flow branch type!!!")); + return false; + } + builder.Append(" finish "); if (squash) builder.Append("--squash "); @@ -166,14 +100,5 @@ namespace SourceGit.Commands finish.Log = log; return finish.Exec(); } - - private static readonly List SUPPORTED_BRANCH_TYPES = new List() - { - "feature", - "release", - "bugfix", - "hotfix", - "support", - }; } } diff --git a/src/Models/GitFlow.cs b/src/Models/GitFlow.cs new file mode 100644 index 00000000..5d26072b --- /dev/null +++ b/src/Models/GitFlow.cs @@ -0,0 +1,46 @@ +namespace SourceGit.Models +{ + public enum GitFlowBranchType + { + None = 0, + Feature, + Release, + Hotfix, + } + + public class GitFlow + { + public string Master { get; set; } = string.Empty; + public string Develop { get; set; } = string.Empty; + public string FeaturePrefix { get; set; } = string.Empty; + public string ReleasePrefix { get; set; } = string.Empty; + public string HotfixPrefix { get; set; } = string.Empty; + + public bool IsValid + { + get + { + return !string.IsNullOrEmpty(Master) && + !string.IsNullOrEmpty(Develop) && + !string.IsNullOrEmpty(FeaturePrefix) && + !string.IsNullOrEmpty(ReleasePrefix) && + !string.IsNullOrEmpty(HotfixPrefix); + } + } + + public string GetPrefix(GitFlowBranchType type) + { + switch (type) + { + case GitFlowBranchType.Feature: + return FeaturePrefix; + case GitFlowBranchType.Release: + return ReleasePrefix; + case GitFlowBranchType.Hotfix: + return HotfixPrefix; + default: + return string.Empty; + } + } + } +} diff --git a/src/ViewModels/GitFlowFinish.cs b/src/ViewModels/GitFlowFinish.cs index d7ad5d31..bef4c2d9 100644 --- a/src/ViewModels/GitFlowFinish.cs +++ b/src/ViewModels/GitFlowFinish.cs @@ -9,9 +9,11 @@ namespace SourceGit.ViewModels get; } - public bool IsFeature => _type == "feature"; - public bool IsRelease => _type == "release"; - public bool IsHotfix => _type == "hotfix"; + public Models.GitFlowBranchType Type + { + get; + private set; + } public bool Squash { @@ -31,27 +33,27 @@ namespace SourceGit.ViewModels set; } = false; - public GitFlowFinish(Repository repo, Models.Branch branch, string type, string prefix) + public GitFlowFinish(Repository repo, Models.Branch branch, Models.GitFlowBranchType type) { _repo = repo; - _type = type; - _prefix = prefix; Branch = branch; + Type = type; } public override Task Sure() { _repo.SetWatcherEnabled(false); + ProgressDescription = $"Git Flow - Finish {Branch.Name} ..."; - var name = Branch.Name.StartsWith(_prefix) ? Branch.Name.Substring(_prefix.Length) : Branch.Name; - ProgressDescription = $"Git Flow - finishing {_type} {name} ..."; - - var log = _repo.CreateLog("Gitflow - Finish"); + var log = _repo.CreateLog("GitFlow - Finish"); Use(log); + var prefix = _repo.GitFlow.GetPrefix(Type); + var name = Branch.Name.StartsWith(prefix) ? Branch.Name.Substring(prefix.Length) : Branch.Name; + return Task.Run(() => { - var succ = Commands.GitFlow.Finish(_repo.FullPath, _type, name, Squash, AutoPush, KeepBranch, log); + var succ = Commands.GitFlow.Finish(_repo.FullPath, Type, name, Squash, AutoPush, KeepBranch, log); log.Complete(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; @@ -59,7 +61,5 @@ namespace SourceGit.ViewModels } private readonly Repository _repo; - private readonly string _type; - private readonly string _prefix; } } diff --git a/src/ViewModels/GitFlowStart.cs b/src/ViewModels/GitFlowStart.cs index 8e44984a..3ecba883 100644 --- a/src/ViewModels/GitFlowStart.cs +++ b/src/ViewModels/GitFlowStart.cs @@ -5,6 +5,18 @@ namespace SourceGit.ViewModels { public class GitFlowStart : Popup { + public Models.GitFlowBranchType Type + { + get; + private set; + } + + public string Prefix + { + get; + private set; + } + [Required(ErrorMessage = "Name is required!!!")] [RegularExpression(@"^[\w\-/\.#]+$", ErrorMessage = "Bad branch name format!")] [CustomValidation(typeof(GitFlowStart), nameof(ValidateBranchName))] @@ -14,27 +26,19 @@ namespace SourceGit.ViewModels set => SetProperty(ref _name, value, true); } - public string Prefix - { - get => _prefix; - } - - public bool IsFeature => _type == "feature"; - public bool IsRelease => _type == "release"; - public bool IsHotfix => _type == "hotfix"; - - public GitFlowStart(Repository repo, string type) + public GitFlowStart(Repository repo, Models.GitFlowBranchType type) { _repo = repo; - _type = type; - _prefix = Commands.GitFlow.GetPrefix(repo.FullPath, type); + + Type = type; + Prefix = _repo.GitFlow.GetPrefix(type); } public static ValidationResult ValidateBranchName(string name, ValidationContext ctx) { if (ctx.ObjectInstance is GitFlowStart starter) { - var check = $"{starter._prefix}{name}"; + var check = $"{starter.Prefix}{name}"; foreach (var b in starter._repo.Branches) { if (b.FriendlyName == check) @@ -48,14 +52,14 @@ namespace SourceGit.ViewModels public override Task Sure() { _repo.SetWatcherEnabled(false); - ProgressDescription = $"Git Flow - starting {_type} {_name} ..."; + ProgressDescription = $"Git Flow - Start {Prefix}{_name} ..."; - var log = _repo.CreateLog("Gitflow - Start"); + var log = _repo.CreateLog("GitFlow - Start"); Use(log); return Task.Run(() => { - var succ = Commands.GitFlow.Start(_repo.FullPath, _type, _name, log); + var succ = Commands.GitFlow.Start(_repo.FullPath, Type, _name, log); log.Complete(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; @@ -63,8 +67,6 @@ namespace SourceGit.ViewModels } private readonly Repository _repo; - private readonly string _type; - private readonly string _prefix; private string _name = null; } } diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 4bccfea7..2057a13f 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -975,8 +975,8 @@ namespace SourceGit.ViewModels if (!_repo.IsBare) { - var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, current.Name); - if (detect.IsGitFlowBranch) + var type = _repo.GetGitFlowType(current); + if (type != Models.GitFlowBranchType.None) { var finish = new MenuItem(); finish.Header = App.Text("BranchCM.Finish", current.Name); @@ -984,7 +984,7 @@ namespace SourceGit.ViewModels finish.Click += (_, e) => { if (_repo.CanCreatePopup()) - _repo.ShowPopup(new GitFlowFinish(_repo, current, detect.Type, detect.Prefix)); + _repo.ShowPopup(new GitFlowFinish(_repo, current, type)); e.Handled = true; }; submenu.Items.Add(finish); @@ -1063,8 +1063,8 @@ namespace SourceGit.ViewModels if (!_repo.IsBare) { - var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, branch.Name); - if (detect.IsGitFlowBranch) + var type = _repo.GetGitFlowType(branch); + if (type != Models.GitFlowBranchType.None) { var finish = new MenuItem(); finish.Header = App.Text("BranchCM.Finish", branch.Name); @@ -1072,7 +1072,7 @@ namespace SourceGit.ViewModels finish.Click += (_, e) => { if (_repo.CanCreatePopup()) - _repo.ShowPopup(new GitFlowFinish(_repo, branch, detect.Type, detect.Prefix)); + _repo.ShowPopup(new GitFlowFinish(_repo, branch, type)); e.Handled = true; }; submenu.Items.Add(finish); diff --git a/src/ViewModels/InitGitFlow.cs b/src/ViewModels/InitGitFlow.cs index 1672ef8e..7706375e 100644 --- a/src/ViewModels/InitGitFlow.cs +++ b/src/ViewModels/InitGitFlow.cs @@ -121,7 +121,23 @@ namespace SourceGit.ViewModels log); log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); + + CallUIThread(() => + { + if (succ) + { + var gitflow = new Models.GitFlow(); + gitflow.Master = _master; + gitflow.Develop = _develop; + gitflow.FeaturePrefix = _featurePrefix; + gitflow.ReleasePrefix = _releasePrefix; + gitflow.HotfixPrefix = _hotfixPrefix; + _repo.GitFlow = gitflow; + } + + _repo.SetWatcherEnabled(true); + }); + return succ; }); } diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index a209d8a7..c90cc88c 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -51,6 +51,12 @@ namespace SourceGit.ViewModels get => _settings; } + public Models.GitFlow GitFlow + { + get; + set; + } = new Models.GitFlow(); + public Models.FilterMode HistoriesFilterMode { get => _historiesFilterMode; @@ -595,6 +601,28 @@ namespace SourceGit.ViewModels GetOwnerPage()?.StartPopup(popup); } + public bool IsGitFlowEnabled() + { + return GitFlow is { IsValid: true } && + _branches.Find(x => x.IsLocal && x.Name.Equals(GitFlow.Master, StringComparison.Ordinal)) != null && + _branches.Find(x => x.IsLocal && x.Name.Equals(GitFlow.Develop, StringComparison.Ordinal)) != null; + } + + public Models.GitFlowBranchType GetGitFlowType(Models.Branch b) + { + if (!IsGitFlowEnabled()) + return Models.GitFlowBranchType.None; + + var name = b.Name; + if (name.StartsWith(GitFlow.FeaturePrefix, StringComparison.Ordinal)) + return Models.GitFlowBranchType.Feature; + if (name.StartsWith(GitFlow.ReleasePrefix, StringComparison.Ordinal)) + return Models.GitFlowBranchType.Release; + if (name.StartsWith(GitFlow.HotfixPrefix, StringComparison.Ordinal)) + return Models.GitFlowBranchType.Hotfix; + return Models.GitFlowBranchType.None; + } + public CommandLog CreateLog(string name) { var log = new CommandLog(name); @@ -606,8 +634,19 @@ namespace SourceGit.ViewModels { Task.Run(() => { - var allowedSignersFile = new Commands.Config(_fullpath).Get("gpg.ssh.allowedSignersFile"); - _hasAllowedSignersFile = !string.IsNullOrEmpty(allowedSignersFile); + var config = new Commands.Config(_fullpath).ListAll(); + _hasAllowedSignersFile = config.TryGetValue("gpg.ssh.allowedSignersFile", out var allowedSignersFile) && !string.IsNullOrEmpty(allowedSignersFile); + + if (config.TryGetValue("gitflow.branch.master", out var masterName)) + GitFlow.Master = masterName; + if (config.TryGetValue("gitflow.branch.develop", out var developName)) + GitFlow.Develop = developName; + if (config.TryGetValue("gitflow.prefix.feature", out var featurePrefix)) + GitFlow.FeaturePrefix = featurePrefix; + if (config.TryGetValue("gitflow.prefix.release", out var releasePrefix)) + GitFlow.ReleasePrefix = releasePrefix; + if (config.TryGetValue("gitflow.prefix.hotfix", out var hotfixPrefix)) + GitFlow.HotfixPrefix = hotfixPrefix; }); Task.Run(RefreshBranches); @@ -1377,8 +1416,7 @@ namespace SourceGit.ViewModels var menu = new ContextMenu(); menu.Placement = PlacementMode.BottomEdgeAlignedLeft; - var isGitFlowEnabled = Commands.GitFlow.IsEnabled(_fullpath, _branches); - if (isGitFlowEnabled) + if (IsGitFlowEnabled()) { var startFeature = new MenuItem(); startFeature.Header = App.Text("GitFlow.StartFeature"); @@ -1386,7 +1424,7 @@ namespace SourceGit.ViewModels startFeature.Click += (_, e) => { if (CanCreatePopup()) - ShowPopup(new GitFlowStart(this, "feature")); + ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Feature)); e.Handled = true; }; @@ -1396,7 +1434,7 @@ namespace SourceGit.ViewModels startRelease.Click += (_, e) => { if (CanCreatePopup()) - ShowPopup(new GitFlowStart(this, "release")); + ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Release)); e.Handled = true; }; @@ -1406,7 +1444,7 @@ namespace SourceGit.ViewModels startHotfix.Click += (_, e) => { if (CanCreatePopup()) - ShowPopup(new GitFlowStart(this, "hotfix")); + ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Hotfix)); e.Handled = true; }; @@ -1867,8 +1905,8 @@ namespace SourceGit.ViewModels if (!IsBare) { - var detect = Commands.GitFlow.DetectType(_fullpath, _branches, branch.Name); - if (detect.IsGitFlowBranch) + var type = GetGitFlowType(branch); + if (type != Models.GitFlowBranchType.None) { var finish = new MenuItem(); finish.Header = App.Text("BranchCM.Finish", branch.Name); @@ -1876,7 +1914,7 @@ namespace SourceGit.ViewModels finish.Click += (_, e) => { if (CanCreatePopup()) - ShowPopup(new GitFlowFinish(this, branch, detect.Type, detect.Prefix)); + ShowPopup(new GitFlowFinish(this, branch, type)); e.Handled = true; }; menu.Items.Add(new MenuItem() { Header = "-" }); diff --git a/src/Views/GitFlowFinish.axaml b/src/Views/GitFlowFinish.axaml index 6a16e95c..fa847bba 100644 --- a/src/Views/GitFlowFinish.axaml +++ b/src/Views/GitFlowFinish.axaml @@ -2,7 +2,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:m="using:SourceGit.Models" xmlns:vm="using:SourceGit.ViewModels" + xmlns:c="using:SourceGit.Converters" mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450" x:Class="SourceGit.Views.GitFlowFinish" x:DataType="vm:GitFlowFinish"> @@ -10,15 +12,15 @@ + IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:GitFlowBranchType.Feature}}"/> + IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:GitFlowBranchType.Release}}"/> + IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:GitFlowBranchType.Hotfix}}"/> @@ -11,15 +13,15 @@ + IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:GitFlowBranchType.Feature}}"/> + IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:GitFlowBranchType.Release}}"/> + IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:GitFlowBranchType.Hotfix}}"/>