Skip to content
42 linesCodeBlameRaw
1//! Whose work a usage line is: the agent that did it, by handle, and the
2//! person who asked, by username. Both are written on the run
3//! (`start_run`) and copied onto every ledger line it makes, and on an
4//! agent's sandbox time (`record_sandbox`), so Spend's "by agent" and "by
5//! person" are read from the one ledger that is charged
6//! (`report::attribution`), never from a second count.
7
8/// A handle or username as the ledger stores it: lowercase, without a
9/// leading `@`; none when empty.
10pub(crate) fn handle(given: Option<&str>) -> Option<String> {
11 let name = given?.trim().trim_start_matches('@').to_lowercase();
12 (!name.is_empty()).then_some(name)
13}
14
15/// The agent a run is attributed to: the one the caller names; else the
16/// one a run billed under `<workspace>/@<handle>` names (the agents
17/// service's replies and sessions; no repository has an `@` in its name);
18/// else g1t's own agent at work on a repository, which all shows as @g1t.
19pub(crate) fn agent_of(given: Option<&str>, repo_name: &str) -> Option<String> {
20 handle(given).or_else(|| repo_name.strip_prefix('@').and_then(|h| handle(Some(h)))).or_else(|| Some("g1t".to_owned()))
21}
22
23#[cfg(test)]
24mod tests {
25 use super::*;
26
27 #[test]
28 fn a_run_is_the_agent_named_or_the_one_it_is_billed_under_or_g1t() {
29 assert_eq!(agent_of(Some("Mike"), "@mike").as_deref(), Some("mike"));
30 assert_eq!(agent_of(None, "@margo").as_deref(), Some("margo"));
31 assert_eq!(agent_of(Some(" "), "@margo").as_deref(), Some("margo"));
32 assert_eq!(agent_of(None, "g1t").as_deref(), Some("g1t"));
33 assert_eq!(agent_of(Some("@g1t"), "api").as_deref(), Some("g1t"));
34 }
35
36 #[test]
37 fn who_asked_is_a_username_or_no_one() {
38 assert_eq!(handle(Some("@Chase")).as_deref(), Some("chase"));
39 assert_eq!(handle(Some("")), None);
40 assert_eq!(handle(None), None);
41 }
42}