feat: orgs, hooks, teams, labels

This commit is contained in:
RobWalt 2023-07-28 08:36:12 +02:00
parent e343273668
commit 01696c7e0e
No known key found for this signature in database
GPG key ID: 333C6AC0CEF0CE68
69 changed files with 55489 additions and 650 deletions

243
Cargo.lock generated
View file

@ -38,6 +38,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
[[package]]
name = "approx"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
dependencies = [
"num-traits",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@ -65,6 +74,12 @@ version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "bytes"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "cc"
version = "1.0.79"
@ -195,6 +210,18 @@ dependencies = [
"once_cell",
]
[[package]]
name = "fast-srgb8"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "forgejo-api-types"
version = "0.1.0"
@ -203,6 +230,8 @@ dependencies = [
"clap",
"color-eyre",
"derive-new",
"hyper",
"palette",
"serde",
"serde-email",
"serde_json",
@ -219,6 +248,39 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "futures-channel"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]]
name = "futures-task"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
[[package]]
name = "futures-util"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"pin-utils",
]
[[package]]
name = "gimli"
version = "0.27.3"
@ -231,6 +293,62 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "http"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http-body"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [
"bytes",
"http",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]]
name = "httpdate"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "hyper"
version = "0.14.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "iana-time-zone"
version = "0.1.57"
@ -348,18 +466,90 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "palette"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1641aee47803391405d0a1250e837d2336fdddd18b27f3ddb8c1d80ce8d7f43"
dependencies = [
"approx",
"fast-srgb8",
"palette_derive",
"phf",
"serde",
]
[[package]]
name = "palette_derive"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c02bfa6b3ba8af5434fa0531bf5701f750d983d4260acd6867faca51cdc4484"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.27",
]
[[package]]
name = "percent-encoding"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "phf"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_macros",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
"syn 2.0.27",
]
[[package]]
name = "phf_shared"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [
"siphasher",
]
[[package]]
name = "pin-project-lite"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro2"
version = "1.0.66"
@ -378,6 +568,21 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@ -446,6 +651,12 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "siphasher"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "strum"
version = "0.25.0"
@ -526,6 +737,23 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
dependencies = [
"autocfg",
"backtrace",
"pin-project-lite",
]
[[package]]
name = "tower-service"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]]
name = "tracing"
version = "0.1.37"
@ -568,6 +796,12 @@ dependencies = [
"tracing-core",
]
[[package]]
name = "try-lock"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "unicode-bidi"
version = "0.3.13"
@ -607,6 +841,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"

View file

@ -8,12 +8,12 @@ edition = "2021"
[dependencies]
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.3", default-features = false, features = ["derive", "std"] }
serde_json = "1.0"
color-eyre = "0.6"
derive-new = "0.5"
hyper = "0.14.27"
palette = { version = "0.7.2", features = ["serializing"] }
serde = { version = "1.0", features = ["derive"] }
serde-email = "2.1"
strum = { version = "0.25", features = ["derive"] }
url = { version = "2.4", features = ["serde"] }
[dev-dependencies]
serde_json = "1.0"

1
README.md Normal file
View file

@ -0,0 +1 @@
docs: https://codeberg.org/api/swagger#/organization/orgCreateHook

View file

@ -1,14 +0,0 @@
use std::fmt::Display;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct Branch {
pub name: String,
}
impl Display for Branch {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}

View file

@ -1,13 +0,0 @@
use chrono::{DateTime, Utc};
use serde::Deserialize;
use crate::types::api::user::User;
#[derive(Debug, Deserialize)]
pub struct Comment {
pub body: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub id: usize,
pub user: User,
}

View file

@ -1,12 +0,0 @@
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct CreateCommentOption {
body: String,
}
impl CreateCommentOption {
pub fn new(body: String) -> Self {
Self { body }
}
}

View file

@ -1,16 +0,0 @@
use serde::Serialize;
#[derive(Serialize)]
pub struct CreateForkOption {
name: Option<String>,
organization: Option<String>,
}
impl CreateForkOption {
pub fn same_repo_name() -> Self {
Self {
name: None,
organization: None,
}
}
}

View file

