diff --git a/Cargo.lock b/Cargo.lock index 007c562..62f1cba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -370,7 +370,7 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "git-mover" -version = "1.0.1" +version = "1.0.2" dependencies = [ "clap", "dotenv", diff --git a/Cargo.toml b/Cargo.toml index b4fdb39..513eb33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "git-mover" -version = "1.0.1" +version = "1.0.2" edition = "2021" keywords = ["utility", "git", "cli"] categories = ["command-line-utilities"] diff --git a/src/cli.rs b/src/cli.rs index da37e66..26d9c15 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,8 +1,10 @@ +//! Command line options for the git-mover tool use crate::{config::Config, platform::PlatformType, utils::main_sync}; use clap::Parser; use serde::Deserialize; use std::path::PathBuf; +/// Command line options for the git-mover tool #[derive(Parser, Deserialize, Default, Clone, Debug)] pub struct GitMoverCli { /// The source platform (github, gitlab, codeberg) @@ -26,6 +28,7 @@ pub struct GitMoverCli { pub verbose: u8, } +/// Run the git-mover tool with the provided command line options pub async fn cli_main() { let args = GitMoverCli::parse(); let mut config = match &args.config { diff --git a/src/codeberg/config.rs b/src/codeberg/config.rs index 50cd773..011d8ec 100644 --- a/src/codeberg/config.rs +++ b/src/codeberg/config.rs @@ -1,3 +1,4 @@ +//! Codeberg configuration use super::platform::CodebergPlatform; use crate::{config::Config, config_value_wrap}; use serde::{Deserialize, Serialize}; @@ -5,12 +6,15 @@ use serde::{Deserialize, Serialize}; /// Codeberg configuration #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct CodebergConfig { + /// Codeberg username pub username: Option, + /// Codeberg token pub token: Option, } impl CodebergConfig { + /// Get the codeberg platform pub fn get_plateform(config: &mut Config) -> CodebergPlatform { let username = config_value_wrap!( config, diff --git a/src/codeberg/mod.rs b/src/codeberg/mod.rs index 4d37666..b14218a 100644 --- a/src/codeberg/mod.rs +++ b/src/codeberg/mod.rs @@ -1,6 +1,7 @@ - +//! Codeberg API module. pub(crate) mod config; pub(crate) mod platform; pub(crate) mod repo; +/// Codeberg URL const CODEBERG_URL: &str = "codeberg.org"; diff --git a/src/codeberg/platform.rs b/src/codeberg/platform.rs index 2bbbe66..09b1666 100644 --- a/src/codeberg/platform.rs +++ b/src/codeberg/platform.rs @@ -1,23 +1,26 @@ -use std::pin::Pin; - +//! Codeberg platform implementation use reqwest::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE}; use serde::{Deserialize, Serialize}; +use std::pin::Pin; +use super::{repo::CodebergRepo, CODEBERG_URL}; use crate::{ errors::{GitMoverError, GitMoverErrorKind}, platform::Platform, utils::Repo, }; -use super::{repo::CodebergRepo, CODEBERG_URL}; - +/// Codeberg platform #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct CodebergPlatform { + /// Codeberg username pub username: String, + /// Codeberg token pub token: String, } impl CodebergPlatform { + /// Create a new codeberg platform pub fn new(username: String, token: String) -> Self { Self { username, token } } diff --git a/src/codeberg/repo.rs b/src/codeberg/repo.rs index bd386d7..1f1e3a5 100644 --- a/src/codeberg/repo.rs +++ b/src/codeberg/repo.rs @@ -1,12 +1,20 @@ -use serde::{Deserialize, Serialize}; - +//! Codeberg repository use crate::utils::Repo; +use serde::{Deserialize, Serialize}; +/// Codeberg repository #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct CodebergRepo { + /// Name of the repository pub name: String, + + /// Description of the repository pub description: String, + + /// Whether the repository is private pub private: bool, + + /// Whether the repository is a fork #[serde(skip_serializing)] pub fork: bool, } diff --git a/src/config.rs b/src/config.rs index 0ecc6c2..5ceb67e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,4 @@ +//! Configuration handling use std::{ fs::{create_dir_all, read_to_string, File}, io::Write, @@ -12,6 +13,7 @@ use crate::{ gitlab::config::GitlabConfig, }; +/// Configuration data #[derive(Deserialize, Default, Clone, Debug)] pub struct Config { /// debug level @@ -23,15 +25,19 @@ pub struct Config { /// actual configuration data pub config_data: ConfigData, + /// CLI arguments pub cli_args: Option, } #[derive(Deserialize, Serialize, Default, Clone, Debug)] pub struct ConfigData { + /// Gitlab configuration pub gitlab: Option, + /// Github configuration pub github: Option, + /// Codeberg configuration pub codeberg: Option, } @@ -53,12 +59,15 @@ impl Config { } } + /// Set the config arguments pub fn with_cli_args(mut self, cli_args: GitMoverCli) -> Self { self.cli_args = Some(cli_args); self } /// Create a new Config object from the default path + /// # Panics + /// Panics if the config file can't be opened pub fn new() -> Config { let config_path = Config::get_config_path(); let contents = read_to_string(config_path.clone()) @@ -67,6 +76,8 @@ impl Config { } /// Save the config data to the config file + /// # Panics + /// Panics if the config file can't be created or written to pub fn save(&self) { let config_str = toml::to_string(&self.config_data).expect("Unable to serialize config"); let mut file = File::create(&self.config_path).expect("Unable to create config file"); @@ -75,6 +86,8 @@ impl Config { } /// Create a new Config object from a custom path + /// # Panics + /// Panics if the config file can't be opened pub fn new_from_path(custom_path: &PathBuf) -> Config { let contents = read_to_string(custom_path.clone()) .unwrap_or_else(|_| panic!("Unable to open {:?}", custom_path)); @@ -88,6 +101,8 @@ impl Config { } /// Get the path to the config file + /// # Panics + /// Panics if the home directory can't be found pub fn get_config_path() -> PathBuf { let home_dir = match home_dir() { Some(path) if !path.as_os_str().is_empty() => Ok(path), diff --git a/src/errors.rs b/src/errors.rs index ba03dab..6cd94de 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,17 +1,22 @@ +//! Error handling for the git-mover crate. use std::{error::Error as StdError, fmt}; +/// Error type for the git-mover crate. #[derive(Debug)] pub struct GitMoverError { + /// Inner error. inner: Box, } impl GitMoverError { + /// Create a new error. pub(crate) fn new(kind: GitMoverErrorKind) -> Self { Self { inner: Box::new(Inner { kind, source: None }), } } + /// Create a new error with a source. pub(crate) fn with_text(mut self, text: &str) -> Self { self.inner.source = Some(Box::new(std::io::Error::new( std::io::ErrorKind::Other, @@ -21,24 +26,45 @@ impl GitMoverError { } } +/// Type alias for a boxed error. pub(crate) type BoxError = Box; +/// Inner error type for the git-mover crate. #[derive(Debug)] struct Inner { + /// Error kind. kind: GitMoverErrorKind, + /// Source error. source: Option, } #[derive(Debug)] pub(crate) enum GitMoverErrorKind { + /// Error related to the platform. Platform, + + /// Error related to the reqwest crate. Reqwest, + + /// Error related to serde. Serde, + + /// Error related to the configuration. Unimplemented, + + /// Error related to the RepoEdition func. RepoEdition, + + /// Error related to the GetAllRepo func. GetAllRepos, + + /// Error related to the GetRepo func. GetRepo, + + /// Error related to the RepoCreation func. RepoNotFound, + + /// Error related to the RepoDeletion func. RepoDeletion, } diff --git a/src/github/config.rs b/src/github/config.rs index e2feea6..71e626e 100644 --- a/src/github/config.rs +++ b/src/github/config.rs @@ -1,3 +1,4 @@ +//! Github configuration use super::platform::GithubPlatform; use serde::{Deserialize, Serialize}; @@ -6,12 +7,15 @@ use crate::{config::Config, config_value_wrap}; /// Github configuration #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct GithubConfig { + /// Github username pub username: Option, + /// Github token pub token: Option, } impl GithubConfig { + /// Get the github platform pub fn get_plateform(config: &mut Config) -> GithubPlatform { let username = config_value_wrap!( config, diff --git a/src/github/mod.rs b/src/github/mod.rs index af39ce9..c56eaab 100644 --- a/src/github/mod.rs +++ b/src/github/mod.rs @@ -1,5 +1,7 @@ +//! GitHub API module. pub(crate) mod config; pub(crate) mod platform; pub(crate) mod repo; +/// GitHub URL const GITHUB_URL: &str = "github.com"; diff --git a/src/github/platform.rs b/src/github/platform.rs index 77486bc..7022b9d 100644 --- a/src/github/platform.rs +++ b/src/github/platform.rs @@ -1,3 +1,4 @@ +//! Github Platform use super::GITHUB_URL; use crate::{ errors::{GitMoverError, GitMoverErrorKind}, @@ -12,13 +13,18 @@ use reqwest::{ use serde::{Deserialize, Serialize}; use std::pin::Pin; +/// Github Platform #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct GithubPlatform { + /// Github username pub username: String, + + /// Github token pub token: String, } impl GithubPlatform { + /// Create a new GithubPlatform pub fn new(username: String, token: String) -> Self { Self { username, token } } diff --git a/src/github/repo.rs b/src/github/repo.rs index 601233f..838586a 100644 --- a/src/github/repo.rs +++ b/src/github/repo.rs @@ -1,14 +1,26 @@ -use serde::{Deserialize, Serialize}; - +//! Github Repo struct and conversion to Repo struct use crate::utils::Repo; +use serde::{Deserialize, Serialize}; +/// Github Repo #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct RepoGithub { + /// Repository ID pub id: u64, + + /// Repository name pub name: String, + + /// Repository description pub description: Option, + + /// Repository private status pub private: bool, + + /// Repository URL pub html_url: String, + + /// Repository fork status pub fork: bool, } diff --git a/src/gitlab/config.rs b/src/gitlab/config.rs index d1ae241..86b1d8b 100644 --- a/src/gitlab/config.rs +++ b/src/gitlab/config.rs @@ -1,3 +1,4 @@ +//! Gitlab configuration use super::platform::GitlabPlatform; use crate::config::Config; use crate::config_value_wrap; @@ -6,12 +7,15 @@ use serde::{Deserialize, Serialize}; /// Gitlab configuration #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct GitlabConfig { + /// Gitlab username pub username: Option, + /// Gitlab token pub token: Option, } impl GitlabConfig { + /// Get Gitlab platform pub fn get_plateform(config: &mut Config) -> GitlabPlatform { let username = config_value_wrap!( config, diff --git a/src/gitlab/mod.rs b/src/gitlab/mod.rs index edad2d3..c0a55e9 100644 --- a/src/gitlab/mod.rs +++ b/src/gitlab/mod.rs @@ -1,5 +1,7 @@ +//! Gitlab API module pub(crate) mod config; pub(crate) mod platform; pub(crate) mod repo; +/// Gitlab URL const GITLAB_URL: &str = "gitlab.com"; diff --git a/src/gitlab/platform.rs b/src/gitlab/platform.rs index 2017c5c..a8368d2 100644 --- a/src/gitlab/platform.rs +++ b/src/gitlab/platform.rs @@ -1,3 +1,4 @@ +//! Gitlab platform implementation use crate::errors::GitMoverError; use crate::errors::GitMoverErrorKind; use crate::platform::Platform; @@ -11,18 +12,24 @@ use super::repo::GitlabRepo; use super::repo::GitlabRepoEdition; use super::GITLAB_URL; +/// Gitlab platform #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct GitlabPlatform { + /// Gitlab username username: String, + + /// Gitlab token token: String, } impl GitlabPlatform { + /// Create a new Gitlab platform pub fn new(username: String, token: String) -> Self { Self { username, token } } } +/// Encoded slash const SLASH: &str = "%2F"; impl Platform for GitlabPlatform { diff --git a/src/gitlab/repo.rs b/src/gitlab/repo.rs index b162e8a..08e6ac3 100644 --- a/src/gitlab/repo.rs +++ b/src/gitlab/repo.rs @@ -1,23 +1,36 @@ +//! Gitlab Repo module use crate::utils::Repo; use serde::{Deserialize, Serialize}; +/// Gitlab Repo #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct GitlabRepo { + /// Repo name pub name: String, + + /// Repo description pub description: Option, + + /// Repo visibility pub visibility: String, + + /// Forked from project #[serde(skip_serializing)] pub forked_from_project: Option, } #[derive(Deserialize, Serialize, Default, Debug, Clone)] pub struct ForkRepo { + /// Forked from project id pub id: u64, } #[derive(Deserialize, Serialize, Debug, Clone)] pub struct GitlabRepoEdition { + /// Repo name pub description: String, + + /// Repo visibility pub visibility: String, } diff --git a/src/lib.rs b/src/lib.rs index 9ec546f..fd3e25c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,16 @@ //! -h, --help Print help //! ``` +#![deny( + missing_docs, + clippy::all, + clippy::missing_docs_in_private_items, + clippy::missing_errors_doc, + clippy::missing_panics_doc, + clippy::cargo +)] +#![warn(clippy::multiple_crate_versions)] + pub(crate) mod cli; pub(crate) mod config; pub(crate) mod errors; diff --git a/src/macros.rs b/src/macros.rs index 71a3ad4..24f4949 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,3 +1,5 @@ +//! This module contains the macros used in the project. + /// automatically generate the input path macro_rules! config_value { ($config:ident, $setting_name:ident, $struct_name:ident, $key_name:ident, $string:expr) => { @@ -27,6 +29,7 @@ macro_rules! config_value { }; } +/// automatically generate the input path by wrapping config_value macro macro_rules! config_value_wrap { ($config:ident, $setting_name:ident, $struct_name:ident, $key_name:ident, $string:expr) => { match &$config.config_data.$setting_name { diff --git a/src/platform.rs b/src/platform.rs index d5cf9db..ccdea0b 100644 --- a/src/platform.rs +++ b/src/platform.rs @@ -1,46 +1,57 @@ -use std::pin::Pin; - -use serde::Deserialize; +//! This module contains the Platform trait and PlatformType enum. use crate::{errors::GitMoverError, utils::Repo}; +use serde::Deserialize; +use std::pin::Pin; - - - - +/// The Platform trait is used to interact with different git platforms. pub trait Platform: Sync + Send { + /// Create a new repository on the platform. fn create_repo( &self, repo: Repo, ) -> Pin> + Send + '_>>; + /// Get a repository from the platform. fn get_repo( &self, name: &str, ) -> Pin> + Send + '_>>; + /// Edit a repository on the platform. fn edit_repo( &self, repo: Repo, ) -> Pin> + Send + '_>>; + /// Get all repositories from the platform. fn get_all_repos( &self, ) -> Pin, GitMoverError>> + Send>>; + /// Delete a repository from the platform. fn delete_repo( &self, name: &str, ) -> Pin> + Send + '_>>; + /// Get the username of the platform. fn get_username(&self) -> &str; + + /// Get the platform type. fn get_remote_url(&self) -> &str; } +/// The PlatformType enum is used to specify the platform type. #[derive(Debug, Clone, PartialEq, Deserialize)] pub enum PlatformType { + /// Gitlab platform Gitlab, + + /// Github platform Github, + + /// Codeberg platform Codeberg, } diff --git a/src/sync.rs b/src/sync.rs index d1470d1..3abfae3 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,3 +1,4 @@ +//! Sync repositories from one platform to another use git2::Cred; use rand::thread_rng; use rand::{distributions::Alphanumeric, Rng}; @@ -8,6 +9,7 @@ use crate::errors::GitMoverError; use crate::platform::Platform; use crate::utils::{yes_no_input, Repo}; +/// Sync repositories from one platform to another pub(crate) async fn sync_repos( source_platform: Arc>, destination_platform: Arc>, @@ -65,6 +67,7 @@ pub(crate) async fn sync_repos( Ok(()) } +/// Sync private repositories from one platform to another async fn sync_private_repos( source_platform: Arc>, destination_platform: Arc>, @@ -87,6 +90,7 @@ async fn sync_private_repos( Ok(()) } +/// Sync one repository from one platform to another async fn sync_one_repo( source_platform: Arc>, destination_platform: Arc>, @@ -174,6 +178,7 @@ async fn sync_one_repo( Ok(log_text) } +/// Delete repositories from a platform pub(crate) async fn delete_repos( destination_platform: Arc>, repos: Vec, diff --git a/src/utils.rs b/src/utils.rs index e19525c..44e0246 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,4 @@ +//! Utility functions use std::collections::HashSet; use std::{fmt::Debug, sync::Arc}; @@ -12,19 +13,30 @@ use crate::{ gitlab::config::GitlabConfig, }; +/// Repository information #[derive(Deserialize, Debug, Default, PartialEq, Eq, Hash, Clone)] pub struct Repo { + /// Name of the repository pub name: String, + + /// Description of the repository pub description: String, + + /// Whether the repository is private pub private: bool, + + /// Whether the repository is a fork pub fork: bool, } pub enum Direction { + /// Source platform Source, + /// Destination platform Destination, } +/// Get a number from the user pub fn input_number() -> usize { loop { match input().parse::() { @@ -36,6 +48,7 @@ pub fn input_number() -> usize { } } +/// Get the platform to use pub(crate) fn get_plateform( config: &mut Config, direction: Direction, @@ -86,6 +99,7 @@ pub(crate) fn get_plateform( (Arc::new(correct), chosen_platform) } +/// Main function to sync repositories pub async fn main_sync(config: &mut Config) { let (source_plateform, type_source) = get_plateform(config, Direction::Source); println!("Chosen {} as source", source_plateform.get_remote_url()); @@ -234,6 +248,7 @@ pub(crate) fn input() -> String { s } +/// Get a yes/no input from the user pub(crate) fn yes_no_input(msg: &str) -> bool { loop { println!("{}", msg);