diff --git a/README.md b/README.md index f2eb215..a97f8be 100644 --- a/README.md +++ b/README.md @@ -68,12 +68,45 @@ curl -fsSL https://git.sdf.org/jchenry/provision/raw/branch/main/bootstrap | bas ./provision # Skip components -./provision --skip-apps # Skip GUI applications -./provision --skip-go # Skip Go installation -./provision --skip-p9 # Skip Plan9 installation -./provision --help # Show help +./provision --skip-apps # Skip GUI applications +./provision --skip-go # Skip Go installation +./provision --skip-p9 # Skip Plan9 installation + +# Clone all repositories +./provision --clone-repos # Clone all git.sdf.org/jchenry repos + +# Include work packages +./provision --work # Include work-related packages/apps + +./provision --help # Show help ``` +### Cloning All Repositories + +To clone all your repositories from git.sdf.org: + +```bash +# Option 1: During provision +./provision --clone-repos + +# Option 2: Standalone script +./scripts/clone-repos.sh +``` + +The script will: +- Clone all repositories to `~/.workspace/src/git.sdf.org/jchenry/` +- Skip the `provision` repo (already exists) +- Convert remotes to SSH (port 2222) for future operations +- Update existing repos if already cloned + +**For private repositories**, set the `GITEA_TOKEN` environment variable: +```bash +export GITEA_TOKEN="your_token_here" +./scripts/clone-repos.sh +``` + +Get a token at: https://git.sdf.org/user/settings/applications + ## Structure ``` diff --git a/bootstrap b/bootstrap index bdec8a9..5e73be6 100644 --- a/bootstrap +++ b/bootstrap @@ -69,6 +69,16 @@ else echo "Cloning provision repository..." git clone "$REPO_URL" "$CLONE_DIR" cd "$CLONE_DIR" + + # Convert remote to SSH if possible + echo "Converting git remote to SSH..." + current_url=$(git remote get-url origin) + if [[ "$current_url" =~ ^https://git\.sdf\.org/(.+)$ ]]; then + # SDF uses port 2222 for SSH + new_url="ssh://git@git.sdf.org:2222/${BASH_REMATCH[1]}" + git remote set-url origin "$new_url" + echo "✓ Remote converted to SSH: $new_url" + fi fi echo "" diff --git a/provision b/provision index 8b0821b..8a60318 100755 --- a/provision +++ b/provision @@ -11,18 +11,20 @@ Usage: provision [OPTIONS] Provision macOS or Linux desktop computers. OPTIONS: - -h, --help Show this help - -s, --skip-go Skip Go installation - -p, --skip-p9 Skip Plan9 installation - -a, --skip-apps Skip GUI applications - -w, --work Include work packages and applications + -h, --help Show this help + -s, --skip-go Skip Go installation + -p, --skip-p9 Skip Plan9 installation + -a, --skip-apps Skip GUI applications + -w, --work Include work packages and applications + -r, --clone-repos Clone all git.sdf.org/jchenry repos to workspace EXAMPLES: - provision # Full provision - provision --skip-go # Skip Go - provision --skip-p9 # Skip Plan9 - provision --skip-apps # Skip apps (VSCode, 1Password, etc.) - provision --work # Include work packages/apps + provision # Full provision + provision --skip-go # Skip Go + provision --skip-p9 # Skip Plan9 + provision --skip-apps # Skip apps (VSCode, 1Password, etc.) + provision --work # Include work packages/apps + provision --clone-repos # Clone all repositories EOF exit 0 @@ -33,6 +35,7 @@ SKIP_GO=false SKIP_P9=false SKIP_APPS=false INCLUDE_WORK=false +CLONE_REPOS=false while [[ $# -gt 0 ]]; do case $1 in @@ -55,6 +58,10 @@ while [[ $# -gt 0 ]]; do INCLUDE_WORK=true shift ;; + -r|--clone-repos) + CLONE_REPOS=true + shift + ;; *) log_error "Unknown option: $1" usage @@ -165,6 +172,13 @@ log_info "=== Linking Config Files ===" "$SCRIPT_DIR/config/link-dotfiles.sh" echo "" +# Clone repositories (optional) +if [ "$CLONE_REPOS" = true ]; then + log_info "=== Cloning Repositories ===" + "$SCRIPT_DIR/scripts/clone-repos.sh" + echo "" +fi + log_success "Provision complete!" echo "" log_info "Next steps:" diff --git a/scripts/clone-repos.sh b/scripts/clone-repos.sh new file mode 100755 index 0000000..7ba9389 --- /dev/null +++ b/scripts/clone-repos.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/../lib/common.sh" + +# Configuration +GIT_HOST="git.sdf.org" +GIT_USER="jchenry" +GIT_SSH_PORT="2222" +WORKSPACE_DIR="$HOME/.workspace/src/$GIT_HOST/$GIT_USER" +EXCLUDE_REPOS=("provision") + +# Ensure workspace directory exists +ensure_dir "$WORKSPACE_DIR" + +log_info "Fetching repository list from $GIT_HOST/$GIT_USER" + +# Method 1: Try SSH first (works if SSH keys are set up) +# This gets all repos (public + private) without needing a token +log_info "Attempting to list repositories via SSH..." +REPO_NAMES=$(ssh -p $GIT_SSH_PORT git@$GIT_HOST ls-repos $GIT_USER 2>/dev/null | grep "^$GIT_USER/" | sed "s|^$GIT_USER/||" | sed 's/\.git$//' | sort -u || true) + +# Method 2: Fall back to API if SSH didn't work +if [ -z "$REPO_NAMES" ]; then + log_warn "SSH listing failed, using API method" + + # Try with authentication token if available + if [ -n "${GITEA_TOKEN:-}" ]; then + log_info "Using GITEA_TOKEN for authentication (includes private repos)" + REPOS_JSON=$(curl -fsSL -H "Authorization: token $GITEA_TOKEN" "https://$GIT_HOST/api/v1/user/repos?limit=100") + else + log_warn "GITEA_TOKEN not set - fetching public repositories only" + log_info "To include private repos, either:" + log_info " 1. Set up SSH keys for git@$GIT_HOST:$GIT_SSH_PORT, or" + log_info " 2. Set GITEA_TOKEN environment variable" + log_info " Get a token at: https://$GIT_HOST/user/settings/applications" + REPOS_JSON=$(curl -fsSL "https://$GIT_HOST/api/v1/users/$GIT_USER/repos?limit=100") + fi + + if [ -z "$REPOS_JSON" ] || [ "$REPOS_JSON" = "null" ]; then + log_error "Failed to fetch repository list" + exit 1 + fi + + # Parse repository names from JSON + REPO_NAMES=$(echo "$REPOS_JSON" | jq -r '.[].name' | sort -u) +fi + +if [ -z "$REPO_NAMES" ]; then + log_warn "No repositories found for user $GIT_USER" + exit 0 +fi + +log_info "Found repositories:" +echo "$REPO_NAMES" | sed 's/^/ - /' +echo "" + +# Clone each repository +for repo in $REPO_NAMES; do + # Skip excluded repos + if [[ " ${EXCLUDE_REPOS[@]} " =~ " ${repo} " ]]; then + log_info "Skipping excluded repository: $repo" + continue + fi + + REPO_DIR="$WORKSPACE_DIR/$repo" + + if [ -d "$REPO_DIR" ]; then + log_info "Repository $repo already exists, updating..." + cd "$REPO_DIR" + git pull + log_success "Updated $repo" + else + log_info "Cloning $repo..." + # Clone using HTTPS first (works without SSH keys) + HTTPS_URL="https://$GIT_HOST/$GIT_USER/$repo.git" + + # If we have a token, use it for cloning private repos + if [ -n "${GITEA_TOKEN:-}" ]; then + CLONE_URL="https://$GITEA_TOKEN@$GIT_HOST/$GIT_USER/$repo.git" + else + CLONE_URL="$HTTPS_URL" + fi + + if git clone "$CLONE_URL" "$REPO_DIR" 2>/dev/null; then + # Convert to SSH for future operations (if SSH is configured) + cd "$REPO_DIR" + SSH_URL="ssh://git@$GIT_HOST:$GIT_SSH_PORT/$GIT_USER/$repo.git" + git remote set-url origin "$SSH_URL" + log_success "Cloned $repo (remote set to SSH)" + else + log_error "Failed to clone $repo" + fi + fi + echo "" +done + +log_success "Repository cloning complete!" +log_info "All repositories are in: $WORKSPACE_DIR" +echo "" +log_info "Repository list:" +ls -1 "$WORKSPACE_DIR" | sed 's/^/ - /' diff --git a/scripts/git-ssh-remote.sh b/scripts/git-ssh-remote.sh new file mode 100755 index 0000000..52f3b6e --- /dev/null +++ b/scripts/git-ssh-remote.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/../lib/common.sh" + +# Convert git HTTP(S) remotes to SSH +convert_git_remote_to_ssh() { + local repo_dir="${1:-.}" + + if [ ! -d "$repo_dir/.git" ]; then + log_warn "Not a git repository: $repo_dir" + return 1 + fi + + cd "$repo_dir" + + # Get all remotes + local remotes=$(git remote) + + if [ -z "$remotes" ]; then + log_info "No remotes found in $repo_dir" + return 0 + fi + + for remote in $remotes; do + local url=$(git remote get-url "$remote") + local new_url="" + + # Convert HTTPS to SSH for common Git hosting services + if [[ "$url" =~ ^https://github\.com/(.+)$ ]]; then + new_url="git@github.com:${BASH_REMATCH[1]}" + elif [[ "$url" =~ ^https://gitlab\.com/(.+)$ ]]; then + new_url="git@gitlab.com:${BASH_REMATCH[1]}" + elif [[ "$url" =~ ^https://git\.sdf\.org/(.+)$ ]]; then + # SDF uses port 2222 for SSH + new_url="ssh://git@git.sdf.org:2222/${BASH_REMATCH[1]}" + elif [[ "$url" =~ ^https://bitbucket\.org/(.+)$ ]]; then + new_url="git@bitbucket.org:${BASH_REMATCH[1]}" + elif [[ "$url" =~ ^http://github\.com/(.+)$ ]]; then + new_url="git@github.com:${BASH_REMATCH[1]}" + elif [[ "$url" =~ ^http://gitlab\.com/(.+)$ ]]; then + new_url="git@gitlab.com:${BASH_REMATCH[1]}" + elif [[ "$url" =~ ^http://git\.sdf\.org/(.+)$ ]]; then + # SDF uses port 2222 for SSH + new_url="ssh://git@git.sdf.org:2222/${BASH_REMATCH[1]}" + elif [[ "$url" =~ ^http://bitbucket\.org/(.+)$ ]]; then + new_url="git@bitbucket.org:${BASH_REMATCH[1]}" + fi + + if [ -n "$new_url" ]; then + log_info "Converting $remote: $url -> $new_url" + git remote set-url "$remote" "$new_url" + log_success "Converted $remote to SSH" + else + log_info "$remote already uses SSH or unsupported URL: $url" + fi + done +} + +# If called with a directory argument, use that; otherwise use current directory +TARGET_DIR="${1:-.}" + +log_info "Converting git remotes to SSH in $TARGET_DIR" +convert_git_remote_to_ssh "$TARGET_DIR" +log_success "Git remote conversion complete"