aboutsummaryrefslogtreecommitdiff
path: root/ticket
diff options
context:
space:
mode:
authorMichael Gattozzi <mgattozzi@gmail.com>2019-12-13 13:49:33 -0500
committerMichael Gattozzi <mgattozzi@gmail.com>2019-12-13 13:49:33 -0500
commitb32b1478dec75cc8282036bae56097a1e29fb47f (patch)
treeaac3dd036d940224b080c16c5acca3932fca6be6 /ticket
parenta06e021420e8c374d1e5f76fe69012bec9202e22 (diff)
Add the ability to add comments to tickets
This commit encompasses quite a few changes to add tickets: - The `Ticket` struct is updated to properly order comments using a uuid v1 and to hold the user name, uuid, and their comment - Tickets in the repo are updated to accomodate this change to the ticket. Despite this being a breaking config change, none of these tickets had any comments so it was an easy manual port and the migration tool did not need to be updated. - The TUI was updated to display the tickets a bit better with some coloring and now also showing the comments with them This gets us one step closer to a decent first release for ticket. The only things that are really left to do are adding the ability to comment in the tui, listing tickets on the cli, and adding in issue assignees on both the cli and tui.
Diffstat (limited to 'ticket')
-rw-r--r--ticket/Cargo.toml5
-rw-r--r--ticket/src/actions.rs27
-rw-r--r--ticket/src/main.rs85
-rw-r--r--ticket/src/tui.rs22
4 files changed, 107 insertions, 32 deletions
diff --git a/ticket/Cargo.toml b/ticket/Cargo.toml
index d6fb260..574251a 100644
--- a/ticket/Cargo.toml
+++ b/ticket/Cargo.toml
@@ -10,8 +10,13 @@ license = "GPL-3.0"
[dependencies]
anyhow = "1.0"
colored = "1.9"
+configamajig = { path = "../configamajig" }
chrono = "0.4"
paw = "1.0"
+# Pinning a specific version in case they break everything again and mess up semver,
+# though this won't fix if they break the semver on the core crate. Either way I don't
+# trust this crate enough to not pin it.
+rand = "0.7.2"
rustyline = "5.0"
serde = { version = "1.0", features = ["derive"] }
shared = { path = "../shared" }
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;
}
}