refactor: git-flow supports.

This commit is contained in:
leo 2024-06-15 12:44:35 +08:00
parent 5bb41ed65f
commit 6de92bb4d8
No known key found for this signature in database
GPG key ID: B528468E49CD0E58
7 changed files with 192 additions and 192 deletions

View file

@ -1,90 +1,164 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using Avalonia.Threading; using Avalonia.Threading;
namespace SourceGit.Commands namespace SourceGit.Commands
{ {
public class GitFlow : Command public static class GitFlow
{ {
public GitFlow(string repo) public class BranchDetectResult
{ {
WorkingDirectory = repo; public bool IsGitFlowBranch { get; set; } = false;
Context = repo; public string Type { get; set; } = string.Empty;
public string Prefix { get; set; } = string.Empty;
} }
public bool Init(List<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version) public static bool IsEnabled(string repo, List<Models.Branch> branches)
{
var localBrancheNames = new HashSet<string>();
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<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version)
{ {
var current = branches.Find(x => x.IsCurrent); var current = branches.Find(x => x.IsCurrent);
var masterBranch = branches.Find(x => x.Name == master); var masterBranch = branches.Find(x => x.Name == master);
if (masterBranch == null && current != null) 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); var devBranch = branches.Find(x => x.Name == develop);
if (devBranch == null && current != null) if (devBranch == null && current != null)
Branch.Create(WorkingDirectory, develop, current.Head); Branch.Create(repo, develop, current.Head);
var cmd = new Config(WorkingDirectory); var config = new Config(repo);
cmd.Set("gitflow.branch.master", master); config.Set("gitflow.branch.master", master);
cmd.Set("gitflow.branch.develop", develop); config.Set("gitflow.branch.develop", develop);
cmd.Set("gitflow.prefix.feature", feature); config.Set("gitflow.prefix.feature", feature);
cmd.Set("gitflow.prefix.bugfix", "bugfix/"); config.Set("gitflow.prefix.bugfix", "bugfix/");
cmd.Set("gitflow.prefix.release", release); config.Set("gitflow.prefix.release", release);
cmd.Set("gitflow.prefix.hotfix", hotfix); config.Set("gitflow.prefix.hotfix", hotfix);
cmd.Set("gitflow.prefix.support", "support/"); config.Set("gitflow.prefix.support", "support/");
cmd.Set("gitflow.prefix.versiontag", version, true); config.Set("gitflow.prefix.versiontag", version, true);
Args = "flow init -d"; var init = new Command();
return Exec(); 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<Models.Branch> branches, string branch)
{ {
case Models.GitFlowBranchType.Feature: var rs = new BranchDetectResult();
Args = $"flow feature start {name}"; var localBrancheNames = new HashSet<string>();
break; foreach (var b in branches)
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!!!"); 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)
{
if (!SUPPORTED_BRANCH_TYPES.Contains(type))
{
Dispatcher.UIThread.Post(() =>
{
App.RaiseException(repo, "Bad branch type!!!");
}); });
return false; return false;
} }
return Exec(); var start = new Command();
start.WorkingDirectory = repo;
start.Context = repo;
start.Args = $"flow {type} start {name}";
return start.Exec();
} }
public bool Finish(Models.GitFlowBranchType type, string name, bool keepBranch) 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; var option = keepBranch ? "-k" : string.Empty;
switch (type) var finish = new Command();
{ finish.WorkingDirectory = repo;
case Models.GitFlowBranchType.Feature: finish.Context = repo;
Args = $"flow feature finish {option} {name}"; finish.Args = $"flow {type} finish {option} {name}";
break; return finish.Exec();
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(); private static readonly List<string> SUPPORTED_BRANCH_TYPES = new List<string>()
} {
"feature",
"release",
"bugfix",
"hotfix",
"support",
};
} }
} }

View file

@ -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;
}
}
}

View file

@ -4,10 +4,15 @@ namespace SourceGit.ViewModels
{ {
public class GitFlowFinish : Popup public class GitFlowFinish : Popup
{ {
public Models.Branch Branch => _branch; public Models.Branch Branch
public bool IsFeature => _type == Models.GitFlowBranchType.Feature; {
public bool IsRelease => _type == Models.GitFlowBranchType.Release; get;
public bool IsHotfix => _type == Models.GitFlowBranchType.Hotfix; set;
} = null;
public bool IsFeature => _type == "feature";
public bool IsRelease => _type == "release";
public bool IsHotfix => _type == "hotfix";
public bool KeepBranch public bool KeepBranch
{ {
@ -15,11 +20,13 @@ namespace SourceGit.ViewModels
set; set;
} = false; } = false;
public GitFlowFinish(Repository repo, Models.Branch branch, Models.GitFlowBranchType type) public GitFlowFinish(Repository repo, Models.Branch branch, string type, string prefix)
{ {
_repo = repo; _repo = repo;
_branch = branch;
_type = type; _type = type;
_prefix = prefix;
Branch = branch;
View = new Views.GitFlowFinish() { DataContext = this }; View = new Views.GitFlowFinish() { DataContext = this };
} }
@ -28,29 +35,16 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false); _repo.SetWatcherEnabled(false);
return Task.Run(() => return Task.Run(() =>
{ {
var branch = _branch.Name; var name = Branch.Name.StartsWith(_prefix) ? Branch.Name.Substring(_prefix.Length) : Branch.Name;
switch (_type) SetProgressDescription($"Git Flow - finishing {_type} {name} ...");
{ var succ = Commands.GitFlow.Finish(_repo.FullPath, _type, name, KeepBranch);
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);
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ; return succ;
}); });
} }
private readonly Repository _repo = null; private readonly Repository _repo = null;
private readonly Models.Branch _branch = null; private readonly string _type = "feature";
private readonly Models.GitFlowBranchType _type = Models.GitFlowBranchType.None; private readonly string _prefix = string.Empty;
} }
} }

