diff --git a/src/Commands/GitFlow.cs b/src/Commands/GitFlow.cs index e47631c1..b115844d 100644 --- a/src/Commands/GitFlow.cs +++ b/src/Commands/GitFlow.cs @@ -1,90 +1,164 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Avalonia.Threading; namespace SourceGit.Commands { - public class GitFlow : Command + public static class GitFlow { - public GitFlow(string repo) + public class BranchDetectResult { - WorkingDirectory = repo; - Context = repo; + public bool IsGitFlowBranch { get; set; } = false; + public string Type { get; set; } = string.Empty; + public string Prefix { get; set; } = string.Empty; } - public bool Init(List branches, string master, string develop, string feature, string release, string hotfix, string version) + 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) { var current = branches.Find(x => x.IsCurrent); var masterBranch = branches.Find(x => x.Name == master); if (masterBranch == null && current != null) - Branch.Create(WorkingDirectory, master, current.Head); + Branch.Create(repo, master, current.Head); var devBranch = branches.Find(x => x.Name == develop); if (devBranch == null && current != null) - Branch.Create(WorkingDirectory, develop, current.Head); + Branch.Create(repo, develop, current.Head); - var cmd = new Config(WorkingDirectory); - cmd.Set("gitflow.branch.master", master); - cmd.Set("gitflow.branch.develop", develop); - cmd.Set("gitflow.prefix.feature", feature); - cmd.Set("gitflow.prefix.bugfix", "bugfix/"); - cmd.Set("gitflow.prefix.release", release); - cmd.Set("gitflow.prefix.hotfix", hotfix); - cmd.Set("gitflow.prefix.support", "support/"); - cmd.Set("gitflow.prefix.versiontag", version, true); + var config = new Config(repo); + config.Set("gitflow.branch.master", master); + config.Set("gitflow.branch.develop", develop); + config.Set("gitflow.prefix.feature", feature); + config.Set("gitflow.prefix.bugfix", "bugfix/"); + config.Set("gitflow.prefix.release", release); + config.Set("gitflow.prefix.hotfix", hotfix); + config.Set("gitflow.prefix.support", "support/"); + config.Set("gitflow.prefix.versiontag", version, true); - Args = "flow init -d"; - return Exec(); + var init = new Command(); + init.WorkingDirectory = repo; + init.Context = repo; + init.Args = "flow init -d"; + return init.Exec(); } - public bool Start(Models.GitFlowBranchType type, string name) + public static string Prefix(string repo, string type) { - switch (type) + 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) { - case Models.GitFlowBranchType.Feature: - Args = $"flow feature start {name}"; - break; - case Models.GitFlowBranchType.Release: - Args = $"flow release start {name}"; - break; - case Models.GitFlowBranchType.Hotfix: - Args = $"flow hotfix start {name}"; - break; - default: - Dispatcher.UIThread.Invoke(() => - { - App.RaiseException(Context, "Bad branch type!!!"); - }); - return false; + if (b.IsLocal) + localBrancheNames.Add(b.Name); } - return Exec(); + 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 bool Finish(Models.GitFlowBranchType type, string name, bool keepBranch) + public static bool Start(string repo, string type, string name) { + 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}"; + return start.Exec(); + } + + public static bool Finish(string repo, string type, string name, bool keepBranch) + { + if (!SUPPORTED_BRANCH_TYPES.Contains(type)) + { + Dispatcher.UIThread.Post(() => + { + App.RaiseException(repo, "Bad branch type!!!"); + }); + + return false; + } + var option = keepBranch ? "-k" : string.Empty; - switch (type) - { - case Models.GitFlowBranchType.Feature: - Args = $"flow feature finish {option} {name}"; - break; - case Models.GitFlowBranchType.Release: - Args = $"flow release finish {option} {name} -m \"RELEASE_DONE\""; - break; - case Models.GitFlowBranchType.Hotfix: - Args = $"flow hotfix finish {option} {name} -m \"HOTFIX_DONE\""; - break; - default: - Dispatcher.UIThread.Invoke(() => - { - App.RaiseException(Context, "Bad branch type!!!"); - }); - return false; - } - - return Exec(); + var finish = new Command(); + finish.WorkingDirectory = repo; + finish.Context = repo; + finish.Args = $"flow {type} finish {option} {name}"; + 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 deleted file mode 100644 index 9522236d..00000000 --- a/src/Models/GitFlow.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace SourceGit.Models -{ - public enum GitFlowBranchType - { - None, - Feature, - Release, - Hotfix, - } - - public class GitFlow - { - public string Feature { get; set; } - public string Release { get; set; } - public string Hotfix { get; set; } - - public bool IsEnabled - { - get - { - return !string.IsNullOrEmpty(Feature) - && !string.IsNullOrEmpty(Release) - && !string.IsNullOrEmpty(Hotfix); - } - } - - public GitFlowBranchType GetBranchType(string name) - { - if (!IsEnabled) - return GitFlowBranchType.None; - if (name.StartsWith(Feature)) - return GitFlowBranchType.Feature; - if (name.StartsWith(Release)) - return GitFlowBranchType.Release; - if (name.StartsWith(Hotfix)) - return GitFlowBranchType.Hotfix; - return GitFlowBranchType.None; - } - } -} diff --git a/src/ViewModels/GitFlowFinish.cs b/src/ViewModels/GitFlowFinish.cs index 1fad99ae..7db69366 100644 --- a/src/ViewModels/GitFlowFinish.cs +++ b/src/ViewModels/GitFlowFinish.cs @@ -4,10 +4,15 @@ namespace SourceGit.ViewModels { public class GitFlowFinish : Popup { - public Models.Branch Branch => _branch; - public bool IsFeature => _type == Models.GitFlowBranchType.Feature; - public bool IsRelease => _type == Models.GitFlowBranchType.Release; - public bool IsHotfix => _type == Models.GitFlowBranchType.Hotfix; + public Models.Branch Branch + { + get; + set; + } = null; + + public bool IsFeature => _type == "feature"; + public bool IsRelease => _type == "release"; + public bool IsHotfix => _type == "hotfix"; public bool KeepBranch { @@ -15,11 +20,13 @@ namespace SourceGit.ViewModels set; } = false; - public GitFlowFinish(Repository repo, Models.Branch branch, Models.GitFlowBranchType type) + public GitFlowFinish(Repository repo, Models.Branch branch, string type, string prefix) { _repo = repo; - _branch = branch; _type = type; + _prefix = prefix; + + Branch = branch; View = new Views.GitFlowFinish() { DataContext = this }; } @@ -28,29 +35,16 @@ namespace SourceGit.ViewModels _repo.SetWatcherEnabled(false); return Task.Run(() => { - var branch = _branch.Name; - switch (_type) - { - case Models.GitFlowBranchType.Feature: - branch = branch.Substring(_repo.GitFlow.Feature.Length); - break; - case Models.GitFlowBranchType.Release: - branch = branch.Substring(_repo.GitFlow.Release.Length); - break; - default: - branch = branch.Substring(_repo.GitFlow.Hotfix.Length); - break; - } - - SetProgressDescription($"Git Flow - finishing {_branch.Name} ..."); - var succ = new Commands.GitFlow(_repo.FullPath).Finish(_type, branch, KeepBranch); + var name = Branch.Name.StartsWith(_prefix) ? Branch.Name.Substring(_prefix.Length) : Branch.Name; + SetProgressDescription($"Git Flow - finishing {_type} {name} ..."); + var succ = Commands.GitFlow.Finish(_repo.FullPath, _type, name, KeepBranch); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } private readonly Repository _repo = null; - private readonly Models.Branch _branch = null; - private readonly Models.GitFlowBranchType _type = Models.GitFlowBranchType.None; + private readonly string _type = "feature"; + private readonly string _prefix = string.Empty; } } diff --git a/src/ViewModels/GitFlowStart.cs b/src/ViewModels/GitFlowStart.cs index 33fa3cf4..0806dfb4 100644 --- a/src/ViewModels/GitFlowStart.cs +++ b/src/ViewModels/GitFlowStart.cs @@ -19,27 +19,15 @@ namespace SourceGit.ViewModels get => _prefix; } - public bool IsFeature => _type == Models.GitFlowBranchType.Feature; - public bool IsRelease => _type == Models.GitFlowBranchType.Release; - public bool IsHotfix => _type == Models.GitFlowBranchType.Hotfix; + public bool IsFeature => _type == "feature"; + public bool IsRelease => _type == "release"; + public bool IsHotfix => _type == "hotfix"; - public GitFlowStart(Repository repo, Models.GitFlowBranchType type) + public GitFlowStart(Repository repo, string type) { _repo = repo; _type = type; - - switch (type) - { - case Models.GitFlowBranchType.Feature: - _prefix = repo.GitFlow.Feature; - break; - case Models.GitFlowBranchType.Release: - _prefix = repo.GitFlow.Release; - break; - default: - _prefix = repo.GitFlow.Hotfix; - break; - } + _prefix = Commands.GitFlow.Prefix(repo.FullPath, type); View = new Views.GitFlowStart() { DataContext = this }; } @@ -65,15 +53,15 @@ namespace SourceGit.ViewModels _repo.SetWatcherEnabled(false); return Task.Run(() => { - SetProgressDescription($"Git Flow - starting {_prefix}{_name} ..."); - var succ = new Commands.GitFlow(_repo.FullPath).Start(_type, _name); + SetProgressDescription($"Git Flow - starting {_type} {_name} ..."); + var succ = Commands.GitFlow.Start(_repo.FullPath, _type, _name); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } private readonly Repository _repo = null; - private readonly Models.GitFlowBranchType _type = Models.GitFlowBranchType.Feature; + private readonly string _type = "feature"; private readonly string _prefix = string.Empty; private string _name = null; } diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 1b740f1d..c536731c 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -451,8 +451,8 @@ namespace SourceGit.ViewModels submenu.Items.Add(push); submenu.Items.Add(new MenuItem() { Header = "-" }); - var type = _repo.GitFlow.GetBranchType(current.Name); - if (type != Models.GitFlowBranchType.None) + var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, current.Name); + if (detect.IsGitFlowBranch) { var finish = new MenuItem(); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", current.Name); @@ -460,7 +460,7 @@ namespace SourceGit.ViewModels finish.Click += (o, e) => { if (PopupHost.CanCreatePopup()) - PopupHost.ShowPopup(new GitFlowFinish(_repo, current, type)); + PopupHost.ShowPopup(new GitFlowFinish(_repo, current, detect.Type, detect.Prefix)); e.Handled = true; }; submenu.Items.Add(finish); @@ -510,8 +510,8 @@ namespace SourceGit.ViewModels submenu.Items.Add(merge); submenu.Items.Add(new MenuItem() { Header = "-" }); - var type = _repo.GitFlow.GetBranchType(branch.Name); - if (type != Models.GitFlowBranchType.None) + var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, branch.Name); + if (detect.IsGitFlowBranch) { var finish = new MenuItem(); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); @@ -519,7 +519,7 @@ namespace SourceGit.ViewModels finish.Click += (o, e) => { if (PopupHost.CanCreatePopup()) - PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, type)); + PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, detect.Type, detect.Prefix)); e.Handled = true; }; submenu.Items.Add(finish); diff --git a/src/ViewModels/InitGitFlow.cs b/src/ViewModels/InitGitFlow.cs index 3faf5e61..9e58f4bd 100644 --- a/src/ViewModels/InitGitFlow.cs +++ b/src/ViewModels/InitGitFlow.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -6,7 +7,6 @@ namespace SourceGit.ViewModels { public partial class InitGitFlow : Popup { - [GeneratedRegex(@"^[\w\-/\.]+$")] private static partial Regex TAG_PREFIX(); @@ -62,6 +62,23 @@ namespace SourceGit.ViewModels public InitGitFlow(Repository repo) { _repo = repo; + + var localBranches = new List(); + foreach (var branch in repo.Branches) + { + if (branch.IsLocal) + localBranches.Add(branch.Name); + } + + if (localBranches.Contains("master")) + _master = "master"; + else if (localBranches.Contains("main")) + _master = "main"; + else if (localBranches.Count > 0) + _master = localBranches[0]; + else + _master = "master"; + View = new Views.InitGitFlow() { DataContext = this }; } @@ -79,9 +96,7 @@ namespace SourceGit.ViewModels public static ValidationResult ValidateTagPrefix(string tagPrefix, ValidationContext ctx) { if (!string.IsNullOrWhiteSpace(tagPrefix) && !TAG_PREFIX().IsMatch(tagPrefix)) - { return new ValidationResult("Bad tag prefix format!"); - } return ValidationResult.Success; } @@ -93,14 +108,7 @@ namespace SourceGit.ViewModels return Task.Run(() => { - var succ = new Commands.GitFlow(_repo.FullPath).Init(_repo.Branches, _master, _develop, _featurePrefix, _releasePrefix, _hotfixPrefix, _tagPrefix); - if (succ) - { - _repo.GitFlow.Feature = _featurePrefix; - _repo.GitFlow.Release = _releasePrefix; - _repo.GitFlow.Hotfix = _hotfixPrefix; - } - + var succ = Commands.GitFlow.Init(_repo.FullPath, _repo.Branches, _master, _develop, _featurePrefix, _releasePrefix, _hotfixPrefix, _tagPrefix); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index e9468494..4eb6c5fc 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -51,13 +51,6 @@ namespace SourceGit.ViewModels set; } = new AvaloniaList(); - [JsonIgnore] - public Models.GitFlow GitFlow - { - get => _gitflow; - set => SetProperty(ref _gitflow, value); - } - [JsonIgnore] public int SelectedViewIndex { @@ -298,7 +291,6 @@ namespace SourceGit.ViewModels Task.Run(RefreshSubmodules); Task.Run(RefreshWorkingCopyChanges); Task.Run(RefreshStashes); - Task.Run(RefreshGitFlow); } public void OpenInFileManager() @@ -697,22 +689,6 @@ namespace SourceGit.ViewModels }); } - public void RefreshGitFlow() - { - var config = new Commands.Config(_fullpath).ListAll(); - var gitFlow = new Models.GitFlow(); - if (config.TryGetValue("gitflow.prefix.feature", out var feature)) - gitFlow.Feature = feature; - if (config.TryGetValue("gitflow.prefix.release", out var release)) - gitFlow.Release = release; - if (config.TryGetValue("gitflow.prefix.hotfix", out var hotfix)) - gitFlow.Hotfix = hotfix; - Dispatcher.UIThread.Invoke(() => - { - GitFlow = gitFlow; - }); - } - public void CreateNewBranch() { var current = Branches.Find(x => x.IsCurrent); @@ -797,7 +773,8 @@ namespace SourceGit.ViewModels var menu = new ContextMenu(); menu.Placement = PlacementMode.BottomEdgeAlignedLeft; - if (GitFlow.IsEnabled) + var isGitFlowEnabled = Commands.GitFlow.IsEnabled(_fullpath, _branches); + if (isGitFlowEnabled) { var startFeature = new MenuItem(); startFeature.Header = App.Text("GitFlow.StartFeature"); @@ -805,7 +782,7 @@ namespace SourceGit.ViewModels startFeature.Click += (o, e) => { if (PopupHost.CanCreatePopup()) - PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Feature)); + PopupHost.ShowPopup(new GitFlowStart(this, "feature")); e.Handled = true; }; @@ -815,7 +792,7 @@ namespace SourceGit.ViewModels startRelease.Click += (o, e) => { if (PopupHost.CanCreatePopup()) - PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Release)); + PopupHost.ShowPopup(new GitFlowStart(this, "release")); e.Handled = true; }; @@ -825,7 +802,7 @@ namespace SourceGit.ViewModels startHotfix.Click += (o, e) => { if (PopupHost.CanCreatePopup()) - PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Hotfix)); + PopupHost.ShowPopup(new GitFlowStart(this, "hotfix")); e.Handled = true; }; @@ -1005,8 +982,8 @@ namespace SourceGit.ViewModels } } - var type = GitFlow.GetBranchType(branch.Name); - if (type != Models.GitFlowBranchType.None) + var detect = Commands.GitFlow.DetectType(_fullpath, _branches, branch.Name); + if (detect.IsGitFlowBranch) { var finish = new MenuItem(); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); @@ -1014,7 +991,7 @@ namespace SourceGit.ViewModels finish.Click += (o, e) => { if (PopupHost.CanCreatePopup()) - PopupHost.ShowPopup(new GitFlowFinish(this, branch, type)); + PopupHost.ShowPopup(new GitFlowFinish(this, branch, detect.Type, detect.Prefix)); e.Handled = true; }; menu.Items.Add(new MenuItem() { Header = "-" }); @@ -1532,7 +1509,6 @@ namespace SourceGit.ViewModels private string _fullpath = string.Empty; private string _gitDir = string.Empty; - private Models.GitFlow _gitflow = new Models.GitFlow(); private Models.Watcher _watcher = null; private Histories _histories = null;