//! Pull request types. A pull request is an issue with `kind = 'pull'` plus a `pull_requests` //! row. The stored shape is in migrations/0007_pulls.sql; the store functions live in //! store/pulls.rs. use crate::error::{Error, Result}; use crate::issues::Issue; use crate::model::Id; /// Mergeability of a pull request, as last computed. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Mergeable { Unknown, Clean, Conflict, Merged, UpToDate, } impl Mergeable { pub fn as_str(&self) -> &'static str { match self { Mergeable::Unknown => "unknown", Mergeable::Clean => "clean", Mergeable::Conflict => "conflict", Mergeable::Merged => "merged", Mergeable::UpToDate => "up_to_date", } } } impl std::str::FromStr for Mergeable { type Err = Error; fn from_str(s: &str) -> Result { match s { "unknown" => Ok(Mergeable::Unknown), "clean" => Ok(Mergeable::Clean), "conflict" => Ok(Mergeable::Conflict), "merged" => Ok(Mergeable::Merged), "up_to_date" => Ok(Mergeable::UpToDate), other => Err(Error::Invalid(format!("mergeable {other:?}"))), } } } #[derive(Debug, Clone, PartialEq)] pub struct PullRequest { /// The backing issue row (`kind = 'pull'`): number, title, state, author and so on. pub issue: Issue, pub base_branch: String, /// `None` once the head repo has been deleted. pub head_repo_id: Option, pub head_branch: String, /// Last known head commit (also `refs/pull/N/head` in the base repo). pub head_oid: String, /// Base branch tip when mergeability was last computed. pub base_oid: String, pub merge_base: Option, pub mergeable: Mergeable, pub conflict_files: Vec, pub merged_at: Option, pub merged_by: Option, pub merge_commit: Option, } /// How a pull request is merged into its base branch. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum MergeStyle { Merge, Squash, FastForward, } impl MergeStyle { /// The value used in forms and URLs. pub fn as_str(&self) -> &'static str { match self { MergeStyle::Merge => "merge", MergeStyle::Squash => "squash", MergeStyle::FastForward => "ff", } } } impl std::str::FromStr for MergeStyle { type Err = Error; fn from_str(s: &str) -> Result { match s { "merge" => Ok(MergeStyle::Merge), "squash" => Ok(MergeStyle::Squash), "ff" => Ok(MergeStyle::FastForward), other => Err(Error::Invalid(format!("merge style {other:?}"))), } } } #[cfg(test)] mod tests { use super::*; #[test] fn mergeable_round_trips() { for m in [ Mergeable::Unknown, Mergeable::Clean, Mergeable::Conflict, Mergeable::Merged, Mergeable::UpToDate, ] { assert_eq!(m.as_str().parse::().ok(), Some(m)); } assert!("Clean".parse::().is_err()); } #[test] fn merge_style_round_trips() { for s in [ MergeStyle::Merge, MergeStyle::Squash, MergeStyle::FastForward, ] { assert_eq!(s.as_str().parse::().ok(), Some(s)); } assert_eq!(MergeStyle::FastForward.as_str(), "ff"); assert!("rebase".parse::().is_err()); } }