enhance: tag creation & pushing (#141)

* supports creating lightweight tags
* supports GPG signed tags
* add option to push selected tag to all remotes
This commit is contained in:
leo 2024-05-24 10:31:20 +08:00
parent 0dea7ed0e2
commit b556feb3d3
11 changed files with 122 additions and 42 deletions

View file

@ -5,12 +5,22 @@ namespace SourceGit.Commands
{
public static class Tag
{
public static bool Add(string repo, string name, string basedOn, string message)
public static bool Add(string repo, string name, string basedOn)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"tag -a {name} {basedOn} ";
cmd.Args = $"tag {name} {basedOn}";
return cmd.Exec();
}
public static bool Add(string repo, string name, string basedOn, string message, bool sign)
{
var param = sign ? "-s -a" : "-a";
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"tag {param} {name} {basedOn} ";
if (!string.IsNullOrEmpty(message))
{

View file

@ -114,10 +114,14 @@
<x:String x:Key="Text.CreateBranch.Title" xml:space="preserve">Create Local Branch</x:String>
<x:String x:Key="Text.CreateTag" xml:space="preserve">Create Tag</x:String>
<x:String x:Key="Text.CreateTag.BasedOn" xml:space="preserve">New Tag At :</x:String>
<x:String x:Key="Text.CreateTag.GPGSign" xml:space="preserve">Enable GPG signing</x:String>
<x:String x:Key="Text.CreateTag.Message" xml:space="preserve">Tag Message :</x:String>
<x:String x:Key="Text.CreateTag.Message.Placeholder" xml:space="preserve">Optional.</x:String>
<x:String x:Key="Text.CreateTag.Name" xml:space="preserve">Tag Name :</x:String>
<x:String x:Key="Text.CreateTag.Name.Placeholder" xml:space="preserve">Recommended format v1.0.0-alpha</x:String>
<x:String x:Key="Text.CreateTag.Type" xml:space="preserve">Kind </x:String>
<x:String x:Key="Text.CreateTag.Type.Annotated" xml:space="preserve">annotated</x:String>
<x:String x:Key="Text.CreateTag.Type.Lightweight" xml:space="preserve">lightweight</x:String>
<x:String x:Key="Text.Cut" xml:space="preserve">Cut</x:String>
<x:String x:Key="Text.DeleteBranch" xml:space="preserve">Delete Branch</x:String>
<x:String x:Key="Text.DeleteBranch.Branch" xml:space="preserve">Branch :</x:String>
@ -312,6 +316,7 @@
<x:String x:Key="Text.Push.To" xml:space="preserve">Remote Branch :</x:String>
<x:String x:Key="Text.Push.WithAllTags" xml:space="preserve">Push all tags</x:String>
<x:String x:Key="Text.PushTag" xml:space="preserve">Push Tag To Remote</x:String>
<x:String x:Key="Text.PushTag.PushAllRemotes" xml:space="preserve">Push to all remotes</x:String>
<x:String x:Key="Text.PushTag.Remote" xml:space="preserve">Remote :</x:String>
<x:String x:Key="Text.PushTag.Tag" xml:space="preserve">Tag :</x:String>
<x:String x:Key="Text.Quit" xml:space="preserve">Quit</x:String>

View file

@ -114,10 +114,14 @@
<x:String x:Key="Text.CreateBranch.Title" xml:space="preserve">创建本地分支</x:String>
<x:String x:Key="Text.CreateTag" xml:space="preserve">新建标签</x:String>
<x:String x:Key="Text.CreateTag.BasedOn" xml:space="preserve">标签位于 </x:String>
<x:String x:Key="Text.CreateTag.GPGSign" xml:space="preserve">使用GPG签名</x:String>
<x:String x:Key="Text.CreateTag.Message" xml:space="preserve">标签描述 </x:String>
<x:String x:Key="Text.CreateTag.Message.Placeholder" xml:space="preserve">选填。</x:String>
<x:String x:Key="Text.CreateTag.Name" xml:space="preserve">标签名 </x:String>
<x:String x:Key="Text.CreateTag.Name.Placeholder" xml:space="preserve">推荐格式 v1.0.0-alpha</x:String>
<x:String x:Key="Text.CreateTag.Type" xml:space="preserve">类型 </x:String>
<x:String x:Key="Text.CreateTag.Type.Annotated" xml:space="preserve">附注标签</x:String>
<x:String x:Key="Text.CreateTag.Type.Lightweight" xml:space="preserve">轻量标签</x:String>
<x:String x:Key="Text.Cut" xml:space="preserve">剪切</x:String>
<x:String x:Key="Text.DeleteBranch" xml:space="preserve">删除分支确认</x:String>
<x:String x:Key="Text.DeleteBranch.Branch" xml:space="preserve">分支名 </x:String>
@ -312,6 +316,7 @@
<x:String x:Key="Text.Push.To" xml:space="preserve">远程分支 </x:String>
<x:String x:Key="Text.Push.WithAllTags" xml:space="preserve">同时推送标签</x:String>
<x:String x:Key="Text.PushTag" xml:space="preserve">推送标签到远程仓库</x:String>
<x:String x:Key="Text.PushTag.PushAllRemotes" xml:space="preserve">推送到所有远程仓库</x:String>
<x:String x:Key="Text.PushTag.Remote" xml:space="preserve">远程仓库 </x:String>
<x:String x:Key="Text.PushTag.Tag" xml:space="preserve">标签 </x:String>
<x:String x:Key="Text.Quit" xml:space="preserve">退出</x:String>

View file

@ -1,12 +1,16 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
namespace SourceGit.ViewModels
{
public class CreateTag : Popup
{
public object BasedOn
{
get;
private set;
}
[Required(ErrorMessage = "Tag name is required!")]
[RegularExpression(@"^[\w\-\.]+$", ErrorMessage = "Bad tag name format!")]
[CustomValidation(typeof(CreateTag), nameof(ValidateTagName))]
@ -22,11 +26,17 @@ namespace SourceGit.ViewModels
set;
}
public object BasedOn
public bool Annotated
{
get => _annotated;
set => SetProperty(ref _annotated, value);
}
public bool SignTag
{
get;
private set;
}
set;
} = false;
public CreateTag(Repository repo, Models.Branch branch)
{
@ -65,7 +75,11 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
Commands.Tag.Add(_repo.FullPath, TagName, _basedOn, Message);
if (_annotated)
Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, Message, SignTag);
else
Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn);
CallUIThread(() => _repo.SetWatcherEnabled(true));
return true;
});
@ -73,6 +87,7 @@ namespace SourceGit.ViewModels
private readonly Repository _repo = null;
private string _tagName = string.Empty;
private bool _annotated = true;
private readonly string _basedOn = string.Empty;
}
}

