Skip to content

Commit

Permalink
fetch labels when pulling tasks one by one
Browse files Browse the repository at this point in the history
  • Loading branch information
jhspetersson committed Dec 22, 2024
1 parent 49535d9 commit 7465494
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 22 deletions.
59 changes: 50 additions & 9 deletions src/connectors/github.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use std::sync::{Arc, LazyLock};

use futures_util::TryStreamExt;
use futures_util::{StreamExt, TryStreamExt};
use graphql_client::{reqwest::post_graphql_blocking as post_graphql, GraphQLQuery};
use octocrab::Octocrab;
use octocrab::models::{CommentId, IssueState};
Expand Down Expand Up @@ -40,8 +40,20 @@ impl RemoteConnector for GithubRemoteConnector {
RUNTIME.block_on(list_issues(user, repo, with_comments, limit, state, task_statuses))
}

fn get_remote_task(&self, user: &String, repo: &String, task_id: &String, with_comments: bool, task_statuses: &Vec<String>) -> Option<Task> {
RUNTIME.block_on(get_issue(&user, &repo, task_id.parse().unwrap(), with_comments, task_statuses))
fn get_remote_task(
&self,
user: &String,
repo: &String,
task_id: &String,
with_comments: bool,
with_labels: bool,
task_statuses: &Vec<String>
) -> Option<Task> {
RUNTIME.block_on(
get_issue(
&user, &repo, task_id.parse().unwrap(), with_comments, with_labels, task_statuses
)
)
}

fn create_remote_task(&self, user: &String, repo: &String, task: &Task) -> Result<String, String> {
Expand Down Expand Up @@ -212,7 +224,14 @@ async fn list_issue_comments(user: &String, repo: &String, n: u64) -> Vec<Commen
result
}

async fn get_issue(user: &String, repo: &String, n: u64, with_comments: bool, task_statuses: &Vec<String>) -> Option<Task> {
async fn get_issue(
user: &String,
repo: &String,
n: u64,
with_comments: bool,
with_labels: bool,
task_statuses: &Vec<String>
) -> Option<Task> {
let crab = get_octocrab_instance().await;
let issue = crab.issues(user, repo).get(n).await;
match issue {
Expand All @@ -231,6 +250,16 @@ async fn get_issue(user: &String, repo: &String, n: u64, with_comments: bool, ta
task.set_comments(task_comments);
}

if with_labels {
let labels = issue.labels.iter()
.map(|l| Label::new(
l.name.to_string(),
Some(l.color.to_string()),
l.description.clone()
)).collect();
task.set_labels(labels);
}

Some(task)
},
_ => None
Expand Down Expand Up @@ -267,15 +296,27 @@ async fn add_label(
label_description: Option<&String>,
) -> Result<(), String> {
let crab = get_octocrab_instance().await;

let existing_labels = crab
let existing_labels_stream = crab
.issues(user, repo)
.list_labels_for_repo()
.per_page(100)
.send()
.await
.map_err(|e| e.to_string())?;
.await.unwrap()
.into_stream(&crab);
pin!(existing_labels_stream);
let mut existing_label = None;
while let Some(label) = existing_labels_stream.next().await {
if label.as_ref().unwrap().name == label_name.to_string() {
existing_label = Some(Label::new(
label.as_ref().unwrap().name.clone(),
Some(label.as_ref().unwrap().color.clone()),
label.as_ref().unwrap().description.clone(),
));
break;
}
}

if !existing_labels.items.iter().any(|l| label_name == &l.name) {
if existing_label.is_none() {
let _ = crab
.issues(user, repo)
.create_label(
Expand Down
39 changes: 37 additions & 2 deletions src/connectors/gitlab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ struct GitlabComment {
created_at: String,
}

#[derive(Serialize, Deserialize)]
struct GitlabLabel {
name: String,
color: String,
description: String,
}

#[derive(Deserialize)]
struct DeleteIssueResult {}

Expand All @@ -55,7 +62,15 @@ impl RemoteConnector for GitlabRemoteConnector {
}
}

fn list_remote_tasks(&self, user: &String, repo: &String, with_comments: bool, limit: Option<usize>, state: RemoteTaskState, task_statuses: &Vec<String>) -> Vec<Task> {
fn list_remote_tasks(
&self,
user: &String,
repo: &String,
with_comments: bool,
limit: Option<usize>,
state: RemoteTaskState,
task_statuses: &Vec<String>
) -> Vec<Task> {
let state = match state {
RemoteTaskState::Open => Some(IssueState::Opened),
RemoteTaskState::Closed => Some(IssueState::Closed),
Expand Down Expand Up @@ -96,7 +111,15 @@ impl RemoteConnector for GitlabRemoteConnector {
result
}

fn get_remote_task(&self, user: &String, repo: &String, task_id: &String, with_comments: bool, task_statuses: &Vec<String>) -> Option<Task> {
fn get_remote_task(
&self,
user: &String,
repo: &String,
task_id: &String,
with_comments: bool,
with_labels: bool,
task_statuses: &Vec<String>
) -> Option<Task> {
let client = get_client(get_token_from_env().unwrap().as_str());
let mut endpoint = gitlab::api::projects::issues::Issue::builder();
let mut endpoint = endpoint.project(user.to_string() + "/" + repo);
Expand All @@ -119,6 +142,18 @@ impl RemoteConnector for GitlabRemoteConnector {
task.set_comments(comments);
}

if with_labels {
let mut endpoint = gitlab::api::projects::labels::Labels::builder();
let endpoint = endpoint.project(user.to_string() + "/" + repo);
let endpoint = endpoint.build().unwrap();
let labels: Vec<GitlabLabel> = gitlab::api::paged(endpoint, Pagination::All).query(&client).unwrap();
let labels = issue.labels.iter()
.map(|l| labels.iter().find(|gl| gl.name == l.to_string()).unwrap())
.map(|gl| Label::new(gl.name.to_string(), Some(gl.color.to_string()), Some(gl.description.to_string())))
.collect();
task.set_labels(labels);
}

Some(task)
},
Err(_) => {
Expand Down
2 changes: 1 addition & 1 deletion src/connectors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub enum RemoteTaskState {
pub trait RemoteConnector {
fn supports_remote(&self, url: &str) -> Option<(String, String)>;
fn list_remote_tasks(&self, user: &String, repo: &String, with_comments: bool, limit: Option<usize>, state: RemoteTaskState, task_statuses: &Vec<String>) -> Vec<Task>;
fn get_remote_task(&self, user: &String, repo: &String, task_id: &String, with_comments: bool, task_statuses: &Vec<String>) -> Option<Task>;
fn get_remote_task(&self, user: &String, repo: &String, task_id: &String, with_comments: bool, with_labels: bool, task_statuses: &Vec<String>) -> Option<Task>;
fn create_remote_task(&self, user: &String, repo: &String, task: &Task) -> Result<String, String>;
fn create_remote_comment(&self, user: &String, repo: &String, task_id: &String, comment: &Comment) -> Result<String, String>;
fn create_remote_label(&self, user: &String, repo: &String, task_id: &String, label: &Label) -> Result<(), String>;
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ impl Comment {
}

impl Label {
pub fn new(name: String, color: Option<String>, description: Option<String>) -> Label {
Label {
name, color, description
}
}

pub fn get_name(&self) -> String {
self.name.to_string()
}
Expand Down
12 changes: 9 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,11 @@ enum Command {
#[arg(short, long)]
remote: Option<String>,
/// Don't import task comments
#[arg(short, long)]
#[arg(long, aliases = ["nc"])]
no_comments: bool,
/// Don't import task labels
#[arg(long, aliases = ["nl"])]
no_labels: bool,
},
/// Push task status to the remote source (e.g., GitHub)
Push {
Expand All @@ -229,6 +232,9 @@ enum Command {
/// Don't create task comments
#[arg(short, long)]
no_comments: bool,
/// Don't create task labels
#[arg(long, aliases = ["nl"])]
no_labels: bool,
/// Disable colors
#[arg(long)]
no_color: bool,
Expand Down Expand Up @@ -596,8 +602,8 @@ fn main() -> ExitCode {
Some(Command::Label { subcommand }) => task_label(subcommand),
Some(Command::Import { ids, format }) => task_import(ids, format),
Some(Command::Export { ids, status, limit, format, pretty }) => task_export(ids, status, limit, format, pretty),
Some(Command::Pull { ids, limit, status, remote, no_comments }) => task_pull(ids, limit, status, &remote, no_comments),
Some(Command::Push { ids, remote, no_comments, no_color }) => task_push(ids, &remote, no_comments, no_color),
Some(Command::Pull { ids, limit, status, remote, no_comments, no_labels }) => task_pull(ids, limit, status, &remote, no_comments, no_labels),
Some(Command::Push { ids, remote, no_comments, no_labels, no_color }) => task_push(ids, &remote, no_comments, no_labels, no_color),
Some(Command::Stats { no_color }) => task_stats(no_color),
Some(Command::Delete { ids, status, push, remote }) => task_delete(ids, status, push, &remote),
Some(Command::Clear) => task_clear(),
Expand Down
21 changes: 14 additions & 7 deletions src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub(crate) fn task_set(ids: String, prop_name: String, value: String, push: bool
println!("Task ID {id} -> {value} updated");

if push {
task_push(value.clone(), remote, false, no_color);
task_push(value.clone(), remote, false, false, no_color);
}
},
Err(e) => {
Expand All @@ -108,7 +108,7 @@ pub(crate) fn task_set(ids: String, prop_name: String, value: String, push: bool
println!("Task ID {id} updated");

if push {
task_push(id.to_string(), remote, false, no_color);
task_push(id.to_string(), remote, false, false, no_color);
}
},
Err(e) => {
Expand Down Expand Up @@ -149,7 +149,7 @@ pub(crate) fn task_replace(ids: String, prop_name: String, search: String, repla
Ok(_) => {
println!("Task ID {id} updated");
if push {
task_push(id.to_string(), remote, false, no_color);
task_push(id.to_string(), remote, false, false, no_color);
}
},
Err(e) => eprintln!("ERROR: {e}")
Expand Down Expand Up @@ -271,7 +271,14 @@ fn import_from_input(ids: Option<String>, input: &String) -> bool {
}
}

pub(crate) fn task_pull(ids: Option<String>, limit: Option<usize>, status: Option<String>, remote: &Option<String>, no_comments: bool) -> bool {
pub(crate) fn task_pull(
ids: Option<String>,
limit: Option<usize>,
status: Option<String>,
remote: &Option<String>,
no_comments: bool,
no_labels: bool,
) -> bool {
match get_user_repo(remote) {
Ok((connector, user, repo)) => {
println!("Pulling tasks from {user}/{repo}...");
Expand All @@ -286,7 +293,7 @@ pub(crate) fn task_pull(ids: Option<String>, limit: Option<usize>, status: Optio

if ids.is_some() {
for id in ids.unwrap() {
match connector.get_remote_task(&user, &repo, &id, !no_comments, &task_statuses) {
match connector.get_remote_task(&user, &repo, &id, !no_comments, !no_labels, &task_statuses) {
Some(task) => {
match import_remote_task(task, no_comments) {
Ok(Some(id)) => println!("Task ID {id} updated"),
Expand Down Expand Up @@ -443,7 +450,7 @@ pub(crate) fn task_export(ids: Option<String>, status: Option<Vec<String>>, limi
}
}

pub(crate) fn task_push(ids: String, remote: &Option<String>, no_comments: bool, no_color: bool) -> bool {
pub(crate) fn task_push(ids: String, remote: &Option<String>, no_comments: bool, no_labels: bool, no_color: bool) -> bool {
let ids = parse_ids(ids);

match get_user_repo(remote) {
Expand All @@ -458,7 +465,7 @@ pub(crate) fn task_push(ids: String, remote: &Option<String>, no_comments: bool,
println!("Sync: task ID {id}");
if let Ok(Some(local_task)) = gittask::find_task(&id) {
println!("Sync: LOCAL task ID {id} found");
let remote_task = connector.get_remote_task(&user, &repo, &id, !no_comments, &task_statuses);
let remote_task = connector.get_remote_task(&user, &repo, &id, !no_comments, !no_labels, &task_statuses);
if let Some(remote_task) = remote_task {
println!("Sync: REMOTE task ID {id} found");

Expand Down

0 comments on commit 7465494

Please sign in to comment.