Centralize Gitea domain workflows
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
use std::{error::Error, io::Read};
|
||||
|
||||
use gotcha_gitea::{
|
||||
Client, apis,
|
||||
Client, CreateIssue, EditIssue, IssueQuery,
|
||||
models::{
|
||||
ChangedFile, Comment, Commit, CreateIssueCommentOption, CreateIssueOption,
|
||||
CreateMilestoneOption, CreatePullRequestOption, EditIssueOption, EditMilestoneOption,
|
||||
EditPullRequestOption, Issue, MergePullRequestOption, Milestone, PullRequest, PullReview,
|
||||
ChangedFile, Comment, Commit, CreateIssueOption, CreateMilestoneOption,
|
||||
CreatePullRequestOption, EditIssueOption, EditMilestoneOption, EditPullRequestOption,
|
||||
Issue, MergePullRequestOption, Milestone, PullRequest, PullReview,
|
||||
},
|
||||
pull_state,
|
||||
};
|
||||
use serde::{Deserialize, de::DeserializeOwned};
|
||||
|
||||
@@ -248,69 +249,48 @@ pub async fn run(
|
||||
selection: &Selection,
|
||||
client: &Client,
|
||||
) -> Result<bool, Box<dyn Error>> {
|
||||
let configuration = client.configuration();
|
||||
match command {
|
||||
[domain, action, arguments @ ..] if domain == "issue" && action == "list" => {
|
||||
let options = parse_issue_list(arguments)?;
|
||||
let scope = scope(selection, options.repository.as_deref())?;
|
||||
let issues = apis::issue_api::issue_list_issues(
|
||||
&configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
Some(&options.state),
|
||||
options.labels.as_deref(),
|
||||
options.keyword.as_deref(),
|
||||
Some(&options.kind),
|
||||
options.milestones.as_deref(),
|
||||
options.from,
|
||||
options.until,
|
||||
options.author.as_deref(),
|
||||
options.assignee.as_deref(),
|
||||
options.mentions.as_deref(),
|
||||
Some(options.page),
|
||||
Some(options.limit),
|
||||
)
|
||||
.await?;
|
||||
print_issues(&issues);
|
||||
let issues = client
|
||||
.issues(
|
||||
&scope,
|
||||
&IssueQuery {
|
||||
state: options.state,
|
||||
labels: options.labels,
|
||||
keyword: options.keyword,
|
||||
kind: options.kind,
|
||||
milestones: options.milestones,
|
||||
from: options.from,
|
||||
until: options.until,
|
||||
author: options.author,
|
||||
assignee: options.assignee,
|
||||
mentions: options.mentions,
|
||||
page: options.page,
|
||||
limit: options.limit,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
print_issues(&issues.items);
|
||||
}
|
||||
[domain, action, index] if domain == "issue" && action == "show" => {
|
||||
let scope = scope(selection, None)?;
|
||||
print_issue(
|
||||
&apis::issue_api::issue_get_issue(
|
||||
&configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
number(index)?,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
print_issue(&client.issue(&scope, number(index)?).await?);
|
||||
}
|
||||
[domain, action, index, repository] if domain == "issue" && action == "show" => {
|
||||
let scope = scope(selection, Some(repository))?;
|
||||
print_issue(
|
||||
&apis::issue_api::issue_get_issue(
|
||||
&configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
number(index)?,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
print_issue(&client.issue(&scope, number(index)?).await?);
|
||||
}
|
||||
[domain, action] if domain == "issue" && action == "create" => {
|
||||
create_issue(&configuration, &scope(selection, None)?).await?;
|
||||
create_issue(client, &scope(selection, None)?).await?;
|
||||
}
|
||||
[domain, action, repository] if domain == "issue" && action == "create" => {
|
||||
create_issue(&configuration, &scope(selection, Some(repository))?).await?;
|
||||
create_issue(client, &scope(selection, Some(repository))?).await?;
|
||||
}
|
||||
[domain, action, arguments @ ..] if domain == "issue" && action == "edit" => {
|
||||
let (indexes, repository) = issue_targets(arguments)?;
|
||||
edit_issues(
|
||||
&configuration,
|
||||
&scope(selection, repository.as_deref())?,
|
||||
&indexes,
|
||||
)
|
||||
.await?;
|
||||
edit_issues(client, &scope(selection, repository.as_deref())?, &indexes).await?;
|
||||
}
|
||||
[domain, action, arguments @ ..]
|
||||
if domain == "issue" && matches!(action.as_str(), "close" | "reopen") =>
|
||||
@@ -318,7 +298,7 @@ pub async fn run(
|
||||
let (indexes, repository) = issue_targets(arguments)?;
|
||||
let scope = scope(selection, repository.as_deref())?;
|
||||
set_issue_state(
|
||||
&configuration,
|
||||
client,
|
||||
&scope,
|
||||
&indexes,
|
||||
if action == "close" { "closed" } else { "open" },
|
||||
@@ -326,129 +306,93 @@ pub async fn run(
|
||||
.await?;
|
||||
}
|
||||
[domain, action, index] if domain == "issue" && action == "delete" => {
|
||||
delete_issue(&configuration, &scope(selection, None)?, number(index)?).await?;
|
||||
delete_issue(client, &scope(selection, None)?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index, repository] if domain == "issue" && action == "delete" => {
|
||||
delete_issue(
|
||||
&configuration,
|
||||
&scope(selection, Some(repository))?,
|
||||
number(index)?,
|
||||
)
|
||||
.await?;
|
||||
delete_issue(client, &scope(selection, Some(repository))?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index] if domain == "issue" && action == "comments" => {
|
||||
list_comments(&configuration, &scope(selection, None)?, number(index)?).await?;
|
||||
list_comments(client, &scope(selection, None)?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index, repository] if domain == "issue" && action == "comments" => {
|
||||
list_comments(
|
||||
&configuration,
|
||||
&scope(selection, Some(repository))?,
|
||||
number(index)?,
|
||||
)
|
||||
.await?;
|
||||
list_comments(client, &scope(selection, Some(repository))?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index] if domain == "issue" && action == "comment" => {
|
||||
create_comment(&configuration, &scope(selection, None)?, number(index)?).await?;
|
||||
create_comment(client, &scope(selection, None)?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index, repository] if domain == "issue" && action == "comment" => {
|
||||
create_comment(
|
||||
&configuration,
|
||||
&scope(selection, Some(repository))?,
|
||||
number(index)?,
|
||||
)
|
||||
.await?;
|
||||
create_comment(client, &scope(selection, Some(repository))?, number(index)?).await?;
|
||||
}
|
||||
[domain, action] if domain == "milestone" && action == "list" => {
|
||||
list_milestones(&configuration, &scope(selection, None)?).await?;
|
||||
list_milestones(client, &scope(selection, None)?).await?;
|
||||
}
|
||||
[domain, action, repository] if domain == "milestone" && action == "list" => {
|
||||
list_milestones(&configuration, &scope(selection, Some(repository))?).await?;
|
||||
list_milestones(client, &scope(selection, Some(repository))?).await?;
|
||||
}
|
||||
[domain, action, id] if domain == "milestone" && action == "show" => {
|
||||
show_milestone(&configuration, &scope(selection, None)?, id).await?;
|
||||
show_milestone(client, &scope(selection, None)?, id).await?;
|
||||
}
|
||||
[domain, action, id, repository] if domain == "milestone" && action == "show" => {
|
||||
show_milestone(&configuration, &scope(selection, Some(repository))?, id).await?;
|
||||
show_milestone(client, &scope(selection, Some(repository))?, id).await?;
|
||||
}
|
||||
[domain, action] if domain == "milestone" && action == "create" => {
|
||||
create_milestone(&configuration, &scope(selection, None)?).await?;
|
||||
create_milestone(client, &scope(selection, None)?).await?;
|
||||
}
|
||||
[domain, action, repository] if domain == "milestone" && action == "create" => {
|
||||
create_milestone(&configuration, &scope(selection, Some(repository))?).await?;
|
||||
create_milestone(client, &scope(selection, Some(repository))?).await?;
|
||||
}
|
||||
[domain, action, id] if domain == "milestone" && action == "edit" => {
|
||||
edit_milestone(&configuration, &scope(selection, None)?, id).await?;
|
||||
edit_milestone(client, &scope(selection, None)?, id).await?;
|
||||
}
|
||||
[domain, action, id, repository] if domain == "milestone" && action == "edit" => {
|
||||
edit_milestone(&configuration, &scope(selection, Some(repository))?, id).await?;
|
||||
edit_milestone(client, &scope(selection, Some(repository))?, id).await?;
|
||||
}
|
||||
[domain, action, id] if domain == "milestone" && action == "delete" => {
|
||||
delete_milestone(&configuration, &scope(selection, None)?, id).await?;
|
||||
delete_milestone(client, &scope(selection, None)?, id).await?;
|
||||
}
|
||||
[domain, action, id, repository] if domain == "milestone" && action == "delete" => {
|
||||
delete_milestone(&configuration, &scope(selection, Some(repository))?, id).await?;
|
||||
delete_milestone(client, &scope(selection, Some(repository))?, id).await?;
|
||||
}
|
||||
[domain, action] if domain == "pull" && action == "list" => {
|
||||
list_pulls(&configuration, &scope(selection, None)?).await?;
|
||||
list_pulls(client, &scope(selection, None)?).await?;
|
||||
}
|
||||
[domain, action, repository] if domain == "pull" && action == "list" => {
|
||||
list_pulls(&configuration, &scope(selection, Some(repository))?).await?;
|
||||
list_pulls(client, &scope(selection, Some(repository))?).await?;
|
||||
}
|
||||
[domain, action, index] if domain == "pull" && action == "show" => {
|
||||
show_pull(&configuration, &scope(selection, None)?, number(index)?).await?;
|
||||
show_pull(client, &scope(selection, None)?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index, repository] if domain == "pull" && action == "show" => {
|
||||
show_pull(
|
||||
&configuration,
|
||||
&scope(selection, Some(repository))?,
|
||||
number(index)?,
|
||||
)
|
||||
.await?;
|
||||
show_pull(client, &scope(selection, Some(repository))?, number(index)?).await?;
|
||||
}
|
||||
[domain, action] if domain == "pull" && action == "create" => {
|
||||
create_pull(&configuration, &scope(selection, None)?).await?;
|
||||
create_pull(client, &scope(selection, None)?).await?;
|
||||
}
|
||||
[domain, action, repository] if domain == "pull" && action == "create" => {
|
||||
create_pull(&configuration, &scope(selection, Some(repository))?).await?;
|
||||
create_pull(client, &scope(selection, Some(repository))?).await?;
|
||||
}
|
||||
[domain, action, index] if domain == "pull" && action == "edit" => {
|
||||
edit_pull(&configuration, &scope(selection, None)?, number(index)?).await?;
|
||||
edit_pull(client, &scope(selection, None)?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index, repository] if domain == "pull" && action == "edit" => {
|
||||
edit_pull(
|
||||
&configuration,
|
||||
&scope(selection, Some(repository))?,
|
||||
number(index)?,
|
||||
)
|
||||
.await?;
|
||||
edit_pull(client, &scope(selection, Some(repository))?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index] if domain == "pull" && action == "merge" => {
|
||||
merge_pull(&configuration, &scope(selection, None)?, number(index)?).await?;
|
||||
merge_pull(client, &scope(selection, None)?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index, repository] if domain == "pull" && action == "merge" => {
|
||||
merge_pull(
|
||||
&configuration,
|
||||
&scope(selection, Some(repository))?,
|
||||
number(index)?,
|
||||
)
|
||||
.await?;
|
||||
merge_pull(client, &scope(selection, Some(repository))?, number(index)?).await?;
|
||||
}
|
||||
[domain, action, index]
|
||||
if domain == "pull" && matches!(action.as_str(), "commits" | "files" | "reviews") =>
|
||||
{
|
||||
pull_details(
|
||||
&configuration,
|
||||
&scope(selection, None)?,
|
||||
number(index)?,
|
||||
action,
|
||||
)
|
||||
.await?;
|
||||
pull_details(client, &scope(selection, None)?, number(index)?, action).await?;
|
||||
}
|
||||
[domain, action, index, repository]
|
||||
if domain == "pull" && matches!(action.as_str(), "commits" | "files" | "reviews") =>
|
||||
{
|
||||
pull_details(
|
||||
&configuration,
|
||||
client,
|
||||
&scope(selection, Some(repository))?,
|
||||
number(index)?,
|
||||
action,
|
||||
@@ -497,475 +441,193 @@ fn parse_yaml<T: DeserializeOwned>(input: &str) -> Result<T, Box<dyn Error>> {
|
||||
Ok(serde_yaml::from_str(input)?)
|
||||
}
|
||||
|
||||
async fn create_issue(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
scope: &RepositoryScope,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut input: CreateIssueInput = read_yaml()?;
|
||||
if input.issue.title.trim().is_empty() {
|
||||
return Err("issue title must not be empty".into());
|
||||
}
|
||||
if input.issue.milestone.is_some() && input.milestone_name.is_some() {
|
||||
return Err("use either milestone or milestone_name, not both".into());
|
||||
}
|
||||
if let Some(name) = input.milestone_name.as_deref() {
|
||||
input.issue.milestone = Some(resolve_milestone_id(configuration, scope, name).await?);
|
||||
}
|
||||
if !input.label_names.is_empty() {
|
||||
input
|
||||
.issue
|
||||
.labels
|
||||
.get_or_insert_default()
|
||||
.extend(resolve_label_ids(configuration, scope, &input.label_names).await?);
|
||||
}
|
||||
async fn create_issue(client: &Client, scope: &RepositoryScope) -> Result<(), Box<dyn Error>> {
|
||||
let input: CreateIssueInput = read_yaml()?;
|
||||
print_issue(
|
||||
&apis::issue_api::issue_create_issue(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
Some(input.issue),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn edit_issues(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
scope: &RepositoryScope,
|
||||
indexes: &[i64],
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut input: EditIssueInput = read_yaml()?;
|
||||
if input.issue.milestone.is_some() && input.milestone_name.is_some() {
|
||||
return Err("use either milestone or milestone_name, not both".into());
|
||||
}
|
||||
if let Some(name) = input.milestone_name.as_deref() {
|
||||
input.issue.milestone = Some(resolve_milestone_id(configuration, scope, name).await?);
|
||||
}
|
||||
if input.issue.assignees.is_some() && !input.add_assignees.is_empty() {
|
||||
return Err("use either assignees or add_assignees, not both".into());
|
||||
}
|
||||
let remove = resolve_label_ids(configuration, scope, &input.remove_labels).await?;
|
||||
let add = resolve_label_ids(configuration, scope, &input.add_labels).await?;
|
||||
for &index in indexes {
|
||||
apply_issue_edit(configuration, scope, index, &input, &remove, &add).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn apply_issue_edit(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
scope: &RepositoryScope,
|
||||
index: i64,
|
||||
input: &EditIssueInput,
|
||||
remove: &[i64],
|
||||
add: &[i64],
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut edit = input.issue.clone();
|
||||
if !input.add_assignees.is_empty() {
|
||||
let issue =
|
||||
apis::issue_api::issue_get_issue(configuration, &scope.owner, &scope.repository, index)
|
||||
.await?;
|
||||
let mut assignees = issue
|
||||
.assignees
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.filter_map(|user| user.login.clone())
|
||||
.collect::<Vec<_>>();
|
||||
for assignee in &input.add_assignees {
|
||||
if !assignees.contains(assignee) {
|
||||
assignees.push(assignee.clone());
|
||||
}
|
||||
}
|
||||
edit.assignees = Some(assignees);
|
||||
}
|
||||
if edit != EditIssueOption::default() {
|
||||
apis::issue_api::issue_edit_issue(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
Some(edit),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
for &id in remove {
|
||||
apis::issue_api::issue_remove_label(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
id,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
if !add.is_empty() {
|
||||
apis::issue_api::issue_add_label(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
Some(gotcha_gitea::models::IssueLabelsOption {
|
||||
labels: Some(add.iter().copied().map(serde_json::Value::from).collect()),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
print_issue(
|
||||
&apis::issue_api::issue_get_issue(configuration, &scope.owner, &scope.repository, index)
|
||||
&client
|
||||
.create_issue(
|
||||
scope,
|
||||
CreateIssue {
|
||||
option: input.issue,
|
||||
label_names: input.label_names,
|
||||
milestone_name: input.milestone_name,
|
||||
},
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn resolve_label_ids(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
async fn edit_issues(
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
names: &[String],
|
||||
) -> Result<Vec<i64>, Box<dyn Error>> {
|
||||
if names.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
let mut labels = Vec::new();
|
||||
let mut page = 1;
|
||||
loop {
|
||||
let batch = apis::issue_api::issue_list_labels(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
Some(page),
|
||||
Some(50),
|
||||
indexes: &[i64],
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let input: EditIssueInput = read_yaml()?;
|
||||
for issue in client
|
||||
.edit_issues(
|
||||
scope,
|
||||
indexes,
|
||||
EditIssue {
|
||||
option: input.issue,
|
||||
replace_labels: None,
|
||||
add_labels: input.add_labels,
|
||||
remove_labels: input.remove_labels,
|
||||
add_assignees: input.add_assignees,
|
||||
milestone_name: input.milestone_name,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
let has_more = batch.len() == 50;
|
||||
labels.extend(batch);
|
||||
if !has_more {
|
||||
break;
|
||||
}
|
||||
page += 1;
|
||||
.await?
|
||||
{
|
||||
print_issue(&issue);
|
||||
}
|
||||
names
|
||||
.iter()
|
||||
.map(|name| {
|
||||
labels
|
||||
.iter()
|
||||
.find(|label| label.name.as_deref() == Some(name))
|
||||
.and_then(|label| label.id)
|
||||
.ok_or_else(|| format!("unknown label {name:?}").into())
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn resolve_milestone_id(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
scope: &RepositoryScope,
|
||||
name: &str,
|
||||
) -> Result<i64, Box<dyn Error>> {
|
||||
apis::issue_api::issue_get_milestones_list(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
Some("all"),
|
||||
Some(name),
|
||||
Some(1),
|
||||
Some(2),
|
||||
)
|
||||
.await?
|
||||
.into_iter()
|
||||
.find(|milestone| milestone.title.as_deref() == Some(name))
|
||||
.and_then(|milestone| milestone.id)
|
||||
.ok_or_else(|| format!("unknown milestone {name:?}").into())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_issue_state(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
indexes: &[i64],
|
||||
state: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
for &index in indexes {
|
||||
let issue = apis::issue_api::issue_edit_issue(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
Some(EditIssueOption {
|
||||
state: Some(state.into()),
|
||||
..Default::default()
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
for issue in client.set_issue_state(scope, indexes, state).await? {
|
||||
print_issue(&issue);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_issue(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
index: i64,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
apis::issue_api::issue_delete(configuration, &scope.owner, &scope.repository, index).await?;
|
||||
client.delete_issue(scope, index).await?;
|
||||
println!("Deleted issue #{index}.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn list_comments(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
index: i64,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let comments = apis::issue_api::issue_get_comments(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let comments = client.issue_comments(scope, index).await?;
|
||||
print_comments(&comments);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_comment(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
index: i64,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let body = read_stdin()?.trim_end().to_owned();
|
||||
let comment = apis::issue_api::issue_create_comment(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
Some(CreateIssueCommentOption::new(body)),
|
||||
)
|
||||
.await?;
|
||||
let comment = client.create_issue_comment(scope, index, body).await?;
|
||||
print_comments(&[comment]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn list_milestones(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
scope: &RepositoryScope,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let milestones = apis::issue_api::issue_get_milestones_list(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
async fn list_milestones(client: &Client, scope: &RepositoryScope) -> Result<(), Box<dyn Error>> {
|
||||
let milestones = client.milestones(scope).await?;
|
||||
print_milestones(&milestones);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn show_milestone(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
id: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let milestone =
|
||||
apis::issue_api::issue_get_milestone(configuration, &scope.owner, &scope.repository, id)
|
||||
.await?;
|
||||
let milestone = client.milestone(scope, number(id)?).await?;
|
||||
print_milestone(&milestone);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_milestone(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
scope: &RepositoryScope,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
async fn create_milestone(client: &Client, scope: &RepositoryScope) -> Result<(), Box<dyn Error>> {
|
||||
let body: CreateMilestoneOption = read_yaml()?;
|
||||
if body.title.as_deref().unwrap_or_default().trim().is_empty() {
|
||||
return Err("milestone title must not be empty".into());
|
||||
}
|
||||
let milestone = apis::issue_api::issue_create_milestone(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
Some(body),
|
||||
)
|
||||
.await?;
|
||||
let milestone = client.create_milestone(scope, body).await?;
|
||||
print_milestone(&milestone);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn edit_milestone(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
id: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let milestone = apis::issue_api::issue_edit_milestone(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
id,
|
||||
Some(read_yaml::<EditMilestoneOption>()?),
|
||||
)
|
||||
.await?;
|
||||
let milestone = client
|
||||
.edit_milestone(scope, id, read_yaml::<EditMilestoneOption>()?)
|
||||
.await?;
|
||||
print_milestone(&milestone);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_milestone(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
id: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
apis::issue_api::issue_delete_milestone(configuration, &scope.owner, &scope.repository, id)
|
||||
.await?;
|
||||
client.delete_milestone(scope, id).await?;
|
||||
println!("Deleted milestone {id}.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn list_pulls(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
scope: &RepositoryScope,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let pulls = apis::repository_api::repo_list_pull_requests(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
print_pulls(&pulls);
|
||||
async fn list_pulls(client: &Client, scope: &RepositoryScope) -> Result<(), Box<dyn Error>> {
|
||||
print_pulls(&client.repository_pulls(scope, "open", 1, 30).await?.items);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn show_pull(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
index: i64,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let pull = apis::repository_api::repo_get_pull_request(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
)
|
||||
.await?;
|
||||
let pull = client.pull(scope, index).await?;
|
||||
print_pull(&pull);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_pull(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
scope: &RepositoryScope,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
async fn create_pull(client: &Client, scope: &RepositoryScope) -> Result<(), Box<dyn Error>> {
|
||||
let body: CreatePullRequestOption = read_yaml()?;
|
||||
if [
|
||||
body.title.as_deref(),
|
||||
body.head.as_deref(),
|
||||
body.base.as_deref(),
|
||||
]
|
||||
.into_iter()
|
||||
.any(|value| value.unwrap_or_default().trim().is_empty())
|
||||
{
|
||||
return Err("pull request title, head, and base must not be empty".into());
|
||||
}
|
||||
let pull = apis::repository_api::repo_create_pull_request(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
Some(body),
|
||||
)
|
||||
.await?;
|
||||
let pull = client.create_pull(scope, body).await?;
|
||||
print_pull(&pull);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn edit_pull(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
index: i64,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let pull = apis::repository_api::repo_edit_pull_request(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
Some(read_yaml::<EditPullRequestOption>()?),
|
||||
)
|
||||
.await?;
|
||||
let pull = client
|
||||
.edit_pull(scope, index, read_yaml::<EditPullRequestOption>()?)
|
||||
.await?;
|
||||
print_pull(&pull);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn merge_pull(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
index: i64,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
apis::repository_api::repo_merge_pull_request(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
Some(read_yaml::<MergePullRequestOption>()?),
|
||||
)
|
||||
.await?;
|
||||
client
|
||||
.merge_pull(scope, index, read_yaml::<MergePullRequestOption>()?)
|
||||
.await?;
|
||||
println!("Merged pull request #{index}.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn pull_details(
|
||||
configuration: &apis::configuration::Configuration,
|
||||
client: &Client,
|
||||
scope: &RepositoryScope,
|
||||
index: i64,
|
||||
action: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
match action {
|
||||
"commits" => print_commits(
|
||||
&apis::repository_api::repo_get_pull_request_commits(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?,
|
||||
),
|
||||
"files" => print_files(
|
||||
&apis::repository_api::repo_get_pull_request_files(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?,
|
||||
),
|
||||
"reviews" => print_reviews(
|
||||
&apis::repository_api::repo_list_pull_reviews(
|
||||
configuration,
|
||||
&scope.owner,
|
||||
&scope.repository,
|
||||
index,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?,
|
||||
),
|
||||
"commits" => print_commits(&client.pull_commits(scope, index).await?),
|
||||
"files" => print_files(&client.pull_files(scope, index).await?),
|
||||
"reviews" => print_reviews(&client.pull_reviews(scope, index).await?),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
@@ -1129,7 +791,7 @@ fn print_pull(pull: &PullRequest) {
|
||||
println!(
|
||||
"#{} [{}] {}",
|
||||
pull.number.unwrap_or_default(),
|
||||
pull.state.as_deref().unwrap_or("unknown"),
|
||||
pull_state(pull),
|
||||
pull.title.as_deref().unwrap_or("")
|
||||
);
|
||||
field("url", pull.html_url.as_deref());
|
||||
|
||||
Reference in New Issue
Block a user