View file

@ -19,27 +19,15 @@ namespace SourceGit.ViewModels
get => _prefix; get => _prefix;
} }
public bool IsFeature => _type == Models.GitFlowBranchType.Feature; public bool IsFeature => _type == "feature";
public bool IsRelease => _type == Models.GitFlowBranchType.Release; public bool IsRelease => _type == "release";
public bool IsHotfix => _type == Models.GitFlowBranchType.Hotfix; public bool IsHotfix => _type == "hotfix";
public GitFlowStart(Repository repo, Models.GitFlowBranchType type) public GitFlowStart(Repository repo, string type)
{ {
_repo = repo; _repo = repo;
_type = type; _type = type;
_prefix = Commands.GitFlow.Prefix(repo.FullPath, 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;
}
View = new Views.GitFlowStart() { DataContext = this }; View = new Views.GitFlowStart() { DataContext = this };
} }
@ -65,15 +53,15 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false); _repo.SetWatcherEnabled(false);
return Task.Run(() => return Task.Run(() =>
{ {
SetProgressDescription($"Git Flow - starting {_prefix}{_name} ..."); SetProgressDescription($"Git Flow - starting {_type} {_name} ...");
var succ = new Commands.GitFlow(_repo.FullPath).Start(_type, _name); var succ = Commands.GitFlow.Start(_repo.FullPath, _type, _name);
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ; return succ;
}); });
} }
private readonly Repository _repo = null; 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 readonly string _prefix = string.Empty;
private string _name = null; private string _name = null;
} }

View file

@ -451,8 +451,8 @@ namespace SourceGit.ViewModels
submenu.Items.Add(push); submenu.Items.Add(push);
submenu.Items.Add(new MenuItem() { Header = "-" }); submenu.Items.Add(new MenuItem() { Header = "-" });
var type = _repo.GitFlow.GetBranchType(current.Name); var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, current.Name);
if (type != Models.GitFlowBranchType.None) if (detect.IsGitFlowBranch)
{ {
var finish = new MenuItem(); var finish = new MenuItem();
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", current.Name); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", current.Name);
@ -460,7 +460,7 @@ namespace SourceGit.ViewModels
finish.Click += (o, e) => finish.Click += (o, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowFinish(_repo, current, type)); PopupHost.ShowPopup(new GitFlowFinish(_repo, current, detect.Type, detect.Prefix));
e.Handled = true; e.Handled = true;
}; };
submenu.Items.Add(finish); submenu.Items.Add(finish);
@ -510,8 +510,8 @@ namespace SourceGit.ViewModels
submenu.Items.Add(merge); submenu.Items.Add(merge);
submenu.Items.Add(new MenuItem() { Header = "-" }); submenu.Items.Add(new MenuItem() { Header = "-" });
var type = _repo.GitFlow.GetBranchType(branch.Name); var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, branch.Name);
if (type != Models.GitFlowBranchType.None) if (detect.IsGitFlowBranch)
{ {
var finish = new MenuItem(); var finish = new MenuItem();
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name);
@ -519,7 +519,7 @@ namespace SourceGit.ViewModels
finish.Click += (o, e) => finish.Click += (o, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, type)); PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, detect.Type, detect.Prefix));
e.Handled = true; e.Handled = true;
}; };
submenu.Items.Add(finish); submenu.Items.Add(finish);