@ -1,42 +0,0 @@
use serde::Serialize;
#[derive(Serialize)]
pub struct CreateIssueOption {
title: String,
body: String,
assignees: Vec<String>,
labels: Vec<usize>,
milestone: Option<usize>,
}
impl CreateIssueOption {
pub fn new(title: String) -> Self {
Self {
title,
body: Default::default(),
assignees: Default::default(),
labels: Default::default(),
milestone: Default::default(),
}
}
pub fn with_body(mut self, body: String) -> Self {
self.body = body;
self
}
pub fn with_assignees(mut self, assignees: Vec<String>) -> Self {
self.assignees = assignees;
self
}
pub fn with_labels(mut self, labels: Vec<usize>) -> Self {
self.labels = labels;
self
}
pub fn with_milestone(mut self, milestone_id: usize) -> Self {
self.milestone.replace(milestone_id);
self
}
}

View file

@ -1,28 +0,0 @@
use serde::Serialize;
#[derive(Serialize)]
pub struct CreateLabelOption {
color: String,
description: String,
name: String,
}
impl CreateLabelOption {
pub fn new(name: String) -> Self {
Self {
color: String::from("#000000"),
description: String::from("No description"),
name,
}
}
pub fn with_color(mut self, color: String) -> Self {
self.color = color;
self
}
pub fn with_description(mut self, description: String) -> Self {
self.description = description;
self
}
}

View file

@ -1,23 +0,0 @@
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct CreateMilestoneOption {
title: String,
due_on: Option<String>,
description: Option<String>,
}
impl CreateMilestoneOption {
pub fn new(title: String) -> Self {
Self {
title,
due_on: Default::default(),
description: Default::default(),
}
}
pub fn with_description(mut self, description: String) -> Self {
self.description.replace(description);
self
}
}

View file

@ -1,46 +0,0 @@
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct CreatePullRequestOption {
assignees: Vec<String>,
base: String,
body: String,
head: String,
labels: Vec<usize>,
title: String,
milestone: Option<usize>,
}
impl CreatePullRequestOption {
pub fn new(title: String, from: String, to: String) -> Self {
Self {
title,
head: from,
base: to,
assignees: Default::default(),
body: Default::default(),
labels: Default::default(),
milestone: Default::default(),
}
}
pub fn with_assignees(mut self, assignees: Vec<String>) -> Self {
self.assignees = assignees;
self
}
pub fn with_description(mut self, description: String) -> Self {
self.body = description;
self
}
pub fn with_labels(mut self, labels: Vec<usize>) -> Self {
self.labels = labels;
self
}
pub fn with_milestone(mut self, milestone_id: usize) -> Self {
self.milestone.replace(milestone_id);
self
}
}

View file

@ -1,47 +0,0 @@
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct CreateRepoOption {
default_branch: String,
description: String,
name: String,
private: bool,
readme: String,
}
impl CreateRepoOption {
pub fn new(name: String) -> Self {
Self {
default_branch: String::from("main"),
description: Default::default(),
name,
private: true,
readme: Default::default(),
}
}
pub fn with_default_branch(mut self, default_branch: String) -> Self {
self.default_branch = default_branch;
self
}
pub fn with_description(mut self, description: String) -> Self {
self.description = description;
self
}
pub fn private(mut self) -> Self {
self.private = true;
self
}
pub fn public(mut self) -> Self {
self.private = false;
self
}
pub fn with_readme(mut self, readme: String) -> Self {
self.readme = readme;
self
}
}

View file

@ -1,7 +0,0 @@
pub mod create_comment_option;
pub mod create_fork_option;
pub mod create_issue_options;
pub mod create_label_options;
pub mod create_milestone_option;
pub mod create_pull_request_option;
pub mod create_repo_options;

View file

@ -0,0 +1,47 @@
use std::fmt::Display;
use serde::{Deserialize, Serialize};
use crate::types::misc::color::Color;
use crate::types::misc::exclusive::Exclusive;
/// CreateLabelOption represents options for creating a label.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CreateLabelOption {
/// The color of the label (in hexadecimal format).
pub color: Color,
/// The description of the label.
pub description: String,
/// Indicates whether the label is exclusive.
pub exclusive: Exclusive,
/// The name of the label.
pub name: String,
}
impl Display for CreateLabelOption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CreateLabelOption: {}", self.name)
}
}
#[cfg(test)]
mod tests {
use palette::rgb::Rgb;
use crate::types::api::creation::label::CreateLabelOption;
use crate::types::misc::color::Color;
use crate::types::misc::exclusive::Exclusive;
#[test]
fn deserialize_create_label_option() {
let json_data = include_str!("../../../../test_data/example_create_label.json");
let option: CreateLabelOption = serde_json::from_str(&json_data).unwrap();
let expected = CreateLabelOption {
color: Color(Rgb::new(0x00, 0xaa, 0xbb)),
description: "CreateLabelOption options for creating a label".to_string(),
exclusive: Exclusive::No,
name: "example_label".to_string(),
};
assert_eq!(option, expected);
}
}

