Skip to content

Commit

Permalink
feat: use libgit2 for parsing git information in mitre/git plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickjcasey committed Nov 26, 2024
1 parent 7b2e5a5 commit fa18ac5
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 1,525 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions plugins/git/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ publish = false
[dependencies]
anyhow = "1.0.91"
clap = { version = "4.5.21", features = ["derive"] }
git2 = "0.19.0"
hipcheck-sdk = { path = "../../sdk/rust", features = ["macros"]}
jiff = { version = "0.1.14", features = ["serde"] }
log = "0.4.22"
Expand Down
101 changes: 98 additions & 3 deletions plugins/git/src/data.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0

use hipcheck_sdk::types::LocalGitRepo;
use jiff::Timestamp;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::{
Expand All @@ -21,7 +22,7 @@ pub struct DetailedGitRepo {
}

/// Commits as they come directly out of `git log`.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct RawCommit {
pub hash: String,

Expand All @@ -32,6 +33,29 @@ pub struct RawCommit {
pub committed_on: Result<String, String>,
}

impl From<git2::Commit<'_>> for RawCommit {
fn from(value: git2::Commit<'_>) -> Self {
let hash = value.id().to_string();
let author = &value.author();
let committer = &value.committer();

let written_time_sec_since_epoch = jiff::Timestamp::from_second(
author.when().seconds() + (author.when().offset_minutes() as i64 * 60),
);
let commit_time_sec_since_epoch = jiff::Timestamp::from_second(
committer.when().seconds() + (committer.when().offset_minutes() as i64 * 60),
);

RawCommit {
hash,
author: author.into(),
written_on: jiff_timestamp_result_to_string(written_time_sec_since_epoch),
committer: committer.into(),
committed_on: jiff_timestamp_result_to_string(commit_time_sec_since_epoch),
}
}
}

/// Commits as understood in Hipcheck's data model.
/// The `written_on` and `committed_on` datetime fields contain Strings that are created from `jiff:Timestamps`.
/// Because `Timestamp` does not `impl JsonSchema`, we display the datetimes as Strings for passing out of this plugin.
Expand All @@ -45,6 +69,47 @@ pub struct Commit {
pub committed_on: Result<String, String>,
}

fn jiff_timestamp_result_to_string(
timestamp_res: Result<Timestamp, jiff::Error>,
) -> Result<String, String> {
match timestamp_res {
Ok(timestamp) => Ok(timestamp.to_string()),
Err(e) => Err(format!(
"Error converting commit author time to Timestamp: {}",
e
)),
}
}

impl From<git2::Commit<'_>> for Commit {
fn from(value: git2::Commit) -> Self {
let author = &value.author();
let committer = &value.author();
let written_on = jiff::Timestamp::from_second(
author.when().seconds() + (author.when().offset_minutes() as i64 * 60),
);
let committed_on = jiff::Timestamp::from_second(
committer.when().seconds() + (author.when().offset_minutes() as i64 * 60),
);

Self {
hash: value.id().to_string(),
written_on: jiff_timestamp_result_to_string(written_on),
committed_on: jiff_timestamp_result_to_string(committed_on),
}
}
}

impl From<RawCommit> for Commit {
fn from(value: RawCommit) -> Self {
Self {
hash: value.hash,
written_on: value.written_on.map(|x| x.to_string()),
committed_on: value.committed_on.map(|x| x.to_string()),
}
}
}

impl Display for Commit {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.hash)
Expand All @@ -60,6 +125,15 @@ pub struct Contributor {
pub email: String,
}

impl From<&git2::Signature<'_>> for Contributor {
fn from(value: &git2::Signature) -> Self {
Self {
name: value.name().unwrap_or_default().to_string(),
email: value.email().unwrap_or_default().to_string(),
}
}
}

impl Display for Contributor {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{} <{}>", self.name, self.email)
Expand Down Expand Up @@ -98,6 +172,12 @@ pub struct CommitDiff {
pub diff: Diff,
}

impl CommitDiff {
pub fn new(commit: Commit, diff: Diff) -> Self {
Self { commit, diff }
}
}

impl Display for CommitDiff {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(
Expand Down Expand Up @@ -130,7 +210,22 @@ pub struct Diff {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
pub struct FileDiff {
pub file_name: Arc<String>,
pub additions: Option<i64>,
pub deletions: Option<i64>,
pub additions: i64,
pub deletions: i64,
pub patch: String,
}

impl FileDiff {
pub fn increment_additions(&mut self, amount: i64) {
self.additions += amount
}

pub fn increment_deletions(&mut self, amount: i64) {
self.additions += amount
}

pub fn add_to_patch(&mut self, contents: &[u8]) {
let contents = String::from_utf8_lossy(contents);
self.patch.push_str(&contents);
}
}
Loading

0 comments on commit fa18ac5

Please sign in to comment.