Logs to file

This commit is contained in:
Daniel Flanagan 2024-04-16 15:15:40 -05:00
parent d2e3c60bb4
commit 3fe83e83f1
9 changed files with 449 additions and 12 deletions

319
Cargo.lock generated
View file

@ -17,6 +17,18 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.2"
@ -26,6 +38,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]]
name = "android-tzdata"
version = "0.1.1"
@ -115,6 +133,21 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cassowary"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "castaway"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc"
dependencies = [
"rustversion",
]
[[package]]
name = "cc"
version = "1.0.90"
@ -178,6 +211,19 @@ dependencies = [
"tracing-error",
]
[[package]]
name = "compact_str"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
dependencies = [
"castaway",
"cfg-if",
"itoa",
"ryu",
"static_assertions",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
@ -203,6 +249,15 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
@ -218,6 +273,40 @@ version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "crossterm"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
dependencies = [
"bitflags 2.5.0",
"crossterm_winapi",
"libc",
"mio",
"parking_lot 0.12.1",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "either"
version = "1.9.0"
@ -446,6 +535,16 @@ name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
@ -573,6 +672,12 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "indoc"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "instant"
version = "0.1.12"
@ -591,6 +696,15 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.10"
@ -640,6 +754,15 @@ version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "lru"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc"
dependencies = [
"hashbrown",
]
[[package]]
name = "matchers"
version = "0.1.0"
@ -693,6 +816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.48.0",
]
@ -725,6 +849,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.18"
@ -863,6 +993,12 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "percent-encoding"
version = "2.3.1"
@ -887,6 +1023,12 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@ -941,6 +1083,32 @@ dependencies = [
"getrandom",
]
[[package]]
name = "ratatui"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a564a852040e82671dc50a37d88f3aa83bbc690dfc6844cfe7a2591620206a80"
dependencies = [
"bitflags 2.5.0",
"cassowary",
"compact_str",
"crossterm",
"indoc",
"itertools",
"lru",
"paste",
"stability",
"strum",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "redact"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7301863b5e5486c9f18320ccc1aedce9a5fdf3056ae89fa021933d6f054430f"
[[package]]
name = "redox_syscall"
version = "0.2.16"
@ -1138,6 +1306,12 @@ dependencies = [
"base64",
]
[[package]]
name = "rustversion"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
[[package]]
name = "ryu"
version = "1.0.17"
@ -1234,6 +1408,27 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "signal-hook"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
@ -1284,6 +1479,44 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "stability"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strum"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "2.0.53"
@ -1339,6 +1572,9 @@ dependencies = [
"chrono",
"chrono-humanize",
"color-eyre",
"crossterm",
"ratatui",
"redact",
"regex",
"reqwest",
"reqwest-middleware",
@ -1349,7 +1585,9 @@ dependencies = [
"sled",
"tokio",
"tracing",
"tracing-appender",
"tracing-subscriber",
"xdg",
]
[[package]]
@ -1394,6 +1632,37 @@ dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -1492,6 +1761,18 @@ dependencies = [
"tracing-core",
]
[[package]]
name = "tracing-appender"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf"
dependencies = [
"crossbeam-channel",
"thiserror",
"time",
"tracing-subscriber",
]
[[package]]
name = "tracing-attributes"
version = "0.1.27"
@ -1588,6 +1869,18 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "url"
version = "2.5.0"
@ -1895,3 +2188,29 @@ dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "xdg"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -10,6 +10,9 @@ anyhow = "1.0.81"
chrono = { version = "0.4.35", features = ["serde"] }
chrono-humanize = "0.2.3"
color-eyre = "0.6.3"
crossterm = "0.27.0"
ratatui = "0.26.2"
redact = "0.1.9"
regex = "1.10.3"
reqwest = { version = "0.11.26", features = ["json", "socks"] }
reqwest-middleware = "0.2.5"
@ -20,7 +23,9 @@ serde_json = "1.0.114"
sled = "0.34.7"
tokio = { version = "1.36.0", features = ["full"] }
tracing = "0.1.40"
tracing-appender = "0.2.3"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
xdg = "2.5.2"
[profile.dev]
opt-level = 1

View file

@ -49,6 +49,7 @@
lldb
# libs
libopus
openssl
pkg-config
];

47
readme.md Normal file
View file

@ -0,0 +1,47 @@
# Task Management
Currently, at my job, I have a number of layers of red tape to work through just
to actually make commits.
- I must have a Jira ticket to work against. This is almost never provided to
me and is something I make myself.
- I must have a GitLab branch name that matches the Jira ticket.
- I must progress the Jira ticket separately from the GitLab branch.
My goal is to unify these without having to page through these applications
which often breaks flow. Here's how I'm hoping to structure this:
- I run a command indicating a new task that I am working on.
- Something like `task new 'fix slack token being logged'`
- Perhaps also prompts me with a fuzzy finder for a project as well?
- This gives me a ticket ID
- If I provided a project as well, it should checkout a new branch with the
correct branch name for that project branching off the latest default branch
from the origin
- Perhaps it also moves my current working directory into the project
- Perhaps it even further opens my text editor
- I make commits and push them up
- Each project needs to have hooks setup in the git config with GitLab that
create a draft MR
- I need those commits to be reviewed, so I need a way to ask for reviews
- Something like `task request-review $ID`?
- Marks the review as "ready" (not a "draft")
- This then has different flows depending on the project, but primarily would
mean sending a message in Slack with the format `!review $LINK_TO_MR -
$SUMMARY_OF_CHANGE`
- Once the MR is ready to merge, I need to be notified as I want to merge and
deploy it
- The code review bot does notify in the review thread. Perhaps I can listen
for this?
- I need to merge the MR
- If the project requires it, I need to manually confirm that I want to deploy
to production
- Once my change has been deployed, I need to close the related Jira ticket
My goal is to codify this process as generically as possible and make way for
project-specific details as well so that I can minimize my personal overhead as
I go through this process and possibly even across the organization.
It would also be nice to manage tasks across the team, dumping the state of my
Jira board and diffing that over intervals of time would be useful to see how
tasks progress over time.

View file

@ -16,6 +16,7 @@ pub trait ResourceRequest {
impl ResourceRequest for RequestBuilder {
async fn res<T: de::DeserializeOwned>(self) -> Result<T> {
// TODO: make this a field on this struct or something?
/*
use tracing::debug;
let body = self.send().await?.text().await?;

View file

@ -25,6 +25,7 @@ pub struct User {
impl GitLab {
pub fn try_new(url: &str, token: &str) -> Result<Self> {
let mut headers = HeaderMap::new();
// TODO: ensure this token cannot be leaked to logs?
headers.insert("PRIVATE-TOKEN", HeaderValue::from_str(token)?);
headers.insert("content-type", HeaderValue::from_str("application/json")?);
headers.insert("accepts", HeaderValue::from_str("application/json")?);

View file

@ -86,6 +86,7 @@ pub struct IssueSearch {
impl Jira {
pub fn try_new(url: &str, token: &str) -> Result<Self> {
let mut headers = HeaderMap::new();
// TODO: ensure this token cannot be leaked to logs?
headers.insert(
"Authorization",
HeaderValue::from_str(&format!("Basic {}", token.trim()))?,

View file

@ -1,3 +1,5 @@
#![warn(clippy::all)]
mod client;
mod config;
mod gitlab;
@ -11,17 +13,35 @@ use tasks::Tasks;
use tracing::{error, info};
use tracing_subscriber::{filter::LevelFilter, EnvFilter};
use crossterm::{
event::{self, KeyCode, KeyEventKind},
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
ExecutableCommand,
};
use ratatui::{
prelude::{CrosstermBackend, Stylize, Terminal},
widgets::Paragraph,
};
use std::io::stdout;
#[allow(dead_code)]
const ANSI_CLEAR: &'static str = "\x1b[2J\x1b[1;1H";
#[tokio::main]
async fn main() -> Result<()> {
let logs_dir = xdg::BaseDirectories::new()?.create_cache_directory("taskr/logs")?;
let file_appender = tracing_appender::rolling::hourly(logs_dir, "log");
let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
color_eyre::install().expect("Failed to install color_eyre");
let filter = EnvFilter::builder()
.with_default_directive(LevelFilter::TRACE.into())
.parse_lossy("info,tasks=trace");
tracing_subscriber::fmt().with_env_filter(filter).init();
tracing_subscriber::fmt()
.with_writer(non_blocking)
.with_env_filter(filter)
.init();
match run().await {
Ok(()) => Ok(()),
@ -47,8 +67,38 @@ async fn run() -> Result<()> {
}
let mut vtasks: Vec<&task::Task> = tasks.values().collect();
vtasks.sort_unstable();
for t in vtasks {
for t in &vtasks {
info!("{}", t);
}
info!("Number of tasks: {}", vtasks.len());
tui().await
}
async fn tui() -> Result<()> {
stdout().execute(EnterAlternateScreen)?;
enable_raw_mode()?;
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
terminal.clear()?;
loop {
terminal.draw(|frame| {
let area = frame.size();
frame.render_widget(
Paragraph::new("Hello Ratatui! (press 'q' to quit)").white(),
area,
);
})?;
if event::poll(std::time::Duration::from_millis(10))? {
if let event::Event::Key(key) = event::read()? {
if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') {
break;
}
}
}
}
// TODO main loop
stdout().execute(LeaveAlternateScreen)?;
disable_raw_mode()?;
Ok(())
}

View file

@ -25,26 +25,38 @@ pub struct Task {
const STATUS_PRIORITY: [&str; 4] = ["Blocked", "InProgress", "DevReady", "Backlog"];
impl PartialOrd for Task {
/// We sort tasks first by their status. If those are equal, we sort by their priority, favoring the `local_priority`.
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Task {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
if self.eq(other) {
return Some(Ordering::Equal);
return Ordering::Equal;
}
let a = STATUS_PRIORITY.iter().position(self.status);
let b = STATUS_PRIORITY.iter().position(other.status);
if Some(o) = a.partial_cmp(b) {
{
let a = STATUS_PRIORITY.iter().position(|s| **s == self.status);
let b = STATUS_PRIORITY.iter().position(|s| **s == other.status);
let o = a.cmp(&b);
if o != Ordering::Equal {
return o;
}
}
{
let o = self.local_priority.cmp(&other.local_priority);
if o != Ordering::Equal {
return o;
}
}
self.jira_priority.cmp(&other.jira_priority)
}
}
// impl Ord for Task {
// fn cmp(&self, other: &Self) -> std::cmp::Ordering {
// todo!()
// }
// }
impl Display for Task {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self {