View file

@ -0,0 +1,2 @@
pub mod label;
pub mod organization;

View file

@ -0,0 +1,60 @@
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use crate::types::misc::team_access::RepoAdminCanChangeTeamAccess;
use crate::types::misc::url::OptionalUrl;
use crate::types::misc::visibility::Visibility;
/// CreateOrgOption represents options for creating an organization
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct CreateOrgOption {
/// The organization's description
pub description: String,
/// Full name of the organization
pub full_name: String,
/// Location of the organization as a string
pub location: String,
/// Boolean flag indicating if repo admin can change team access
pub repo_admin_change_team_access: RepoAdminCanChangeTeamAccess,
/// The organization's username
pub username: String,
/// Visibility of the organization
pub visibility: Visibility,
/// The organization's website URL (optional)
pub website: OptionalUrl,
}
impl Display for CreateOrgOption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CreateOrgOption: {}", self.full_name)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use url::Url;
use crate::types::api::creation::organization::CreateOrgOption;
use crate::types::misc::team_access::RepoAdminCanChangeTeamAccess;
use crate::types::misc::url::OptionalUrl;
use crate::types::misc::visibility::Visibility;
#[test]
fn deserialize_works() {
let data = include_str!("../../../../test_data/example_create_organization.json");
let org_option: CreateOrgOption = serde_json::from_str(data).unwrap();
let expected = CreateOrgOption {
description: String::from("Sample organization"),
full_name: String::from("SampleOrg"),
location: String::from("Sample City, Country"),
repo_admin_change_team_access: RepoAdminCanChangeTeamAccess::Yes,
username: String::from("sample_org"),
visibility: Visibility::Public,
website: OptionalUrl::Some(Url::from_str("https://sample.org").unwrap()),
};
assert_eq!(org_option, expected);
}
}

View file

@ -0,0 +1,57 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::types::misc::active::ActiveStatus;
use crate::types::misc::header::Header;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct EditHookOption {
/// Description of the options when modifying a hook
description: String,
/// Boolean flag indicating if the hook is active
active: ActiveStatus,
/// Authorization header for the hook (if required)
authorization_header: Header,
/// Branch filter for the hook
branch_filter: String,
/// Configuration options for the hook
config: HashMap<String, String>,
/// Events that trigger the hook
events: Vec<String>,
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use hyper::http::{HeaderName, HeaderValue};
use crate::types::api::edit::hook::EditHookOption;
use crate::types::misc::active::ActiveStatus;
use crate::types::misc::header::Header;
#[test]
fn deserialize_works() {
let data = include_str!("../../../../test_data/example_edit_hook.json");
let edit_hook_option: EditHookOption = serde_json::from_str(data).unwrap();
// Example usage:
let expected = EditHookOption {
description: "Options when modifying a hook".to_string(),
active: ActiveStatus::Active,
authorization_header: Header(hyper::HeaderMap::from_iter(std::iter::once((
HeaderName::from_static("bearer"),
HeaderValue::from_static("TOKEN"),
)))),
branch_filter: "main".to_string(),
config: {
let mut config = HashMap::new();
config.insert("key1".to_string(), "value1".to_string());
config.insert("key2".to_string(), "value2".to_string());
config
},
events: vec!["push".to_string(), "pull_request".to_string()],
};
assert_eq!(edit_hook_option, expected);
}
}

View file

@ -0,0 +1,47 @@
use std::fmt::Display;
use serde::{Deserialize, Serialize};
use crate::types::misc::color::Color;
use crate::types::misc::exclusive::Exclusive;
/// CreateLabelOption represents options for creating a label.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EditLabelOption {
/// The color of the label (in hexadecimal format).
pub color: Color,
/// The description of the label.
pub description: String,
/// Indicates whether the label is exclusive.
pub exclusive: Exclusive,
/// The name of the label.
pub name: String,
}
impl Display for EditLabelOption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "EditLabelOption: {}", self.name)
}
}
#[cfg(test)]
mod tests {
use palette::rgb::Rgb;
use crate::types::api::creation::label::CreateLabelOption;
use crate::types::misc::color::Color;
use crate::types::misc::exclusive::Exclusive;
#[test]
fn deserialize_edit_label_option() {
let json_data = include_str!("../../../../test_data/example_edit_label.json");
let option: CreateLabelOption = serde_json::from_str(&json_data).unwrap();
let expected = CreateLabelOption {
color: Color(Rgb::new(0x00, 0xaa, 0xbb)),
description: "EditLabelOption options for updating a label".to_string(),
exclusive: Exclusive::No,
name: "example_label".to_string(),
};
assert_eq!(option, expected);
}
}