View file

@ -22,6 +22,12 @@ namespace SourceGit.ViewModels
set;
}
public bool PushAllRemotes
{
get => _pushAllRemotes;
set => SetProperty(ref _pushAllRemotes, value);
}
public PushTag(Repository repo, Models.Tag target)
{
_repo = repo;
@ -37,12 +43,27 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
var succ = new Commands.Push(_repo.FullPath, SelectedRemote.Name, Target.Name, false).Exec();
bool succ = true;
if (_pushAllRemotes)
{
foreach (var remote in _repo.Remotes)
{
succ = new Commands.Push(_repo.FullPath, remote.Name, Target.Name, false).Exec();
if (!succ)
break;
}
}
else
{
succ = new Commands.Push(_repo.FullPath, SelectedRemote.Name, Target.Name, false).Exec();
}
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});
}
private readonly Repository _repo = null;
private bool _pushAllRemotes = false;
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.ComponentModel;
using System.ComponentModel;
using Avalonia.Controls;

View file

@ -13,7 +13,7 @@
<TextBlock FontSize="18"
Classes="bold"
Text="{DynamicResource Text.CreateTag}"/>
<Grid Margin="0,16,8,0" RowDefinitions="32,32,64" ColumnDefinitions="150,*">
<Grid Margin="0,16,8,0" RowDefinitions="32,32,32,Auto,Auto" ColumnDefinitions="150,*">
<TextBlock Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
@ -49,16 +49,37 @@
v:AutoFocusBehaviour.IsEnabled="True"/>
<TextBlock Grid.Row="2" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.CreateTag.Type}"/>
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal">
<RadioButton Content="{DynamicResource Text.CreateTag.Type.Annotated}"
GroupName="TagKind"
IsChecked="{Binding Annotated, Mode=TwoWay}"/>
<RadioButton Content="{DynamicResource Text.CreateTag.Type.Lightweight}"
GroupName="TagKind"
Margin="8,0,0,0"/>
</StackPanel>
<TextBlock Grid.Row="3" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="0,6,8,0"
Text="{DynamicResource Text.CreateTag.Message}"/>
<TextBox Grid.Row="2" Grid.Column="1"
Height="56"
Text="{DynamicResource Text.CreateTag.Message}"
IsVisible="{Binding Annotated}"/>
<TextBox Grid.Row="3" Grid.Column="1"
Height="64"
AcceptsReturn="True" AcceptsTab="False"
VerticalAlignment="Center" VerticalContentAlignment="Top"
CornerRadius="2"
Watermark="{DynamicResource Text.CreateTag.Message.Placeholder}"
Text="{Binding Message, Mode=TwoWay}"/>
Text="{Binding Message, Mode=TwoWay}"
IsVisible="{Binding Annotated}"/>
<CheckBox Grid.Row="4" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.CreateTag.GPGSign}"
IsChecked="{Binding SignTag, Mode=TwoWay}"
IsVisible="{Binding Annotated}"/>
</Grid>
</StackPanel>
</UserControl>

