Skip to content

Commit 6c6dfd0

Browse files
committed
refactor
1 parent c9a312e commit 6c6dfd0

File tree

2 files changed

+29
-97
lines changed

2 files changed

+29
-97
lines changed

gix-object/src/commit/message/body.rs

Lines changed: 17 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ pub struct Trailers<'a> {
2323
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
2424
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2525
pub struct TrailerRef<'a> {
26-
/// The name of the trailer, like "Signed-off-by", up to the separator ": "
26+
/// The name of the trailer, like "Signed-off-by", up to the separator `: `.
2727
#[cfg_attr(feature = "serde", serde(borrow))]
2828
pub token: &'a BStr,
29-
/// The value right after the separator ": ", with leading and trailing whitespace trimmed.
29+
/// The value right after the separator `: `, with leading and trailing whitespace trimmed.
3030
/// Note that multi-line values aren't currently supported.
3131
pub value: &'a BStr,
3232
}
@@ -93,7 +93,7 @@ impl<'a> BodyRef<'a> {
9393
self.body_without_trailer
9494
}
9595

96-
/// Return an iterator over the trailers parsed from the last paragraph of the body. May be empty.
96+
/// Return an iterator over the trailers parsed from the last paragraph of the body. Maybe empty.
9797
pub fn trailers(&self) -> Trailers<'a> {
9898
Trailers {
9999
cursor: self.start_of_trailer,
@@ -115,72 +115,65 @@ impl Deref for BodyRef<'_> {
115115
}
116116
}
117117

118+
/// Convenience methods
118119
impl TrailerRef<'_> {
119-
/// Check if this trailer is a "Signed-off-by" trailer (case-insensitive).
120+
/// Check if this trailer is a `Signed-off-by` trailer (case-insensitive).
120121
pub fn is_signed_off_by(&self) -> bool {
121122
self.token.eq_ignore_ascii_case(b"Signed-off-by")
122123
}
123124

124-
/// Check if this trailer is a "Co-authored-by" trailer (case-insensitive).
125+
/// Check if this trailer is a `Co-authored-by` trailer (case-insensitive).
125126
pub fn is_co_authored_by(&self) -> bool {
126127
self.token.eq_ignore_ascii_case(b"Co-authored-by")
127128
}
128129

129-
/// Check if this trailer is an "Acked-by" trailer (case-insensitive).
130+
/// Check if this trailer is an `Acked-by` trailer (case-insensitive).
130131
pub fn is_acked_by(&self) -> bool {
131132
self.token.eq_ignore_ascii_case(b"Acked-by")
132133
}
133134

134-
/// Check if this trailer is a "Reviewed-by" trailer (case-insensitive).
135+
/// Check if this trailer is a `Reviewed-by` trailer (case-insensitive).
135136
pub fn is_reviewed_by(&self) -> bool {
136137
self.token.eq_ignore_ascii_case(b"Reviewed-by")
137138
}
138139

139-
/// Check if this trailer is a "Tested-by" trailer (case-insensitive).
140+
/// Check if this trailer is a `Tested-by` trailer (case-insensitive).
140141
pub fn is_tested_by(&self) -> bool {
141142
self.token.eq_ignore_ascii_case(b"Tested-by")
142143
}
143144

144145
/// Check if this trailer represents any kind of authorship or attribution
145-
/// (Signed-off-by, Co-authored-by, etc.).
146+
/// (`Signed-off-by`, `Co-authored-by`, etc.).
146147
pub fn is_attribution(&self) -> bool {
147148
self.is_signed_off_by()
148149
|| self.is_co_authored_by()
149150
|| self.is_acked_by()
150151
|| self.is_reviewed_by()
151152
|| self.is_tested_by()
152153
}
153-
154-
/// Get the token as a case-normalized string for comparison purposes.
155-
/// This can be useful for custom filtering logic.
156-
pub fn token_normalized(&self) -> String {
157-
String::from_utf8_lossy(self.token).to_ascii_lowercase()
158-
}
159154
}
160155

156+
/// Convenience methods
161157
impl<'a> Trailers<'a> {
162-
/// Filter trailers to only include "Signed-off-by" entries.
158+
/// Filter trailers to only include `Signed-off-by` entries.
163159
pub fn signed_off_by(self) -> impl Iterator<Item = TrailerRef<'a>> {
164160
self.filter(TrailerRef::is_signed_off_by)
165161
}
166162

167-
/// Filter trailers to only include "Co-authored-by" entries.
163+
/// Filter trailers to only include `Co-authored-by` entries.
168164
pub fn co_authored_by(self) -> impl Iterator<Item = TrailerRef<'a>> {
169165
self.filter(TrailerRef::is_co_authored_by)
170166
}
171167

172-
/// Filter trailers to only include attribution-related entries
173-
/// (Signed-off-by, Co-authored-by, Acked-by, Reviewed-by, Tested-by).
168+
/// Filter trailers to only include attribution-related entries.
169+
/// (`Signed-off-by`, `Co-authored-by`, `Acked-by`, `Reviewed-by`, `Tested-by`).
174170
pub fn attributions(self) -> impl Iterator<Item = TrailerRef<'a>> {
175171
self.filter(TrailerRef::is_attribution)
176172
}
177173

178-
/// Collect all unique authors from Signed-off-by and Co-authored-by trailers.
179-
/// Returns a Vec of author strings.
180-
pub fn collect_authors(self) -> Vec<&'a BStr> {
174+
/// Filter trailers to only include authors from `Signed-off-by` and `Co-authored-by` entries.
175+
pub fn authors(self) -> impl Iterator<Item = TrailerRef<'a>> {
181176
self.filter(|trailer| trailer.is_signed_off_by() || trailer.is_co_authored_by())
182-
.map(|trailer| trailer.value)
183-
.collect()
184177
}
185178
}
186179

