crates/cli/git-ents/src/commands/account.rs
account.rshistorycomment on this file
| 1 | //! `git ents account create`: link a member to a login identity at the |
| 2 | //! fixed `refs/meta/account` ref (`model.account`). |
| 3 | |
| 4 | use ents_model::{Account, MemberId, namespace}; |
| 5 | use ents_receive::{Identity, propose_entity}; |
| 6 | use gix_ref_store::RefStoreRead; |
| 7 | |
| 8 | use super::{actor, signer}; |
| 9 | use crate::error::{Error, Result}; |
| 10 | use crate::mutate::outcome_to_result; |
| 11 | use crate::root::LocalRoot; |
| 12 | |
| 13 | /// `git ents account show`: this repository's account identity. |
| 14 | /// |
| 15 | /// # Errors |
| 16 | /// |
| 17 | /// [`Error::NotFound`] if no account has been created yet |
| 18 | /// (`git ents account create` first). |
| 19 | pub fn show(root: &LocalRoot) -> Result<Account> { |
| 20 | #[expect( |
| 21 | clippy::expect_used, |
| 22 | clippy::unwrap_in_result, |
| 23 | reason = "ACCOUNT_REF is a fixed, compile-time-known-valid refname literal" |
| 24 | )] |
| 25 | let name: gix::refs::FullName = namespace::ACCOUNT_REF |
| 26 | .try_into() |
| 27 | .expect("fixed, valid refname"); |
| 28 | let Some(tip) = root.refs.get(name.as_ref())? else { |
| 29 | return Err(Error::NotFound { |
| 30 | what: "account".to_owned(), |
| 31 | }); |
| 32 | }; |
| 33 | let tree = super::commit_tree(&root.objects, tip)?; |
| 34 | Ok(facet_git_tree::deserialize::<Account>( |
| 35 | &tree, |
| 36 | &root.objects, |
| 37 | )?) |
| 38 | } |
| 39 | |
| 40 | /// Run `git ents account create`. |
| 41 | /// |
| 42 | /// # Errors |
| 43 | /// |
| 44 | /// [`Error::NotFound`] if `member` is given but no such member exists (or, |
| 45 | /// when omitted, the signer's own key is not enrolled yet — enroll it with |
| 46 | /// `git ents members add` first); otherwise see |
| 47 | /// [`crate::mutate::outcome_to_result`]. |
| 48 | pub fn create( |
| 49 | root: &LocalRoot, |
| 50 | member: Option<String>, |
| 51 | login: String, |
| 52 | key: Option<std::path::PathBuf>, |
| 53 | ) -> Result<()> { |
| 54 | let signer = signer(root, key.clone())?; |
| 55 | let member_id = match member { |
| 56 | Some(username) => MemberId::new(username), |
| 57 | None => { |
| 58 | let (username, _) = |
| 59 | super::members::check(root, key)?.ok_or_else(|| Error::NotFound { |
| 60 | what: "member for the current signing key".to_owned(), |
| 61 | })?; |
| 62 | MemberId::new(username) |
| 63 | } |
| 64 | }; |
| 65 | let account = Account { |
| 66 | member: member_id, |
| 67 | login, |
| 68 | }; |
| 69 | #[expect( |
| 70 | clippy::expect_used, |
| 71 | clippy::unwrap_in_result, |
| 72 | reason = "ACCOUNT_REF is a fixed, compile-time-known-valid refname literal" |
| 73 | )] |
| 74 | let name: gix::refs::FullName = namespace::ACCOUNT_REF |
| 75 | .try_into() |
| 76 | .expect("fixed, valid refname"); |
| 77 | let identity = Identity { |
| 78 | actor: actor(&signer), |
| 79 | author: None, |
| 80 | sign: &|payload| signer.sign(payload), |
| 81 | }; |
| 82 | let outcome = propose_entity( |
| 83 | &root.refs, |
| 84 | &root.objects, |
| 85 | &root.events, |
| 86 | name, |
| 87 | &account, |
| 88 | &identity, |
| 89 | "Create account", |
| 90 | root.mode(), |
| 91 | )?; |
| 92 | outcome_to_result(outcome, None)?; |
| 93 | Ok(()) |
| 94 | } |