use anyhow::Result;
use radicle::cob::issue::{Issue, IssueId};
use radicle::cob::Label;
use radicle::issue::cache::Issues;
use radicle::issue::State;
use radicle::prelude::{Did, Signer};
use radicle::storage::git::Repository;
use radicle::Profile;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Filter {
state: Option<State>,
assigned: bool,
assignees: Vec<Did>,
}
impl Default for Filter {
fn default() -> Self {
Self {
state: Some(State::default()),
assigned: false,
assignees: vec![],
}
}
}
impl Filter {
pub fn with_state(mut self, state: Option<State>) -> Self {
self.state = state;
self
}
pub fn with_assgined(mut self, assigned: bool) -> Self {
self.assigned = assigned;
self
}
pub fn with_assginee(mut self, assignee: Did) -> Self {
self.assignees.push(assignee);
self
}
}
impl ToString for Filter {
fn to_string(&self) -> String {
let mut filter = String::new();
if let Some(state) = &self.state {
filter.push_str(&format!("is:{}", state));
filter.push(' ');
}
if self.assigned {
filter.push_str("is:assigned");
filter.push(' ');
}
if !self.assignees.is_empty() {
filter.push_str("assignees:");
filter.push('[');
let mut assignees = self.assignees.iter().peekable();
while let Some(assignee) = assignees.next() {
filter.push_str(&assignee.encode());
if assignees.peek().is_some() {
filter.push(',');
}
}
filter.push(']');
}
filter
}
}
pub fn all(profile: &Profile, repository: &Repository) -> Result<Vec<(IssueId, Issue)>> {
let cache = profile.issues(repository)?;
let issues = cache.list()?;
Ok(issues.flatten().collect())
}
pub fn find(profile: &Profile, repository: &Repository, id: &IssueId) -> Result<Option<Issue>> {
let cache = profile.issues(repository)?;
Ok(cache.get(id)?)
}
pub fn create<G: Signer>(
profile: &Profile,
repository: &Repository,
signer: &G,
title: String,
description: String,
labels: &[Label],
assignees: &[Did],
) -> Result<IssueId> {
let mut issues = profile.issues_mut(repository)?;
let issue = issues.create(title, description.trim(), labels, assignees, [], signer)?;
Ok(*issue.id())
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use anyhow::Result;
use radicle::issue;
use super::*;
#[test]
fn issue_filter_display_with_state_should_succeed() -> Result<()> {
let actual = Filter::default().with_state(Some(issue::State::Open));
assert_eq!(String::from("is:open "), actual.to_string());
Ok(())
}
#[test]
fn issue_filter_display_with_state_and_assigned_should_succeed() -> Result<()> {
let actual = Filter::default()
.with_state(Some(issue::State::Open))
.with_assgined(true);
assert_eq!(String::from("is:open is:assigned "), actual.to_string());
Ok(())
}
#[test]
fn issue_filter_display_with_status_and_author_should_succeed() -> Result<()> {
let actual = Filter::default()
.with_state(Some(issue::State::Open))
.with_assginee(Did::from_str(
"did:key:z6MkswQE8gwZw924amKatxnNCXA55BMupMmRg7LvJuim2C1V",
)?);
assert_eq!(
String::from(
"is:open assignees:[did:key:z6MkswQE8gwZw924amKatxnNCXA55BMupMmRg7LvJuim2C1V]"
),
actual.to_string()
);
Ok(())
}
}