cli: Add `--tag` option to `rad issue open`

Also include a simple script for importing GitHub issues.
This commit is contained in:
Alexis Sellier 2023-04-19 12:41:53 +02:00
parent 8667553740
commit 9fd3527196
No known key found for this signature in database
3 changed files with 74 additions and 9 deletions

View File

@ -27,7 +27,7 @@ Usage
rad issue [<option>...] rad issue [<option>...]
rad issue delete <issue-id> [<option>...] rad issue delete <issue-id> [<option>...]
rad issue list [--assigned <did>] [<option>...] rad issue list [--assigned <did>] [<option>...]
rad issue open [--title <title>] [--description <text>] [<option>...] rad issue open [--title <title>] [--description <text>] [--tag <tag>] [<option>...]
rad issue react <issue-id> [--emoji <char>] [<option>...] rad issue react <issue-id> [--emoji <char>] [<option>...]
rad issue show <issue-id> [<option>...] rad issue show <issue-id> [<option>...]
rad issue state <issue-id> [--closed | --open | --solved] [<option>...] rad issue state <issue-id> [--closed | --open | --solved] [<option>...]
@ -42,7 +42,7 @@ Options
#[derive(serde::Deserialize, serde::Serialize, Debug)] #[derive(serde::Deserialize, serde::Serialize, Debug)]
pub struct Metadata { pub struct Metadata {
title: String, title: String,
labels: Vec<Tag>, tags: Vec<Tag>,
assignees: Vec<Did>, assignees: Vec<Did>,
} }
@ -70,6 +70,7 @@ pub enum Operation {
Open { Open {
title: Option<String>, title: Option<String>,
description: Option<String>, description: Option<String>,
tags: Vec<Tag>,
}, },
Show { Show {
id: Rev, id: Rev,
@ -108,6 +109,7 @@ impl Args for Options {
let mut reaction: Option<Reaction> = None; let mut reaction: Option<Reaction> = None;
let mut description: Option<String> = None; let mut description: Option<String> = None;
let mut state: Option<State> = None; let mut state: Option<State> = None;
let mut tags = Vec::new();
let mut announce = true; let mut announce = true;
while let Some(arg) = parser.next()? { while let Some(arg) = parser.next()? {
@ -118,6 +120,13 @@ impl Args for Options {
Long("title") if op == Some(OperationName::Open) => { Long("title") if op == Some(OperationName::Open) => {
title = Some(parser.value()?.to_string_lossy().into()); title = Some(parser.value()?.to_string_lossy().into());
} }
Long("tag") if op == Some(OperationName::Open) => {
let val = parser.value()?;
let name = term::args::string(&val);
let tag = Tag::new(name)?;
tags.push(tag);
}
Long("closed") if op == Some(OperationName::State) => { Long("closed") if op == Some(OperationName::State) => {
state = Some(State::Closed { state = Some(State::Closed {
reason: CloseReason::Other, reason: CloseReason::Other,
@ -172,7 +181,11 @@ impl Args for Options {
} }
let op = match op.unwrap_or_default() { let op = match op.unwrap_or_default() {
OperationName::Open => Operation::Open { title, description }, OperationName::Open => Operation::Open {
title,
description,
tags,
},
OperationName::Show => Operation::Show { OperationName::Show => Operation::Show {
id: id.ok_or_else(|| anyhow!("an issue must be provided"))?, id: id.ok_or_else(|| anyhow!("an issue must be provided"))?,
}, },
@ -215,8 +228,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
Operation::Open { Operation::Open {
title: Some(title), title: Some(title),
description: Some(description), description: Some(description),
tags,
} => { } => {
let issue = issues.create(title, description, &[], &[], &signer)?; let issue = issues.create(title, description, tags.as_slice(), &[], &signer)?;
show_issue(&issue)?; show_issue(&issue)?;
} }
Operation::Show { id } => { Operation::Show { id } => {
@ -238,10 +252,14 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
issue.react(*comment_id, reaction, &signer)?; issue.react(*comment_id, reaction, &signer)?;
} }
} }
Operation::Open { title, description } => { Operation::Open {
title,
description,
tags,
} => {
let meta = Metadata { let meta = Metadata {
title: title.unwrap_or("Enter a title".to_owned()), title: title.unwrap_or("Enter a title".to_owned()),
labels: vec![], tags,
assignees: vec![], assignees: vec![],
}; };
let yaml = serde_yaml::to_string(&meta)?; let yaml = serde_yaml::to_string(&meta)?;
@ -278,7 +296,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let issue = issues.create( let issue = issues.create(
&meta.title, &meta.title,
description.trim(), description.trim(),
meta.labels.as_slice(), meta.tags.as_slice(),
meta.assignees meta.assignees
.into_iter() .into_iter()
.map(cob::ActorId::from) .map(cob::ActorId::from)

View File

@ -117,8 +117,8 @@ pub enum TagError {
pub struct Tag(String); pub struct Tag(String);
impl Tag { impl Tag {
pub fn new(name: impl Into<String>) -> Result<Self, TagError> { pub fn new(name: impl ToString) -> Result<Self, TagError> {
let name = name.into(); let name = name.to_string();
if name.chars().any(|c| c.is_whitespace()) || name.is_empty() { if name.chars().any(|c| c.is_whitespace()) || name.is_empty() {
return Err(TagError::InvalidName(name)); return Err(TagError::InvalidName(name));

47
scripts/import-issue.sh Executable file
View File

@ -0,0 +1,47 @@
#!/bin/bash
#
# Import a GitHub issue into Radicle.
#
set -e
if ! command -v curl > /dev/null; then
echo "Error: curl is not installed"
exit 1
fi
if ! command -v jq > /dev/null; then
echo "Error: jq is not installed"
exit 1
fi
if ! command -v rad > /dev/null; then
echo "Error: rad is not installed"
exit 1
fi
# Check if the correct number of arguments is provided
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <org> <repo> <issue>"
exit 1
fi
owner="$1"
repo="$2"
issue="$3"
url="https://api.github.com/repos/${owner}/${repo}/issues/${issue}"
# Fetch the issue data using the GitHub API
response="$(curl -s "$url")"
# Extract the title and body from the JSON response
title="$(echo "$response" | jq -r '.title')"
body="$(echo "$response" | jq -r '.body')"
labels="$(echo "$response" | jq -r '.labels | .[].name')"
tags=()
for label in $labels; do
tags+=("--tag" "$label")
done
rad issue open --title "$title" "${tags[@]}" --description "$body" --no-announce