View file

@ -0,0 +1,3 @@
pub mod hook;
pub mod label;
pub mod organization;

View file

@ -0,0 +1,57 @@
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use crate::types::misc::team_access::RepoAdminCanChangeTeamAccess;
use crate::types::misc::url::OptionalUrl;
use crate::types::misc::visibility::Visibility;
/// EditOrgOption represents options for editing an organization
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct EditOrgOption {
/// The organization's description
pub description: String,
/// Full name of the organization
pub full_name: String,
/// Location of the organization as a string
pub location: String,
/// Boolean flag indicating if repo admin can change team access
pub repo_admin_change_team_access: RepoAdminCanChangeTeamAccess,
/// Visibility of the organization
pub visibility: Visibility,
/// The organization's website URL (optional)
pub website: OptionalUrl,
}
impl Display for EditOrgOption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "EditOrgOption: {}", self.full_name)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use url::Url;
use crate::types::api::edit::organization::EditOrgOption;
use crate::types::misc::team_access::RepoAdminCanChangeTeamAccess;
use crate::types::misc::url::OptionalUrl;
use crate::types::misc::visibility::Visibility;
#[test]
fn deserialize_works() {
let data = include_str!("../../../../test_data/example_edit_organization.json");
let edit_org_option: EditOrgOption = serde_json::from_str(data).unwrap();
let expected = EditOrgOption {
description: String::from("Updated organization"),
full_name: String::from("UpdatedOrg"),
location: String::from("Updated City, Country"),
repo_admin_change_team_access: RepoAdminCanChangeTeamAccess::No,
visibility: Visibility::Private,
website: OptionalUrl::Some(Url::from_str("https://updated.org").unwrap()),
};
assert_eq!(edit_org_option, expected);
}
}

View file

@ -1,32 +0,0 @@
use serde::Serialize;
use crate::types::api::issue::Issue;
use crate::types::api::state_type::StateType;
#[derive(Debug, Clone, Serialize, Default)]
pub struct EditIssueOption {
pub assignees: Option<Vec<String>>,
pub body: Option<String>,
pub state: Option<StateType>,
pub title: Option<String>,
}
impl EditIssueOption {
pub fn from_issue(issue: &Issue) -> Self {
Self {
assignees: issue.assignees.as_ref().map(|assignees| {
assignees
.iter()
.map(|assignee| assignee.login.to_owned())
.collect::<Vec<_>>()
}),
body: Some(issue.body.clone()),
state: issue
.pull_request
.as_ref()
.map(|pr_meta| (!pr_meta.merged).then_some(issue.state))
.unwrap_or(Some(issue.state)),
title: Some(issue.title.clone()),
}
}
}

View file

@ -1,20 +0,0 @@
use serde::Serialize;
use crate::types::api::label::Label;
#[derive(Debug, Clone, Serialize, Default)]
pub struct EditLabelOption {
pub name: Option<String>,
pub description: Option<String>,
pub color: Option<String>,
}
impl EditLabelOption {
pub fn from_label(label: &Label) -> Self {
Self {
name: Some(label.name.to_string()),
description: Some(label.description.to_string()),
color: Some(label.color.to_string()),
}
}
}

View file

@ -1,24 +0,0 @@
use chrono::{DateTime, Utc};
use serde::Serialize;
use crate::types::api::milestone::Milestone;
use crate::types::api::state_type::StateType;
#[derive(Debug, Clone, Serialize, Default)]
pub struct EditMilestoneOption {
pub description: Option<String>,
pub state: Option<StateType>,
pub title: Option<String>,
pub due_on: Option<DateTime<Utc>>,
}
impl EditMilestoneOption {
pub fn from_milestone(milestone: &Milestone) -> Self {
Self {
description: milestone.description.clone(),
due_on: milestone.due_on,
state: Some(milestone.state),
title: Some(milestone.title.clone()),
}
}
}

View file