@@ -221,68 +214,3 @@ mod test_parse_trailer {
221214
assert_eq!(parse("foo: bar\r\n"), ("foo".into(), "bar".into()));
222215
}
223216
}
224-
225-
#[cfg(test)]
226-
mod test_trailer_convenience {
227-
use super::*;
228-
229-
#[test]
230-
fn test_signed_off_by_detection() {
231-
let trailer = TrailerRef {
232-
token: "Signed-off-by".into(),
233-
value: "John Doe <john@example.com>".into(),
234-
};
235-
assert!(trailer.is_signed_off_by());
236-
assert!(!trailer.is_co_authored_by());
237-
assert!(trailer.is_attribution());
238-
}
239-
240-
#[test]
241-
fn test_case_insensitive_detection() {
242-
let trailer = TrailerRef {
243-
token: "signed-off-by".into(),
244-
value: "John Doe <john@example.com>".into(),
245-
};
246-
assert!(trailer.is_signed_off_by());
247-
248-
let trailer2 = TrailerRef {
249-
token: "CO-AUTHORED-BY".into(),
250-
value: "Jane Smith <jane@example.com>".into(),
251-
};
252-
assert!(trailer2.is_co_authored_by());
253-
assert!(trailer2.is_attribution());
254-
}
255-
256-
#[test]
257-
fn test_multiple_trailer_types() {
258-
let trailer1 = TrailerRef {
259-
token: "Reviewed-by".into(),
260-
value: "Reviewer <reviewer@example.com>".into(),
261-
};
262-
let trailer2 = TrailerRef {
263-
token: "Custom-Field".into(),
264-
value: "Some value".into(),
265-
};
266-
267-
assert!(trailer1.is_reviewed_by());
268-
assert!(trailer1.is_attribution());
269-
assert!(!trailer2.is_attribution());
270-
}
271-
272-
#[test]
273-
fn test_collect_authors() {
274-
// This would need to be tested with actual Trailers iterator
275-
// but shows the expected behavior
276-
let trailer1 = TrailerRef {
277-
token: "Signed-off-by".into(),
278-
value: "John Doe <john@example.com>".into(),
279-
};
280-
let trailer2 = TrailerRef {
281-
token: "Co-authored-by".into(),
282-
value: "Jane Smith <jane@example.com>".into(),
283-
};
284-
285-
assert!(trailer1.is_signed_off_by());
286-
assert!(trailer2.is_co_authored_by());
287-
}
288-
}

gix-object/src/commit/message/mod.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,44 @@ impl<'a> CommitRef<'a> {
1717
}
1818

1919
/// Return an iterator over message trailers as obtained from the last paragraph of the commit message.
20-
/// May be empty.
20+
/// Maybe empty.
2121
pub fn message_trailers(&self) -> body::Trailers<'a> {
2222
BodyRef::from_bytes(self.message).trailers()
2323
}
24+
}
2425

25-
/// Get an iterator over all Signed-off-by trailers in the commit message.
26+
/// Convenience methods
27+
impl<'a> CommitRef<'a> {
28+
/// Get an iterator over all `Signed-off-by` trailers in the commit message.
2629
/// This is useful for finding who signed off on the commit.
2730
pub fn signed_off_by_trailers(&self) -> impl Iterator<Item = body::TrailerRef<'a>> {
2831
self.message_trailers().signed_off_by()
2932
}
3033

31-
/// Get an iterator over all Co-authored-by trailers in the commit message.
34+
/// Get an iterator over `Co-authored-by` trailers in the commit message.
3235
/// This is useful for squashed commits that contain multiple authors.
3336
pub fn co_authored_by_trailers(&self) -> impl Iterator<Item = body::TrailerRef<'a>> {
3437
self.message_trailers().co_authored_by()
3538
}
3639

37-
/// Get all authors mentioned in Signed-off-by and Co-authored-by trailers.
40+
/// Get all authors mentioned in `Signed-off-by` and `Co-authored-by` trailers.
3841
/// This is useful for squashed commits that contain multiple authors.
3942
/// Returns a Vec of author strings that can include both signers and co-authors.
40-
pub fn all_authors(&self) -> Vec<&'a BStr> {
41-
self.message_trailers().collect_authors()
43+
pub fn author_trailers(&self) -> impl Iterator<Item = body::TrailerRef<'a>> {
44+
self.message_trailers().authors()
4245
}
4346

4447
/// Get an iterator over all attribution-related trailers
45-
/// (Signed-off-by, Co-authored-by, Acked-by, Reviewed-by, Tested-by).
48+
/// (`Signed-off-by,` `Co-authored-by`, `Acked-by`, `Reviewed-by`, `Tested-by`).
4649
/// This provides a comprehensive view of everyone who contributed to or reviewed the commit.
50+
/// Note that the same name may occur multiple times, it's not a unified list.
4751
pub fn attribution_trailers(&self) -> impl Iterator<Item = body::TrailerRef<'a>> {
4852
self.message_trailers().attributions()
4953
}
5054
}
5155

5256
impl<'a> MessageRef<'a> {
53-
/// Parse the given `input` as message.
57+
/// Parse the given `input` as a message.
5458
///
5559
/// Note that this cannot fail as everything will be interpreted as title if there is no body separator.
5660
pub fn from_bytes(input: &'a [u8]) -> Self {

0 commit comments

Comments
 (0)