diff --git a/Cargo.lock b/Cargo.lock index 288db2b..8780bed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -230,6 +230,27 @@ dependencies = [ "url", ] +[[package]] +name = "gitea_client" +version = "0.1.0" +dependencies = [ + "async-trait", + "gitea_raw_client", + "reqwest", +] + +[[package]] +name = "gitea_raw_client" +version = "1.17.3" +dependencies = [ + "reqwest", + "serde", + "serde_derive", + "serde_json", + "url", + "uuid", +] + [[package]] name = "h2" version = "0.3.15" @@ -588,6 +609,7 @@ dependencies = [ "async-trait", "eyre", "git2", + "gitea_client", "hex", "rand", "serde", @@ -602,6 +624,7 @@ version = "0.1.0" dependencies = [ "eyre", "octopush_core", + "tracing", ] [[package]] @@ -610,18 +633,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" -[[package]] -name = "openapi" -version = "1.17.3" -dependencies = [ - "reqwest", - "serde", - "serde_derive", - "serde_json", - "url", - "uuid", -] - [[package]] name = "openssl" version = "0.10.43" diff --git a/Cargo.toml b/Cargo.toml index d25d334..0fe200a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "crates/octopush_infra", "crates/octopush_core", "crates/gitea_raw_client", + "crates/gitea_client", ] [workspace.dependencies] diff --git a/_examples/actions/write_a_readme/dist/bin b/_examples/actions/write_a_readme/dist/bin index 1e966c1..a562e14 100755 Binary files a/_examples/actions/write_a_readme/dist/bin and b/_examples/actions/write_a_readme/dist/bin differ diff --git a/_examples/actions/write_a_readme/main.go b/_examples/actions/write_a_readme/main.go index a344b29..8326ca8 100644 --- a/_examples/actions/write_a_readme/main.go +++ b/_examples/actions/write_a_readme/main.go @@ -1,6 +1,10 @@ package main -import "github.com/bitfield/script" +import ( + "os" + + "github.com/bitfield/script" +) func main() { _, err := script. @@ -10,4 +14,25 @@ func main() { if err != nil { panic(err) } + println("ran stuff") + entries, err := os.ReadDir(".") + if err != nil { + panic(err) + } + for _, entry := range entries { + if !entry.IsDir() { + file, err := os.ReadFile(entry.Name()) + if err != nil { + panic(err) + } + println(string(file)) + } + } + + wd, err := os.Getwd() + if err != nil { + panic(err) + } + + println(wd) } diff --git a/_examples/actions/write_a_readme/octopush.yml b/_examples/actions/write_a_readme/octopush.yml index b45a24f..9d7a62e 100644 --- a/_examples/actions/write_a_readme/octopush.yml +++ b/_examples/actions/write_a_readme/octopush.yml @@ -1,19 +1,19 @@ apiVersion: action name: write-a-readme select: - github: - repositories: - - kjuulh/octopush-test - push: - pull-request: - name: "write a readme" + # github: + # repositories: + # - kjuulh/octopush-test + # push: + # pull-request: + # name: "write a readme" - gitea: - repositories: - - kjuulh/octopush-test - push: - pull-request: - name: "write a readme" + # gitea: + # repositories: + # - kjuulh/octopush-test + # push: + # pull-request: + # name: "write a readme" git: repositories: diff --git a/crates/gitea_client/Cargo.toml b/crates/gitea_client/Cargo.toml new file mode 100644 index 0000000..2b8c3a2 --- /dev/null +++ b/crates/gitea_client/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "gitea_client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +gitea_raw_client = { path = "../gitea_raw_client" } + +async-trait = { workspace = true } + +reqwest = "0.11.13" diff --git a/crates/gitea_client/src/apis/defaults/mod.rs b/crates/gitea_client/src/apis/defaults/mod.rs new file mode 100644 index 0000000..bb787f4 --- /dev/null +++ b/crates/gitea_client/src/apis/defaults/mod.rs @@ -0,0 +1 @@ +pub mod repository; diff --git a/crates/gitea_client/src/apis/defaults/repository.rs b/crates/gitea_client/src/apis/defaults/repository.rs new file mode 100644 index 0000000..49b32a1 --- /dev/null +++ b/crates/gitea_client/src/apis/defaults/repository.rs @@ -0,0 +1,1115 @@ +use std::sync::Arc; + +use async_trait::async_trait; +use gitea_raw_client::{ + apis::{configuration::Configuration, repository_api::*, Error}, + models, +}; + +use crate::apis::repository::Repository; + +pub struct DefaultRepository { + conf: Arc, +} + +impl DefaultRepository { + pub fn new(conf: Arc) -> Self { + Self { conf } + } +} + +#[allow(dead_code, unused_variables)] +#[async_trait] +impl Repository for DefaultRepository { + async fn accept_transfer( + &self, + owner: &str, + repo: &str, + ) -> Result> { + todo!("not implemented") + } + async fn create_current_user_repo( + &self, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn create_fork( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn generate_repo( + &self, + template_owner: &str, + template_repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn get_annotated_tag( + &self, + owner: &str, + repo: &str, + sha: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_blob( + &self, + owner: &str, + repo: &str, + sha: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_tree( + &self, + owner: &str, + repo: &str, + sha: &str, + recursive: Option, + page: Option, + per_page: Option, + ) -> Result> { + todo!("not implemented") + } + async fn list_forks( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn reject_transfer( + &self, + owner: &str, + repo: &str, + ) -> Result> { + todo!("not implemented") + } + async fn add_collaborator( + &self, + owner: &str, + repo: &str, + collaborator: &str, + body: Option, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn add_team( + &self, + owner: &str, + repo: &str, + team: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn add_topic( + &self, + owner: &str, + repo: &str, + topic: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn apply_diff_patch( + &self, + owner: &str, + repo: &str, + body: models::UpdateFileOptions, + ) -> Result> { + todo!("not implemented") + } + async fn cancel_scheduled_auto_merge( + &self, + owner: &str, + repo: &str, + index: i64, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn check_collaborator( + &self, + owner: &str, + repo: &str, + collaborator: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn check_team( + &self, + owner: &str, + repo: &str, + team: &str, + ) -> Result> { + todo!("not implemented") + } + async fn create_branch( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn create_branch_protection( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn create_file( + &self, + owner: &str, + repo: &str, + filepath: &str, + body: models::CreateFileOptions, + ) -> Result> { + todo!("not implemented") + } + async fn create_hook( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn create_key( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn create_pull_request( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + gitea_raw_client::apis::repository_api::repo_create_pull_request( + &self.conf, owner, repo, body, + ) + .await + } + async fn create_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + body: models::CreatePullReviewOptions, + ) -> Result> { + todo!("not implemented") + } + async fn create_pull_review_requests( + &self, + owner: &str, + repo: &str, + index: i64, + body: models::PullReviewRequestOptions, + ) -> Result, Error> { + todo!("not implemented") + } + async fn create_release( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn create_release_attachment( + &self, + owner: &str, + repo: &str, + id: i64, + attachment: std::path::PathBuf, + name: Option<&str>, + ) -> Result> { + todo!("not implemented") + } + async fn create_status( + &self, + owner: &str, + repo: &str, + sha: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn create_tag( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn create_wiki_page( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn delete(&self, owner: &str, repo: &str) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_branch( + &self, + owner: &str, + repo: &str, + branch: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_branch_protection( + &self, + owner: &str, + repo: &str, + name: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_collaborator( + &self, + owner: &str, + repo: &str, + collaborator: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_file( + &self, + owner: &str, + repo: &str, + filepath: &str, + body: models::DeleteFileOptions, + ) -> Result> { + todo!("not implemented") + } + async fn delete_git_hook( + &self, + owner: &str, + repo: &str, + id: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_hook( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_key( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_pull_review_requests( + &self, + owner: &str, + repo: &str, + index: i64, + body: models::PullReviewRequestOptions, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_release( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_release_attachment( + &self, + owner: &str, + repo: &str, + id: i64, + attachment_id: i64, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_release_by_tag( + &self, + owner: &str, + repo: &str, + tag: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_tag( + &self, + owner: &str, + repo: &str, + tag: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_team( + &self, + owner: &str, + repo: &str, + team: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_topic( + &self, + owner: &str, + repo: &str, + topic: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn delete_wiki_page( + &self, + owner: &str, + repo: &str, + page_name: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn dismiss_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + body: models::DismissPullReviewOptions, + ) -> Result> { + todo!("not implemented") + } + async fn download_commit_diff_or_patch( + &self, + owner: &str, + repo: &str, + sha: &str, + diff_type: &str, + ) -> Result> { + todo!("not implemented") + } + async fn download_pull_diff_or_patch( + &self, + owner: &str, + repo: &str, + index: i64, + diff_type: &str, + binary: Option, + ) -> Result> { + todo!("not implemented") + } + async fn edit( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn edit_branch_protection( + &self, + owner: &str, + repo: &str, + name: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn edit_git_hook( + &self, + owner: &str, + repo: &str, + id: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn edit_hook( + &self, + owner: &str, + repo: &str, + id: i64, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn edit_pull_request( + &self, + owner: &str, + repo: &str, + index: i64, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn edit_release( + &self, + owner: &str, + repo: &str, + id: i64, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn edit_release_attachment( + &self, + owner: &str, + repo: &str, + id: i64, + attachment_id: i64, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn edit_wiki_page( + &self, + owner: &str, + repo: &str, + page_name: &str, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn get( + &self, + owner: &str, + repo: &str, + ) -> Result> { + gitea_raw_client::apis::repository_api::repo_get(&self.conf, owner, repo).await + } + async fn get_all_commits( + &self, + owner: &str, + repo: &str, + sha: Option<&str>, + path: Option<&str>, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn get_archive( + &self, + owner: &str, + repo: &str, + archive: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn get_assignees( + &self, + owner: &str, + repo: &str, + ) -> Result, Error> { + todo!("not implemented") + } + async fn get_branch( + &self, + owner: &str, + repo: &str, + branch: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_branch_protection( + &self, + owner: &str, + repo: &str, + name: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_by_id(&self, id: i64) -> Result> { + todo!("not implemented") + } + async fn get_combined_status_by_ref( + &self, + owner: &str, + repo: &str, + r#ref: &str, + page: Option, + limit: Option, + ) -> Result> { + todo!("not implemented") + } + async fn get_contents( + &self, + owner: &str, + repo: &str, + filepath: &str, + r#ref: Option<&str>, + ) -> Result> { + todo!("not implemented") + } + async fn get_contents_list( + &self, + owner: &str, + repo: &str, + r#ref: Option<&str>, + ) -> Result, Error> { + todo!("not implemented") + } + async fn get_editor_config( + &self, + owner: &str, + repo: &str, + filepath: &str, + r#ref: Option<&str>, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn get_git_hook( + &self, + owner: &str, + repo: &str, + id: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_hook( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result> { + todo!("not implemented") + } + async fn get_issue_templates( + &self, + owner: &str, + repo: &str, + ) -> Result, Error> { + todo!("not implemented") + } + async fn get_key( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result> { + todo!("not implemented") + } + async fn get_languages( + &self, + owner: &str, + repo: &str, + ) -> Result<::std::collections::HashMap, Error> { + todo!("not implemented") + } + async fn get_note( + &self, + owner: &str, + repo: &str, + sha: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_pull_request( + &self, + owner: &str, + repo: &str, + index: i64, + ) -> Result> { + todo!("not implemented") + } + async fn get_pull_request_commits( + &self, + owner: &str, + repo: &str, + index: i64, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn get_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + ) -> Result> { + todo!("not implemented") + } + async fn get_pull_review_comments( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + ) -> Result, Error> { + todo!("not implemented") + } + async fn get_raw_file( + &self, + owner: &str, + repo: &str, + filepath: &str, + r#ref: Option<&str>, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn get_raw_file_or_lfs( + &self, + owner: &str, + repo: &str, + filepath: &str, + r#ref: Option<&str>, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn get_release( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result> { + todo!("not implemented") + } + async fn get_release_attachment( + &self, + owner: &str, + repo: &str, + id: i64, + attachment_id: i64, + ) -> Result> { + todo!("not implemented") + } + async fn get_release_by_tag( + &self, + owner: &str, + repo: &str, + tag: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_repo_permissions( + &self, + owner: &str, + repo: &str, + collaborator: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_reviewers( + &self, + owner: &str, + repo: &str, + ) -> Result, Error> { + todo!("not implemented") + } + async fn get_single_commit( + &self, + owner: &str, + repo: &str, + sha: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_tag( + &self, + owner: &str, + repo: &str, + tag: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_wiki_page( + &self, + owner: &str, + repo: &str, + page_name: &str, + ) -> Result> { + todo!("not implemented") + } + async fn get_wiki_page_revisions( + &self, + owner: &str, + repo: &str, + page_name: &str, + page: Option, + ) -> Result> { + todo!("not implemented") + } + async fn get_wiki_pages( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_all_git_refs( + &self, + owner: &str, + repo: &str, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_branch_protection( + &self, + owner: &str, + repo: &str, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_branches( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_collaborators( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_git_hooks( + &self, + owner: &str, + repo: &str, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_git_refs( + &self, + owner: &str, + repo: &str, + r#ref: &str, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_hooks( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_keys( + &self, + owner: &str, + repo: &str, + key_id: Option, + fingerprint: Option<&str>, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_pull_requests( + &self, + owner: &str, + repo: &str, + state: Option<&str>, + sort: Option<&str>, + milestone: Option, + labels: Option>, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_pull_reviews( + &self, + owner: &str, + repo: &str, + index: i64, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_release_attachments( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_releases( + &self, + owner: &str, + repo: &str, + draft: Option, + pre_release: Option, + per_page: Option, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_stargazers( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_statuses( + &self, + owner: &str, + repo: &str, + sha: &str, + sort: Option<&str>, + state: Option<&str>, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_statuses_by_ref( + &self, + owner: &str, + repo: &str, + r#ref: &str, + sort: Option<&str>, + state: Option<&str>, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_subscribers( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_tags( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_teams( + &self, + owner: &str, + repo: &str, + ) -> Result, Error> { + todo!("not implemented") + } + async fn list_topics( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result> { + todo!("not implemented") + } + async fn merge_pull_request( + &self, + owner: &str, + repo: &str, + index: i64, + body: Option, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn migrate( + &self, + body: Option, + ) -> Result> { + todo!("not implemented") + } + async fn mirror_sync(&self, owner: &str, repo: &str) -> Result<(), Error> { + todo!("not implemented") + } + async fn pull_request_is_merged( + &self, + owner: &str, + repo: &str, + index: i64, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn search( + &self, + q: Option<&str>, + topic: Option, + include_desc: Option, + uid: Option, + priority_owner_id: Option, + team_id: Option, + starred_by: Option, + private: Option, + is_private: Option, + template: Option, + archived: Option, + mode: Option<&str>, + exclusive: Option, + sort: Option<&str>, + order: Option<&str>, + page: Option, + limit: Option, + ) -> Result> { + todo!("not implemented") + } + async fn signing_key( + &self, + owner: &str, + repo: &str, + ) -> Result> { + todo!("not implemented") + } + async fn submit_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + body: models::SubmitPullReviewOptions, + ) -> Result> { + todo!("not implemented") + } + async fn test_hook( + &self, + owner: &str, + repo: &str, + id: i64, + r#ref: Option<&str>, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn tracked_times( + &self, + owner: &str, + repo: &str, + user: Option<&str>, + since: Option, + before: Option, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn transfer( + &self, + owner: &str, + repo: &str, + body: models::TransferRepoOption, + ) -> Result> { + todo!("not implemented") + } + async fn un_dismiss_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + ) -> Result> { + todo!("not implemented") + } + async fn update_file( + &self, + owner: &str, + repo: &str, + filepath: &str, + body: models::UpdateFileOptions, + ) -> Result> { + todo!("not implemented") + } + async fn update_pull_request( + &self, + owner: &str, + repo: &str, + index: i64, + style: Option<&str>, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn update_topics( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn topic_search( + &self, + q: &str, + page: Option, + limit: Option, + ) -> Result, Error> { + todo!("not implemented") + } + async fn user_current_check_subscription( + &self, + owner: &str, + repo: &str, + ) -> Result> { + todo!("not implemented") + } + async fn user_current_delete_subscription( + &self, + owner: &str, + repo: &str, + ) -> Result<(), Error> { + todo!("not implemented") + } + async fn user_current_put_subscription( + &self, + owner: &str, + repo: &str, + ) -> Result> { + todo!("not implemented") + } + async fn user_tracked_times( + &self, + owner: &str, + repo: &str, + user: &str, + ) -> Result, Error> { + todo!("not implemented") + } +} diff --git a/crates/gitea_client/src/apis/mod.rs b/crates/gitea_client/src/apis/mod.rs new file mode 100644 index 0000000..4e31914 --- /dev/null +++ b/crates/gitea_client/src/apis/mod.rs @@ -0,0 +1,2 @@ +pub mod defaults; +pub mod repository; diff --git a/crates/gitea_client/src/apis/repository.rs b/crates/gitea_client/src/apis/repository.rs new file mode 100644 index 0000000..34a5c64 --- /dev/null +++ b/crates/gitea_client/src/apis/repository.rs @@ -0,0 +1,841 @@ +use std::sync::Arc; + +use async_trait::async_trait; +use gitea_raw_client::{apis::Error, models}; + +pub use gitea_raw_client::apis::repository_api::*; + +#[async_trait] +pub trait Repository { + async fn accept_transfer( + &self, + owner: &str, + repo: &str, + ) -> Result>; + async fn create_current_user_repo( + &self, + body: Option, + ) -> Result>; + async fn create_fork( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn generate_repo( + &self, + template_owner: &str, + template_repo: &str, + body: Option, + ) -> Result>; + async fn get_annotated_tag( + &self, + owner: &str, + repo: &str, + sha: &str, + ) -> Result>; + async fn get_blob( + &self, + owner: &str, + repo: &str, + sha: &str, + ) -> Result>; + async fn get_tree( + &self, + owner: &str, + repo: &str, + sha: &str, + recursive: Option, + page: Option, + per_page: Option, + ) -> Result>; + async fn list_forks( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn reject_transfer( + &self, + owner: &str, + repo: &str, + ) -> Result>; + async fn add_collaborator( + &self, + owner: &str, + repo: &str, + collaborator: &str, + body: Option, + ) -> Result<(), Error>; + async fn add_team( + &self, + owner: &str, + repo: &str, + team: &str, + ) -> Result<(), Error>; + async fn add_topic( + &self, + owner: &str, + repo: &str, + topic: &str, + ) -> Result<(), Error>; + async fn apply_diff_patch( + &self, + owner: &str, + repo: &str, + body: models::UpdateFileOptions, + ) -> Result>; + async fn cancel_scheduled_auto_merge( + &self, + owner: &str, + repo: &str, + index: i64, + ) -> Result<(), Error>; + async fn check_collaborator( + &self, + owner: &str, + repo: &str, + collaborator: &str, + ) -> Result<(), Error>; + async fn check_team( + &self, + owner: &str, + repo: &str, + team: &str, + ) -> Result>; + async fn create_branch( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn create_branch_protection( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn create_file( + &self, + owner: &str, + repo: &str, + filepath: &str, + body: models::CreateFileOptions, + ) -> Result>; + async fn create_hook( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn create_key( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn create_pull_request( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn create_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + body: models::CreatePullReviewOptions, + ) -> Result>; + async fn create_pull_review_requests( + &self, + owner: &str, + repo: &str, + index: i64, + body: models::PullReviewRequestOptions, + ) -> Result, Error>; + async fn create_release( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn create_release_attachment( + &self, + owner: &str, + repo: &str, + id: i64, + attachment: std::path::PathBuf, + name: Option<&str>, + ) -> Result>; + async fn create_status( + &self, + owner: &str, + repo: &str, + sha: &str, + body: Option, + ) -> Result>; + async fn create_tag( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn create_wiki_page( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn delete(&self, owner: &str, repo: &str) -> Result<(), Error>; + async fn delete_branch( + &self, + owner: &str, + repo: &str, + branch: &str, + ) -> Result<(), Error>; + async fn delete_branch_protection( + &self, + owner: &str, + repo: &str, + name: &str, + ) -> Result<(), Error>; + async fn delete_collaborator( + &self, + owner: &str, + repo: &str, + collaborator: &str, + ) -> Result<(), Error>; + async fn delete_file( + &self, + owner: &str, + repo: &str, + filepath: &str, + body: models::DeleteFileOptions, + ) -> Result>; + async fn delete_git_hook( + &self, + owner: &str, + repo: &str, + id: &str, + ) -> Result<(), Error>; + async fn delete_hook( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result<(), Error>; + async fn delete_key( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result<(), Error>; + async fn delete_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + ) -> Result<(), Error>; + async fn delete_pull_review_requests( + &self, + owner: &str, + repo: &str, + index: i64, + body: models::PullReviewRequestOptions, + ) -> Result<(), Error>; + async fn delete_release( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result<(), Error>; + async fn delete_release_attachment( + &self, + owner: &str, + repo: &str, + id: i64, + attachment_id: i64, + ) -> Result<(), Error>; + async fn delete_release_by_tag( + &self, + owner: &str, + repo: &str, + tag: &str, + ) -> Result<(), Error>; + async fn delete_tag( + &self, + owner: &str, + repo: &str, + tag: &str, + ) -> Result<(), Error>; + async fn delete_team( + &self, + owner: &str, + repo: &str, + team: &str, + ) -> Result<(), Error>; + async fn delete_topic( + &self, + owner: &str, + repo: &str, + topic: &str, + ) -> Result<(), Error>; + async fn delete_wiki_page( + &self, + owner: &str, + repo: &str, + page_name: &str, + ) -> Result<(), Error>; + async fn dismiss_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + body: models::DismissPullReviewOptions, + ) -> Result>; + async fn download_commit_diff_or_patch( + &self, + owner: &str, + repo: &str, + sha: &str, + diff_type: &str, + ) -> Result>; + async fn download_pull_diff_or_patch( + &self, + owner: &str, + repo: &str, + index: i64, + diff_type: &str, + binary: Option, + ) -> Result>; + async fn edit( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result>; + async fn edit_branch_protection( + &self, + owner: &str, + repo: &str, + name: &str, + body: Option, + ) -> Result>; + async fn edit_git_hook( + &self, + owner: &str, + repo: &str, + id: &str, + body: Option, + ) -> Result>; + async fn edit_hook( + &self, + owner: &str, + repo: &str, + id: i64, + body: Option, + ) -> Result>; + async fn edit_pull_request( + &self, + owner: &str, + repo: &str, + index: i64, + body: Option, + ) -> Result>; + async fn edit_release( + &self, + owner: &str, + repo: &str, + id: i64, + body: Option, + ) -> Result>; + async fn edit_release_attachment( + &self, + owner: &str, + repo: &str, + id: i64, + attachment_id: i64, + body: Option, + ) -> Result>; + async fn edit_wiki_page( + &self, + owner: &str, + repo: &str, + page_name: &str, + body: Option, + ) -> Result>; + async fn get(&self, owner: &str, repo: &str) + -> Result>; + async fn get_all_commits( + &self, + owner: &str, + repo: &str, + sha: Option<&str>, + path: Option<&str>, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn get_archive( + &self, + owner: &str, + repo: &str, + archive: &str, + ) -> Result<(), Error>; + async fn get_assignees( + &self, + owner: &str, + repo: &str, + ) -> Result, Error>; + async fn get_branch( + &self, + owner: &str, + repo: &str, + branch: &str, + ) -> Result>; + async fn get_branch_protection( + &self, + owner: &str, + repo: &str, + name: &str, + ) -> Result>; + async fn get_by_id(&self, id: i64) -> Result>; + async fn get_combined_status_by_ref( + &self, + owner: &str, + repo: &str, + r#ref: &str, + page: Option, + limit: Option, + ) -> Result>; + async fn get_contents( + &self, + owner: &str, + repo: &str, + filepath: &str, + r#ref: Option<&str>, + ) -> Result>; + async fn get_contents_list( + &self, + owner: &str, + repo: &str, + r#ref: Option<&str>, + ) -> Result, Error>; + async fn get_editor_config( + &self, + owner: &str, + repo: &str, + filepath: &str, + r#ref: Option<&str>, + ) -> Result<(), Error>; + async fn get_git_hook( + &self, + owner: &str, + repo: &str, + id: &str, + ) -> Result>; + async fn get_hook( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result>; + async fn get_issue_templates( + &self, + owner: &str, + repo: &str, + ) -> Result, Error>; + async fn get_key( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result>; + async fn get_languages( + &self, + owner: &str, + repo: &str, + ) -> Result<::std::collections::HashMap, Error>; + async fn get_note( + &self, + owner: &str, + repo: &str, + sha: &str, + ) -> Result>; + async fn get_pull_request( + &self, + owner: &str, + repo: &str, + index: i64, + ) -> Result>; + async fn get_pull_request_commits( + &self, + owner: &str, + repo: &str, + index: i64, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn get_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + ) -> Result>; + async fn get_pull_review_comments( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + ) -> Result, Error>; + async fn get_raw_file( + &self, + owner: &str, + repo: &str, + filepath: &str, + r#ref: Option<&str>, + ) -> Result<(), Error>; + async fn get_raw_file_or_lfs( + &self, + owner: &str, + repo: &str, + filepath: &str, + r#ref: Option<&str>, + ) -> Result<(), Error>; + async fn get_release( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result>; + async fn get_release_attachment( + &self, + owner: &str, + repo: &str, + id: i64, + attachment_id: i64, + ) -> Result>; + async fn get_release_by_tag( + &self, + owner: &str, + repo: &str, + tag: &str, + ) -> Result>; + async fn get_repo_permissions( + &self, + owner: &str, + repo: &str, + collaborator: &str, + ) -> Result>; + async fn get_reviewers( + &self, + owner: &str, + repo: &str, + ) -> Result, Error>; + async fn get_single_commit( + &self, + owner: &str, + repo: &str, + sha: &str, + ) -> Result>; + async fn get_tag( + &self, + owner: &str, + repo: &str, + tag: &str, + ) -> Result>; + async fn get_wiki_page( + &self, + owner: &str, + repo: &str, + page_name: &str, + ) -> Result>; + async fn get_wiki_page_revisions( + &self, + owner: &str, + repo: &str, + page_name: &str, + page: Option, + ) -> Result>; + async fn get_wiki_pages( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_all_git_refs( + &self, + owner: &str, + repo: &str, + ) -> Result, Error>; + async fn list_branch_protection( + &self, + owner: &str, + repo: &str, + ) -> Result, Error>; + async fn list_branches( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_collaborators( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_git_hooks( + &self, + owner: &str, + repo: &str, + ) -> Result, Error>; + async fn list_git_refs( + &self, + owner: &str, + repo: &str, + r#ref: &str, + ) -> Result, Error>; + async fn list_hooks( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_keys( + &self, + owner: &str, + repo: &str, + key_id: Option, + fingerprint: Option<&str>, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_pull_requests( + &self, + owner: &str, + repo: &str, + state: Option<&str>, + sort: Option<&str>, + milestone: Option, + labels: Option>, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_pull_reviews( + &self, + owner: &str, + repo: &str, + index: i64, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_release_attachments( + &self, + owner: &str, + repo: &str, + id: i64, + ) -> Result, Error>; + async fn list_releases( + &self, + owner: &str, + repo: &str, + draft: Option, + pre_release: Option, + per_page: Option, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_stargazers( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_statuses( + &self, + owner: &str, + repo: &str, + sha: &str, + sort: Option<&str>, + state: Option<&str>, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_statuses_by_ref( + &self, + owner: &str, + repo: &str, + r#ref: &str, + sort: Option<&str>, + state: Option<&str>, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_subscribers( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_tags( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn list_teams( + &self, + owner: &str, + repo: &str, + ) -> Result, Error>; + async fn list_topics( + &self, + owner: &str, + repo: &str, + page: Option, + limit: Option, + ) -> Result>; + async fn merge_pull_request( + &self, + owner: &str, + repo: &str, + index: i64, + body: Option, + ) -> Result<(), Error>; + async fn migrate( + &self, + body: Option, + ) -> Result>; + async fn mirror_sync(&self, owner: &str, repo: &str) -> Result<(), Error>; + async fn pull_request_is_merged( + &self, + owner: &str, + repo: &str, + index: i64, + ) -> Result<(), Error>; + async fn search( + &self, + q: Option<&str>, + topic: Option, + include_desc: Option, + uid: Option, + priority_owner_id: Option, + team_id: Option, + starred_by: Option, + private: Option, + is_private: Option, + template: Option, + archived: Option, + mode: Option<&str>, + exclusive: Option, + sort: Option<&str>, + order: Option<&str>, + page: Option, + limit: Option, + ) -> Result>; + async fn signing_key( + &self, + owner: &str, + repo: &str, + ) -> Result>; + async fn submit_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + body: models::SubmitPullReviewOptions, + ) -> Result>; + async fn test_hook( + &self, + owner: &str, + repo: &str, + id: i64, + r#ref: Option<&str>, + ) -> Result<(), Error>; + async fn tracked_times( + &self, + owner: &str, + repo: &str, + user: Option<&str>, + since: Option, + before: Option, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn transfer( + &self, + owner: &str, + repo: &str, + body: models::TransferRepoOption, + ) -> Result>; + async fn un_dismiss_pull_review( + &self, + owner: &str, + repo: &str, + index: i64, + id: i64, + ) -> Result>; + async fn update_file( + &self, + owner: &str, + repo: &str, + filepath: &str, + body: models::UpdateFileOptions, + ) -> Result>; + async fn update_pull_request( + &self, + owner: &str, + repo: &str, + index: i64, + style: Option<&str>, + ) -> Result<(), Error>; + async fn update_topics( + &self, + owner: &str, + repo: &str, + body: Option, + ) -> Result<(), Error>; + async fn topic_search( + &self, + q: &str, + page: Option, + limit: Option, + ) -> Result, Error>; + async fn user_current_check_subscription( + &self, + owner: &str, + repo: &str, + ) -> Result>; + async fn user_current_delete_subscription( + &self, + owner: &str, + repo: &str, + ) -> Result<(), Error>; + async fn user_current_put_subscription( + &self, + owner: &str, + repo: &str, + ) -> Result>; + async fn user_tracked_times( + &self, + owner: &str, + repo: &str, + user: &str, + ) -> Result, Error>; +} + +pub type DynRepository = Arc; diff --git a/crates/gitea_client/src/builder.rs b/crates/gitea_client/src/builder.rs new file mode 100644 index 0000000..fbb3470 --- /dev/null +++ b/crates/gitea_client/src/builder.rs @@ -0,0 +1,66 @@ +use gitea_raw_client::apis::configuration::{ApiKey, Configuration}; + +use crate::client::GiteaClient; + +pub struct GiteaClientBuilder { + conf: Configuration, +} + +impl GiteaClientBuilder { + pub fn new() -> Self { + Self::default() + } + + pub fn set_basic_auth(mut self, username: String, password: Option) -> Self { + self.conf.basic_auth = Some((username, password)); + self + } + + pub fn set_oauth(mut self, oauth_token: String) -> Self { + self.conf.oauth_access_token = Some(oauth_token); + self + } + + pub fn set_bearer(mut self, bearer_token: String) -> Self { + self.conf.bearer_access_token = Some(bearer_token); + self + } + + pub fn set_api_key(mut self, api_key: String, prefix: Option) -> Self { + self.conf.api_key = Some(ApiKey { + key: api_key, + prefix, + }); + self + } + + pub fn set_base_path(mut self, base_path: &String) -> Self { + self.conf.base_path = base_path.clone(); + self + } + + pub fn set_client(mut self, client: reqwest::Client) -> Self { + self.conf.client = client; + self + } + + pub fn build(self) -> GiteaClient { + GiteaClient::new(self.conf) + } +} + +impl Default for GiteaClientBuilder { + fn default() -> Self { + Self { + conf: Configuration::default(), + } + } +} + +impl From for GiteaClientBuilder { + fn from(conf: Configuration) -> Self { + let mut s = Self::default(); + s.conf = conf; + s + } +} diff --git a/crates/gitea_client/src/client.rs b/crates/gitea_client/src/client.rs new file mode 100644 index 0000000..13c26a5 --- /dev/null +++ b/crates/gitea_client/src/client.rs @@ -0,0 +1,29 @@ +use std::sync::Arc; + +use gitea_raw_client::apis::configuration::Configuration; + +use crate::apis::{defaults::repository::DefaultRepository, repository::DynRepository}; + +pub struct GiteaClient { + repository: DynRepository, +} + +impl GiteaClient { + pub fn new(config: Configuration) -> Self { + let conf = Arc::new(config); + + Self { + repository: Arc::new(DefaultRepository::new(conf.clone())), + } + } + + pub fn repository(&self) -> DynRepository { + self.repository.clone() + } +} + +impl From for GiteaClient { + fn from(conf: Configuration) -> Self { + Self::new(conf) + } +} diff --git a/crates/gitea_client/src/lib.rs b/crates/gitea_client/src/lib.rs new file mode 100644 index 0000000..621c360 --- /dev/null +++ b/crates/gitea_client/src/lib.rs @@ -0,0 +1,8 @@ +pub mod apis; +pub mod builder; +pub mod client; + +pub mod models { + pub use gitea_raw_client::models::*; +} + diff --git a/crates/octopush_cli/Cargo.toml b/crates/octopush_cli/Cargo.toml index 2bbd299..807b1d9 100644 --- a/crates/octopush_cli/Cargo.toml +++ b/crates/octopush_cli/Cargo.toml @@ -13,4 +13,4 @@ eyre = { workspace = true } tracing = { workspace = true } tokio = { workspace = true } -clap = { version = "4.0.18" } +clap = { version = "4.0.18", features = ["env"] } diff --git a/crates/octopush_cli/src/commands/execute.rs b/crates/octopush_cli/src/commands/execute.rs index 99a343d..763f35c 100644 --- a/crates/octopush_cli/src/commands/execute.rs +++ b/crates/octopush_cli/src/commands/execute.rs @@ -1,7 +1,10 @@ use std::{path::PathBuf, sync::Arc}; use clap::{Arg, ArgAction, ArgMatches, Command}; -use octopush_core::schema; +use octopush_core::{ + git::{git::LocalGitProviderOptions, gitea::client::DefaultGiteaClientOptions}, + schema, +}; use octopush_infra::service_register::ServiceRegister; use tokio::sync::Mutex; @@ -17,6 +20,12 @@ pub fn execute_cmd() -> Command { .long_help("action path to your local octopush.yaml file") .required(true), ) + .arg( + Arg::new("gitea-http-token") + .long("gitea-http-token") + .action(ArgAction::Set) + .required(false), + ) } pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { @@ -24,7 +33,17 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { .get_one::("action") .ok_or(eyre::anyhow!("--action is required"))?; - let service_register = ServiceRegister::new(); + let gitea_http_token = args.get_one::("gitea-http-token"); + + let service_register = ServiceRegister::new( + LocalGitProviderOptions { + http_auth: gitea_http_token.map(|t| t.clone()), + }, + DefaultGiteaClientOptions { + url: "https://git.front.kjuulh.io/api/v1".into(), + basicauth: Some("kjuulh:379341972ba6d23ff85367ca1c10c82efea76f0c".into()), + }, + ); let action_path: PathBuf = action.into(); @@ -57,13 +76,15 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { } let mut gitea_paths = Vec::new(); - if let Some(gitea) = &select.gitea { + if let Some(gitea) = select.gitea.clone() { let mut repo_clones = Vec::with_capacity(gitea.repositories.len()); for repo in gitea.repositories { let gp = service_register.gitea_provider.clone(); - repo_clones.push(tokio::spawn( - async move { gp.clone_from_qualified(repo).await }, - )) + repo_clones.push(tokio::spawn(async move { + gp.clone_from_qualified(repo.clone()) + .await + .map(|(p, r)| (p, r, repo)) + })) } for repo_clone in repo_clones { @@ -78,7 +99,7 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { if let Some(push) = git.push { service_register .git_provider - .create_branch(repo.clone(), &push.branch) + .create_branch(repo.clone(), &push.branch.name) .await?; } } @@ -92,7 +113,33 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { if let Some(push) = git.push { service_register .git_provider - .push_branch(repo, &push.branch) + .push_branch(repo, &push.branch.name) + .await?; + } + } + } + + for (path, repo, repo_name) in gitea_paths { + let repo = Arc::new(Mutex::new(repo)); + if let Some(gitea) = select.gitea.clone() { + if let Some(push) = gitea.push { + service_register + .gitea_provider + .create_branch(repo.clone(), &push.pull_request) + .await?; + } + } + + service_register + .executor + .execute(path.clone(), action_path.clone(), action.clone()) + .await?; + + if let Some(gitea) = select.gitea.clone() { + if let Some(push) = gitea.push { + service_register + .gitea_provider + .create_pull_request(repo, &repo_name, &push.pull_request) .await?; } } diff --git a/crates/octopush_core/Cargo.toml b/crates/octopush_core/Cargo.toml index 4a17767..15c0945 100644 --- a/crates/octopush_core/Cargo.toml +++ b/crates/octopush_core/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +gitea_client = { path = "../gitea_client" } + async-trait = { workspace = true } eyre = { workspace = true } tokio = { workspace = true } diff --git a/crates/octopush_core/src/executor/default_executor.rs b/crates/octopush_core/src/executor/default_executor.rs index 324fc25..3092303 100644 --- a/crates/octopush_core/src/executor/default_executor.rs +++ b/crates/octopush_core/src/executor/default_executor.rs @@ -27,9 +27,13 @@ impl Executor for DefaultExecutor { action_path: PathBuf, action: Action, ) -> eyre::Result<()> { + tracing::trace!( + victim_path = victim_path.to_string_lossy().to_string(), + "execute" + ); let bin = self.builder.build(action_path, action.clone()).await?; match action { - Action::Go { entry } => { + Action::Go { .. } => { GolangExecutor::new() .execute(GolangExecutorOpts { bin, victim_path }) .await? diff --git a/crates/octopush_core/src/git/git.rs b/crates/octopush_core/src/git/git.rs index 773d593..f0df79e 100644 --- a/crates/octopush_core/src/git/git.rs +++ b/crates/octopush_core/src/git/git.rs @@ -1,19 +1,29 @@ use std::{path::PathBuf, sync::Arc}; +use eyre::ContextCompat; use git2::{Cred, PushOptions, RemoteCallbacks, Repository}; use tokio::sync::Mutex; -use crate::{schema::models::GitPushBranch, storage::DynStorageEngine}; +use crate::storage::DynStorageEngine; use super::GitProvider; +#[derive(Clone, Debug)] +pub struct LocalGitProviderOptions { + pub http_auth: Option, +} + pub struct LocalGitProvider { storage_engine: DynStorageEngine, + options: LocalGitProviderOptions, } impl LocalGitProvider { - pub fn new(storage_engine: DynStorageEngine) -> Self { - Self { storage_engine } + pub fn new(options: LocalGitProviderOptions, storage_engine: DynStorageEngine) -> Self { + Self { + storage_engine, + options, + } } } @@ -22,20 +32,37 @@ impl GitProvider for LocalGitProvider { async fn clone_from_url(&self, url: String) -> eyre::Result<(PathBuf, Repository)> { tracing::debug!(url, "allocating dir"); let dir = self.storage_engine.allocate_dir().await?; + let options = self.options.clone(); let dirpath = dir.clone().path(); let repo = tokio::task::spawn_blocking(move || { let mut callbacks = RemoteCallbacks::new(); callbacks.credentials(|url, username_from_url, _allowed_types| { tracing::debug!(username_from_url, url, "pulling key from ssh-agent"); - Cred::ssh_key_from_agent(username_from_url.unwrap()) + + if let Some(auth) = &options.http_auth { + tracing::trace!(auth, "authenticating"); + let (user, pass) = auth + .split_once(":") + .ok_or("http_auth is not formatted correctly") + .unwrap(); + + Cred::userpass_plaintext(user, pass) + } else { + let username = username_from_url + .context("could not find username_from_url") + .unwrap(); + Cred::ssh_key_from_agent(username) + } }); let mut fo = git2::FetchOptions::new(); fo.remote_callbacks(callbacks); + let checkout_builder = git2::build::CheckoutBuilder::new(); + let mut builder = git2::build::RepoBuilder::new(); - builder.fetch_options(fo); + builder.fetch_options(fo).with_checkout(checkout_builder); tracing::debug!( url, @@ -54,7 +81,7 @@ impl GitProvider for LocalGitProvider { async fn create_branch( &self, repo: Arc>, - branch: &GitPushBranch, + branch_name: &String, ) -> eyre::Result<()> { let repo = repo.lock().await; @@ -64,7 +91,7 @@ impl GitProvider for LocalGitProvider { .ok_or(eyre::anyhow!("could not get access to target commit"))?; let head_commit = repo.find_commit(head_commit_oid)?; let newbranch = repo.branch( - &branch.name.to_lowercase().replace(" ", "-"), + &branch_name.to_lowercase().replace(" ", "-"), &head_commit, true, )?; @@ -82,13 +109,23 @@ impl GitProvider for LocalGitProvider { async fn push_branch( &self, repo: Arc>, - branch: &GitPushBranch, + branch_name: &String, ) -> eyre::Result<()> { let repo = repo.lock().await; + let options = self.options.clone(); tracing::trace!("pulling signature from local git"); let signature = repo.signature()?; + for rev in repo.revwalk()? { + let rev = rev?; + let commit = repo.find_commit(rev)?; + let summary = commit + .summary() + .ok_or(eyre::anyhow!("could not find commit"))?; + tracing::info!(summary, "summary") + } + tracing::trace!("fetching index and adding changed files to working tree"); let mut index = repo.index()?; index.add_all(&["."], git2::IndexAddOption::DEFAULT, None)?; @@ -104,10 +141,10 @@ impl GitProvider for LocalGitProvider { tracing::trace!("writing commit object"); repo.commit( - None, + Some("HEAD"), &signature, &signature, - branch.name.to_lowercase().replace(" ", "-").as_str(), + branch_name.to_lowercase().replace(" ", "-").as_str(), &tree, &[&parents], )?; @@ -121,7 +158,19 @@ impl GitProvider for LocalGitProvider { let mut remote_callbacks = RemoteCallbacks::new(); remote_callbacks.credentials(|url, username_from_url, _allowed_types| { tracing::debug!(username_from_url, url, "pulling key from ssh-agent"); - Cred::ssh_key_from_agent(username_from_url.unwrap()) + + if let Some(auth) = &options.http_auth { + tracing::trace!(auth, "authenticating"); + let (user, pass) = auth + .split_once(":") + .ok_or("http_auth is not formatted correctly") + .unwrap(); + + Cred::userpass_plaintext(user, pass) + } else { + let username = username_from_url.unwrap(); + Cred::ssh_key_from_agent(username) + } }); let mut push_options = PushOptions::new(); diff --git a/crates/octopush_core/src/git/gitea/client.rs b/crates/octopush_core/src/git/gitea/client.rs index 9ba09e9..9133614 100644 --- a/crates/octopush_core/src/git/gitea/client.rs +++ b/crates/octopush_core/src/git/gitea/client.rs @@ -1,7 +1,76 @@ -pub struct DefaultGiteaClient {} +use std::sync::Arc; + +use async_trait::async_trait; +use gitea_client::{builder::GiteaClientBuilder, models::CreatePullRequestOption}; + +use super::GiteaClient; + +pub struct DefaultGiteaClientOptions { + pub url: String, + pub basicauth: Option, +} + +pub struct DefaultGiteaClient { + gitea_client: Arc, +} impl DefaultGiteaClient { - pub fn new() -> Self { - Self {} + pub fn new(options: &DefaultGiteaClientOptions) -> Self { + let mut gitea = GiteaClientBuilder::new().set_base_path(&options.url); + + if let Some(basicauth) = options.basicauth.clone() { + if let Some((username, password)) = basicauth.split_once(":") { + gitea = gitea.set_basic_auth(username.into(), Some(password.into())); + } + } + + Self { + gitea_client: Arc::new(gitea.build()), + } + } +} + +#[async_trait] +impl GiteaClient for DefaultGiteaClient { + async fn get_clone_url(&self, owner: String, repo_name: String) -> eyre::Result { + let repo = self + .gitea_client + .repository() + .get(&owner, &repo_name) + .await?; + + let clone_url = repo + .ssh_url + .ok_or(eyre::anyhow!("clone_url is not set for repository"))?; + + Ok(clone_url) + } + + async fn create_pull_request( + &self, + owner: &String, + repo_name: &String, + pull_request_name: &String, + ) -> eyre::Result<()> { + self.gitea_client + .repository() + .create_pull_request( + &owner, + &repo_name, + Some(CreatePullRequestOption { + assignee: None, + assignees: None, + base: Some("main".into()), + body: None, + due_date: None, + head: Some(pull_request_name.to_lowercase().replace(" ", "-")), + labels: None, + milestone: None, + title: Some(pull_request_name.clone()), + }), + ) + .await?; + + Ok(()) } } diff --git a/crates/octopush_core/src/git/gitea/mod.rs b/crates/octopush_core/src/git/gitea/mod.rs index c745ac5..1f3e469 100644 --- a/crates/octopush_core/src/git/gitea/mod.rs +++ b/crates/octopush_core/src/git/gitea/mod.rs @@ -1,17 +1,42 @@ pub mod client; pub mod provider; -use std::sync::Arc; +use std::{path::PathBuf, sync::Arc}; use async_trait::async_trait; +use git2::Repository; +use tokio::sync::Mutex; -pub trait GiteaClient {} +use crate::schema::models::GitPushPullRequest; + +#[async_trait] +pub trait GiteaClient { + async fn get_clone_url(&self, owner: String, repo_name: String) -> eyre::Result; + async fn create_pull_request( + &self, + owner: &String, + repo_name: &String, + pull_request_name: &String, + ) -> eyre::Result<()>; +} pub type DynGiteaClient = Arc; #[async_trait] pub trait GiteaProvider { - async fn clone_from_qualified(repo: String) -> eyre::Result; + async fn clone_from_qualified(&self, repo: String) -> eyre::Result<(PathBuf, Repository)>; + async fn create_branch( + &self, + repo: Arc>, + branch: &GitPushPullRequest, + ) -> eyre::Result<()>; + + async fn create_pull_request( + &self, + repo: Arc>, + repo_name: &String, + pull_request: &GitPushPullRequest, + ) -> eyre::Result<()>; } pub type DynGiteaProvider = Arc; diff --git a/crates/octopush_core/src/git/gitea/provider.rs b/crates/octopush_core/src/git/gitea/provider.rs index eda97dc..381484d 100644 --- a/crates/octopush_core/src/git/gitea/provider.rs +++ b/crates/octopush_core/src/git/gitea/provider.rs @@ -1,12 +1,16 @@ -use async_trait::async_trait; +use std::{path::PathBuf, sync::Arc}; -use crate::{git::DynGitProvider, storage::DynStorageEngine}; +use async_trait::async_trait; +use git2::Repository; +use tokio::sync::Mutex; + +use crate::{git::DynGitProvider, schema::models::GitPushPullRequest, storage::DynStorageEngine}; use super::{DynGiteaClient, GiteaProvider}; pub struct DefaultGiteaProvider { git_provider: DynGitProvider, - storage_engine: DynStorageEngine, + _storage_engine: DynStorageEngine, gitea_client: DynGiteaClient, } @@ -18,7 +22,7 @@ impl DefaultGiteaProvider { ) -> Self { Self { git_provider, - storage_engine, + _storage_engine: storage_engine, gitea_client, } } @@ -26,7 +30,50 @@ impl DefaultGiteaProvider { #[async_trait] impl GiteaProvider for DefaultGiteaProvider { - async fn clone_from_qualified(repo: String) -> eyre::Result { - todo!() + async fn clone_from_qualified(&self, repo: String) -> eyre::Result<(PathBuf, Repository)> { + let (owner, repo_name) = repo + .split_once("/") + .ok_or(eyre::anyhow!("repo is not a valid format"))?; + + let clone_url = self + .gitea_client + .get_clone_url(owner.into(), repo_name.into()) + .await?; + + let (path, repo) = self.git_provider.clone_from_url(clone_url).await?; + + Ok((path, repo)) + } + + async fn create_branch( + &self, + repo: Arc>, + pull_request: &GitPushPullRequest, + ) -> eyre::Result<()> { + tracing::trace!("creating branch"); + self.git_provider + .create_branch(repo, &pull_request.name) + .await + } + + async fn create_pull_request( + &self, + repo: Arc>, + repo_name: &String, + pull_request: &GitPushPullRequest, + ) -> eyre::Result<()> { + let (owner, repo_name) = repo_name + .split_once("/") + .ok_or(eyre::anyhow!("repo is not a valid format"))?; + + tracing::trace!("push_branch"); + self.git_provider + .push_branch(repo, &pull_request.name) + .await?; + + tracing::trace!("create_pull_request"); + self.gitea_client + .create_pull_request(&owner.into(), &repo_name.into(), &pull_request.name) + .await } } diff --git a/crates/octopush_core/src/git/mod.rs b/crates/octopush_core/src/git/mod.rs index 91d3132..9eb51b7 100644 --- a/crates/octopush_core/src/git/mod.rs +++ b/crates/octopush_core/src/git/mod.rs @@ -15,12 +15,12 @@ pub trait GitProvider { async fn create_branch( &self, repo: Arc>, - branch: &GitPushBranch, + branch_name: &String, ) -> eyre::Result<()>; async fn push_branch( &self, repo: Arc>, - branch: &GitPushBranch, + branch_name: &String, ) -> eyre::Result<()>; } diff --git a/crates/octopush_core/src/schema/models.rs b/crates/octopush_core/src/schema/models.rs index 85eb35d..2640a60 100644 --- a/crates/octopush_core/src/schema/models.rs +++ b/crates/octopush_core/src/schema/models.rs @@ -25,12 +25,14 @@ pub struct Git { #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub struct GitHubPush { - pub branch: GitPushPullRequest, + #[serde(rename = "pull-request")] + pub pull_request: GitPushPullRequest, } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub struct GiteaPush { - pub branch: GitPushPullRequest, + #[serde(rename = "pull-request")] + pub pull_request: GitPushPullRequest, } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] diff --git a/crates/octopush_core/src/shell/mod.rs b/crates/octopush_core/src/shell/mod.rs index 77fd0f0..ea5d588 100644 --- a/crates/octopush_core/src/shell/mod.rs +++ b/crates/octopush_core/src/shell/mod.rs @@ -43,7 +43,7 @@ pub async fn execute_shell(cmd: String, path: Option) -> eyre::Result<( }); while let Some(line) = reader.next_line().await? { - tracing::trace!("something: {}", line) + tracing::trace!("{}", line) } Ok(()) diff --git a/crates/octopush_infra/Cargo.toml b/crates/octopush_infra/Cargo.toml index 0f8cd42..471daf0 100644 --- a/crates/octopush_infra/Cargo.toml +++ b/crates/octopush_infra/Cargo.toml @@ -9,3 +9,4 @@ edition = "2021" octopush_core = { path = "../octopush_core" } eyre = { workspace = true } +tracing = { workspace = true } diff --git a/crates/octopush_infra/src/service_register.rs b/crates/octopush_infra/src/service_register.rs index 334a8be..acbd0d1 100644 --- a/crates/octopush_infra/src/service_register.rs +++ b/crates/octopush_infra/src/service_register.rs @@ -4,8 +4,12 @@ use octopush_core::{ builder::{builder_capabilities::BuilderCapabilities, DynBuilder}, executor::{default_executor::DefaultExecutor, executor::DynExecutor}, git::{ - git::LocalGitProvider, - gitea::{provider::DefaultGiteaProvider, DynGiteaProvider}, + git::{LocalGitProvider, LocalGitProviderOptions}, + gitea::{ + client::{DefaultGiteaClient, DefaultGiteaClientOptions}, + provider::DefaultGiteaProvider, + DynGiteaProvider, + }, DynGitProvider, }, schema::parser::{DefaultSchemaParser, DynSchemaParser}, @@ -22,13 +26,24 @@ pub struct ServiceRegister { } impl ServiceRegister { - pub fn new() -> Self { + pub fn new( + git_provider_options: LocalGitProviderOptions, + gitea_client_options: DefaultGiteaClientOptions, + ) -> Self { let storage_engine = Arc::new(LocalStorageEngine::new("/tmp/octopush".into())); - let git_provider = Arc::new(LocalGitProvider::new(storage_engine.clone())); + let git_provider = Arc::new(LocalGitProvider::new( + git_provider_options, + storage_engine.clone(), + )); let schema_parser = Arc::new(DefaultSchemaParser::new()); let builder = Arc::new(BuilderCapabilities::new()); let executor = Arc::new(DefaultExecutor::new(builder.clone())); - let gitea_provider = Arc::new(DefaultGiteaProvider::new(git_provider.clone())); + let gitea_client = Arc::new(DefaultGiteaClient::new(&gitea_client_options)); + let gitea_provider = Arc::new(DefaultGiteaProvider::new( + git_provider.clone(), + storage_engine.clone(), + gitea_client.clone(), + )); Self { storage_engine,