diff --git a/Cargo.toml b/Cargo.toml index 0df9c11..171fefd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.2.0" edition = "2021" description = "Standalone CLI for configuring git repos — hooks, .gitignore, and .gitattributes" license = "MIT" -repository = "https://github.com/JheisonMB/gitkit" +repository = "https://github.com/UniverLab/gitkit" keywords = ["git", "hooks", "cli", "gitignore", "gitattributes"] categories = ["command-line-utilities", "development-tools"] diff --git a/README.md b/README.md index 3e52a04..6970793 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ ░░░░░░ ``` -[![CI](https://github.com/JheisonMB/gitkit/actions/workflows/ci.yml/badge.svg)](https://github.com/JheisonMB/gitkit/actions/workflows/ci.yml) -[![Release](https://github.com/JheisonMB/gitkit/actions/workflows/release.yml/badge.svg)](https://github.com/JheisonMB/gitkit/actions/workflows/release.yml) +[![CI](https://github.com/UniverLab/gitkit/actions/workflows/ci.yml/badge.svg)](https://github.com/UniverLab/gitkit/actions/workflows/ci.yml) +[![Release](https://github.com/UniverLab/gitkit/actions/workflows/release.yml/badge.svg)](https://github.com/UniverLab/gitkit/actions/workflows/release.yml) [![Crates.io](https://img.shields.io/crates/v/gitkit)](https://crates.io/crates/gitkit) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) @@ -28,13 +28,13 @@ Configure a git repo in seconds — hooks, `.gitignore`, `.gitattributes`, and g **Linux / macOS:** ```bash -curl -fsSL https://raw.githubusercontent.com/JheisonMB/gitkit/main/install.sh | sh +curl -fsSL https://raw.githubusercontent.com/UniverLab/gitkit/main/scripts/install.sh | sh ``` **Windows (PowerShell):** ```powershell -irm https://raw.githubusercontent.com/JheisonMB/gitkit/main/install.ps1 | iex +irm https://raw.githubusercontent.com/UniverLab/gitkit/main/scripts/install.ps1 | iex ``` ### Via cargo @@ -47,7 +47,7 @@ Available on [crates.io](https://crates.io/crates/gitkit). ### GitHub Releases -Check the [Releases](https://github.com/JheisonMB/gitkit/releases) page for precompiled binaries (Linux x86_64, macOS x86_64/ARM64, Windows x86_64). +Check the [Releases](https://github.com/UniverLab/gitkit/releases) page for precompiled binaries (Linux x86_64, macOS x86_64/ARM64, Windows x86_64). ### Uninstall @@ -65,7 +65,13 @@ Remove-Item "$env:LOCALAPPDATA\gitkit\gitkit.exe" -Force ## Quick Start -Interactive wizard — guided setup for a new repo: +**Clone and configure a repo in one command:** + +```bash +gitkit clone https://github.com/user/repo +``` + +Or configure an existing repo: ```bash gitkit init @@ -91,12 +97,51 @@ Interactive wizard that guides you through configuring a repo step by step. - `.gitattributes` — line endings and binary file presets - Git config — 6 individual options, recommended ones pre-selected -``` +Automatically initializes a git repository if one doesn't exist: + +```bash gitkit init ``` --- +## `gitkit clone` + +Clone a repository and automatically run `gitkit init` to configure it. + +**Usage:** + +```bash +gitkit clone [OPTIONS] [DIRECTORY] +``` + +**Arguments:** + +- `` — Repository URL or path to clone +- `[DIRECTORY]` — Target directory (defaults to repository name) + +**Options:** + +- `-b, --branch ` — Clone specific branch (defaults to repository default) +- `-h, --help` — Print help + +**Examples:** + +```bash +# Clone and auto-configure +gitkit clone https://github.com/user/repo + +# Clone specific branch +gitkit clone -b develop https://github.com/user/repo + +# Clone to custom directory +gitkit clone https://github.com/user/repo my-project +``` + +The wizard runs automatically after cloning, allowing you to configure hooks, `.gitignore`, `.gitattributes`, and git config in one workflow. + +--- + ## Commands ### Hooks diff --git a/install.ps1 b/scripts/install.ps1 similarity index 91% rename from install.ps1 rename to scripts/install.ps1 index 3df1502..86ff107 100644 --- a/install.ps1 +++ b/scripts/install.ps1 @@ -1,5 +1,5 @@ # install.ps1 — download and install gitkit on Windows -# Usage: irm https://raw.githubusercontent.com/JheisonMB/gitkit/main/install.ps1 | iex +# Usage: irm https://raw.githubusercontent.com/UniverLab/gitkit/main/scripts/install.ps1 | iex # # Options (set as env vars before running): # $env:VERSION = "0.1.0" # pin a specific version @@ -7,7 +7,7 @@ $ErrorActionPreference = "Stop" -$Repo = "JheisonMB/gitkit" +$Repo = "UniverLab/gitkit" $Binary = "gitkit.exe" $Target = "x86_64-pc-windows-msvc" $InstallDir = if ($env:INSTALL_DIR) { $env:INSTALL_DIR } else { "$env:USERPROFILE\.local\bin" } @@ -72,4 +72,4 @@ Remove-Item $Tmp -Recurse -Force $ver = & "$InstallDir\$Binary" --version 2>$null Info "done" $ver Write-Host "" -Info "ready" "Run 'gitkit hooks init commit-msg conventional-commits' to get started!" +Info "ready" "Run 'gitkit init' to get started!" diff --git a/install.sh b/scripts/install.sh similarity index 92% rename from install.sh rename to scripts/install.sh index 15b50ac..633af69 100644 --- a/install.sh +++ b/scripts/install.sh @@ -1,9 +1,9 @@ #!/bin/sh # install.sh — download and install gitkit from GitHub Releases -# Usage: curl -fsSL https://raw.githubusercontent.com/JheisonMB/gitkit/main/install.sh | sh +# Usage: curl -fsSL https://raw.githubusercontent.com/UniverLab/gitkit/main/scripts/install.sh | sh set -eu -REPO="JheisonMB/gitkit" +REPO="UniverLab/gitkit" BINARY="gitkit" INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/bin}" @@ -79,4 +79,4 @@ esac # --- verify --- info "done" "$($INSTALL_DIR/$BINARY --version 2>/dev/null || echo "$BINARY installed")" echo "" -info "ready" "Run 'gitkit hooks init commit-msg conventional-commits' to get started!" +info "ready" "Run 'gitkit init' to get started!" diff --git a/src/clone.rs b/src/clone.rs new file mode 100644 index 0000000..f0f3b41 --- /dev/null +++ b/src/clone.rs @@ -0,0 +1,70 @@ +use anyhow::Result; +use clap::Parser; +use std::process::Command; + +#[derive(Parser)] +pub struct CloneArgs { + /// Repository URL or path to clone + repository: String, + + /// Directory to clone into (defaults to repository name) + directory: Option, + + /// Clone specific branch + #[arg(short, long)] + branch: Option, +} + +pub fn run(args: CloneArgs) -> Result<()> { + let repository = &args.repository; + let directory = &args.directory; + let branch = &args.branch; + + println!(); + println!(" ◇ cloning repository..."); + + let mut cmd = Command::new("git"); + cmd.arg("clone"); + + if let Some(b) = branch { + cmd.arg("--branch").arg(b); + } + + cmd.arg(repository); + if let Some(d) = directory { + cmd.arg(d); + } + + let status = cmd + .output() + .map_err(|e| anyhow::anyhow!("Failed to run 'git clone': {}", e))? + .status; + + if !status.success() { + anyhow::bail!("git clone failed"); + } + + println!(" ◇ clone completed ✓"); + + let target_dir = if let Some(d) = directory { + d.to_string() + } else { + repository + .split('/') + .next_back() + .unwrap_or(repository) + .trim_end_matches(".git") + .to_string() + }; + + std::env::set_current_dir(&target_dir) + .map_err(|e| anyhow::anyhow!("Failed to enter directory '{}': {}", target_dir, e))?; + + println!(); + println!(" ◇ running gitkit init..."); + println!(); + + crate::init::run()?; + + Ok(()) +} diff --git a/src/git.rs b/src/git.rs new file mode 100644 index 0000000..1bed8cd --- /dev/null +++ b/src/git.rs @@ -0,0 +1,35 @@ +use anyhow::Result; +use std::path::Path; +use std::process::Command; + +/// Check if directory is a valid git repository. +pub fn is_git_repo() -> bool { + Command::new("git") + .args(["rev-parse", "--is-inside-work-tree"]) + .output() + .map(|o| o.status.success()) + .unwrap_or(false) +} + +/// Check if .git directory exists. +fn git_dir_exists() -> bool { + Path::new(".git").exists() +} + +/// Initialize git repository if not already a git repo. +pub fn init_if_needed() -> Result { + if git_dir_exists() { + return Ok(false); + } + + Command::new("git") + .arg("init") + .output() + .map_err(|e| anyhow::anyhow!("Failed to run 'git init': {}", e))?; + + if !is_git_repo() { + anyhow::bail!("git init succeeded but .git not found"); + } + + Ok(true) +} diff --git a/src/init.rs b/src/init.rs index 041d765..6298e33 100644 --- a/src/init.rs +++ b/src/init.rs @@ -1,7 +1,7 @@ use anyhow::Result; use inquire::{MultiSelect, Text}; -use crate::{attributes, config, hooks, ignore}; +use crate::{attributes, config, git, hooks, ignore}; const BANNER: &str = r#" ███ █████ █████ ███ █████ @@ -18,6 +18,12 @@ const BANNER: &str = r#" "#; pub fn run() -> Result<()> { + // Initialize git repository if not already one + let git_initialized = git::init_if_needed()?; + if git_initialized { + println!(" ◇ git repository initialized ✓"); + } + println!("{BANNER}"); println!(" Configure your git repo\n"); diff --git a/src/main.rs b/src/main.rs index e5f6027..55ddc74 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,9 @@ use anyhow::Result; use clap::{Parser, Subcommand}; mod attributes; +mod clone; mod config; +mod git; mod hooks; mod ignore; mod init; @@ -23,6 +25,8 @@ struct Cli { enum Command { /// Interactive wizard to configure your repo Init, + /// Clone repository and run init wizard + Clone(clone::CloneArgs), /// Manage git hooks Hooks { #[command(subcommand)] @@ -49,6 +53,7 @@ fn main() -> Result<()> { let cli = Cli::parse(); match cli.command { Command::Init => init::run(), + Command::Clone(args) => clone::run(args), Command::Hooks { action } => hooks::run(action), Command::Ignore { action } => ignore::run(action), Command::Attributes { action } => attributes::run(action),