Skip to content

Commit af12221

Browse files
Abhijaymhammerly
authored andcommitted
feat: add support for git branchless --show-signature
1 parent 7d05e41 commit af12221

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

git-branchless-lib/src/core/node_descriptors.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,79 @@ impl NodeDescriptor for RelativeTimeDescriptor {
516516
}
517517
}
518518

519+
/// Display the GPG signature status for a commit.
520+
#[derive(Debug)]
521+
pub struct SignatureStatusDescriptor {
522+
is_enabled: bool,
523+
repo_path: String,
524+
}
525+
526+
impl SignatureStatusDescriptor {
527+
/// Constructor.
528+
pub fn new(repo: &Repo, is_enabled: bool) -> eyre::Result<Self> {
529+
let repo_path = repo.get_path().to_string_lossy().to_string();
530+
Ok(Self {
531+
is_enabled,
532+
repo_path,
533+
})
534+
}
535+
}
536+
537+
impl NodeDescriptor for SignatureStatusDescriptor {
538+
#[instrument]
539+
fn describe_node(
540+
&mut self,
541+
_glyphs: &Glyphs,
542+
object: &NodeObject,
543+
) -> eyre::Result<Option<StyledString>> {
544+
if !self.is_enabled {
545+
return Ok(None);
546+
}
547+
548+
let oid = object.get_oid().to_string();
549+
550+
// Use git command-line to get signature information as git2 doesn't
551+
// expose GPG signature verification directly
552+
let output = std::process::Command::new("git")
553+
.args(["-C", &self.repo_path, "verify-commit", &oid, "--raw"])
554+
.output();
555+
556+
match output {
557+
Ok(output) => {
558+
if output.status.success() {
559+
// Good signature
560+
let mut result = StyledString::new();
561+
result.append_styled("[G]", BaseColor::Green.light());
562+
Ok(Some(result))
563+
} else {
564+
// Bad signature
565+
let stderr = String::from_utf8_lossy(&output.stderr);
566+
if stderr.contains("BAD signature") {
567+
let mut result = StyledString::new();
568+
result.append_styled("[B]", BaseColor::Red.light());
569+
Ok(Some(result))
570+
} else if stderr.contains("No signature") {
571+
let mut result = StyledString::new();
572+
result.append_styled("[N]", BaseColor::Yellow.light());
573+
Ok(Some(result))
574+
} else {
575+
// Unknown error
576+
let mut result = StyledString::new();
577+
result.append_styled("[?]", BaseColor::Magenta.light());
578+
Ok(Some(result))
579+
}
580+
}
581+
}
582+
Err(_) => {
583+
// Error running command
584+
let mut result = StyledString::new();
585+
result.append_styled("[E]", BaseColor::Red.light());
586+
Ok(Some(result))
587+
}
588+
}
589+
}
590+
}
591+
519592
#[cfg(test)]
520593
mod tests {
521594
use std::ops::{Add, Sub};

git-branchless-opts/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,10 @@ pub struct SmartlogArgs {
406406
/// Options for resolving revset expressions.
407407
#[clap(flatten)]
408408
pub resolve_revset_options: ResolveRevsetOptions,
409+
410+
/// Show GPG signature status for each commit.
411+
#[clap(action, long = "show-signature")]
412+
pub show_signature: bool,
409413
}
410414

411415
/// The Git hosting provider to use, called a "forge".

git-branchless-smartlog/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use lib::core::formatting::Pluralize;
3434
use lib::core::node_descriptors::{
3535
BranchesDescriptor, CommitMessageDescriptor, CommitOidDescriptor,
3636
DifferentialRevisionDescriptor, ObsolescenceExplanationDescriptor, Redactor,
37-
RelativeTimeDescriptor,
37+
RelativeTimeDescriptor, SignatureStatusDescriptor,
3838
};
3939
use lib::git::{GitRunInfo, Repo};
4040

@@ -753,6 +753,9 @@ mod render {
753753

754754
/// Normally HEAD and the main branch are included. Set this to exclude them.
755755
pub exact: bool,
756+
757+
/// Show GPG signature status for each commit.
758+
pub show_signature: bool,
756759
}
757760
}
758761

@@ -769,6 +772,7 @@ pub fn smartlog(
769772
resolve_revset_options,
770773
reverse,
771774
exact,
775+
show_signature,
772776
} = options;
773777

774778
let repo = Repo::from_dir(&git_run_info.working_directory)?;
@@ -845,6 +849,7 @@ pub fn smartlog(
845849
&Redactor::Disabled,
846850
)?,
847851
&mut DifferentialRevisionDescriptor::new(&repo, &Redactor::Disabled)?,
852+
&mut SignatureStatusDescriptor::new(&repo, show_signature)?,
848853
&mut CommitMessageDescriptor::new(&Redactor::Disabled)?,
849854
],
850855
)?
@@ -916,6 +921,7 @@ pub fn command_main(ctx: CommandContext, args: SmartlogArgs) -> EyreExitOr<()> {
916921
resolve_revset_options,
917922
reverse,
918923
exact,
924+
show_signature,
919925
} = args;
920926

921927
smartlog(
@@ -927,6 +933,7 @@ pub fn command_main(ctx: CommandContext, args: SmartlogArgs) -> EyreExitOr<()> {
927933
resolve_revset_options,
928934
reverse,
929935
exact,
936+
show_signature,
930937
},
931938
)
932939
}

0 commit comments

Comments
 (0)