From a17901a6d6a1b1037c03953faf43b310f442968f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 8 Jan 2024 13:26:09 +0100 Subject: [PATCH] write workpackage on openproject --- .gitignore | 1 + Cargo.lock | 590 +++++++++++++++++++++++++++++++++---- Cargo.toml | 5 +- config.toml.dist | 8 +- docker-compose.yaml | 15 + src/cli.rs | 3 +- src/config.rs | 7 + src/error.rs | 4 + src/gitlab/issue.rs | 14 + src/gitlab/mod.rs | 13 + src/main.rs | 42 ++- src/openproject/client.rs | 48 +++ src/openproject/mod.rs | 3 + src/openproject/work.rs | 36 +++ src/planning/issue2work.rs | 32 +- 15 files changed, 739 insertions(+), 82 deletions(-) create mode 100644 docker-compose.yaml create mode 100644 src/error.rs create mode 100644 src/gitlab/issue.rs create mode 100644 src/gitlab/mod.rs create mode 100644 src/openproject/client.rs create mode 100644 src/openproject/mod.rs create mode 100644 src/openproject/work.rs diff --git a/.gitignore b/.gitignore index 4f4613f..49a01b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ config.toml /target .idea/* +.docker-data/* diff --git a/Cargo.lock b/Cargo.lock index a9a055c..89e6ced 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "bumpalo" version = "3.12.0" @@ -72,9 +78,12 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -101,7 +110,10 @@ version = "0.1.0" dependencies = [ "clap", "gitlab", + "reqwest", "serde", + "simple-home-dir", + "tokio", "toml", "url", ] @@ -112,7 +124,7 @@ version = "4.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c911b090850d79fc64fe9ea01e28e465f65e821e08813ced95bced72f7a8a9b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", "is-terminal", @@ -166,10 +178,31 @@ dependencies = [ ] [[package]] -name = "core-foundation-sys" -version = "0.8.3" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cron" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff76b51e4c068c52bfd2866e1567bee7c567ae8f24ada09fd4307019e25eab7" +dependencies = [ + "chrono", + "nom", + "once_cell", +] [[package]] name = "cxx" @@ -307,6 +340,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -317,12 +360,33 @@ dependencies = [ "libc", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -381,15 +445,27 @@ dependencies = [ ] [[package]] -name = "gitlab" -version = "0.1510.0" +name = "getrandom" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5137ee8a0cfc15daeebb427257b623e35914d19d713729cb131bcae52c69934c" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gitlab" +version = "0.1607.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1e6513047a74a6f787355c0a44305fd98e355464336dc176e4fab31df8826" dependencies = [ "async-trait", "base64 0.13.1", "bytes", "chrono", + "cron", "derive_builder", "futures-util", "graphql_client", @@ -569,10 +645,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.2" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ + "futures-util", "http", "hyper", "rustls", @@ -580,6 +657,19 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.54" @@ -638,7 +728,7 @@ checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -655,8 +745,8 @@ checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix", - "windows-sys", + "rustix 0.36.11", + "windows-sys 0.45.0", ] [[package]] @@ -691,9 +781,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "link-cplusplus" @@ -710,6 +800,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + [[package]] name = "log" version = "0.4.17" @@ -731,6 +827,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" version = "0.8.6" @@ -740,7 +842,35 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.45.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", ] [[package]] @@ -778,6 +908,50 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "openssl" +version = "0.10.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.10", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_str_bytes" version = "6.5.0" @@ -802,6 +976,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" + [[package]] name = "proc-macro2" version = "1.0.54" @@ -821,10 +1001,19 @@ dependencies = [ ] [[package]] -name = "reqwest" -version = "0.11.15" +name = "redox_syscall" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ba30cc2c0cd02af1222ed216ba659cdb2f879dfe3181852fe7c50b1d0005949" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "reqwest" +version = "0.11.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ "base64 0.21.0", "bytes", @@ -836,10 +1025,12 @@ dependencies = [ "http-body", "hyper", "hyper-rustls", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -848,7 +1039,9 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", + "tokio-native-tls", "tokio-rustls", "tower-service", "url", @@ -868,36 +1061,63 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", - "untrusted", + "spin 0.5.2", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] + [[package]] name = "rustix" version = "0.36.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" dependencies = [ - "bitflags", - "errno", + "bitflags 1.3.2", + "errno 0.2.8", "io-lifetimes", "libc", - "linux-raw-sys", - "windows-sys", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno 0.3.8", + "libc", + "linux-raw-sys 0.4.12", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring", + "ring 0.17.7", + "rustls-webpki", "sct", - "webpki", ] [[package]] @@ -909,12 +1129,31 @@ dependencies = [ "base64 0.21.0", ] +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + [[package]] name = "ryu" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +[[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 = "scratch" version = "1.0.5" @@ -927,8 +1166,31 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -983,6 +1245,15 @@ dependencies = [ "serde", ] +[[package]] +name = "simple-home-dir" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2248bffb36839d917a8d3e046b7cc043ee6ef61970de8f6e7104098113297619" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "slab" version = "0.4.8" @@ -1008,6 +1279,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "strsim" version = "0.10.0" @@ -1036,6 +1313,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix 0.38.28", + "windows-sys 0.52.0", +] + [[package]] name = "termcolor" version = "1.2.0" @@ -1094,18 +1405,39 @@ dependencies = [ "num_cpus", "pin-project-lite", "socket2", - "windows-sys", + "tokio-macros", + "windows-sys 0.45.0", +] + +[[package]] +name = "tokio-macros" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", ] [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", - "webpki", ] [[package]] @@ -1230,6 +1562,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.3.1" @@ -1241,6 +1579,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "void" version = "1.0.2" @@ -1339,24 +1683,11 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" [[package]] name = "winapi" @@ -1395,7 +1726,7 @@ version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", ] [[package]] @@ -1404,7 +1735,25 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -1413,13 +1762,43 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -1428,42 +1807,126 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.4.1" @@ -1475,9 +1938,10 @@ dependencies = [ [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] diff --git a/Cargo.toml b/Cargo.toml index aa88fe7..c277988 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,10 @@ edition = "2021" [dependencies] clap = { version = "4.1.13", features = ["derive"] } -gitlab = "0.1510.0" +gitlab = "0.1607.0" +reqwest = "0.11.23" serde = { version = "1.0.158", features = ["derive"] } toml = "0.7.3" url = "2.3.1" +tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros"] } +simple-home-dir = "0.2.1" diff --git a/config.toml.dist b/config.toml.dist index 766c514..0d5804d 100644 --- a/config.toml.dist +++ b/config.toml.dist @@ -1,2 +1,8 @@ [gitlab] -token = "glpat-example" \ No newline at end of file +# generate from https://gitlab.com/-/user_settings/personal_access_tokens +token = "glpat-example" + +[openproject] +# generate api token from https://champs-libres.openproject.com/my/access_token +token = "a8715-example" +base_url = "https://champs-libres.openproject.com" diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..8e1eba6 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,15 @@ +version: '3' + +services: + openproject: + image: openproject/community:13 + environment: + OPENPROJECT_SECRET_KEY_BASE: secret + OPENPROJECT_HOST__NAME: 'localhost:8080' + OPENPROJECT_HTTPS: 'false' + OPENPROJECT_DEFAULT__LANGUAGE: en + ports: + - "127.0.0.1:8080:80" + volumes: + - "./.docker-data/openproject/pgdata:/var/openproject/pgdata" + - "./.docker-data/openproject/assets:/var/openproject/assets" \ No newline at end of file diff --git a/src/cli.rs b/src/cli.rs index 9aa199b..e4578b4 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -25,5 +25,6 @@ pub(crate) enum Planning { #[derive(Args, Debug)] pub(crate) struct Issue2Work { - pub issue_url: String + pub issue_url: String, + pub project_id: String, } diff --git a/src/config.rs b/src/config.rs index b5310c1..fa2244e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,9 +3,16 @@ use serde::Deserialize; #[derive(Deserialize, Debug)] pub(crate) struct Config { pub gitlab: GitlabConfig, + pub openproject: OpenProjectConfig, } #[derive(Deserialize, Debug)] pub(crate) struct GitlabConfig { pub token: String, +} + +#[derive(Deserialize, Debug)] +pub(crate) struct OpenProjectConfig { + pub token: String, + pub base_url: String, } \ No newline at end of file diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..6f9e34f --- /dev/null +++ b/src/error.rs @@ -0,0 +1,4 @@ + +pub struct GeneralError { + pub(crate) description: String, +} diff --git a/src/gitlab/issue.rs b/src/gitlab/issue.rs new file mode 100644 index 0000000..2a61698 --- /dev/null +++ b/src/gitlab/issue.rs @@ -0,0 +1,14 @@ +use gitlab::Issue; +use gitlab::Project; + +/// A struct which contains Issue and Project +pub struct IssueBundle { + pub issue: Issue, + pub project: Project +} + +impl IssueBundle { + pub fn new(issue: &Issue, project: &Project) -> Self { + IssueBundle{issue: issue.clone(), project: project.clone()} + } +} \ No newline at end of file diff --git a/src/gitlab/mod.rs b/src/gitlab/mod.rs new file mode 100644 index 0000000..a3afa9f --- /dev/null +++ b/src/gitlab/mod.rs @@ -0,0 +1,13 @@ +pub mod issue; + +use gitlab::GitlabError; +use crate::error::GeneralError; + +impl From for GeneralError { + fn from(value: GitlabError) -> Self { + GeneralError{ + description: value.to_string() + } + } +} + diff --git a/src/main.rs b/src/main.rs index d2e2f91..6deabd1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,35 +1,57 @@ extern crate serde; extern crate clap; +extern crate reqwest; +extern crate simple_home_dir; mod cli; mod config; mod planning; +mod openproject; +mod error; +mod gitlab; use std::fs; use std::path::PathBuf; +use std::process::exit; use clap::Parser; use cli::Cli; use config::Config; use crate::cli::Commands::Planning; use crate::cli::Planning::I2work; +use crate::error::GeneralError; -fn main() { +#[tokio::main] +async fn main() { let cli = Cli::parse(); - let default_config_path = PathBuf::from("/etc/config.toml"); + let mut default_config_path = PathBuf::new(); + default_config_path.push(simple_home_dir::home_dir().unwrap()); + default_config_path.push(".config/cl-cli/config.toml"); + let config_path = match cli.config.as_deref() { Some(p) => p, None => &default_config_path }; - let config_path_content = fs::read_to_string(config_path) - .expect("Could not read config file"); + let config_path_content = match fs::read_to_string(config_path) { + Ok(content) => content, + Err(e) => { + println!("Could not read config file at {:?}, error: {}", config_path, e); + exit(1); + } + }; let config: Config = toml::from_str(&*config_path_content).expect("Could not parse config"); - match cli.command { - Some(Planning(I2work(args))) => { - planning::issue2work::issue2work(config, &args); - }, - None => {} - } + let result = match cli.command { + Some(Planning(I2work(args))) => planning::issue2work::issue2work(config, &args).await, + None => Err(GeneralError{description: "No command launched".to_string()}) + }; + + match result { + Ok(()) => exit(0), + Err(e) => { + println!("Error: {}", e.description); + exit(1) + } + }; } diff --git a/src/openproject/client.rs b/src/openproject/client.rs new file mode 100644 index 0000000..3151caf --- /dev/null +++ b/src/openproject/client.rs @@ -0,0 +1,48 @@ +use crate::config::OpenProjectConfig; +use crate::error::GeneralError; +use crate::openproject::work::{WorkPackageWriter, WorkPackage}; + +pub(crate) struct Error { + description: String, +} + +impl From for Error { + fn from(value: reqwest::Error) -> Self { + Error { + description: format!("Error while connecting to openproject instance: {}", value) + } + } +} + +impl From for GeneralError { + fn from(value: Error) -> GeneralError { + GeneralError{description: value.description} + } +} + +pub(crate) struct Client { + base_url: String, + token: String, +} + +impl Client { + pub fn from_config(config: &OpenProjectConfig) -> Client { + Client{base_url: config.base_url.clone(), token: config.token.clone()} + } + + pub async fn create_work_package(&self, work_package: &WorkPackageWriter, project_id: &String) -> Result { + + let client = reqwest::Client::new(); + + let work_package: WorkPackage = client + .post(format!("{}/api/v3/projects/{}/work_packages", self.base_url, project_id)) + .basic_auth("apikey", Some(&self.token)) + .json(&work_package) + .send() + .await? + .json() + .await?; + + Ok(work_package) + } +} diff --git a/src/openproject/mod.rs b/src/openproject/mod.rs new file mode 100644 index 0000000..533ff88 --- /dev/null +++ b/src/openproject/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod client; +mod work; + diff --git a/src/openproject/work.rs b/src/openproject/work.rs new file mode 100644 index 0000000..fcc6ea2 --- /dev/null +++ b/src/openproject/work.rs @@ -0,0 +1,36 @@ +use serde::{Deserialize, Serialize}; +use crate::gitlab::issue::IssueBundle; + +#[derive(Serialize, Debug)] +pub struct WorkPackageWriter { + subject: String, + #[serde(alias = "type")] + work_type: String, + description: DescriptionWriter, +} + +#[derive(Serialize, Debug)] +pub struct DescriptionWriter { + format: String, + raw: String, +} + +#[derive(Deserialize, Debug)] +pub struct WorkPackage { + pub id: u64, + pub subject: String, +} + +impl From<&IssueBundle> for WorkPackageWriter { + + fn from(value: &IssueBundle) -> Self { + WorkPackageWriter { + subject: format!("{} ({}/{})", value.issue.title, value.project.name_with_namespace, value.issue.iid), + work_type: "TASK".into(), + description: DescriptionWriter { + format: "markdown".into(), + raw: format!("From gitlab: {}", value.issue.web_url) + } + } + } +} diff --git a/src/planning/issue2work.rs b/src/planning/issue2work.rs index 6bb2eb6..e08d31b 100644 --- a/src/planning/issue2work.rs +++ b/src/planning/issue2work.rs @@ -1,8 +1,11 @@ use crate::cli::Issue2Work; use crate::config::Config; -use gitlab::{Gitlab, Issue}; -use gitlab::api::{Query, issues}; +use crate::openproject::client::Client; +use gitlab::{ GitlabBuilder, Issue, Project}; +use gitlab::api::{issues, AsyncQuery, projects}; use url::Url; +use crate::error::GeneralError; +use crate::gitlab::issue::IssueBundle; #[derive(Debug)] struct IssueInfo { @@ -10,22 +13,39 @@ struct IssueInfo { iid: u64, } -pub(crate) fn issue2work(config: Config, args: &Issue2Work) { +pub(crate) async fn issue2work(config: Config, args: &Issue2Work) -> Result<(), GeneralError> { let url = Url::parse(&*args.issue_url) .expect("issue_url is not valid"); let data = extract_issue_info(&url).unwrap(); - let client = Gitlab::new("gitlab.com", config.gitlab.token).unwrap(); + let client = GitlabBuilder::new("gitlab.com", config.gitlab.token).build_async().await?; let endpoint = issues::ProjectIssues::builder() .iid(data.iid) .project(String::from(data.project)) .build() + .unwrap() + ; + + let issues: Vec = endpoint.query_async(&client).await.unwrap(); + let issue = issues.first().unwrap(); + + let project_endpoint = projects::Project::builder() + .project(issue.project_id.value()) + .build() .unwrap(); - let issue: Vec = endpoint.query(&client).unwrap(); + let project: Project = project_endpoint.query_async(&client).await.unwrap(); - println!("{:?}", issue.first()); + let issue_bundle = IssueBundle::new(&issue, &project); + + let open_project_client = Client::from_config(&config.openproject); + + let work_package = open_project_client.create_work_package(&(&issue_bundle).into(), &args.project_id).await?; + + println!("new work package created: {:?}, edit at {}/projects/{}/work_packages/{}", work_package.subject, config.openproject.base_url, args.project_id, work_package.id); + + Ok(()) } fn extract_issue_info(url: &Url) -> Option {