@ -1,30 +0,0 @@
use serde::Serialize;
use crate::types::api::pull_request::PullRequest;
use crate::types::api::state_type::StateType;
#[derive(Debug, Clone, Serialize, Default)]
pub struct EditPullRequestOption {
pub assignees: Option<Vec<String>>,
pub body: Option<String>,
pub state: Option<StateType>,
pub title: Option<String>,
pub labels: Option<Vec<usize>>,
}
impl EditPullRequestOption {
pub fn from_pull_request(pr: &PullRequest) -> Self {
Self {
assignees: pr.assignees.as_ref().map(|assignees| {
assignees
.iter()
.map(|assignee| assignee.login.to_owned())
.collect::<Vec<_>>()
}),
body: Some(pr.body.clone()),
state: (!pr.merged).then_some(pr.state),
title: Some(pr.title.clone()),
labels: Some(pr.labels.iter().map(|label| label.id).collect::<Vec<_>>()),
}
}
}

View file

@ -1,4 +0,0 @@
pub mod edit_issue_option;
pub mod edit_label_option;
pub mod edit_milestone_option;
pub mod edit_pull_request_option;

View file

@ -1,4 +0,0 @@
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct FollowersInfo {}

View file

@ -1,4 +0,0 @@
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct FollowingInfo {}

80
src/types/api/hook.rs Normal file
View file

@ -0,0 +1,80 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::Display;
use crate::types::misc::active::ActiveStatus;
use crate::types::misc::header::Header;
/// Hook represents a web hook when one repository is changed
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Hook {
/// Boolean flag indicating if the hook is active
pub active: ActiveStatus,
/// Authorization header for the Hook
///
/// This deviates a bit from the swagger docs and I'm not sure how it's even used correctly or
/// what it does
pub authorization_header: Header,
/// Configuration options for the hook
pub config: HashMap<String, String>,
/// Timestamp when the hook was created
pub created_at: DateTime<Utc>,
/// Events that trigger the hook
pub events: Vec<String>,
/// Unique ID of the hook
pub id: usize,
// ๐Ÿšง๐Ÿšง TODO ๐Ÿšง๐Ÿšง : enum?
/// Type of the hook
pub r#type: String,
/// Timestamp when the hook was last updated
pub updated_at: DateTime<Utc>,
}
impl Display for Hook {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Hook ID: {}", self.id)
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use std::str::FromStr;
use chrono::DateTime;
use hyper::http::{HeaderName, HeaderValue};
use crate::types::api::hook::Hook;
use crate::types::misc::active::ActiveStatus;
use crate::types::misc::header::Header;
#[test]
fn deserialize_works() {
let data = include_str!("../../../test_data/example_hook.json");
let hook: Hook = serde_json::from_str(data).unwrap();
let expected = Hook {
active: ActiveStatus::Active,
authorization_header: Header(hyper::HeaderMap::from_iter(std::iter::once((
HeaderName::from_static("bearer"),
HeaderValue::from_static("TOKEN"),
)))),
config: {
let mut config = HashMap::new();
config.insert(
String::from("url"),
String::from("https://example.com/webhook"),
);
config.insert(String::from("content_type"), String::from("json"));
config
},
created_at: DateTime::from_str("2023-07-27T12:34:56Z").unwrap(),
events: vec![String::from("push"), String::from("pull_request")],
id: 123456,
r#type: String::from("web"),
updated_at: DateTime::from_str("2023-07-27T14:45:56Z").unwrap(),
};
assert_eq!(hook, expected);
}
}

View file

@ -1,32 +0,0 @@
use std::fmt::Display;
use chrono::{DateTime, Utc};
use serde::Deserialize;
use crate::types::api::label::Label;
use crate::types::api::milestone::Milestone;
use crate::types::api::pull_request_meta::PullRequestMeta;
use crate::types::api::state_type::StateType;
use crate::types::api::user::User;
#[derive(Debug, Clone, Deserialize)]
pub struct Issue {
pub title: String,
pub number: usize,
pub labels: Vec<Label>,
pub assignees: Option<Vec<User>>,
pub body: String,
pub state: StateType,
pub pull_request: Option<PullRequestMeta>,
pub milestone: Option<Milestone>,
pub closed_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub due_date: Option<DateTime<Utc>>,
pub updated_at: DateTime<Utc>,
}
impl Display for Issue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "#{} {}", self.number, self.title)
}
}

View file

@ -1,6 +0,0 @@
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct IssueLabelsOption {
pub labels: Vec<usize>,
}

View file

