//! Types of the Oxygenhub JSON API (hub spec §12.1). Everything here is //! `serde` data with no behaviour, so clients in other languages can be //! generated from it and the server can never drift from them. //! //! Shapes reuse `oxy --json`'s where one exists (hashes as lowercase hex, //! times as milliseconds since the epoch), so tools written against the //! command line work against the hub. use serde::{Deserialize, Serialize}; /// A repository as the API lists it. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Repository { pub owner: String, pub name: String, pub description: String, pub default_bookmark: String, pub visibility: Visibility, /// Milliseconds since the epoch. pub created_ms: i64, pub updated_ms: i64, /// `https://…/{owner}/{name}`, what `oxy clone` takes. pub clone_url: String, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum Visibility { Public, Internal, Private, } impl Visibility { pub fn as_str(self) -> &'static str { match self { Visibility::Public => "public", Visibility::Internal => "internal", Visibility::Private => "private", } } pub fn parse(s: &str) -> Option { Some(match s { "public" => Visibility::Public, "internal" => Visibility::Internal, "private" => Visibility::Private, _ => return None, }) } } /// A bookmark: a name for a set of heads (spec §10.1). #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Bookmark { pub name: String, pub heads: Vec, /// Number of changes in the bookmark's state. pub changes: usize, pub default: bool, } /// A tag: a name for one state, with its attestation when signed. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Tag { pub name: String, pub heads: Vec, pub message: String, pub signer: Option, } /// One change in a history listing. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct ChangeSummary { pub hash: String, pub message: String, pub author: Author, pub when_ms: u64, pub deps: Vec, pub head: bool, pub signature: Signature, } /// Who wrote a change: the linked account when the signing key is linked, /// else the key alone. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Author { pub name: String, pub email: String, pub key: String, /// The hub account this key is linked to, when any. pub account: Option, } /// Signature status of a change as `oxy verify` reports it. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "status", rename_all = "lowercase")] pub enum Signature { Unsigned, Valid { key: String, sealed: bool, revoked: bool }, Invalid { reason: String }, } /// An RFC 7807 problem response. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Problem { pub status: u16, pub title: String, pub detail: String, } #[cfg(test)] mod tests { use super::*; #[test] fn visibility_round_trips() { for v in [Visibility::Public, Visibility::Internal, Visibility::Private] { assert_eq!(Visibility::parse(v.as_str()), Some(v)); } assert_eq!(Visibility::parse("secret"), None); } } // ---------------------------------------------------------------- proposals /// A proposal: a request to add changes to a target bookmark (hub spec §7). #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Proposal { pub number: i64, pub title: String, pub body: String, pub author: String, pub state: ProposalState, pub target: String, pub source: ProposalSource, /// The changes the proposal adds, dependency order, newest last. pub changes: Vec, /// Heads of the projected state (target plus the changes), when computed. pub projected_heads: Vec, pub projected_state: Option, pub conflicted: bool, pub approvals: Vec, pub landable: bool, pub blockers: Vec, pub created_ms: i64, pub updated_ms: i64, /// `https://hub/{owner}/{name}/proposal/{number}`. pub url: String, /// Where `oxy` fetches the changes from. pub repository_url: String, /// The fork's clone URL when the source is a fork. pub source_url: Option, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum ProposalState { Draft, Open, Landed, Closed, } impl ProposalState { pub fn as_str(self) -> &'static str { match self { ProposalState::Draft => "draft", ProposalState::Open => "open", ProposalState::Landed => "landed", ProposalState::Closed => "closed", } } pub fn parse(s: &str) -> Option { Some(match s { "draft" => ProposalState::Draft, "open" => ProposalState::Open, "landed" => ProposalState::Landed, "closed" => ProposalState::Closed, _ => return None, }) } } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "lowercase")] pub enum ProposalSource { /// A bookmark of the same repository. Bookmark { bookmark: String }, /// A bookmark of a fork. Fork { owner: String, name: String, bookmark: String }, /// An explicit list of change hashes. Changes { hashes: Vec }, } /// A reviewer's approval, counted only when backed by a seal over every /// change of the proposal signed with a key linked to the reviewer. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Approval { pub account: String, pub sealed: bool, pub key: Option, }