View file

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -6,7 +7,6 @@ namespace SourceGit.ViewModels
{ {
public partial class InitGitFlow : Popup public partial class InitGitFlow : Popup
{ {
[GeneratedRegex(@"^[\w\-/\.]+$")] [GeneratedRegex(@"^[\w\-/\.]+$")]
private static partial Regex TAG_PREFIX(); private static partial Regex TAG_PREFIX();
@ -62,6 +62,23 @@ namespace SourceGit.ViewModels
public InitGitFlow(Repository repo) public InitGitFlow(Repository repo)
{ {
_repo = repo; _repo = repo;
var localBranches = new List<string>();
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 }; View = new Views.InitGitFlow() { DataContext = this };
} }
@ -79,9 +96,7 @@ namespace SourceGit.ViewModels
public static ValidationResult ValidateTagPrefix(string tagPrefix, ValidationContext ctx) public static ValidationResult ValidateTagPrefix(string tagPrefix, ValidationContext ctx)
{ {
if (!string.IsNullOrWhiteSpace(tagPrefix) && !TAG_PREFIX().IsMatch(tagPrefix)) if (!string.IsNullOrWhiteSpace(tagPrefix) && !TAG_PREFIX().IsMatch(tagPrefix))
{
return new ValidationResult("Bad tag prefix format!"); return new ValidationResult("Bad tag prefix format!");
}
return ValidationResult.Success; return ValidationResult.Success;
} }
@ -93,14 +108,7 @@ namespace SourceGit.ViewModels
return Task.Run(() => return Task.Run(() =>
{ {
var succ = new Commands.GitFlow(_repo.FullPath).Init(_repo.Branches, _master, _develop, _featurePrefix, _releasePrefix, _hotfixPrefix, _tagPrefix); var succ = Commands.GitFlow.Init(_repo.FullPath, _repo.Branches, _master, _develop, _featurePrefix, _releasePrefix, _hotfixPrefix, _tagPrefix);
if (succ)
{
_repo.GitFlow.Feature = _featurePrefix;
_repo.GitFlow.Release = _releasePrefix;
_repo.GitFlow.Hotfix = _hotfixPrefix;
}
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ; return succ;
}); });

View file

@ -51,13 +51,6 @@ namespace SourceGit.ViewModels
set; set;
} = new AvaloniaList<string>(); } = new AvaloniaList<string>();
[JsonIgnore]
public Models.GitFlow GitFlow
{
get => _gitflow;
set => SetProperty(ref _gitflow, value);
}
[JsonIgnore] [JsonIgnore]
public int SelectedViewIndex public int SelectedViewIndex
{ {
@ -298,7 +291,6 @@ namespace SourceGit.ViewModels
Task.Run(RefreshSubmodules); Task.Run(RefreshSubmodules);
Task.Run(RefreshWorkingCopyChanges); Task.Run(RefreshWorkingCopyChanges);
Task.Run(RefreshStashes); Task.Run(RefreshStashes);
Task.Run(RefreshGitFlow);
} }
public void OpenInFileManager() 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() public void CreateNewBranch()
{ {
var current = Branches.Find(x => x.IsCurrent); var current = Branches.Find(x => x.IsCurrent);
@ -797,7 +773,8 @@ namespace SourceGit.ViewModels
var menu = new ContextMenu(); var menu = new ContextMenu();
menu.Placement = PlacementMode.BottomEdgeAlignedLeft; menu.Placement = PlacementMode.BottomEdgeAlignedLeft;
if (GitFlow.IsEnabled) var isGitFlowEnabled = Commands.GitFlow.IsEnabled(_fullpath, _branches);
if (isGitFlowEnabled)
{ {
var startFeature = new MenuItem(); var startFeature = new MenuItem();
startFeature.Header = App.Text("GitFlow.StartFeature"); startFeature.Header = App.Text("GitFlow.StartFeature");
@ -805,7 +782,7 @@ namespace SourceGit.ViewModels
startFeature.Click += (o, e) => startFeature.Click += (o, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Feature)); PopupHost.ShowPopup(new GitFlowStart(this, "feature"));
e.Handled = true; e.Handled = true;
}; };
@ -815,7 +792,7 @@ namespace SourceGit.ViewModels
startRelease.Click += (o, e) => startRelease.Click += (o, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Release)); PopupHost.ShowPopup(new GitFlowStart(this, "release"));
e.Handled = true; e.Handled = true;
}; };
@ -825,7 +802,7 @@ namespace SourceGit.ViewModels
startHotfix.Click += (o, e) => startHotfix.Click += (o, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Hotfix)); PopupHost.ShowPopup(new GitFlowStart(this, "hotfix"));
e.Handled = true; e.Handled = true;
}; };
@ -1005,8 +982,8 @@ namespace SourceGit.ViewModels
} }
} }
var type = GitFlow.GetBranchType(branch.Name); var detect = Commands.GitFlow.DetectType(_fullpath, _branches, branch.Name);
if (type != Models.GitFlowBranchType.None) if (detect.IsGitFlowBranch)
{ {
var finish = new MenuItem(); var finish = new MenuItem();
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name);
@ -1014,7 +991,7 @@ namespace SourceGit.ViewModels
finish.Click += (o, e) => finish.Click += (o, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowFinish(this, branch, type)); PopupHost.ShowPopup(new GitFlowFinish(this, branch, detect.Type, detect.Prefix));
e.Handled = true; e.Handled = true;
}; };
menu.Items.Add(new MenuItem() { Header = "-" }); menu.Items.Add(new MenuItem() { Header = "-" });
@ -1532,7 +1509,6 @@ namespace SourceGit.ViewModels
private string _fullpath = string.Empty; private string _fullpath = string.Empty;
private string _gitDir = string.Empty; private string _gitDir = string.Empty;
private Models.GitFlow _gitflow = new Models.GitFlow();
private Models.Watcher _watcher = null; private Models.Watcher _watcher = null;
private Histories _histories = null; private Histories _histories = null;