View file

@ -396,17 +396,10 @@
<Grid Margin="8" RowDefinitions="32,32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preference.GPG.Enabled}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<CheckBox Grid.Row="0" Grid.Column="1"
IsChecked="{Binding #me.EnableGPGSigning, Mode=TwoWay}"/>
<TextBlock Grid.Row="1" Grid.Column="0"
Text="{DynamicResource Text.Preference.GPG.Path}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<TextBox Grid.Row="1" Grid.Column="1"
<TextBox Grid.Row="0" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding #me.GPGExecutableFile, Mode=TwoWay}">
@ -417,15 +410,19 @@
</TextBox.InnerRightContent>
</TextBox>
<TextBlock Grid.Row="2" Grid.Column="0"
<TextBlock Grid.Row="1" Grid.Column="0"
Text="{DynamicResource Text.Preference.GPG.UserKey}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<TextBox Grid.Row="2" Grid.Column="1"
<TextBox Grid.Row="1" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding #me.GPGUserKey, Mode=TwoWay}"
Watermark="{DynamicResource Text.Preference.GPG.UserKey.Placeholder}"/>
<CheckBox Grid.Row="2" Grid.Column="1"
Content="{DynamicResource Text.Preference.GPG.Enabled}"
IsChecked="{Binding #me.EnableGPGSigning, Mode=TwoWay}"/>
</Grid>
</TabItem>

View file

@ -207,10 +207,17 @@ namespace SourceGit.Views
private async void SelectGPGExecutable(object sender, RoutedEventArgs e)
{
var pattern = OperatingSystem.IsWindows() ? "gpg.exe" : "gpg";
var patterns = new List<string>();
if (OperatingSystem.IsWindows())
patterns.Add("gpg.exe");
else if (OperatingSystem.IsLinux())
patterns.AddRange(new string[] { "gpg", "gpg2" });
else
patterns.Add("gpg");
var options = new FilePickerOpenOptions()
{
FileTypeFilter = [new FilePickerFileType("GPG Executable") { Patterns = [pattern] }],
FileTypeFilter = [new FilePickerFileType("GPG Executable") { Patterns = patterns }],
AllowMultiple = false,
};

View file

@ -12,7 +12,7 @@
<TextBlock FontSize="18"
Classes="bold"
Text="{DynamicResource Text.PushTag}"/>
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="150,*">
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="150,*">
<TextBlock Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
@ -31,7 +31,8 @@
Height="28" Padding="8,0"
VerticalAlignment="Center" HorizontalAlignment="Stretch"
ItemsSource="{Binding Remotes}"
SelectedItem="{Binding SelectedRemote, Mode=TwoWay}">
SelectedItem="{Binding SelectedRemote, Mode=TwoWay}"
IsEnabled="{Binding !PushAllRemotes}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="{x:Type m:Remote}">
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
@ -41,6 +42,10 @@
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<CheckBox Grid.Row="2" Grid.Column="1"
Content="{DynamicResource Text.PushTag.PushAllRemotes}"
IsChecked="{Binding PushAllRemotes, Mode=TwoWay}"/>
</Grid>
</StackPanel>
</UserControl>

View file

@ -47,23 +47,18 @@
Text="{Binding HttpProxy, Mode=TwoWay}"/>
<TextBlock Grid.Row="3" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.Preference.GPG.Enabled}"/>
<CheckBox Grid.Row="3" Grid.Column="1"
x:Name="chkGPGSigningEnabled"
IsChecked="{Binding GPGSigningEnabled, Mode=TwoWay}"/>
<TextBlock Grid.Row="4" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.Preference.GPG.UserKey}"/>
<TextBox Grid.Row="4" Grid.Column="1"
<TextBox Grid.Row="3" Grid.Column="1"
Height="28"
CornerRadius="3"
Watermark="{DynamicResource Text.Preference.GPG.UserKey.Placeholder}"
Text="{Binding GPGUserSigningKey, Mode=TwoWay}"
IsEnabled="{Binding #chkGPGSigningEnabled.IsChecked}"/>
Text="{Binding GPGUserSigningKey, Mode=TwoWay}"/>
<CheckBox Grid.Row="4" Grid.Column="1"
Content="{DynamicResource Text.Preference.GPG.Enabled}"
IsChecked="{Binding GPGSigningEnabled, Mode=TwoWay}"/>
</Grid>
</StackPanel>
</UserControl>