Skip to content

Commit a36058e

Browse files
committed
feature: supports custom actions (#638)
Signed-off-by: leo <[email protected]>
1 parent 7c5de7e commit a36058e

17 files changed

+478
-2
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Text;
4+
5+
using Avalonia.Threading;
6+
7+
namespace SourceGit.Commands
8+
{
9+
public static class ExecuteCustomAction
10+
{
11+
public static void Run(string repo, string file, string args, Action<string> outputHandler)
12+
{
13+
var start = new ProcessStartInfo();
14+
start.FileName = file;
15+
start.Arguments = args;
16+
start.UseShellExecute = false;
17+
start.CreateNoWindow = true;
18+
start.RedirectStandardOutput = true;
19+
start.RedirectStandardError = true;
20+
start.StandardOutputEncoding = Encoding.UTF8;
21+
start.StandardErrorEncoding = Encoding.UTF8;
22+
start.WorkingDirectory = repo;
23+
24+
// Force using en_US.UTF-8 locale to avoid GCM crash
25+
if (OperatingSystem.IsLinux())
26+
start.Environment.Add("LANG", "en_US.UTF-8");
27+
28+
// Fix macOS `PATH` env
29+
if (OperatingSystem.IsMacOS() && !string.IsNullOrEmpty(Native.OS.CustomPathEnv))
30+
start.Environment.Add("PATH", Native.OS.CustomPathEnv);
31+
32+
var proc = new Process() { StartInfo = start };
33+
proc.OutputDataReceived += (_, e) =>
34+
{
35+
if (e.Data != null)
36+
outputHandler?.Invoke(e.Data);
37+
};
38+
39+
proc.ErrorDataReceived += (_, e) =>
40+
{
41+
if (e.Data != null)
42+
outputHandler?.Invoke(e.Data);
43+
};
44+
45+
try
46+
{
47+
proc.Start();
48+
}
49+
catch (Exception e)
50+
{
51+
Dispatcher.UIThread.Invoke(() =>
52+
{
53+
App.RaiseException(repo, e.Message);
54+
});
55+
}
56+
57+
proc.BeginOutputReadLine();
58+
proc.BeginErrorReadLine();
59+
proc.WaitForExit();
60+
proc.Close();
61+
}
62+
}
63+
}

src/Models/CustomAction.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
3+
namespace SourceGit.Models
4+
{
5+
public enum CustomActionScope
6+
{
7+
Repository,
8+
Commit,
9+
}
10+
11+
public class CustomAction : ObservableObject
12+
{
13+
public string Name
14+
{
15+
get => _name;
16+
set => SetProperty(ref _name, value);
17+
}
18+
19+
public CustomActionScope Scope
20+
{
21+
get => _scope;
22+
set => SetProperty(ref _scope, value);
23+
}
24+
25+
public string Executable
26+
{
27+
get => _executable;
28+
set => SetProperty(ref _executable, value);
29+
}
30+
31+
public string Arguments
32+
{
33+
get => _arguments;
34+
set => SetProperty(ref _arguments, value);
35+
}
36+
37+
private string _name = string.Empty;
38+
private CustomActionScope _scope = CustomActionScope.Repository;
39+
private string _executable = string.Empty;
40+
private string _arguments = string.Empty;
41+
}
42+
}

src/Models/RepositorySettings.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ public AvaloniaList<IssueTrackerRule> IssueTrackerRules
100100
set;
101101
} = new AvaloniaList<IssueTrackerRule>();
102102

103+
public AvaloniaList<CustomAction> CustomActions
104+
{
105+
get;
106+
set;
107+
} = new AvaloniaList<CustomAction>();
108+
103109
public bool EnableAutoFetch
104110
{
105111
get;
@@ -230,5 +236,22 @@ public void RemoveIssueTracker(IssueTrackerRule rule)
230236
if (rule != null)
231237
IssueTrackerRules.Remove(rule);
232238
}
239+
240+
public CustomAction AddNewCustomAction()
241+
{
242+
var act = new CustomAction()
243+
{
244+
Name = "Unnamed Custom Action",
245+
};
246+
247+
CustomActions.Add(act);
248+
return act;
249+
}
250+
251+
public void RemoveCustomAction(CustomAction act)
252+
{
253+
if (act != null)
254+
CustomActions.Remove(act);
255+
}
233256
}
234257
}

