aboutsummaryrefslogtreecommitdiff
path: root/ticket/src
diff options
context:
space:
mode:
Diffstat (limited to 'ticket/src')
-rw-r--r--ticket/src/actions.rs27
-rw-r--r--ticket/src/main.rs85
-rw-r--r--ticket/src/tui.rs22
3 files changed, 102 insertions, 32 deletions
diff --git a/ticket/src/actions.rs b/ticket/src/actions.rs
index 0d371b3..b6d8cb0 100644
--- a/ticket/src/actions.rs
+++ b/ticket/src/actions.rs
@@ -6,15 +6,31 @@ use anyhow::{
bail,
Result,
};
+use chrono::prelude::*;
use log::*;
+use rand::prelude::*;
use shared::find_root;
use std::{
+ convert::TryInto,
fs,
path::{
Path,
PathBuf,
},
};
+use uuid::{
+ v1::{
+ Context,
+ Timestamp,
+ },
+ Uuid,
+};
+
+pub fn get_all_tickets() -> Result<Vec<Ticket>> {
+ let mut tickets = get_open_tickets()?;
+ tickets.extend(get_closed_tickets()?);
+ Ok(tickets)
+}
pub fn get_open_tickets() -> Result<Vec<Ticket>> {
get_tickets(&open_tickets()?)
@@ -90,3 +106,14 @@ fn get_ticketsv0(path: &Path) -> Result<Vec<TicketV0>> {
out.sort_by(|a, b| a.number.cmp(&b.number));
Ok(out)
}
+
+pub fn uuid_v1() -> Result<Uuid> {
+ Ok(Uuid::new_v1(
+ Timestamp::from_unix(
+ Context::new(random()),
+ Utc::now().timestamp().try_into()?,
+ 0,
+ ),
+ &[random(), random(), random(), random(), random(), random()],
+ )?)
+}
diff --git a/ticket/src/main.rs b/ticket/src/main.rs
index 74a5699..c889da2 100644
--- a/ticket/src/main.rs
+++ b/ticket/src/main.rs
@@ -7,10 +7,11 @@ mod tui;
use actions::*;
use anyhow::{
bail,
+ format_err,
Result,
};
-use chrono::prelude::*;
use colored::*;
+use configamajig::*;
use log::*;
use rustyline::{
error::ReadlineError,
@@ -21,7 +22,7 @@ use serde::{
Serialize,
};
use std::{
- convert::TryInto,
+ collections::BTreeMap,
env,
fs,
process,
@@ -29,13 +30,7 @@ use std::{
thread,
time,
};
-use uuid::{
- v1::{
- Context,
- Timestamp,
- },
- Uuid,
-};
+use uuid::Uuid;
#[derive(structopt::StructOpt)]
struct Args {
@@ -53,8 +48,10 @@ enum Cmd {
New,
/// Show a ticket on the command line
Show { id: Uuid },
- /// Close a ticket on the command line
+ /// Close a ticket from the command line
Close { id: Uuid },
+ /// Comment on a ticket from the command line
+ Comment { id: Uuid, message: String },
}
#[paw::main]
@@ -71,6 +68,7 @@ fn main(args: Args) {
Cmd::Migrate => migrate(),
Cmd::Show { id } => show(id),
Cmd::Close { id } => close(id),
+ Cmd::Comment { id, message } => comment(id, message),
} {
error!("{}", e);
std::process::exit(1);
@@ -134,17 +132,10 @@ fn new() -> Result<()> {
let t = Ticket {
title,
status: Status::Open,
- id: Uuid::new_v1(
- Timestamp::from_unix(
- Context::new(1),
- Utc::now().timestamp().try_into()?,
- 0,
- ),
- &[0, 5, 2, 4, 9, 3],
- )?,
+ id: uuid_v1()?,
assignees: Vec::new(),
description: description_contents,
- comments: Vec::new(),
+ comments: BTreeMap::new(),
version: Version::V1,
};
@@ -195,7 +186,7 @@ fn show(id: Uuid) -> Result<()> {
);
}
- print!(
+ println!(
"{}{}\n\n{}",
"Status: ".bold().purple(),
match ticket.status {
@@ -204,6 +195,9 @@ fn show(id: Uuid) -> Result<()> {
},
ticket.description
);
+ for (_, name, comment) in ticket.comments.values() {
+ println!("{}\n{}\n", name.0.cyan(), comment.0);
+ }
found = true;
break;
}
@@ -256,7 +250,6 @@ fn close(id: Uuid) -> Result<()> {
/// Upgrade from V0 to V1 of the ticket
fn migrate() -> Result<()> {
- let ctx = Context::new(1);
let tickets = get_all_ticketsv0()?;
let open_tickets_path = open_tickets()?;
@@ -266,13 +259,10 @@ fn migrate() -> Result<()> {
let ticket = Ticket {
title: t.title,
status: t.status,
- id: Uuid::new_v1(
- Timestamp::from_unix(&ctx, Utc::now().timestamp().try_into()?, 0),
- &[0, 5, 2, 4, 9, 3],
- )?,
+ id: uuid_v1()?,
assignees: t.assignee.map_or_else(Vec::new, |a| vec![a]),
description: t.description,
- comments: Vec::new(),
+ comments: BTreeMap::new(),
version: Version::V1,
};
@@ -297,6 +287,38 @@ fn migrate() -> Result<()> {
Ok(())
}
+fn comment(id: Uuid, message: String) -> Result<()> {
+ let mut ticket = get_all_tickets()?
+ .into_iter()
+ .find(|t| t.id == id)
+ .ok_or_else(|| {
+ format_err!("The uuid '{}' is not associated with any ticket")
+ })?;
+ let user_config = get_user_config()?;
+ let _ = ticket.comments.insert(
+ uuid_v1()?,
+ (user_config.uuid, Name(user_config.name), Comment(message)),
+ );
+ for (k, v) in &ticket.comments {
+ info!("{:?} = {:?}", k, v);
+ }
+ let open_tickets_path = open_tickets()?;
+ let closed_tickets_path = closed_tickets()?;
+ let path = match ticket.status {
+ Status::Open => &open_tickets_path,
+ Status::Closed => &closed_tickets_path,
+ };
+ let mut name = ticket
+ .title
+ .split_whitespace()
+ .collect::<Vec<&str>>()
+ .join("-");
+ name.push_str(".toml");
+ name = name.to_lowercase();
+ fs::write(path.join(&name), toml::to_string_pretty(&ticket)?)?;
+
+ Ok(())
+}
#[derive(Serialize, Deserialize, Debug)]
/// The fundamental type this tool revolves around. The ticket represents
/// everything about an issue or future plan for the code base.
@@ -306,8 +328,9 @@ pub struct Ticket {
id: Uuid,
assignees: Vec<String>,
description: String,
- comments: Vec<(User, String)>,
version: Version,
+ #[serde(serialize_with = "toml::ser::tables_last")]
+ comments: BTreeMap<Uuid, (Uuid, Name, Comment)>,
}
#[derive(Serialize, Deserialize, Debug)]
@@ -319,8 +342,12 @@ pub enum Version {
}
#[derive(Serialize, Deserialize, Debug)]
-/// Newtype to represent a User or maintainer
-pub struct User(String);
+/// Newtype to represent a users Name
+pub struct Name(String);
+
+#[derive(Serialize, Deserialize, Debug)]
+/// Newtype to represent a Comment
+pub struct Comment(String);
#[derive(Serialize, Deserialize, Debug)]
/// Original version of the tickets on disk. This exists for historical reasons
diff --git a/ticket/src/tui.rs b/ticket/src/tui.rs
index 01f00bf..57c8aca 100644
--- a/ticket/src/tui.rs
+++ b/ticket/src/tui.rs
@@ -233,7 +233,7 @@ pub fn run() -> Result<()> {
app.table("Open").render(&mut f, horizontal[0]);
Paragraph::new(app.description("Open").iter())
- .block(Block::default().title("Description").borders(Borders::ALL))
+ .block(Block::default().borders(Borders::ALL))
.alignment(Alignment::Left)
.wrap(true)
.render(&mut f, horizontal[1]);
@@ -242,7 +242,7 @@ pub fn run() -> Result<()> {
app.table("Closed").render(&mut f, horizontal[0]);
Paragraph::new(app.description("Closed").iter())
- .block(Block::default().title("Description").borders(Borders::ALL))
+ .block(Block::default().borders(Borders::ALL))
.alignment(Alignment::Left)
.wrap(true)
.render(&mut f, horizontal[1]);
@@ -314,7 +314,23 @@ impl<'a> App<'a> {
let mut description = vec![];
for (idx, i) in self.tickets.tickets.get(tab).unwrap().iter().enumerate() {
if idx == self.tickets.index {
- description = vec![Text::raw(i.description.to_owned())];
+ description = {
+ let header = Style::default().fg(Color::Red).modifier(Modifier::BOLD);
+ let mut desc = vec![
+ Text::styled("Description\n-------------\n", header),
+ Text::raw(i.description.to_owned()),
+ ];
+ let name_style =
+ Style::default().fg(Color::Cyan).modifier(Modifier::BOLD);
+ if i.comments.is_empty() {
+ desc.push(Text::styled("\nComments\n--------\n", header));
+ for (_, name, comment) in i.comments.values() {
+ desc.push(Text::styled(format!("\n{}\n", name.0), name_style));
+ desc.push(Text::raw(format!("{}\n", comment.0)));
+ }
+ }
+ desc
+ };
break;
}
}