mirror of
https://fastgit.cc/github.com/sourcegit-scm/sourcegit
synced 2026-04-21 13:20:30 +08:00
feature: supports to share issuetracker rules in .issuetracker file (#1567)
Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
94
src/Commands/SharedIssueTracker.cs
Normal file
94
src/Commands/SharedIssueTracker.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class SharedIssueTracker : Command
|
||||
{
|
||||
public SharedIssueTracker(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
_file = $"{repo}/.issuetracker";
|
||||
}
|
||||
|
||||
public async Task<List<Models.IssueTrackerRule>> ReadAllAsync()
|
||||
{
|
||||
if (!File.Exists(_file))
|
||||
return [];
|
||||
|
||||
Args = $"config -f {_file.Quoted()} -l";
|
||||
|
||||
var output = await ReadToEndAsync().ConfigureAwait(false);
|
||||
var rs = new List<Models.IssueTrackerRule>();
|
||||
if (output.IsSuccess)
|
||||
{
|
||||
var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var parts = line.Split('=', 2);
|
||||
if (parts.Length < 2)
|
||||
continue;
|
||||
|
||||
var key = parts[0];
|
||||
var value = parts[1];
|
||||
|
||||
if (!key.StartsWith("issuetracker.", StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
if (key.EndsWith(".regex", StringComparison.Ordinal))
|
||||
{
|
||||
var prefixLen = "issuetracker.".Length;
|
||||
var suffixLen = ".regex".Length;
|
||||
var ruleName = key.Substring(prefixLen, key.Length - prefixLen - suffixLen);
|
||||
FindOrAdd(rs, ruleName).RegexString = value;
|
||||
}
|
||||
else if (key.EndsWith(".url", StringComparison.Ordinal))
|
||||
{
|
||||
var prefixLen = "issuetracker.".Length;
|
||||
var suffixLen = ".url".Length;
|
||||
var ruleName = key.Substring(prefixLen, key.Length - prefixLen - suffixLen);
|
||||
FindOrAdd(rs, ruleName).URLTemplate = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
public async Task<bool> AddAsync(Models.IssueTrackerRule rule)
|
||||
{
|
||||
Args = $"config -f {_file.Quoted()} issuetracker.{rule.Name.Quoted()}.regex {rule.RegexString.Quoted()}";
|
||||
|
||||
var succ = await ExecAsync().ConfigureAwait(false);
|
||||
if (succ)
|
||||
{
|
||||
Args = $"config -f {_file.Quoted()} issuetracker.{rule.Name.Quoted()}.url {rule.URLTemplate.Quoted()}";
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveAsync(Models.IssueTrackerRule rule)
|
||||
{
|
||||
Args = $"config -f {_file.Quoted()} --remove-section issuetracker.{rule.Name.Quoted()}";
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private Models.IssueTrackerRule FindOrAdd(List<Models.IssueTrackerRule> rules, string ruleName)
|
||||
{
|
||||
var rule = rules.Find(x => x.Name.Equals(ruleName, StringComparison.Ordinal));
|
||||
if (rule != null)
|
||||
return rule;
|
||||
|
||||
rule = new Models.IssueTrackerRule() { IsShared = true, Name = ruleName };
|
||||
rules.Add(rule);
|
||||
return rule;
|
||||
}
|
||||
|
||||
private readonly string _file;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,12 @@ namespace SourceGit.Models
|
||||
{
|
||||
public class IssueTrackerRule : ObservableObject
|
||||
{
|
||||
public bool IsShared
|
||||
{
|
||||
get => _isShared;
|
||||
set => SetProperty(ref _isShared, value);
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
@@ -70,6 +76,7 @@ namespace SourceGit.Models
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isShared;
|
||||
private string _name;
|
||||
private string _regexString;
|
||||
private string _urlTemplate;
|
||||
|
||||
@@ -204,6 +204,7 @@
|
||||
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">New Rule</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Issue Regex Expression:</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Rule Name:</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.Share" xml:space="preserve">Share this rule in .issuetracker file</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">Result URL:</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Please use $1, $2 to access regex groups values.</x:String>
|
||||
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">AI</x:String>
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">新增自定义规则</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">匹配ISSUE的正则表达式 :</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">规则名 :</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.Share" xml:space="preserve">写入 .issuetracker 文件共享此规则</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">为ISSUE生成的URL链接 :</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">可在URL中使用$1,$2等变量填入正则表达式匹配的内容</x:String>
|
||||
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">AI</x:String>
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">新增自訂規則</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">符合 Issue 的正規表達式:</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">規則名稱:</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.Share" xml:space="preserve">寫入 .issuetracker 檔案以分享此規則</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">為 Issue 產生的網址連結:</x:String>
|
||||
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">可在網址中使用 $1、$2 等變數填入正規表達式相符的內容</x:String>
|
||||
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">AI</x:String>
|
||||
|
||||
@@ -546,6 +546,13 @@ namespace SourceGit.ViewModels
|
||||
|
||||
_settings.LastCommitMessage = _workingCopy.CommitMessage;
|
||||
|
||||
var sharedIssueTrackers = new List<Models.IssueTrackerRule>();
|
||||
foreach (var rule in _settings.IssueTrackerRules)
|
||||
if (rule.IsShared)
|
||||
sharedIssueTrackers.Add(rule);
|
||||
|
||||
_settings.IssueTrackerRules.RemoveAll(sharedIssueTrackers);
|
||||
|
||||
try
|
||||
{
|
||||
using var stream = File.Create(Path.Combine(_gitDir, "sourcegit.settings"));
|
||||
@@ -704,6 +711,10 @@ namespace SourceGit.ViewModels
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var sharedIssueTrackers = await new Commands.SharedIssueTracker(_fullpath).ReadAllAsync().ConfigureAwait(false);
|
||||
if (sharedIssueTrackers.Count > 0)
|
||||
Dispatcher.UIThread.Post(() => _settings.IssueTrackerRules.InsertRange(0, sharedIssueTrackers));
|
||||
|
||||
var config = await new Commands.Config(_fullpath).ReadAllAsync().ConfigureAwait(false);
|
||||
_hasAllowedSignersFile = config.TryGetValue("gpg.ssh.allowedSignersFile", out var allowedSignersFile) && !string.IsNullOrEmpty(allowedSignersFile);
|
||||
|
||||
|
||||
@@ -295,6 +295,17 @@ namespace SourceGit.ViewModels
|
||||
SelectedIssueTrackerRule = null;
|
||||
}
|
||||
|
||||
public async Task ChangeIssueTrackerShareModeAsync()
|
||||
{
|
||||
if (_selectedIssueTrackerRule is not { } rule)
|
||||
return;
|
||||
|
||||
if (rule.IsShared)
|
||||
await new Commands.SharedIssueTracker(_repo.FullPath).AddAsync(rule);
|
||||
else
|
||||
await new Commands.SharedIssueTracker(_repo.FullPath).RemoveAsync(rule);
|
||||
}
|
||||
|
||||
public void AddNewCustomAction()
|
||||
{
|
||||
SelectedCustomAction = _repo.Settings.AddNewCustomAction();
|
||||
|
||||
@@ -355,7 +355,7 @@
|
||||
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="m:IssueTrackerRule">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,32">
|
||||
<TextBlock Grid.Row="0" Text="{DynamicResource Text.Configure.IssueTracker.RuleName}"/>
|
||||
<TextBox Grid.Row="1" Margin="0,4,0,0" CornerRadius="3" Height="28" Text="{Binding Name, Mode=TwoWay}"/>
|
||||
|
||||
@@ -369,6 +369,12 @@
|
||||
<TextBlock Grid.Row="4" Margin="0,12,0,0" Text="{DynamicResource Text.Configure.IssueTracker.URLTemplate}"/>
|
||||
<TextBox Grid.Row="5" Margin="0,4,0,0" CornerRadius="3" Height="28" Text="{Binding URLTemplate, Mode=TwoWay}"/>
|
||||
<TextBlock Grid.Row="6" Margin="0,2,0,0" Text="{DynamicResource Text.Configure.IssueTracker.URLTemplate.Tip}" Foreground="{DynamicResource Brush.FG2}"/>
|
||||
|
||||
<CheckBox Grid.Row="7" Grid.Column="1"
|
||||
Margin="0,4,0,0"
|
||||
Content="{DynamicResource Text.Configure.IssueTracker.Share}"
|
||||
IsChecked="{Binding IsShared, Mode=TwoWay}"
|
||||
Click="OnIssueTrackerIsSharedChanged"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
|
||||
@@ -48,5 +48,14 @@ namespace SourceGit.Views
|
||||
await dialog.ShowDialog(this);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private async void OnIssueTrackerIsSharedChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.RepositoryConfigure configure)
|
||||
{
|
||||
await configure.ChangeIssueTrackerShareModeAsync();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user