src/Resources/Icons.axaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
2+
<StreamGeometry x:Key="Icons.Action">M41 512c0-128 46-241 138-333C271 87 384 41 512 41s241 46 333 138c92 92 138 205 138 333s-46 241-138 333c-92 92-205 138-333 138s-241-46-333-138C87 753 41 640 41 512zm87 0c0 108 36 195 113 271s164 113 271 113c108 0 195-36 271-113s113-164 113-271-36-195-113-271c-77-77-164-113-271-113-108 0-195 36-271 113C164 317 128 404 128 512zm256 148V292l195 113L768 512l-195 113-195 113v-77zm148-113-61 36V440l61 36 61 36-61 36z</StreamGeometry>
23
<StreamGeometry x:Key="Icons.AIAssist">M951 419a255 255 0 00-22-209 258 258 0 00-278-124A259 259 0 00213 178a255 255 0 00-171 124 258 258 0 0032 303 255 255 0 0022 210 258 258 0 00278 124A255 255 0 00566 1024a258 258 0 00246-179 256 256 0 00171-124 258 258 0 00-32-302zM566 957a191 191 0 01-123-44l6-3 204-118a34 34 0 0017-29v-287l86 50a3 3 0 012 2v238a192 192 0 01-192 192zM154 781a191 191 0 01-23-129l6 4 204 118a33 33 0 0033 0l249-144v99a3 3 0 01-1 3L416 851a192 192 0 01-262-70zM100 337a191 191 0 01101-84V495a33 33 0 0017 29l248 143-86 50a3 3 0 01-3 0l-206-119A192 192 0 01100 336zm708 164-249-145L645 307a3 3 0 013 0l206 119a192 192 0 01-29 346v-242a34 34 0 00-17-28zm86-129-6-4-204-119a33 33 0 00-33 0L401 394V294a3 3 0 011-3l206-119a192 192 0 01285 199zm-539 176-86-50a3 3 0 01-2-2V259a192 192 0 01315-147l-6 3-204 118a34 34 0 00-17 29zm47-101 111-64 111 64v128l-111 64-111-64z</StreamGeometry>
34
<StreamGeometry x:Key="Icons.Archive">M296 392h64v64h-64zM296 582v160h128V582h-64v-62h-64v62zm80 48v64h-32v-64h32zM360 328h64v64h-64zM296 264h64v64h-64zM360 456h64v64h-64zM360 200h64v64h-64zM855 289 639 73c-6-6-14-9-23-9H192c-18 0-32 14-32 32v832c0 18 14 32 32 32h640c18 0 32-14 32-32V311c0-9-3-17-9-23zM790 326H602V138L790 326zm2 562H232V136h64v64h64v-64h174v216c0 23 19 42 42 42h216v494z</StreamGeometry>
45
<StreamGeometry x:Key="Icons.Binary">M71 1024V0h661L953 219V1024H71zm808-731-220-219H145V951h735V293zM439 512h-220V219h220V512zm-74-219H292v146h74v-146zm0 512h74v73h-220v-73H292v-146H218V585h147v219zm294-366h74V512H512v-73h74v-146H512V219h147v219zm74 439H512V585h220v293zm-74-219h-74v146h74v-146z</StreamGeometry>

src/Resources/Locales/en_US.axaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Compare with Worktree</x:String>
109109
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Copy Info</x:String>
110110
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copy SHA</x:String>
111+
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Custom Action</x:String>
111112
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Interactive Rebase ${0}$ to Here</x:String>
112113
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Rebase ${0}$ to Here</x:String>
113114
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Reset ${0}$ to Here</x:String>
@@ -139,6 +140,14 @@
139140
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">COMMIT TEMPLATE</x:String>
140141
<x:String x:Key="Text.Configure.CommitMessageTemplate.Name" xml:space="preserve">Template Name:</x:String>
141142
<x:String x:Key="Text.Configure.CommitMessageTemplate.Content" xml:space="preserve">Template Content:</x:String>
143+
<x:String x:Key="Text.Configure.CustomAction" xml:space="preserve">CUSTOM ACTION</x:String>
144+
<x:String x:Key="Text.Configure.CustomAction.Arguments" xml:space="preserve">Arguments:</x:String>
145+
<x:String x:Key="Text.Configure.CustomAction.Arguments.Tip" xml:space="preserve">${REPO} - Repository's path; ${SHA} - Selected commit's SHA</x:String>
146+
<x:String x:Key="Text.Configure.CustomAction.Executable" xml:space="preserve">Executable File:</x:String>
147+
<x:String x:Key="Text.Configure.CustomAction.Name" xml:space="preserve">Name:</x:String>
148+
<x:String x:Key="Text.Configure.CustomAction.Scope" xml:space="preserve">Scope:</x:String>
149+
<x:String x:Key="Text.Configure.CustomAction.Scope.Commit" xml:space="preserve">Commit</x:String>
150+
<x:String x:Key="Text.Configure.CustomAction.Scope.Repository" xml:space="preserve">Repository</x:String>
142151
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Address</x:String>
143152
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email address</x:String>
144153
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
@@ -252,6 +261,8 @@
252261
<x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">Target:</x:String>
253262
<x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">Edit Selected Group</x:String>
254263
<x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">Edit Selected Repository</x:String>
264+
<x:String x:Key="Text.ExecuteCustomAction" xml:space="preserve">Run Custom Action</x:String>
265+
<x:String x:Key="Text.ExecuteCustomAction.Name" xml:space="preserve">Action Name:</x:String>
255266
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Fast-Forward (without checkout)</x:String>
256267
<x:String x:Key="Text.Fetch" xml:space="preserve">Fetch</x:String>
257268
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Fetch all remotes</x:String>
@@ -516,6 +527,8 @@
516527
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Clear all</x:String>
517528
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Configure this repository</x:String>
518529
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">CONTINUE</x:String>
530+
<x:String x:Key="Text.Repository.CustomActions" xml:space="preserve">Custom Actions</x:String>
531+
<x:String x:Key="Text.Repository.CustomActions.Empty" xml:space="preserve">No Custom Actions</x:String>
519532
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Enable '--reflog' Option</x:String>
520533
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Open In File Browser</x:String>
521534
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Search Branches/Tags/Submodules</x:String>

