1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use semver::Version;
use crate::commit::Commit;
use crate::error::ReleaseError;
/// Information about a git tag.
#[derive(Debug, Clone)]
pub struct TagInfo {
pub name: String,
pub version: Version,
pub sha: String,
}
/// Abstraction over git operations.
pub trait GitRepository: Send + Sync {
/// Find the latest semver tag matching the configured prefix.
fn latest_tag(&self, prefix: &str) -> Result<Option<TagInfo>, ReleaseError>;
/// List commits between a starting point (exclusive) and HEAD (inclusive).
/// If `from` is `None`, returns all commits reachable from HEAD.
fn commits_since(&self, from: Option<&str>) -> Result<Vec<Commit>, ReleaseError>;
/// Create an annotated tag at HEAD. When `sign` is true, uses `-s` for GPG/SSH signing.
fn create_tag(&self, name: &str, message: &str, sign: bool) -> Result<(), ReleaseError>;
/// Push a tag to the remote.
fn push_tag(&self, name: &str) -> Result<(), ReleaseError>;
/// Stage files and commit. Returns Ok(false) if nothing to commit.
fn stage_and_commit(&self, paths: &[&str], message: &str) -> Result<bool, ReleaseError>;
/// Push current branch to origin.
fn push(&self) -> Result<(), ReleaseError>;
/// Check if a tag exists locally.
fn tag_exists(&self, name: &str) -> Result<bool, ReleaseError>;
/// Check if a tag exists on the remote.
fn remote_tag_exists(&self, name: &str) -> Result<bool, ReleaseError>;
/// List all semver tags matching prefix, sorted by version ascending.
fn all_tags(&self, prefix: &str) -> Result<Vec<TagInfo>, ReleaseError>;
/// List commits between two refs (exclusive `from`, inclusive `to`).
/// If `from` is None, returns all commits reachable from `to`.
fn commits_between(&self, from: Option<&str>, to: &str) -> Result<Vec<Commit>, ReleaseError>;
/// Get the date (YYYY-MM-DD) of the commit a tag points to.
fn tag_date(&self, tag_name: &str) -> Result<String, ReleaseError>;
/// Force-create a lightweight tag at HEAD, overwriting if it already exists.
fn force_create_tag(&self, name: &str) -> Result<(), ReleaseError>;
/// Force-push a tag to the remote, overwriting the remote tag if it exists.
fn force_push_tag(&self, name: &str) -> Result<(), ReleaseError>;
/// Return the full SHA of HEAD.
fn head_sha(&self) -> Result<String, ReleaseError>;
/// Like `commits_since`, but only includes commits that touched files under `path`.
fn commits_since_in_path(
&self,
from: Option<&str>,
path: &str,
) -> Result<Vec<Commit>, ReleaseError> {
// Default: ignore path filter (for test fakes and backwards compat)
let _ = path;
self.commits_since(from)
}
/// Like `commits_between`, but only includes commits that touched files under `path`.
fn commits_between_in_path(
&self,
from: Option<&str>,
to: &str,
path: &str,
) -> Result<Vec<Commit>, ReleaseError> {
let _ = path;
self.commits_between(from, to)
}
}