@ -1,13 +1,26 @@
use std::fmt::Display;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
use crate::types::misc::color::Color;
use crate::types::misc::exclusive::Exclusive;
/// Label represents a label attached to an issue or a PR.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Label {
pub color: String,
/// The color of the label (in hexadecimal format).
pub color: Color,
/// The description of the label.
pub description: String,
pub name: String,
/// Indicates whether the label is exclusive.
pub exclusive: Exclusive,
/// The unique ID of the label.
pub id: usize,
/// The name of the label.
pub name: String,
/// The URL of the label.
pub url: Url,
}
impl Display for Label {
@ -15,3 +28,30 @@ impl Display for Label {
write!(f, "{}", self.name)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use palette::rgb::Rgb;
use url::Url;
use crate::types::api::label::Label;
use crate::types::misc::color::Color;
use crate::types::misc::exclusive::Exclusive;
#[test]
fn deserialize_label() {
let data = include_str!("../../../test_data/example_label.json");
let label: Label = serde_json::from_str(&data).unwrap();
let expected = Label {
color: Color(Rgb::from_str("00aabb").unwrap()),
description: "Label a label to an issue or a pr".to_string(),
exclusive: Exclusive::No,
id: 42,
name: "bug".to_string(),
url: Url::from_str("https://example.com/labels/bug").unwrap(),
};
assert_eq!(label, expected);
}
}

View file

@ -1,23 +0,0 @@
use std::fmt::Display;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::types::api::state_type::StateType;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Milestone {
pub id: usize,
pub title: String,
pub due_on: Option<DateTime<Utc>>,
pub state: StateType,
pub open_issues: usize,
pub closed_issues: usize,
pub description: Option<String>,
}
impl Display for Milestone {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.title)
}
}

View file

@ -1,18 +1,7 @@
pub mod branch;
pub mod comment;
pub mod create_options;
pub mod edit_options;
pub mod followers_info;
pub mod following_info;
pub mod issue;
pub mod issue_labels_option;
pub mod creation;
pub mod edit;
pub mod hook;
pub mod label;
pub mod milestone;
pub mod notification;
pub mod privacy_type;
pub mod pull_request;
pub mod pull_request_meta;
pub mod repository;
pub mod search_results;
pub mod state_type;
pub mod organization;
pub mod team;
pub mod user;

View file

@ -1,5 +0,0 @@
pub mod notification_count;
pub mod notification_state_type;
pub mod notification_subject;
pub mod notification_thread;
pub mod notification_type;

View file

@ -1,6 +0,0 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct NotificationCount {
new: usize,
}

View file

@ -1,29 +0,0 @@
use clap::ValueEnum;
use serde::{Deserialize, Serialize};
use strum::{Display, EnumIter, EnumString};
#[derive(Debug, Clone, Copy, Serialize, Deserialize, ValueEnum, Display, EnumIter, EnumString)]
#[strum(serialize_all = "lowercase")]
#[serde(rename(serialize = "lowercase"))]
pub enum NotificationStateType {
Unread,
Read,
Pinned,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, ValueEnum, Display, EnumIter, EnumString)]
#[strum(serialize_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum NotificationStateTypeApi {
Closed,
Open,
All,
Merged,
}
impl NotificationStateType {
pub fn available_for_choosing() -> [Self; 3] {
use NotificationStateType::*;
[Unread, Read, Pinned]
}
}

View file

@ -1,15 +0,0 @@
use serde::{Deserialize, Serialize};
use crate::types::api::notification::notification_state_type::NotificationStateTypeApi;
use crate::types::api::notification::notification_type::NotificationSubjectType;
#[derive(Debug, Serialize, Deserialize)]
pub struct NotificationSubject {
pub html_url: String,
pub latest_comment_html_url: String,
pub latest_comment_url: String,
pub state: NotificationStateTypeApi,
pub title: String,
#[serde(rename = "type")]
pub notify_type: NotificationSubjectType,
}

View file

@ -1,29 +0,0 @@
use std::fmt::Display;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::types::api::notification::notification_subject::NotificationSubject;
use crate::types::api::repository::Repository;
#[derive(Debug, Serialize, Deserialize)]
pub struct NotificationThread {
pub id: usize,
pub pinned: bool,
pub repository: Repository,
pub subject: NotificationSubject,
pub unread: bool,
pub updated_at: DateTime<Utc>,
pub url: String,
}
impl Display for NotificationThread {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(if self.unread { "๐Ÿ“• " } else { "๐Ÿ“– " })?;
if self.pinned {
f.write_str("๐Ÿ“Œ ")?;
}
f.write_str(self.subject.title.as_str())?;
Ok(())
}
}