src/Resources/Locales/zh_CN.axaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">与本地工作树比较</x:String>
112112
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">复制简要信息</x:String>
113113
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">复制提交指纹</x:String>
114+
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">自定义操作</x:String>
114115
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">交互式变基(rebase -i) ${0}$ 到此处</x:String>
115116
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">变基(rebase) ${0}$ 到此处</x:String>
116117
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">重置(reset) ${0}$ 到此处</x:String>
@@ -142,6 +143,14 @@
142143
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">提交信息模板</x:String>
143144
<x:String x:Key="Text.Configure.CommitMessageTemplate.Name" xml:space="preserve">模板名 :</x:String>
144145
<x:String x:Key="Text.Configure.CommitMessageTemplate.Content" xml:space="preserve">模板内容 :</x:String>
146+
<x:String x:Key="Text.Configure.CustomAction" xml:space="preserve">自定义操作</x:String>
147+
<x:String x:Key="Text.Configure.CustomAction.Arguments" xml:space="preserve">命令行参数 :</x:String>
148+
<x:String x:Key="Text.Configure.CustomAction.Arguments.Tip" xml:space="preserve">请使用${REPO}代替仓库路径,${SHA}代替提交哈希</x:String>
149+
<x:String x:Key="Text.Configure.CustomAction.Executable" xml:space="preserve">可执行文件路径 :</x:String>
150+
<x:String x:Key="Text.Configure.CustomAction.Name" xml:space="preserve">名称 :</x:String>
151+
<x:String x:Key="Text.Configure.CustomAction.Scope" xml:space="preserve">作用目标 :</x:String>
152+
<x:String x:Key="Text.Configure.CustomAction.Scope.Commit" xml:space="preserve">选中的提交</x:String>
153+
<x:String x:Key="Text.Configure.CustomAction.Scope.Repository" xml:space="preserve">仓库</x:String>
145154
<x:String x:Key="Text.Configure.Email" xml:space="preserve">电子邮箱</x:String>
146155
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">邮箱地址</x:String>
147156
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT配置</x:String>
@@ -255,6 +264,8 @@
255264
<x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">目标 :</x:String>
256265
<x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">编辑分组</x:String>
257266
<x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">编辑仓库</x:String>
267+
<x:String x:Key="Text.ExecuteCustomAction" xml:space="preserve">执行自定义操作</x:String>
268+
<x:String x:Key="Text.ExecuteCustomAction.Name" xml:space="preserve">自定义操作 :</x:String>
258269
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">快进(fast-forward,无需checkout)</x:String>
259270
<x:String x:Key="Text.Fetch" xml:space="preserve">拉取(fetch)</x:String>
260271
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">拉取所有的远程仓库</x:String>
@@ -519,6 +530,8 @@
519530
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">清空过滤规则</x:String>
520531
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">配置本仓库</x:String>
521532
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">下一步</x:String>
533+
<x:String x:Key="Text.Repository.CustomActions" xml:space="preserve">自定义操作</x:String>
534+
<x:String x:Key="Text.Repository.CustomActions.Empty" xml:space="preserve">自定义操作未设置</x:String>
522535
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">启用 --reflog 选项</x:String>
523536
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">在文件浏览器中打开</x:String>
524537
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">快速查找分支/标签/子模块</x:String>

