mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-10-31 13:03:20 -07:00
feature: show commit gpg sign status (#614)
Some checks are pending
Some checks are pending
Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
parent
5c92fbdb37
commit
279b1819a3
7 changed files with 131 additions and 1 deletions
30
src/Commands/QueryCommitSignInfo.cs
Normal file
30
src/Commands/QueryCommitSignInfo.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
namespace SourceGit.Commands
|
||||||
|
{
|
||||||
|
public class QueryCommitSignInfo : Command
|
||||||
|
{
|
||||||
|
public QueryCommitSignInfo(string repo, string sha)
|
||||||
|
{
|
||||||
|
WorkingDirectory = repo;
|
||||||
|
Context = repo;
|
||||||
|
|
||||||
|
var allowedSignersFile = new Config(repo).Get("gpg.ssh.allowedSignersFile");
|
||||||
|
if (string.IsNullOrEmpty(allowedSignersFile))
|
||||||
|
Args = $"-c gpg.ssh.allowedSignersFile=/dev/null show --no-show-signature --pretty=format:\"%G? %GK\" -s {sha}";
|
||||||
|
else
|
||||||
|
Args = $"show --no-show-signature --pretty=format:\"%G? %GK\" -s {sha}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Models.CommitSignInfo Result()
|
||||||
|
{
|
||||||
|
var rs = ReadToEnd();
|
||||||
|
if (!rs.IsSuccess)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var raw = rs.StdOut.Trim();
|
||||||
|
if (raw.Length > 1)
|
||||||
|
return new Models.CommitSignInfo() { VerifyResult = raw[0], Key = raw.Substring(2) };
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
src/Models/CommitSignInfo.cs
Normal file
58
src/Models/CommitSignInfo.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
using Avalonia.Media;
|
||||||
|
|
||||||
|
namespace SourceGit.Models
|
||||||
|
{
|
||||||
|
public class CommitSignInfo
|
||||||
|
{
|
||||||
|
public string Key { get; set; } = string.Empty;
|
||||||
|
public char VerifyResult { get; set; } = 'N';
|
||||||
|
|
||||||
|
public IBrush Brush
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (VerifyResult)
|
||||||
|
{
|
||||||
|
case 'G':
|
||||||
|
case 'U':
|
||||||
|
return Brushes.Green;
|
||||||
|
case 'X':
|
||||||
|
case 'Y':
|
||||||
|
case 'R':
|
||||||
|
return Brushes.DarkOrange;
|
||||||
|
case 'B':
|
||||||
|
case 'E':
|
||||||
|
return Brushes.Red;
|
||||||
|
default:
|
||||||
|
return Brushes.Transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToolTip
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (VerifyResult)
|
||||||
|
{
|
||||||
|
case 'G':
|
||||||
|
return $"Good Signature.\n\nKey: {Key}";
|
||||||
|
case 'B':
|
||||||
|
return $"Bad Signature.\n\nKey: {Key}";
|
||||||
|
case 'U':
|
||||||
|
return $"Good Signature with unknown validity.\n\nKey: {Key}";
|
||||||
|
case 'X':
|
||||||
|
return $"Good Signature but has expired.\n\nKey: {Key}";
|
||||||
|
case 'Y':
|
||||||
|
return $"Good Signature made by expired key.\n\nKey: {Key}";
|
||||||
|
case 'R':
|
||||||
|
return $"Good signature made by a revoked key.\n\nKey: {Key}";
|
||||||
|
case 'E':
|
||||||
|
return $"Signature cannot be checked.\n\nKey: {Key}";
|
||||||
|
default:
|
||||||
|
return "No signature.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -121,6 +121,7 @@
|
||||||
<StreamGeometry x:Key="Icons.Undo">M762 1024C876 818 895 504 448 514V768L64 384l384-384v248c535-14 595 472 314 776z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Undo">M762 1024C876 818 895 504 448 514V768L64 384l384-384v248c535-14 595 472 314 776z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.Unlock">M832 464H332V240c0-31 25-56 56-56h248c31 0 56 25 56 56v68c0 4 4 8 8 8h56c4 0 8-4 8-8v-68c0-71-57-128-128-128H388c-71 0-128 57-128 128v224h-68c-18 0-32 14-32 32v384c0 18 14 32 32 32h640c18 0 32-14 32-32V496c0-18-14-32-32-32zM540 701v53c0 4-4 8-8 8h-40c-4 0-8-4-8-8v-53c-12-9-20-23-20-39 0-27 22-48 48-48s48 22 48 48c0 16-8 30-20 39z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Unlock">M832 464H332V240c0-31 25-56 56-56h248c31 0 56 25 56 56v68c0 4 4 8 8 8h56c4 0 8-4 8-8v-68c0-71-57-128-128-128H388c-71 0-128 57-128 128v224h-68c-18 0-32 14-32 32v384c0 18 14 32 32 32h640c18 0 32-14 32-32V496c0-18-14-32-32-32zM540 701v53c0 4-4 8-8 8h-40c-4 0-8-4-8-8v-53c-12-9-20-23-20-39 0-27 22-48 48-48s48 22 48 48c0 16-8 30-20 39z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.Up">M170 831l343-342L855 831l105-105-448-448L64 726 170 831z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Up">M170 831l343-342L855 831l105-105-448-448L64 726 170 831z</StreamGeometry>
|
||||||
|
<StreamGeometry x:Key="Icons.Verified">M880 128A722 722 0 01555 13a77 77 0 00-85 0 719 719 0 01-325 115c-40 4-71 38-71 80v369c0 246 329 446 439 446 110 0 439-200 439-446V207c0-41-31-76-71-80zM465 692a36 36 0 01-53 0L305 579a42 42 0 010-57 36 36 0 0153 0l80 85L678 353a36 36 0 0153 0 42 42 0 01-0 57L465 692z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.Waiting">M812 864h-29V654c0-21-11-40-28-52l-133-88 134-89c18-12 28-31 28-52V164h28c18 0 32-14 32-32s-14-32-32-32H212c-18 0-32 14-32 32s14 32 32 32h30v210c0 21 11 40 28 52l133 88-134 89c-18 12-28 31-28 52V864H212c-18 0-32 14-32 32s14 32 32 32h600c18 0 32-14 32-32s-14-32-32-32zM441 566c18-12 28-31 28-52s-11-40-28-52L306 373V164h414v209l-136 90c-18 12-28 31-28 52 0 21 11 40 28 52l135 89V695c-9-7-20-13-32-19-30-15-93-41-176-41-63 0-125 14-175 38-12 6-22 12-31 18v-36l136-90z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Waiting">M812 864h-29V654c0-21-11-40-28-52l-133-88 134-89c18-12 28-31 28-52V164h28c18 0 32-14 32-32s-14-32-32-32H212c-18 0-32 14-32 32s14 32 32 32h30v210c0 21 11 40 28 52l133 88-134 89c-18 12-28 31-28 52V864H212c-18 0-32 14-32 32s14 32 32 32h600c18 0 32-14 32-32s-14-32-32-32zM441 566c18-12 28-31 28-52s-11-40-28-52L306 373V164h414v209l-136 90c-18 12-28 31-28 52 0 21 11 40 28 52l135 89V695c-9-7-20-13-32-19-30-15-93-41-176-41-63 0-125 14-175 38-12 6-22 12-31 18v-36l136-90z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.Whitespace">M0 512M1024 512M512 0M512 1024M762 412v100h-500v-100h-150v200h800v-200h-150z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Whitespace">M0 512M1024 512M512 0M512 1024M762 412v100h-500v-100h-150v200h800v-200h-150z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.Window.Close">M519 459 222 162a37 37 0 10-52 52l297 297L169 809a37 37 0 1052 52l297-297 297 297a37 37 0 1052-52l-297-297 297-297a37 37 0 10-52-52L519 459z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Window.Close">M519 459 222 162a37 37 0 10-52 52l297 297L169 809a37 37 0 1052 52l297-297 297 297a37 37 0 1052-52l-297-297 297-297a37 37 0 10-52-52L519 459z</StreamGeometry>
|
||||||
|
|
|
@ -45,6 +45,12 @@ namespace SourceGit.ViewModels
|
||||||
private set => SetProperty(ref _fullMessage, value);
|
private set => SetProperty(ref _fullMessage, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Models.CommitSignInfo SignInfo
|
||||||
|
{
|
||||||
|
get => _signInfo;
|
||||||
|
private set => SetProperty(ref _signInfo, value);
|
||||||
|
}
|
||||||
|
|
||||||
public List<Models.Change> Changes
|
public List<Models.Change> Changes
|
||||||
{
|
{
|
||||||
get => _changes;
|
get => _changes;
|
||||||
|
@ -131,6 +137,7 @@ namespace SourceGit.ViewModels
|
||||||
_visibleChanges.Clear();
|
_visibleChanges.Clear();
|
||||||
if (_selectedChanges != null)
|
if (_selectedChanges != null)
|
||||||
_selectedChanges.Clear();
|
_selectedChanges.Clear();
|
||||||
|
_signInfo = null;
|
||||||
_searchChangeFilter = null;
|
_searchChangeFilter = null;
|
||||||
_diffContext = null;
|
_diffContext = null;
|
||||||
_viewRevisionFileContent = null;
|
_viewRevisionFileContent = null;
|
||||||
|
@ -474,6 +481,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
_changes = null;
|
_changes = null;
|
||||||
FullMessage = string.Empty;
|
FullMessage = string.Empty;
|
||||||
|
SignInfo = null;
|
||||||
Changes = [];
|
Changes = [];
|
||||||
VisibleChanges = null;
|
VisibleChanges = null;
|
||||||
SelectedChanges = null;
|
SelectedChanges = null;
|
||||||
|
@ -488,6 +496,12 @@ namespace SourceGit.ViewModels
|
||||||
Dispatcher.UIThread.Invoke(() => FullMessage = fullMessage);
|
Dispatcher.UIThread.Invoke(() => FullMessage = fullMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var signInfo = new Commands.QueryCommitSignInfo(_repo.FullPath, _commit.SHA).Result();
|
||||||
|
Dispatcher.UIThread.Invoke(() => SignInfo = signInfo);
|
||||||
|
});
|
||||||
|
|
||||||
if (_cancelToken != null)
|
if (_cancelToken != null)
|
||||||
_cancelToken.Requested = true;
|
_cancelToken.Requested = true;
|
||||||
|
|
||||||
|
@ -637,6 +651,7 @@ namespace SourceGit.ViewModels
|
||||||
private int _activePageIndex = 0;
|
private int _activePageIndex = 0;
|
||||||
private Models.Commit _commit = null;
|
private Models.Commit _commit = null;
|
||||||
private string _fullMessage = string.Empty;
|
private string _fullMessage = string.Empty;
|
||||||
|
private Models.CommitSignInfo _signInfo = null;
|
||||||
private List<Models.Change> _changes = null;
|
private List<Models.Change> _changes = null;
|
||||||
private List<Models.Change> _visibleChanges = null;
|
private List<Models.Change> _visibleChanges = null;
|
||||||
private List<Models.Change> _selectedChanges = null;
|
private List<Models.Change> _selectedChanges = null;
|
||||||
|
|
|
@ -60,6 +60,22 @@
|
||||||
Margin="12,0,4,0"
|
Margin="12,0,4,0"
|
||||||
VerticalAlignment="Center"/>
|
VerticalAlignment="Center"/>
|
||||||
|
|
||||||
|
<ContentControl Content="{Binding #ThisControl.SignInfo}">
|
||||||
|
<ContentControl.Styles>
|
||||||
|
<Style Selector="ToolTip">
|
||||||
|
<Setter Property="MaxWidth" Value="800"/>
|
||||||
|
</Style>
|
||||||
|
</ContentControl.Styles>
|
||||||
|
|
||||||
|
<ContentControl.DataTemplates>
|
||||||
|
<DataTemplate DataType="m:CommitSignInfo">
|
||||||
|
<Border Width="24" Background="Transparent" ToolTip.Tip="{Binding ToolTip}">
|
||||||
|
<Path Width="14" Height="14" Data="{StaticResource Icons.Verified}" Fill="{Binding Brush}"/>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ContentControl.DataTemplates>
|
||||||
|
</ContentControl>
|
||||||
|
|
||||||
<Button Classes="icon_button" Width="24" Cursor="Hand" Click="OnCopyCommitSHA" ToolTip.Tip="{DynamicResource Text.Copy}">
|
<Button Classes="icon_button" Width="24" Cursor="Hand" Click="OnCopyCommitSHA" ToolTip.Tip="{DynamicResource Text.Copy}">
|
||||||
<Path Width="12" Height="12" Data="{StaticResource Icons.Copy}"/>
|
<Path Width="12" Height="12" Data="{StaticResource Icons.Copy}"/>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -17,6 +17,15 @@ namespace SourceGit.Views
|
||||||
set => SetValue(MessageProperty, value);
|
set => SetValue(MessageProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<Models.CommitSignInfo> SignInfoProperty =
|
||||||
|
AvaloniaProperty.Register<CommitBaseInfo, Models.CommitSignInfo>(nameof(SignInfo));
|
||||||
|
|
||||||
|
public Models.CommitSignInfo SignInfo
|
||||||
|
{
|
||||||
|
get => GetValue(SignInfoProperty);
|
||||||
|
set => SetValue(SignInfoProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly StyledProperty<bool> SupportsContainsInProperty =
|
public static readonly StyledProperty<bool> SupportsContainsInProperty =
|
||||||
AvaloniaProperty.Register<CommitBaseInfo, bool>(nameof(SupportsContainsIn));
|
AvaloniaProperty.Register<CommitBaseInfo, bool>(nameof(SupportsContainsIn));
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<!-- Base Information -->
|
<!-- Base Information -->
|
||||||
<v:CommitBaseInfo Content="{Binding Commit}"
|
<v:CommitBaseInfo Content="{Binding Commit}"
|
||||||
Message="{Binding FullMessage}"
|
Message="{Binding FullMessage}"
|
||||||
|
SignInfo="{Binding SignInfo}"
|
||||||
SupportsContainsIn="True"
|
SupportsContainsIn="True"
|
||||||
WebLinks="{Binding WebLinks}"
|
WebLinks="{Binding WebLinks}"
|
||||||
IssueTrackerRules="{Binding IssueTrackerRules}"/>
|
IssueTrackerRules="{Binding IssueTrackerRules}"/>
|
||||||
|
|
Loading…
Reference in a new issue