diff --git a/.env.example b/.env.example index ee16ac9..e93f8c4 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,4 @@ DISCORD_TOKEN= +GITHUB_TOKEN= +DISCORD_SERVER_ID= +GITHUB_ORG=hyprland-community diff --git a/Cargo.lock b/Cargo.lock index ef8c199..de164d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,6 +47,12 @@ version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayvec" version = "0.7.4" @@ -94,6 +100,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -346,6 +358,12 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "either" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" + [[package]] name = "encoding_rs" version = "0.8.34" @@ -419,6 +437,7 @@ checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -441,6 +460,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -514,8 +544,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -555,6 +587,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -594,6 +632,29 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body 1.0.0", + "pin-project-lite", +] + [[package]] name = "httparse" version = "1.8.0" @@ -618,7 +679,7 @@ dependencies = [ "futures-util", "h2", "http 0.2.12", - "http-body", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -630,6 +691,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -638,18 +718,71 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper", + "hyper 0.14.28", "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.3.1", + "hyper-util", + "log", + "rustls 0.22.4", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.25.0", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +dependencies = [ + "hyper 1.3.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.3.1", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "hyprmaid" version = "0.1.0" dependencies = [ "anyhow", "dotenvy", + "octocrab", "poise", "tokio", "tracing-subscriber", @@ -710,6 +843,16 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "iri-string" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f5f6c2df22c009ac44f6f1499308e7a3ac7ba42cd2378475cc691510e1eef1b" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "itoa" version = "1.0.11" @@ -725,6 +868,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -835,12 +993,31 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -869,12 +1046,56 @@ dependencies = [ "memchr", ] +[[package]] +name = "octocrab" +version = "0.38.0" +source = "git+https://github.com/flick0/octocrab.git#662131e2ba47b709df0cba2d5fe046be4e0f6a34" +dependencies = [ + "arc-swap", + "async-trait", + "base64 0.22.1", + "bytes", + "cfg-if", + "chrono", + "either", + "futures", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", + "hyper-rustls 0.26.0", + "hyper-timeout", + "hyper-util", + "jsonwebtoken", + "once_cell", + "percent-encoding", + "pin-project", + "secrecy", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "snafu", + "tokio", + "tower", + "tower-http", + "tracing", + "url", +] + [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "overload" version = "0.1.1" @@ -904,12 +1125,42 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1081,16 +1332,16 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", "http 0.2.12", - "http-body", - "hyper", - "hyper-rustls", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", @@ -1100,7 +1351,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.21.12", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -1179,13 +1430,36 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", ] [[package]] @@ -1230,6 +1504,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1256,6 +1539,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.22" @@ -1296,6 +1602,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1316,7 +1632,7 @@ checksum = "c64da29158bb55d70677cacd4f4f8eab1acef005fb830d9c3bea411b090e96a9" dependencies = [ "arrayvec", "async-trait", - "base64", + "base64 0.21.7", "bitflags 2.5.0", "bytes", "chrono", @@ -1360,6 +1676,18 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + [[package]] name = "skeptic" version = "0.13.7" @@ -1390,6 +1718,27 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "snafu" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75976f4748ab44f6e5332102be424e7c2dc18daeaf7e725f2040c3ebb133512e" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b19911debfb8c2fb1107bc6cb2d61868aaf53a988449213959bb1b5b1ed95f" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "socket2" version = "0.5.7" @@ -1640,6 +1989,49 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags 2.5.0", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index c076c02..3081daf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,8 @@ strip = true [dependencies] anyhow = "1.0.82" dotenvy = "0.15.7" +octocrab = { git = "https://github.com/flick0/octocrab.git", version = "0.38.0" } +# octocrab = "0.38.0" poise = "0.6.1" tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros"] } tracing-subscriber = { version = "0.3.18", features = [ diff --git a/err.json b/err.json new file mode 100644 index 0000000..e69de29 diff --git a/src/github.rs b/src/github.rs new file mode 100644 index 0000000..d773abb --- /dev/null +++ b/src/github.rs @@ -0,0 +1,233 @@ +use anyhow::Result; +use octocrab::{ + models::{ + hooks::{Config as HookConfig, ContentType, Hook}, + webhook_events::WebhookEventType, + Repository, + }, + Octocrab, Page, +}; +use poise::serenity_prelude::{ + self as serenity, json::json, ChannelType, CreateChannel, GuildChannel, GuildId, Http, +}; + +const DELAY_MS: u64 = 10000; +const BLACKLISTED_REPOS: [&str; 3] = [".GITHUB", "SUBMISSIONS", "COMMUNITY"]; + +pub async fn fetch_repos(octo: Octocrab, org: &String) -> Result> { + let response = octo.orgs(org).list_repos().send().await?; + + Ok(response) +} + +pub async fn fetch_categories(guild_id: GuildId, http: &Http) -> Result> { + let guild = http.get_guild(guild_id).await.unwrap(); + + let channels = guild.channels(http).await.unwrap(); + + let categories = channels + .iter() + .filter(|c| c.1.kind == serenity::model::channel::ChannelType::Category) + .map(|c| c.1.to_owned()) + .collect::>(); + + Ok(categories) +} + +pub struct Github { + pub github_token: Option, + pub bot_token: String, + pub guild_id: GuildId, + pub org: String, + pub webhook_events: Vec, +} + +impl Github { + pub fn new(org: String,github_token: Option, bot_token: String, guild_id: GuildId) -> Self { + Self { + github_token, + bot_token, + guild_id, + org, + webhook_events: vec![ + WebhookEventType::BranchProtectionRule, + WebhookEventType::BranchProtectionRule, + WebhookEventType::CheckRun, + WebhookEventType::CheckSuite, + WebhookEventType::CodeScanningAlert, + WebhookEventType::CommitComment, + WebhookEventType::Create, + WebhookEventType::Delete, + WebhookEventType::DependabotAlert, + WebhookEventType::DeployKey, + WebhookEventType::Deployment, + WebhookEventType::DeploymentStatus, + WebhookEventType::Discussion, + WebhookEventType::DiscussionComment, + WebhookEventType::Fork, + WebhookEventType::Gollum, + WebhookEventType::IssueComment, + WebhookEventType::Issues, + WebhookEventType::Label, + WebhookEventType::Member, + WebhookEventType::MergeGroup, + WebhookEventType::Meta, + WebhookEventType::Milestone, + WebhookEventType::Package, + WebhookEventType::PageBuild, + WebhookEventType::Ping, + WebhookEventType::ProjectCard, + WebhookEventType::Project, + WebhookEventType::ProjectColumn, + WebhookEventType::Public, + WebhookEventType::PullRequest, + WebhookEventType::PullRequestReviewComment, + WebhookEventType::PullRequestReview, + WebhookEventType::PullRequestReviewThread, + WebhookEventType::Push, + WebhookEventType::RegistryPackage, + WebhookEventType::Release, + WebhookEventType::RepositoryAdvisory, + WebhookEventType::Repository, + WebhookEventType::RepositoryImport, + WebhookEventType::RepositoryVulnerabilityAlert, + WebhookEventType::SecretScanningAlert, + WebhookEventType::SecretScanningAlertLocation, + WebhookEventType::SecurityAndAnalysis, + WebhookEventType::Star, + WebhookEventType::Status, + WebhookEventType::TeamAdd, + WebhookEventType::Watch, + ], + } + } + + pub async fn check_loop(&self) -> Result<()> { + let http = Http::new(&self.bot_token); + + let octo = match self.github_token.clone() { + Some(t) => Octocrab::builder().personal_token(t).build()?, + None => Octocrab::builder().build()?, + }; + + loop { + let repos = fetch_repos(octo.clone(), &self.org).await?; + let categories = fetch_categories(self.guild_id, &http).await?; + + println!("checking repos"); + self.update(repos, categories, &http, &octo).await?; + println!("done checking repos"); + + tokio::time::sleep(tokio::time::Duration::from_millis(DELAY_MS)).await; + } + } + + pub async fn update( + &self, + repos: Page, + categories: Vec, + http: &Http, + octo: &Octocrab, + ) -> Result<()> { + let category_names = categories + .iter() + .map(|c| c.name().to_uppercase()) + .collect::>(); + + for repo in repos { + println!("checking repo: {}", repo.name); + + if category_names.contains(&repo.name.to_uppercase()) { + println!("repo already exists"); + continue; + } + + if BLACKLISTED_REPOS.contains(&repo.name.to_uppercase().as_str()) { + println!("repo is blacklisted"); + continue; + } + + // create discord category + let guild = http.get_guild(self.guild_id).await?; + + // category + println!("creating category: {}", repo.name); + let cat = guild + .create_channel( + http, + CreateChannel::new(repo.name.clone()).kind(ChannelType::Category), + ) + .await + .expect("failed to create category"); + + // announcements + println!("creating announcement channel"); + guild + .create_channel( + http, + CreateChannel::new("announcement") + .kind(ChannelType::News) + .category(cat.id), + ) + .await + .expect("failed to create announcement channel"); + + // general + println!("creating general channel"); + guild + .create_channel( + http, + CreateChannel::new(format!("{}-general", repo.name)) + .kind(ChannelType::Text) + .category(cat.id), + ) + .await + .expect("failed to create general channel"); + + // git webhook + println!("creating git channel"); + let git_channel = guild + .create_channel( + http, + CreateChannel::new("git") + .kind(ChannelType::Text) + .category(cat.id), + ) + .await + .expect("failed to create git channel"); + + let map = json!({"name":"GitHub"}); + + println!("creating discord webhook"); + let discord_webhook = http + .create_webhook(git_channel.id, &map, None) + .await + .expect("failed to create discord webhook"); + + let repo_handler = octo.repos(&self.org, &repo.name); + + let hook_config = HookConfig { + url: discord_webhook.url()? + "/github", + content_type: Some(ContentType::Json), + secret: None, + insecure_ssl: None, + }; + + let hook = Hook { + name: "web".to_string(), + active: true, + config: hook_config, + events: self.webhook_events.clone(), + ..Hook::default() + }; + + println!("creating git webhook"); + repo_handler + .create_hook(hook) + .await + .expect("failed to create git webhook"); + } + + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index 13f083c..4599103 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,14 @@ use anyhow::Result; -use poise::serenity_prelude as serenity; +use poise::serenity_prelude::{self as serenity, GuildId}; use dotenvy::dotenv; struct Data {} // User data, which is stored and accessible in all command invocations + type Error = Box; type Context<'a> = poise::Context<'a, Data, Error>; +mod github; + + /// Displays your or another user's account creation date #[poise::command(slash_command, prefix_command)] async fn age( @@ -25,9 +29,20 @@ async fn main() -> Result<()> { let token = std::env::var("DISCORD_TOKEN").expect("missing DISCORD_TOKEN"); let intents = serenity::GatewayIntents::non_privileged(); + let github = github::Github::new( + std::env::var("GITHUB_ORG").expect("missing GITHUB_ORG"), + std::env::var("GITHUB_TOKEN").ok(), + token.clone(), + GuildId::new(std::env::var("DISCORD_SERVER_ID").expect("missing DISCORD_SERVER_ID") + .parse::().expect("invalid DISCORD_SERVER_ID")), + ); + let framework = poise::Framework::builder() .options(poise::FrameworkOptions { - commands: vec![age()], + commands: vec![ + age(), + // commands::github::update_repos() + ], ..Default::default() }) .setup(|ctx, _ready, framework| { @@ -42,7 +57,12 @@ async fn main() -> Result<()> { .framework(framework) .await?; - client.start().await?; + println!("starting bot"); + + let (git, discord) = tokio::join!(github.check_loop(), client.start()); + + git.unwrap(); + discord.unwrap(); Ok(()) }