src/Resources/Locales/zh_TW.axaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">與本機工作區比較</x:String>
112112
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">複製摘要資訊</x:String>
113113
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">複製提交編號</x:String>
114+
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">自訂動作</x:String>
114115
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">互動式重定基底 (rebase -i) ${0}$ 到此處</x:String>
115116
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">重定基底 (rebase) ${0}$ 到此處</x:String>
116117
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">重設 (reset) ${0}$ 到此處</x:String>
@@ -142,6 +143,14 @@
142143
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">提交訊息範本</x:String>
143144
<x:String x:Key="Text.Configure.CommitMessageTemplate.Name" xml:space="preserve">範本名稱:</x:String>
144145
<x:String x:Key="Text.Configure.CommitMessageTemplate.Content" xml:space="preserve">範本內容:</x:String>
146+
<x:String x:Key="Text.Configure.CustomAction" xml:space="preserve">自訂動作</x:String>
147+
<x:String x:Key="Text.Configure.CustomAction.Arguments" xml:space="preserve">指令行參數:</x:String>
148+
<x:String x:Key="Text.Configure.CustomAction.Arguments.Tip" xml:space="preserve">使用${REPO}代表儲存庫的路徑,${SHA}代表所選的提交編號</x:String>
149+
<x:String x:Key="Text.Configure.CustomAction.Executable" xml:space="preserve">可執行檔案路徑:</x:String>
150+
<x:String x:Key="Text.Configure.CustomAction.Name" xml:space="preserve">名稱 :</x:String>
151+
<x:String x:Key="Text.Configure.CustomAction.Scope" xml:space="preserve">執行範圍:</x:String>
152+
<x:String x:Key="Text.Configure.CustomAction.Scope.Commit" xml:space="preserve">選取的提交</x:String>
153+
<x:String x:Key="Text.Configure.CustomAction.Scope.Repository" xml:space="preserve">存放庫</x:String>
145154
<x:String x:Key="Text.Configure.Email" xml:space="preserve">電子郵件</x:String>
146155
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">電子郵件地址</x:String>
147156
<x:String x:Key="Text.Configure.Git" xml:space="preserve">Git 設定</x:String>
@@ -255,6 +264,8 @@
255264
<x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">目標:</x:String>
256265
<x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">編輯群組</x:String>
257266
<x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">編輯存放庫</x:String>
267+
<x:String x:Key="Text.ExecuteCustomAction" xml:space="preserve">執行自訂動作</x:String>
268+
<x:String x:Key="Text.ExecuteCustomAction.Name" xml:space="preserve">自訂動作:</x:String>
258269
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">快進 (fast-forward,無需 checkout)</x:String>
259270
<x:String x:Key="Text.Fetch" xml:space="preserve">提取 (fetch)</x:String>
260271
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">提取所有的遠端存放庫</x:String>
@@ -519,6 +530,8 @@
519530
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">清空篩選規則</x:String>
520531
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">設定本存放庫</x:String>
521532
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">下一步</x:String>
533+
<x:String x:Key="Text.Repository.CustomActions" xml:space="preserve">自訂動作</x:String>
534+
<x:String x:Key="Text.Repository.CustomActions.Empty" xml:space="preserve">沒有自訂的動作</x:String>
522535
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">啟用 [--reflog] 選項</x:String>
523536
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">在檔案瀏覽器中開啟</x:String>
524537
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">快速搜尋分支/標籤/子模組</x:String>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System.Threading.Tasks;
2+
3+
namespace SourceGit.ViewModels
4+
{
5+
public class ExecuteCustomAction : Popup
6+
{
7+
public Models.CustomAction CustomAction
8+
{
9+
get;
10+
private set;
11+
}
12+
13+
public ExecuteCustomAction(Repository repo, Models.CustomAction action, string sha)
14+
{
15+
_repo = repo;
16+
_args = action.Arguments.Replace("${REPO}", _repo.FullPath);
17+
if (!string.IsNullOrEmpty(sha))
18+
_args = _args.Replace("${SHA}", sha);
19+
20+
CustomAction = action;
21+
View = new Views.ExecuteCustomAction() { DataContext = this };
22+
}
23+
24+
public override Task<bool> Sure()
25+
{
26+
_repo.SetWatcherEnabled(false);
27+
ProgressDescription = "Run custom action ...";
28+
29+
return Task.Run(() =>
30+
{
31+
Commands.ExecuteCustomAction.Run(_repo.FullPath, CustomAction.Executable, _args, SetProgressDescription);
32+
CallUIThread(() => _repo.SetWatcherEnabled(true));
33+
return true;
34+
});
35+
}
36+
37+
private readonly Repository _repo = null;
38+
private string _args = string.Empty;
39+
}
40+
}

0 commit comments

Comments
 (0)