diff --git a/BORG_CLI_INSTALLER_README.md b/BORG_CLI_INSTALLER_README.md new file mode 100644 index 0000000..b5a7ead --- /dev/null +++ b/BORG_CLI_INSTALLER_README.md @@ -0,0 +1,192 @@ +# Borg CLI Installer + +A comprehensive installer script for Borg CLI that supports multiple Linux distributions and installation methods. + +## Features + +- **Version Checking**: Only downloads and installs if newer version is available +- **Multiple Installation Methods**: + - Package manager (apt, yum, dnf, pacman, zypper) + - Binary download from GitHub releases +- **Cross-Platform Support**: Debian, Ubuntu, RHEL, CentOS, Fedora, Arch, openSUSE +- **Architecture Support**: x86_64 (amd64), ARM64, ARM +- **Automatic Updates**: Fetches latest version from GitHub API +- **Force Reinstall**: Option to force reinstall even if up-to-date + +## Usage + +### Basic Usage +```bash +# Install latest version (only if newer than current) +./install-borg-cli.sh + +# Install specific version +./install-borg-cli.sh -v 1.4.2 + +# Force reinstall even if up-to-date +./install-borg-cli.sh --force +``` + +### Installation Methods +```bash +# Force installation from package manager +./install-borg-cli.sh --package + +# Force installation from binary +./install-borg-cli.sh --binary +``` + +### Help +```bash +./install-borg-cli.sh --help +``` + +## Installation Logic + +### Version Checking +1. **Check Current Version**: Detects installed Borg CLI version +2. **Fetch Latest**: Gets latest version from GitHub API +3. **Compare Versions**: Only proceeds if newer version available +4. **Force Override**: `--force` flag bypasses version check + +### Installation Priority +1. **Package Manager** (preferred): + - Debian/Ubuntu: Checks for official borgbackup package + - RHEL/CentOS/Fedora: Checks for available borgbackup package + - Arch Linux: Available in pacman repositories + - openSUSE: Checks for available borgbackup package + +2. **Binary Download** (fallback): + - Downloads platform-specific binary from GitHub releases + - Supports x86_64, ARM64, ARM architectures + - Installs to `/usr/local/bin/borg` or `~/bin/borg` + +## File Locations + +### Installation Directory +- Binary: `/usr/local/bin/borg` (system) or `~/bin/borg` (user) +- Symlink: `borg -> borg-1.4.2` (version-specific) + +## Version Comparison + +The installer uses semantic version comparison: +- **Format**: `X.Y.Z` (e.g., `1.4.2`) +- **Logic**: Compares major, minor, patch versions +- **Build Info**: Ignores build hashes/identifiers + +### Examples +```bash +# Current: 1.4.0, Latest: 1.4.2 → Update needed +# Current: 1.4.2, Latest: 1.4.2 → No update needed +# Current: 1.4.3, Latest: 1.4.2 → No update needed (newer installed) +``` + +## System Requirements + +### Required +- `curl` or `wget` (for downloading) +- `sudo` access (for system-wide installation) + +### Optional +- Package manager access (for package installations) +- Internet connection (for downloading releases) + +## Supported Distributions + +### Package Manager Support +- **Debian/Ubuntu**: `borgbackup` package +- **RHEL/CentOS/Fedora**: `borgbackup` package +- **Arch Linux**: `borg` package +- **openSUSE**: `borgbackup` package + +### Binary Support +- **Linux x86_64**: `borg-linux-glibc231-x86_64` +- **Linux ARM64**: `borg-linux-glibc231-aarch64` +- **Linux ARM**: `borg-linux-glibc231-armv7` + +## Troubleshooting + +### Version Detection Issues +```bash +# Check current version manually +borg --version + +# Force reinstall if version detection fails +./install-borg-cli.sh --force +``` + +### Permission Issues +```bash +# For system installation +sudo ./install-borg-cli.sh --binary +``` + +### PATH Issues +```bash +# Check if user bin is in PATH +echo $PATH | grep -q "$HOME/bin" && echo "OK" || echo "Add to PATH" + +# Test borg command +which borg +borg --version +``` + +## Examples + +### Typical Workflow +```bash +# Check if update needed +./install-borg-cli.sh + +# Output if up-to-date: +# [SUCCESS] You already have latest version (1.4.2) +# [SUCCESS] No installation needed. Exiting. + +# Output if update available: +# [INFO] Current version: 1.4.0 (user) +# [INFO] Latest version: 1.4.2 +# [INFO] Newer version available: 1.4.2 > 1.4.0 +# [SUCCESS] Installation completed successfully! +``` + +### Force Binary Installation +```bash +# Force binary installation +./install-borg-cli.sh --force --binary + +# Output: +# [SUCCESS] Borg CLI binary installed successfully +# Next steps: +# 1. Test installation: borg --version +# 2. Initialize repository: borg init --encryption=repokey /path/to/repo +# 3. Create backup: borg create /path/to/repo::backup-name /path/to/backup +# 4. Use Borg CLI: borg --help +``` + +## Integration with Setup Script + +The Borg CLI installer can be integrated with backup setup scripts: +- Automatically called when Borg CLI is needed +- Respects user preferences for installation location +- Provides clear feedback on installation strategy +- Handles both new installations and updates + +## Security Features + +- **Official Releases**: Downloads from official GitHub releases +- **Package Verification**: Uses official package repositories +- **Proper Permissions**: Sets appropriate file ownership and permissions + +## Contributing + +To add support for new distributions or architectures: + +1. Update `detect_os()` function for new package managers +2. Add architecture detection in `get_arch()` function +3. Update installation methods in `install_borg_from_*()` functions +4. Test with target distribution +5. Update documentation + +## License + +This installer script follows the same license as Borg (BSD-3-Clause). \ No newline at end of file diff --git a/GCM_INSTALLER_README.md b/GCM_INSTALLER_README.md new file mode 100644 index 0000000..69e49bb --- /dev/null +++ b/GCM_INSTALLER_README.md @@ -0,0 +1,247 @@ +# Git Credential Manager Installer + +A comprehensive installer script for Git Credential Manager (GCM) that supports multiple Linux distributions and installation methods. + +## Features + +- **Version Checking**: Only downloads and installs if newer version is available +- **Multiple Installation Methods**: + - Package manager (apt, yum, dnf, pacman, zypper) + - DEB packages (Debian/Ubuntu) + - Tar.gz archives (universal) +- **Cross-Platform Support**: Debian, Ubuntu, RHEL, CentOS, Fedora, Arch, openSUSE +- **Architecture Support**: x86_64 (amd64), ARM64 (arm64), ARM (armv7l) +- **Automatic Updates**: Fetches latest version from GitHub releases +- **Force Reinstall**: Option to force reinstallation even if up-to-date + +## Usage + +### Basic Usage +```bash +# Install latest version (only if newer than current) +./install-git-credential-manager.sh + +# Install specific version +./install-git-credential-manager.sh -v v2.6.0 + +# Force reinstall even if up-to-date +./install-git-credential-manager.sh --force +``` + +### Installation Methods +```bash +# Force installation from package manager +./install-git-credential-manager.sh --package + +# Force installation from DEB package +./install-git-credential-manager.sh --deb + +# Force installation from tarball +./install-git-credential-manager.sh --tarball +``` + +### Check Configuration Only +```bash +# Check current Git credential configuration without installing +./install-git-credential-manager.sh --checks + +# Example output: +# ✓ Global credential helper: manager +# ✓ GitHub credential helper configured +# ✗ GitLab credential helper not configured +# ✗ Azure DevOps useHttpPath not configured +# ✗ Bitbucket credential helper not configured +# ✓ Gitea credential helpers configured (1 found) +# +# Run these commands to complete the configuration: +# git config --global credential.https://gitlab.com.helper manager +# git config --global credential.https://dev.azure.com.useHttpPath true +# git config --global credential.https://bitbucket.org.helper manager +``` + +### Help +```bash +./install-git-credential-manager.sh --help +``` + +## Installation Logic + +### Version Checking +1. **Check Current Version**: Detects installed GCM version +2. **Fetch Latest**: Gets latest version from GitHub API +3. **Compare Versions**: Only proceeds if newer version available +4. **Force Override**: `--force` flag bypasses version check + +### Installation Priority +1. **Package Manager** (preferred): + - Debian/Ubuntu: `apt install git-credential-manager` + - Arch Linux: `pacman -S git-credential-manager` + - Others: Falls back to manual installation + +2. **Distribution-Specific**: + - Debian/Ubuntu: Downloads `.deb` package + - Other Linux: Downloads `.tar.gz` archive + +3. **Universal Fallback**: + - Downloads tarball for any architecture + - Extracts and installs binary to `/usr/local/bin` + +## System Requirements + +### Required +- `curl` or `wget` (for downloading) +- `sudo` access (for system-wide installation) +- Git (for configuration) + +### Optional +- Package manager access (for package installations) +- Internet connection (for downloading releases) + +## File Locations + +### Installation Directory +- Binary: `/usr/local/bin/git-credential-manager` +- Symlink: `/usr/local/bin/git-credential-manager-core` +- Libraries: `/usr/local/bin/lib*.so` + +### Configuration +- Git config: `~/.gitconfig` +- Credential storage: Platform-specific secure storage + +## Version Comparison + +The installer uses semantic version comparison: +- **Format**: `vX.Y.Z` (e.g., `v2.6.1`) +- **Logic**: Compares major, minor, patch versions +- **Build Info**: Ignores build hashes/identifiers + +### Examples +```bash +# Current: v2.6.1, Latest: v2.6.1 → No update needed +# Current: v2.6.0, Latest: v2.6.1 → Update needed +# Current: v2.6.1, Latest: v2.6.0 → No update needed (newer installed) +``` + +## Integration with Setup Script + +The installer is automatically integrated with the main Git repository setup script: + +1. **Detection**: Checks for existing credential managers +2. **Offer Installation**: Prompts to install GCM if none found +3. **Configuration**: Sets up Git to use the credential manager +4. **Domain-Specific**: Configures for specific Gitea instances + +## Security Features + +- **Official Releases**: Downloads from official GitHub releases +- **Checksum Verification**: Can verify package integrity (future enhancement) +- **Secure Storage**: Uses OS keyring for credential storage +- **No Plain Text**: Never stores credentials in plain text + +## Troubleshooting + +### Version Detection Issues +```bash +# Check current version manually +git-credential-manager --version + +# Force reinstall if version detection fails +./install-git-credential-manager.sh --force +``` + +### Permission Issues +```bash +# Ensure proper permissions +sudo chown root:root /usr/local/bin/git-credential-manager +sudo chmod 755 /usr/local/bin/git-credential-manager +``` + +### Network Issues +```bash +# Use specific version if network blocks GitHub API +./install-git-credential-manager.sh -v v2.6.1 +``` + +## Examples + +### Typical Workflow +```bash +# Check if update needed +./install-git-credential-manager.sh + +# Output if up-to-date: +# [SUCCESS] You already have the latest version (v2.6.1) +# [SUCCESS] No installation needed. Exiting. + +# Output if update available: +# [INFO] Current version: v2.6.0 +# [INFO] Latest version: v2.6.1 +# [INFO] Newer version available: v2.6.1 > v2.6.0 +# [SUCCESS] Installation completed successfully! +``` + +### Automated Installation +```bash +# Script for automated setup +#!/bin/bash +./install-git-credential-manager.sh --force --package +git config --global credential.helper manager +``` + +## Post-Installation Configuration Check + +After successful installation, the installer automatically checks and configures all required Git presets: + +### ✅ Preset Verification +The installer checks these configurations: +- **Global credential helper**: `credential.helper manager` +- **GitHub**: `credential.https://github.com.helper manager` +- **GitLab**: `credential.https://gitlab.com.helper manager` +- **Bitbucket**: `credential.https://bitbucket.org.helper manager` +- **Azure DevOps**: `credential.https://dev.azure.com.useHttpPath true` +- **Gitea servers**: Domain-specific credential helpers + +### 📋 Configuration Report +The installer provides: +- **Status summary**: Shows which presets are configured (✓) or missing (✗) +- **Exact commands**: Lists the exact `git config` commands needed +- **Testing guidance**: Commands to verify the configuration +- **Service-specific advice**: Tailored guidance for different Git hosting services + +### 🔧 Manual Configuration +If presets are missing, the installer shows exactly what to run: + +```bash +# Example output for missing presets: +Run these commands to complete the configuration: + git config --global credential.https://gitlab.com.helper manager + git config --global credential.https://dev.azure.com.useHttpPath true + git config --global credential.https://bitbucket.org.helper manager + # For Gitea servers, configure domain-specific helper: + git config --global credential.https://go-gitea.mywire.org.helper manager + +After configuring, test with: + git config --global --list | grep credential +``` + +## Integration with Setup Script + +The installer integrates seamlessly with the main setup script: +- Automatically called when Git Credential Manager is needed +- Respects user preferences for installation location +- Provides clear feedback on installation strategy +- Handles both new installations and updates +- **Performs comprehensive preset checking and configuration** + +## Contributing + +To add support for new distributions or architectures: + +1. Update `detect_os()` function for new package managers +2. Add architecture detection in `get_arch()` function +3. Update installation methods in `install_from_*()` functions +4. Test with target distribution + +## License + +This installer script follows the same license as Git Credential Manager (MIT). \ No newline at end of file diff --git a/GITEA_INSTALLER_README.md b/GITEA_INSTALLER_README.md new file mode 100644 index 0000000..a8ed795 --- /dev/null +++ b/GITEA_INSTALLER_README.md @@ -0,0 +1,217 @@ +# Gitea Server Installer + +A comprehensive installer script for Gitea server that supports multiple Linux distributions and installation methods. + +## Features + +- **Version Checking**: Only downloads and installs if newer version is available +- **Multiple Installation Methods**: + - Package manager (apt, yum, dnf, zypper) + - Binary download from GitHub releases +- **Cross-Platform Support**: Debian, Ubuntu, RHEL, CentOS, Fedora, Arch, openSUSE +- **Architecture Support**: x86_64 (amd64), ARM64, ARM +- **Automatic Updates**: Fetches latest version from GitHub releases +- **Force Reinstall**: Option to force reinstall even if up-to-date +- **Service Setup**: Optional systemd service creation and configuration + +## Usage + +### Basic Usage +```bash +# Install latest version (only if newer than current) +./install-gitea-server.sh + +# Install specific version +./install-gitea-server.sh -v v1.25.0 + +# Force reinstall even if up-to-date +./install-gitea-server.sh --force +``` + +### Installation Methods +```bash +# Force installation from package manager +./install-gitea-server.sh --package + +# Force installation from binary +./install-gitea-server.sh --binary + +# Install and set up as systemd service +./install-gitea-server.sh --service +``` + +### Help +```bash +./install-gitea-server.sh --help +``` + +## Installation Logic + +### Version Checking +1. **Check Current Version**: Detects installed Gitea version +2. **Fetch Latest**: Gets latest version from GitHub API +3. **Compare Versions**: Only proceeds if newer version available +4. **Force Override**: `--force` flag bypasses version check + +### Installation Priority +1. **Package Manager** (preferred): + - Debian/Ubuntu: Uses official Gitea repository + - RHEL/CentOS/Fedora: Uses official Gitea repository + - Arch Linux: Available in AUR + - openSUSE: Uses official Gitea repository + +2. **Binary Download** (fallback): + - Downloads platform-specific binary from GitHub releases + - Supports x86_64, ARM64, ARM architectures + - Installs to `/usr/local/bin/gitea` + +### Service Setup +When `--service` is used: +- Creates systemd service file +- Sets up proper user/group permissions +- Creates configuration directories +- Generates basic configuration +- Enables and starts the service + +## File Locations + +### Installation Directory +- Binary: `/usr/local/bin/gitea` +- Service: `/etc/systemd/system/gitea.service` +- Configuration: `/etc/gitea/app.ini` +- Data: `/var/lib/gitea/data` +- Repositories: `/var/lib/gitea/data/repositories` +- Logs: `/var/lib/gitea/log` +- Attachments: `/var/lib/gitea/data/attachments` + +### Configuration +The installer creates a basic configuration with: +- SQLite database (suitable for small installations) +- Security settings with generated secret key +- Local file storage +- Console logging +- Service user/group permissions + +## Version Comparison + +The installer uses semantic version comparison: +- **Format**: `vX.Y.Z` (e.g., `v1.25.1`) +- **Logic**: Compares major, minor, patch versions +- **Build Info**: Ignores build hashes/identifiers + +### Examples + +### Typical Workflow +```bash +# Check if update needed +./install-gitea-server.sh + +# Output if up-to-date: +# [SUCCESS] You already have latest version (v1.25.1) +# [SUCCESS] No installation needed. Exiting. + +# Output if update available: +# [INFO] Current version: v1.25.0 +# [INFO] Latest version: v1.25.1 +# [INFO] Newer version available: v1.25.1 > v1.25.0 +# [SUCCESS] Installation completed successfully! +``` + +### Service Setup +```bash +# Install and set up as service +./install-gitea-server.sh --service + +# Output: +# [SUCCESS] Gitea service setup completed! +# Next steps: +# 1. Start service: sudo systemctl start gitea +# 2. Check status: sudo systemctl status gitea +# 3. View logs: sudo journalctl -u gitea -f +# 4. Configure at: /etc/gitea/app.ini +``` + +## System Requirements + +### Required +- `curl` or `wget` (for downloading) +- `sudo` access (for system-wide installation) +- Systemd (for service setup) + +### Optional +- Package manager access (for package installations) +- Internet connection (for downloading releases) + +## Security Features + +- **Official Releases**: Downloads from official GitHub releases +- **Package Verification**: Uses GPG keys for package manager installations +- **Proper Permissions**: Sets appropriate file ownership and permissions +- **Service Isolation**: Runs as dedicated service user/group + +## Supported Distributions + +### Package Manager Support +- **Debian/Ubuntu**: Official Gitea repository with GPG verification +- **RHEL/CentOS/Fedora**: Official Gitea RPM repository +- **Arch Linux**: Available in AUR (pacman) +- **openSUSE**: Official Gitea repository + +### Binary Support +- **Linux x86_64**: `gitea-1.25.1-linux-amd64` +- **Linux ARM64**: `gitea-1.25.1-linux-arm64` +- **Linux ARM**: `gitea-1.25.1-linux-arm-5` + +## Troubleshooting + +### Version Detection Issues +```bash +# Check current version manually +gitea --version + +# Force reinstall if version detection fails +./install-gitea-server.sh --force +``` + +### Permission Issues +```bash +# Ensure proper permissions +sudo chown root:root /usr/local/bin/gitea +sudo chmod 755 /usr/local/bin/gitea +``` + +### Service Issues +```bash +# Check service status +sudo systemctl status gitea + +# View service logs +sudo journalctl -u gitea -f + +# Restart service +sudo systemctl restart gitea +``` + +## Production Considerations + +For production use, consider: +- Using PostgreSQL/MySQL instead of SQLite +- Configuring reverse proxy (nginx/apache) +- Setting up SSL certificates +- Adjusting firewall settings +- Regular backups +- Monitoring and log rotation + +## Contributing + +To add support for new distributions or architectures: + +1. Update `detect_os()` function for new package managers +2. Add architecture detection in `get_arch()` function +3. Update installation methods in `install_from_*()` functions +4. Test with target distribution +5. Update documentation + +## License + +This installer script follows the same license as Gitea (MIT). \ No newline at end of file diff --git a/GIT_CREDENTIAL_MANAGERS.md b/GIT_CREDENTIAL_MANAGERS.md new file mode 100644 index 0000000..4e31f97 --- /dev/null +++ b/GIT_CREDENTIAL_MANAGERS.md @@ -0,0 +1,205 @@ +# Git Credential Managers for Gitea + +Git credential managers provide secure storage and automatic retrieval of your Git credentials, eliminating the need to repeatedly enter usernames and passwords/tokens. + +## Supported Credential Managers + +### 1. Git Credential Manager (GCM) - Console & GUI +- **Cross-platform**: Windows, macOS, Linux +- **Official Microsoft project** +- **Console-First**: Works perfectly in terminal without GUI +- **Supports**: HTTPS authentication, personal access tokens, OAuth +- **Installation**: + ```bash + # Linux (various distributions) + sudo apt install git-credential-manager # Ubuntu/Debian + sudo yum install git-credential-manager # RHEL/CentOS + sudo pacman -S git-credential-manager # Arch + + # macOS + brew install git-credential-manager + + # Windows + # Included with Git for Windows + ``` +- **Console Usage**: All operations are terminal-based, no GUI required + +### 2. libsecret (Linux) - Console Only +- **Linux native**: Uses system keyring (GNOME Keyring, KWallet) +- **Console-Only**: No GUI components, pure terminal integration +- **Installation**: + ```bash + # Ubuntu/Debian + sudo apt install libsecret-1-0 libsecret-1-dev + + # RHEL/CentOS + sudo yum install libsecret-devel + + # Configure Git + git config --global credential.helper /usr/share/doc/git/contrib/credential/gnome-keyring/git-credential-gnome-keyring + ``` + +### 3. osxkeychain (macOS) - Console & GUI +- **Built-in**: Uses macOS Keychain +- **Console-First**: Works in terminal, can also access GUI keychain +- **Configuration**: + ```bash + git config --global credential.helper osxkeychain + ``` + +### 4. manager (Generic) +- **Built-in**: Simple in-memory cache +- **Configuration**: + ```bash + git config --global credential.helper manager + ``` + +## Configuration for Gitea + +### Method 1: Personal Access Token +1. Generate token in Gitea: User Settings → Applications → Generate Token +2. Configure Git: + ```bash + git config --global credential.helper manager + # First push will prompt for username and token + ``` + +### Method 2: Direct Credential Storage +```bash +# Store credentials for specific Gitea instance +git config --global credential.https://go-gitea.mywire.org.helper manager +``` + +### Method 3: Environment Variables +```bash +export GIT_USERNAME="your_username" +export GIT_PASSWORD="your_access_token" +``` + +## Security Considerations + +### ✅ Secure Options +- **GCM**: Encrypts credentials, integrates with OS keyring +- **libsecret/osxkeychain**: Uses system secure storage +- **Personal Access Tokens**: More secure than passwords, can be revoked + +### ⚠️ Less Secure Options +- **Plain text**: Storing credentials in .netrc files +- **Environment variables**: Visible in process list +- **Cache-only**: Credentials stored in memory only + +## Console-Only Operation + +### How It Works Without GUI +1. **Terminal Prompts**: Git prompts for username/token in console +2. **Secure Storage**: Credentials stored in system keyring (encrypted) +3. **Automatic Retrieval**: Subsequent Git operations use stored credentials +4. **No GUI Required**: All operations happen in terminal + +### Console Workflow Example +```bash +# First time - prompts in terminal +$ git push origin main +Username for 'https://go-gitea.mywire.org': kadu +Password for 'https://kadu@go-gitea.mywire.org': your_access_token + +# Subsequent times - automatic +$ git push origin main +Everything up-to-date + +# No more prompts! +``` + +## Integration with Setup Script + +The setup script can: +1. Detect available credential managers +2. Configure Git to use the best available option +3. Guide users through secure credential setup +4. Test credential storage and retrieval +5. **Check all required Git presets after installation** +6. **Provide exact commands to complete configuration** + +## Post-Installation Configuration Check + +The installer automatically checks and configures these Git presets: + +### ✅ Required Presets +- `credential.helper manager` - Global credential helper +- `credential.https://github.com.helper manager` - GitHub specific +- `credential.https://gitlab.com.helper manager` - GitLab specific +- `credential.https://bitbucket.org.helper manager` - Bitbucket specific +- `credential.https://dev.azure.com.useHttpPath true` - Azure DevOps +- Domain-specific helpers for Gitea servers + +### 📋 Configuration Summary +After installation, the installer provides: +- **Status of each preset** (✓ configured, ✗ missing) +- **Exact commands** to complete configuration +- **Testing commands** to verify setup +- **Usage guidance** for different Git hosting services +5. Work entirely in console mode + +## Best Practices for Gitea + +1. **Use Personal Access Tokens** instead of passwords +2. **Set token expiration** and permissions appropriately +3. **Use HTTPS with credential manager** for most users (console-friendly) +4. **Use SSH keys** for automated/scripted access +5. **Regularly rotate tokens** for security +6. **Console environments**: All credential managers work perfectly in SSH/remote terminals + +## Troubleshooting + +### Common Issues +- **Token not working**: Ensure token has required scopes (repo, user) +- **Credential manager not found**: Install appropriate package for your OS +- **HTTPS certificate errors**: Configure Git to trust your Gitea certificate +- **Authentication prompts**: Check credential helper configuration + +### Debug Commands +```bash +# Test credential storage +git credential fill + +# Check current configuration +git config --global --show-origin --get credential.helper + +# Clear stored credentials +git credential-cache exit +``` + +## Example Workflow (Console Only) + +```bash +# 1. Configure credential manager +git config --global credential.helper manager + +# 2. First time authentication (console prompts) +$ git clone https://go-gitea.mywire.org/username/repo.git +Username for 'https://go-gitea.mywire.org': your_username +Password for 'https://go-gitea.mywire.org': your_access_token + +# 3. Subsequent operations use stored credentials automatically +$ git pull +Already up to date. + +$ git push +Everything up-to-date + +# No more prompts - works in any terminal/SSH session! +``` + +## Remote/SSH Console Usage + +Credential managers work perfectly in remote SSH sessions: + +```bash +# SSH into remote server +ssh user@server + +# Git operations work with stored credentials +cd /project +git pull # Uses stored credentials, no prompts +git push # Automatic authentication +``` \ No newline at end of file diff --git a/README.md b/README.md index ea9b03c..61d8c64 100644 --- a/README.md +++ b/README.md @@ -5,23 +5,137 @@ This script helps you create a git repository from existing codebase and configu ## Features - **Multiple Authentication Methods**: - - SSH (passwordless after key setup) - - HTTPS (with token/password) - - Tea CLI (Gitea's official command-line tool) + - SSH (passwordless with key generation) + - HTTPS (with Git Credential Manager) + - Tea CLI (full Gitea API integration) + +- **Advanced Installation Management**: + - **Tea CLI**: User-specific installations with version symlinks + - **Git Credential Manager**: Automatic detection and setup + - **Borg CLI**: Backup tool with smart version management + - **Smart Updates**: Only downloads when newer versions available - **Automatic Setup**: - Git repository initialization - - SSH key generation (if needed) + - SSH key generation and display - Tea CLI installation and configuration - Remote repository creation - Connection testing ## Usage -1. Make the script executable: - ```bash - chmod +x setup-git-repo.sh - ``` +```bash +# Interactive setup +./setup-git-repo.sh + +# With configuration file +echo '{"gitea": {"server_url": "https://your-gitea.com"}}' > config.json +./setup-git-repo.sh +``` + +## Available Installers + +### Tea CLI Installer +```bash +# Install latest Tea CLI +./install-tea-cli.sh + +# Install specific version +./install-tea-cli.sh -v v0.11.1 + +# Force reinstall +./install-tea-cli.sh --force +``` + +### Borg CLI Installer +```bash +# Install latest Borg CLI +./install-borg-cli.sh + +# Install specific version +./install-borg-cli.sh -v 1.4.2 + +# Force reinstall +./install-borg-cli.sh --force +``` + +### Git Credential Manager Installer +```bash +# Install latest GCM +./install-git-credential-manager.sh + +# Install specific version +./install-git-credential-manager.sh -v v2.6.1 + +# Force reinstall +./install-git-credential-manager.sh --force + +# Check configuration without installing +./install-git-credential-manager.sh --checks +``` + +## Installation Strategies + +All installers implement smart installation strategies: + +### User-Specific Installations (Preferred) +- **Location**: `~/bin/` directory +- **Requirements**: `~/bin` exists and is in PATH +- **Benefits**: No sudo required, user isolation, multiple versions +- **Structure**: + ``` + ~/bin/ + ├── tea -> tea-v0.11.1 # Active version + ├── tea-v0.11.0 # Previous version + └── tea-v0.11.1 # Current version + ``` + +### System-Wide Installations (Fallback) +- **Location**: `/usr/local/bin/` +- **Requirements**: sudo access +- **Benefits**: Available to all users +- **Structure**: + ``` + /usr/local/bin/ + ├── tea -> tea-v0.11.1 + ├── tea-v0.11.0 + └── tea-v0.11.1 + ``` + +### Version Management +- **Symlinks**: Automatic version switching +- **Multiple Versions**: Keep old versions for rollback +- **Smart Updates**: Only download when newer version available + +## Configuration + +The script supports JSON configuration for automation: + +```json +{ + "gitea": { + "server_url": "https://your-gitea.com", + "default_login_name": "$USER", + "login_method": "token", + "has_access_token": true, + "default_auth_method": "3" + }, + "git": { + "default_branch": "main", + "auto_init": false + }, + "ssh": { + "key_type": "ed25519", + "key_path": "~/.ssh/id_ed25519" + }, + "repository": { + "default_private": false, + "auto_add_files": false, + "auto_commit": false, + "auto_push": false + } +} +``` 2. Run the script: ```bash diff --git a/TEA_CLI_ADVANCED_README.md b/TEA_CLI_ADVANCED_README.md new file mode 100644 index 0000000..958226f --- /dev/null +++ b/TEA_CLI_ADVANCED_README.md @@ -0,0 +1,157 @@ +# Tea CLI Installer - Advanced Version Management + +## Enhanced Installation Strategy + +The Tea CLI installer now implements sophisticated version management with user-specific installations: + +### Installation Priority Order + +1. **User Bin Directory** (`~/bin`) - Preferred + - Checks if `~/bin` exists and is in PATH + - Installs binaries with version-specific names + - Creates symlinks for easy version switching + - Allows multiple versions side-by-side + +2. **System Installation** (`/usr/local/bin`) - Fallback + - Used when user bin is not available + - Requires sudo for system-wide installation + - Single version installation + +### Version Management Features + +#### Symlink-Based Version Control +```bash +~/bin/ +├── tea -> tea-v0.11.1 # Active version symlink +├── tea-v0.11.0 # Previous version +├── tea-v0.11.1 # Current version +└── tea-v0.12.0 # Future version (when available) +``` + +#### Automatic Updates +- Detects current version via symlink +- Downloads newer versions with version suffix +- Updates symlink to point to latest version +- Preserves old versions for rollback + +### Installation Strategies + +#### `user_install` - Fresh User Installation +- When Tea CLI not found in user bin +- Creates versioned binary and symlink +- No sudo required + +#### `user_update` - User Version Update +- When newer version available +- Downloads new version with suffix +- Updates symlink to new version +- Keeps old versions + +#### `user_upgrade` - User Upgrade (No Symlink) +- When existing binary found but no symlink +- Creates versioned structure +- Adds symlink management + +#### `system_install` - System Installation +- When user bin not available/in PATH +- Installs to `/usr/local/bin` +- Requires sudo privileges + +### Usage Examples + +#### Normal Usage (Auto-detects strategy) +```bash +./install-tea-cli.sh +# Detects user bin, checks versions, updates if needed +``` + +#### Force Binary Installation +```bash +./install-tea-cli.sh --force --binary +# Forces binary download regardless of current version +``` + +#### Check Current Status +```bash +./install-tea-cli.sh +# Shows current version and installation type +# Exits if no update needed +``` + +### Version Detection Logic + +1. **Check PATH**: Finds `tea` command location +2. **Installation Type**: Determines user vs system installation +3. **Symlink Check**: Detects version-specific symlinks +4. **Version Comparison**: Compares with latest release +5. **Strategy Selection**: Chooses appropriate installation method + +### Benefits + +✅ **User Isolation**: Installations don't affect other users +✅ **Version Control**: Multiple versions can coexist +✅ **Easy Updates**: Symlinks automatically point to latest +✅ **Rollback Support**: Old versions preserved +✅ **No Sudo Required**: User installations don't need root +✅ **System Fallback**: Falls back to system installation when needed + +### Directory Structure + +#### User Installation +``` +~/bin/ +├── tea -> tea-v0.11.1 +├── tea-v0.11.0 +└── tea-v0.11.1 +``` + +#### System Installation +``` +/usr/local/bin/ +├── tea -> tea-v0.11.1 +├── tea-v0.11.0 +└── tea-v0.11.1 +``` + +### PATH Requirements + +For user installations, ensure `~/bin` is in PATH: +```bash +# Add to ~/.bashrc or ~/.profile +export PATH="$HOME/bin:$PATH" +``` + +### Troubleshooting + +#### Version Not Updating +```bash +# Check current symlink +ls -la ~/bin/tea + +# Force reinstall +./install-tea-cli.sh --force +``` + +#### PATH Issues +```bash +# Check if user bin is in PATH +echo $PATH | grep -q "$HOME/bin" && echo "OK" || echo "Add to PATH" + +# Test tea command +which tea +tea --version +``` + +#### Permission Issues +```bash +# For system installation +sudo ./install-tea-cli.sh --binary +``` + +### Integration with Setup Script + +The installer integrates seamlessly with the main setup script: +- Automatically called when Tea CLI is needed +- Respects user preferences for installation location +- Provides clear feedback on installation strategy +- Handles both new installations and updates \ No newline at end of file diff --git a/TEA_CLI_INSTALLER_README.md b/TEA_CLI_INSTALLER_README.md new file mode 100644 index 0000000..7b9031b --- /dev/null +++ b/TEA_CLI_INSTALLER_README.md @@ -0,0 +1,196 @@ +# Tea CLI Installer + +A comprehensive installer script for Gitea Tea CLI that supports multiple Linux distributions and installation methods. + +## Features + +- **Version Checking**: Only downloads and installs if newer version is available +- **Multiple Installation Methods**: + - Package manager (apt, yum, dnf, zypper) + - Binary download from Gitea releases +- **Cross-Platform Support**: Debian, Ubuntu, RHEL, CentOS, Fedora, Arch, openSUSE +- **Architecture Support**: x86_64 (amd64), ARM64, ARM +- **Automatic Updates**: Fetches latest version from Gitea API +- **Force Reinstall**: Option to force reinstall even if up-to-date + +## Usage + +### Basic Usage +```bash +# Install latest version (only if newer than current) +./install-tea-cli.sh + +# Install specific version +./install-tea-cli.sh -v v0.11.0 + +# Force reinstall even if up-to-date +./install-tea-cli.sh --force +``` + +### Installation Methods +```bash +# Force installation from package manager +./install-tea-cli.sh --package + +# Force installation from binary +./install-tea-cli.sh --binary +``` + +### Help +```bash +./install-tea-cli.sh --help +``` + +## Installation Logic + +### Version Checking +1. **Check Current Version**: Detects installed Tea CLI version +2. **Fetch Latest**: Gets latest version from Gitea API +3. **Compare Versions**: Only proceeds if newer version available +4. **Force Override**: `--force` flag bypasses version check + +### Installation Priority +1. **Package Manager** (preferred): + - Debian/Ubuntu: Checks for official Tea CLI package + - RHEL/CentOS/Fedora: Checks for available Tea CLI package + - Arch Linux: Available in AUR (pacman) + - openSUSE: Checks for available Tea CLI package + +2. **Binary Download** (fallback): + - Downloads platform-specific binary from Gitea releases + - Supports x86_64, ARM64, ARM architectures + - Installs to `/usr/local/bin/tea` + +## File Locations + +### Installation Directory +- Binary: `/usr/local/bin/tea` +- Symlink: `/usr/local/bin/tea-` + +## Version Comparison + +The installer uses semantic version comparison: +- **Format**: `vX.Y.Z` (e.g., `v0.11.1`) +- **Logic**: Compares major, minor, patch versions +- **Build Info**: Ignores build hashes/identifiers + +### Examples +```bash +# Current: 0.11.0, Latest: v0.11.1 → Update needed +# Current: 0.11.1, Latest: v0.11.1 → No update needed +# Current: 0.11.2, Latest: v0.11.1 → No update needed (newer installed) +``` + +## System Requirements + +### Required +- `curl` or `wget` (for downloading) +- `sudo` access (for system-wide installation) + +### Optional +- Package manager access (for package installations) +- Internet connection (for downloading releases) + +## Supported Distributions + +### Package Manager Support +- **Debian/Ubuntu**: Checks for official Tea CLI package +- **RHEL/CentOS/Fedora**: Checks for available Tea CLI package +- **Arch Linux**: Available in AUR (pacman) +- **openSUSE**: Checks for available Tea CLI package + +### Binary Support +- **Linux x86_64**: `tea-0.11.1-linux-amd64` +- **Linux ARM64**: `tea-0.11.1-linux-arm64` +- **Linux ARM**: `tea-0.11.1-linux-arm-5`, `tea-0.11.1-linux-arm-6`, `tea-0.11.1-linux-arm-7` + +## Troubleshooting + +### Version Detection Issues +```bash +# Check current version manually +tea --version + +# Force reinstall if version detection fails +./install-tea-cli.sh --force +``` + +### Permission Issues +```bash +# Ensure proper permissions +sudo chown root:root /usr/local/bin/tea +sudo chmod 755 /usr/local/bin/tea +``` + +### PATH Issues +```bash +# Check which tea is being used +which tea + +# Check all tea installations +find /usr -name tea 2>/dev/null +find /home -name tea 2>/dev/null + +# Update PATH if needed +export PATH="/usr/local/bin:$PATH" +``` + +## Examples + +### Typical Workflow +```bash +# Check if update needed +./install-tea-cli.sh + +# Output if up-to-date: +# [SUCCESS] You already have the latest version (0.11.1) +# [SUCCESS] No installation needed. Exiting. + +# Output if update available: +# [INFO] Current version: 0.11.0 +# [INFO] Latest version: v0.11.1 +# [INFO] Newer version available: v0.11.1 > 0.11.0 +# [SUCCESS] Installation completed successfully! +``` + +### Force Binary Installation +```bash +# Force binary installation +./install-tea-cli.sh --force --binary + +# Output: +# [SUCCESS] Tea CLI binary installed successfully +# Next steps: +# 1. Test installation: tea --version +# 2. Configure login: tea login add +# 3. Use Tea CLI: tea --help +``` + +## Integration with Setup Script + +The Tea CLI installer is automatically integrated with the main Git repository setup script: + +1. **Detection**: Checks for existing Tea CLI installations +2. **Offer Installation**: Prompts to install Tea CLI if none found +3. **Configuration**: Guides through login setup +4. **Repository Management**: Enables Gitea repository operations + +## Security Features + +- **Official Releases**: Downloads from official Gitea releases +- **Package Verification**: Uses official package repositories +- **Proper Permissions**: Sets appropriate file ownership and permissions + +## Contributing + +To add support for new distributions or architectures: + +1. Update `detect_os()` function for new package managers +2. Add architecture detection in `get_arch()` function +3. Update installation methods in `install_tea_from_*()` functions +4. Test with target distribution +5. Update documentation + +## License + +This installer script follows the same license as Gitea Tea CLI (MIT). \ No newline at end of file diff --git a/credential-manager-demo.sh b/credential-manager-demo.sh new file mode 100755 index 0000000..15aa208 --- /dev/null +++ b/credential-manager-demo.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# Demo: Git Credential Manager in Console Mode +# This script demonstrates how credential managers work without GUI + +echo "=== Git Credential Manager Console Demo ===" +echo + +# Check available credential managers +echo "1. Checking available credential managers..." +if command -v git-credential-manager >/dev/null 2>&1; then + echo "✓ Git Credential Manager (GCM) found: $(git-credential-manager --version)" +else + echo "✗ Git Credential Manager not found" +fi + +if [[ "$OSTYPE" == "darwin"* ]]; then + if git config --global --get credential.helper 2>/dev/null | grep -q "osxkeychain"; then + echo "✓ macOS Keychain helper configured" + fi +elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + if command -v gnome-keyring-daemon >/dev/null 2>&1; then + echo "✓ GNOME Keyring available" + fi +fi + +echo +echo "2. Current Git credential configuration:" +git config --global --show-origin --get credential.helper 2>/dev/null || echo "No global credential helper configured" + +echo +echo "3. Testing credential storage (console mode)..." +echo "This demonstrates how credentials are stored/retrieved without GUI" + +# Create a test credential input +cat << 'EOF' | git credential-manager get 2>/dev/null || echo "Credential manager ready for input" +protocol=https +host=example.com +username=testuser +EOF + +echo +echo "4. How it works in console:" +echo " - First 'git push/pull' prompts for username/token" +echo " - Credential manager stores them securely" +echo " - Subsequent operations use stored credentials automatically" +echo " - No GUI required - all terminal-based" + +echo +echo "5. Available commands (all console-based):" +echo " git credential-manager configure # Configure settings" +echo " git credential-manager erase # Remove stored credentials" +echo " git credential-manager approve # Approve credential storage" +echo " git credential-manager reject # Reject credential storage" + +echo +echo "=== Demo Complete ===" \ No newline at end of file diff --git a/install-borg-cli.sh b/install-borg-cli.sh new file mode 100755 index 0000000..10c3137 --- /dev/null +++ b/install-borg-cli.sh @@ -0,0 +1,600 @@ +#!/bin/bash + +# Borg CLI Installer +# Downloads and installs the latest Borg CLI binary +# Supports multiple platforms and installation methods + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +GITHUB_REPO="borgbackup/borg" +USER_BIN_DIR="$HOME/bin" +SYSTEM_INSTALL_DIR="/usr/local/bin" +TEMP_DIR="/tmp/borg-install" + +# Function to print colored output +print_status() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to check if command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Function to detect OS and package manager +detect_os() { + if [[ -f /etc/os-release ]]; then + . /etc/os-release + OS="$ID" + OS_VERSION="$VERSION_ID" + else + print_error "Cannot detect operating system" + exit 1 + fi + + # Detect package manager + if command_exists apt; then + PKG_MANAGER="apt" + elif command_exists yum; then + PKG_MANAGER="yum" + elif command_exists dnf; then + PKG_MANAGER="dnf" + elif command_exists pacman; then + PKG_MANAGER="pacman" + elif command_exists zypper; then + PKG_MANAGER="zypper" + else + PKG_MANAGER="unknown" + fi + + print_status "Detected OS: $OS $OS_VERSION" + print_status "Package manager: $PKG_MANAGER" +} + +# Function to get system architecture +get_arch() { + ARCH=$(uname -m) + case $ARCH in + x86_64) + echo "x86_64" + ;; + aarch64|arm64) + echo "aarch64" + ;; + armv7l) + echo "armv7" + ;; + *) + print_error "Unsupported architecture: $ARCH" + exit 1 + ;; + esac +} + +# Function to get current installed version and location +get_current_version() { + if command_exists borg; then + CURRENT_VERSION=$(borg --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n 1) + if [[ -z "$CURRENT_VERSION" ]]; then + CURRENT_VERSION="unknown" + fi + + # Determine installation location + BORG_PATH=$(which borg) + if [[ "$BORG_PATH" == "$USER_BIN_DIR"* ]]; then + INSTALL_TYPE="user" + elif [[ "$BORG_PATH" == "/usr/local/bin"* ]] || [[ "$BORG_PATH" == "/usr/bin"* ]]; then + INSTALL_TYPE="system" + else + INSTALL_TYPE="other" + fi + else + CURRENT_VERSION="not_installed" + INSTALL_TYPE="none" + fi + echo "$CURRENT_VERSION:$INSTALL_TYPE" +} + +# Function to compare versions +compare_versions() { + local version1="$1" + local version2="$2" + + # Remove 'v' prefix if present + version1=${version1#v} + version2=${version2#v} + + # Split versions into arrays + IFS='.' read -ra V1 <<< "$version1" + IFS='.' read -ra V2 <<< "$version2" + + # Compare major, minor, patch + for i in {0..2}; do + local v1=${V1[$i]:-0} + local v2=${V2[$i]:-0} + + if (( v1 > v2 )); then + return 0 # version1 > version2 + elif (( v1 < v2 )); then + return 1 # version1 < version2 + fi + done + + return 0 # versions are equal +} + +# Function to get latest release info +get_latest_release() { + print_status "Fetching latest Borg CLI release information..." + + if command_exists curl; then + RELEASE_INFO=$(curl -s "https://api.github.com/repos/$GITHUB_REPO/releases/latest") + elif command_exists wget; then + RELEASE_INFO=$(wget -qO- "https://api.github.com/repos/$GITHUB_REPO/releases/latest") + else + print_error "curl or wget is required" + exit 1 + fi + + if [[ -z "$RELEASE_INFO" ]]; then + print_error "Failed to fetch release information" + exit 1 + fi + + # Extract version and download URLs + LATEST_VERSION=$(echo "$RELEASE_INFO" | grep -o '"tag_name": *"[^"]*"' | sed -E 's/.*"([^"]+)".*/\1/') + + if [[ -z "$LATEST_VERSION" ]]; then + print_error "Failed to parse release information" + exit 1 + fi + + print_success "Latest version: $LATEST_VERSION" +} + +# Function to check if update is needed +check_update_needed() { + local latest_version="$1" + local current_info=$(get_current_version) + local current_version=$(echo "$current_info" | cut -d: -f1) + local install_type=$(echo "$current_info" | cut -d: -f2) + + print_status "Current version: $current_version ($install_type)" + print_status "Latest version: $latest_version" + + if [[ "$current_version" == "not_installed" ]]; then + print_status "Borg CLI is not installed" + return 0 # Need to install + fi + + if [[ "$current_version" == "unknown" ]]; then + print_warning "Cannot determine current version, proceeding with update" + return 0 # Assume update needed + fi + + # Clean version strings for comparison + local clean_current="${current_version#v}" + local clean_latest="${latest_version#v}" + + if compare_versions "$clean_latest" "$clean_current"; then + if [[ "$clean_latest" == "$clean_current" ]]; then + print_success "You already have the latest version ($current_version)" + if [[ "$force_reinstall" == "true" ]]; then + print_status "Force reinstall requested, proceeding..." + return 0 + else + return 1 # No update needed + fi + else + print_status "Newer version available: $latest_version > $current_version" + return 0 # Update needed + fi + else + print_success "Your version ($current_version) is newer than latest release ($latest_version)" + return 1 # No update needed + fi +} + +# Function to download file +download_file() { + local url="$1" + local filename="$2" + + print_status "Downloading $filename..." + + if command_exists curl; then + curl -L -o "$TEMP_DIR/$filename" "$url" + elif command_exists wget; then + wget -O "$TEMP_DIR/$filename" "$url" + else + print_error "curl or wget is required" + exit 1 + fi + + if [[ ! -f "$TEMP_DIR/$filename" ]]; then + print_error "Failed to download $filename" + exit 1 + fi + + print_success "Downloaded $filename" +} + +# Function to check if user bin directory exists and is in PATH +check_user_bin_setup() { + if [[ ! -d "$USER_BIN_DIR" ]]; then + print_status "User bin directory doesn't exist" + return 1 + fi + + # Check if user bin is in PATH + if [[ ":$PATH:" != *":$USER_BIN_DIR:"* ]]; then + print_warning "User bin directory ($USER_BIN_DIR) is not in PATH" + print_status "Add to PATH: export PATH=\"$USER_BIN_DIR:\$PATH\"" + return 1 + fi + + return 0 +} + +# Function to check for version-specific symlink +check_version_symlink() { + local borg_path=$(which borg 2>/dev/null) + if [[ -z "$borg_path" ]]; then + return 1 + fi + + # Check if it's a symlink + if [[ -L "$borg_path" ]]; then + SYMLINK_TARGET=$(readlink "$borg_path") + # Extract version from symlink target + if [[ "$SYMLINK_TARGET" =~ borg-([0-9]+\.[0-9]+\.[0-9]+) ]]; then + CURRENT_SYMLINK_VERSION="${BASH_REMATCH[1]}" + return 0 + fi + fi + + return 1 +} + +# Function to determine installation strategy +determine_install_strategy() { + local current_info=$(get_current_version) + local current_version=$(echo "$current_info" | cut -d: -f1) + local install_type=$(echo "$current_info" | cut -d: -f2) + + # Strategy 1: Check user bin directory first + if check_user_bin_setup; then + print_status "User bin directory is available and in PATH" + + # Check if borg exists in user bin + if [[ -f "$USER_BIN_DIR/borg" ]]; then + print_status "Borg CLI found in user bin directory" + + # Check for version symlink + if check_version_symlink; then + print_status "Version symlink found: $CURRENT_SYMLINK_VERSION" + INSTALL_STRATEGY="user_update" + TARGET_DIR="$USER_BIN_DIR" + else + print_status "No version symlink found, will create one" + INSTALL_STRATEGY="user_upgrade" + TARGET_DIR="$USER_BIN_DIR" + fi + else + print_status "Borg CLI not found in user bin, will install there" + INSTALL_STRATEGY="user_install" + TARGET_DIR="$USER_BIN_DIR" + fi + else + print_status "User bin directory not available, using system installation" + INSTALL_STRATEGY="system_install" + TARGET_DIR="$SYSTEM_INSTALL_DIR" + fi + + print_status "Installation strategy: $INSTALL_STRATEGY" + print_status "Target directory: $TARGET_DIR" +} + +# Function to install Borg CLI from package manager +install_borg_from_package_manager() { + # Package manager installation only works for system-wide installation + if [[ "$INSTALL_STRATEGY" == user* ]]; then + print_status "Skipping package manager for user installation" + return 1 + fi + + print_status "Attempting to install Borg CLI from package manager..." + + case $PKG_MANAGER in + apt) + # Check if Borg CLI is available in official repositories + if apt-cache show borgbackup 2>/dev/null | grep -q "borg"; then + print_status "Installing Borg CLI from Ubuntu/Debian repositories..." + sudo apt install -y borgbackup + return 0 + else + print_warning "Borg CLI not available in Ubuntu/Debian repositories" + return 1 + fi + ;; + yum) + # Check if Borg CLI is available + if yum list available borgbackup 2>/dev/null | grep -q borgbackup; then + print_status "Installing Borg CLI from yum repositories..." + sudo yum install -y borgbackup + return 0 + else + print_warning "Borg CLI not available in yum repositories" + return 1 + fi + ;; + dnf) + # Check if Borg CLI is available + if dnf list available borgbackup 2>/dev/null | grep -q borgbackup; then + print_status "Installing Borg CLI from dnf repositories..." + sudo dnf install -y borgbackup + return 0 + else + print_warning "Borg CLI not available in dnf repositories" + return 1 + fi + ;; + pacman) + # Borg is available in Arch repositories + if pacman -Si borg 2>/dev/null | grep -q borg; then + print_status "Installing Borg CLI from pacman repositories..." + sudo pacman -S --noconfirm borg + return 0 + else + print_warning "Borg CLI not available in pacman repositories" + return 1 + fi + ;; + zypper) + # Check if Borg CLI is available + if zypper search -x borgbackup 2>/dev/null | grep -q borgbackup; then + print_status "Installing Borg CLI from zypper repositories..." + sudo zypper install -y borgbackup + return 0 + else + print_warning "Borg CLI not available in zypper repositories" + return 1 + fi + ;; + *) + print_warning "Package manager $PKG_MANAGER not supported for automatic installation" + return 1 + ;; + esac +} + +# Function to install Borg CLI from binary +install_borg_from_binary() { + local arch="$1" + local version="$2" + + # Borg uses different naming convention: borg-linux-glibc231-x86_64 + local binary_name="borg-linux-glibc231-$arch" + local download_url="https://github.com/$GITHUB_REPO/releases/download/$version/$binary_name" + + download_file "$download_url" "$binary_name" + + # Determine installation command based on target directory + local install_cmd="install -m 755" + local symlink_cmd="ln -sf" + + if [[ "$TARGET_DIR" == "$SYSTEM_INSTALL_DIR" ]]; then + install_cmd="sudo $install_cmd" + symlink_cmd="sudo $symlink_cmd" + fi + + print_status "Installing Borg CLI binary to $TARGET_DIR..." + + # Install the binary with version suffix + $install_cmd "$TEMP_DIR/$binary_name" "$TARGET_DIR/borg-$version" + + # Create/update symlink to point to this version + $symlink_cmd "$TARGET_DIR/borg-$version" "$TARGET_DIR/borg" + + print_success "Borg CLI binary installed successfully" + print_status "Version symlink: borg -> borg-$version" +} + +# Function to verify Borg CLI installation +verify_borg_installation() { + print_status "Verifying Borg CLI installation..." + + if command_exists borg; then + local version=$(borg --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n 1) + print_success "Borg CLI installed: $version" + return 0 + else + print_error "Borg CLI installation verification failed" + return 1 + fi +} + +# Function to cleanup +cleanup() { + if [[ -d "$TEMP_DIR" ]]; then + rm -rf "$TEMP_DIR" + print_status "Cleaned up temporary files" + fi +} + +# Function to show usage +show_usage() { + echo "Borg CLI Installer" + echo + echo "Usage: $0 [OPTIONS]" + echo + echo "Options:" + echo " -h, --help Show this help message" + echo " -v, --version Install specific version (default: latest)" + echo " -f, --force Force reinstall even if up-to-date" + echo " -p, --package Force installation from package manager" + echo " -b, --binary Force installation from binary" + echo + echo "Examples:" + echo " $0 # Install latest version using best method" + echo " $0 -v v1.2.7 # Install specific version" + echo " $0 --package # Force installation from package manager" + echo " $0 --binary # Force installation from binary" + echo +} + +# Main installation function +main() { + local target_version="" + local force_reinstall=false + local install_method="auto" + + # Parse command line arguments + while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_usage + exit 0 + ;; + -v|--version) + target_version="$2" + shift 2 + ;; + -f|--force) + force_reinstall=true + shift + ;; + -p|--package) + install_method="package" + shift + ;; + -b|--binary) + install_method="binary" + shift + ;; + *) + print_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac + done + + echo "========================================" + echo "Borg CLI Installer" + echo "========================================" + echo + + # Check if running as root for system installation + if [[ $EUID -ne 0 ]]; then + print_warning "Not running as root. Some operations may require sudo." + fi + + # Detect system + detect_os + ARCH=$(get_arch) + + # Get latest version if not specified + if [[ -z "$target_version" ]]; then + get_latest_release + target_version="$LATEST_VERSION" + else + print_status "Using specified version: $target_version" + fi + + # Determine installation strategy + determine_install_strategy + + # Check if update is needed + if ! check_update_needed "$target_version"; then + print_success "No installation needed. Exiting." + exit 0 + fi + + # Create temporary directory + mkdir -p "$TEMP_DIR" + + # Trap cleanup on exit + trap cleanup EXIT + + # Installation logic based on method and strategy + case $install_method in + auto) + # For user installations, prefer binary over package manager + if [[ "$INSTALL_STRATEGY" == user* ]]; then + print_status "Using binary installation for user directory" + install_borg_from_binary "$ARCH" "$target_version" + verify_borg_installation + else + # Try package manager first for system installations + if install_borg_from_package_manager; then + verify_borg_installation + else + install_borg_from_binary "$ARCH" "$target_version" + verify_borg_installation + fi + fi + ;; + package) + if ! install_borg_from_package_manager; then + print_error "Package manager installation failed" + exit 1 + fi + verify_borg_installation + ;; + binary) + install_borg_from_binary "$ARCH" "$target_version" + verify_borg_installation + ;; + esac + + # Installation completed successfully + echo + print_success "Installation completed successfully!" + echo + echo "Installation details:" + echo "- Strategy: $INSTALL_STRATEGY" + echo "- Location: $TARGET_DIR" + if [[ "$INSTALL_STRATEGY" == user* ]]; then + echo "- Binary: borg (symlink to borg-$target_version)" + echo "- Version: $target_version" + fi + echo + echo "Next steps:" + echo "1. Test installation: borg --version" + echo "2. Initialize repository: borg init --encryption=repokey /path/to/repo" + echo "3. Create backup: borg create /path/to/repo::backup-name /path/to/backup" + echo "4. Use Borg CLI: borg --help" + echo + if [[ "$INSTALL_STRATEGY" == user* ]]; then + echo "User-specific installation notes:" + echo "- Binary installed in: $USER_BIN_DIR" + echo "- Ensure $USER_BIN_DIR is in your PATH" + echo "- You can have multiple versions side-by-side" + fi + echo + echo "For more information, visit: https://borgbackup.readthedocs.io/" +} + +# Run main function +main "$@" \ No newline at end of file diff --git a/install-git-credential-manager.sh b/install-git-credential-manager.sh new file mode 100755 index 0000000..39ec267 --- /dev/null +++ b/install-git-credential-manager.sh @@ -0,0 +1,647 @@ +#!/bin/bash + +# Git Credential Manager Installer +# Supports Debian, Ubuntu, RHEL, CentOS, Fedora, and other Linux distributions +# Downloads and installs the latest version from GitHub releases + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +GITHUB_REPO="git-ecosystem/git-credential-manager" +INSTALL_DIR="/usr/local/bin" +TEMP_DIR="/tmp/gcm-install" + +# Function to print colored output +print_status() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to check if command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Function to detect OS and package manager +detect_os() { + if [[ -f /etc/os-release ]]; then + . /etc/os-release + OS="$ID" + OS_VERSION="$VERSION_ID" + else + print_error "Cannot detect operating system" + exit 1 + fi + + # Detect package manager + if command_exists apt; then + PKG_MANAGER="apt" + elif command_exists yum; then + PKG_MANAGER="yum" + elif command_exists dnf; then + PKG_MANAGER="dnf" + elif command_exists pacman; then + PKG_MANAGER="pacman" + elif command_exists zypper; then + PKG_MANAGER="zypper" + else + PKG_MANAGER="unknown" + fi + + print_status "Detected OS: $OS $OS_VERSION" + print_status "Package manager: $PKG_MANAGER" +} + +# Function to get system architecture +get_arch() { + ARCH=$(uname -m) + case $ARCH in + x86_64) + echo "amd64" + ;; + aarch64|arm64) + echo "arm64" + ;; + armv7l) + echo "arm" + ;; + *) + print_error "Unsupported architecture: $ARCH" + exit 1 + ;; + esac +} + +# Function to get current installed version +get_current_version() { + if command_exists git-credential-manager; then + # Extract version from output like "2.6.1+786ab03440ddc82e807a97c0e540f5247e44cec6" + local version_output=$(git-credential-manager --version 2>/dev/null) + CURRENT_VERSION=$(echo "$version_output" | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n 1) + if [[ -n "$CURRENT_VERSION" ]]; then + CURRENT_VERSION="v$CURRENT_VERSION" + else + CURRENT_VERSION="unknown" + fi + else + CURRENT_VERSION="not_installed" + fi + echo "$CURRENT_VERSION" +} + +# Function to compare versions (returns 0 if first >= second, 1 if first < second) +compare_versions() { + local version1="$1" + local version2="$2" + + # Remove 'v' prefix if present + version1=${version1#v} + version2=${version2#v} + + # Split versions into arrays + IFS='.' read -ra V1 <<< "$version1" + IFS='.' read -ra V2 <<< "$version2" + + # Compare major, minor, patch + for i in {0..2}; do + local v1=${V1[$i]:-0} + local v2=${V2[$i]:-0} + + if (( v1 > v2 )); then + return 0 # version1 > version2 + elif (( v1 < v2 )); then + return 1 # version1 < version2 + fi + done + + return 0 # versions are equal +} + +# Function to get latest release info +get_latest_release() { + print_status "Fetching latest release information..." + + if command_exists curl; then + RELEASE_INFO=$(curl -s "https://api.github.com/repos/$GITHUB_REPO/releases/latest") + elif command_exists wget; then + RELEASE_INFO=$(wget -qO- "https://api.github.com/repos/$GITHUB_REPO/releases/latest") + else + print_error "curl or wget is required" + exit 1 + fi + + if [[ -z "$RELEASE_INFO" ]]; then + print_error "Failed to fetch release information" + exit 1 + fi + + # Extract version and download URLs + LATEST_VERSION=$(echo "$RELEASE_INFO" | grep -o '"tag_name": *"[^"]*"' | sed -E 's/.*"([^"]+)".*/\1/') + + if [[ -z "$LATEST_VERSION" ]]; then + print_error "Failed to parse release information" + exit 1 + fi + + print_success "Latest version: $LATEST_VERSION" +} + +# Function to check if update is needed +check_update_needed() { + local current_version=$(get_current_version) + local latest_version="$1" + + print_status "Current version: $current_version" + print_status "Latest version: $latest_version" + + if [[ "$current_version" == "not_installed" ]]; then + print_status "git-credential-manager is not installed" + return 0 # Need to install + fi + + if [[ "$current_version" == "unknown" ]]; then + print_warning "Cannot determine current version, proceeding with update" + return 0 # Assume update needed + fi + + if compare_versions "$latest_version" "$current_version"; then + if [[ "$latest_version" == "$current_version" ]]; then + print_success "You already have the latest version ($current_version)" + if [[ "$force_reinstall" == "true" ]]; then + print_status "Force reinstall requested, proceeding..." + return 0 + else + return 1 # No update needed + fi + else + print_status "Newer version available: $latest_version > $current_version" + return 0 # Update needed + fi + else + print_success "Your version ($current_version) is newer than latest release ($latest_version)" + return 1 # No update needed + fi +} + +# Function to download file +download_file() { + local url="$1" + local filename="$2" + + print_status "Downloading $filename..." + + if command_exists curl; then + curl -L -o "$TEMP_DIR/$filename" "$url" + elif command_exists wget; then + wget -O "$TEMP_DIR/$filename" "$url" + else + print_error "curl or wget is required" + exit 1 + fi + + if [[ ! -f "$TEMP_DIR/$filename" ]]; then + print_error "Failed to download $filename" + exit 1 + fi + + print_success "Downloaded $filename" +} + +# Function to install from package manager +install_from_package_manager() { + print_status "Attempting to install from package manager..." + + case $PKG_MANAGER in + apt) + # Check if git-credential-manager is available in repos + if apt-cache show git-credential-manager >/dev/null 2>&1; then + print_status "Installing git-credential-manager from apt repository..." + sudo apt update + sudo apt install -y git-credential-manager + return 0 + else + print_warning "git-credential-manager not available in apt repositories" + return 1 + fi + ;; + yum|dnf) + # Check EPEL repositories for RHEL/CentOS/Fedora + if command_exists git-credential-manager; then + print_success "git-credential-manager is already installed" + return 0 + else + print_warning "git-credential-manager not available in $PKG_MANAGER repositories" + return 1 + fi + ;; + pacman) + # Arch Linux has git-credential-manager in community repo + if pacman -Si git-credential-manager >/dev/null 2>&1; then + print_status "Installing git-credential-manager from pacman repository..." + sudo pacman -S --noconfirm git-credential-manager + return 0 + else + print_warning "git-credential-manager not available in pacman repositories" + return 1 + fi + ;; + *) + print_warning "Package manager $PKG_MANAGER not supported for automatic installation" + return 1 + ;; + esac +} + +# Function to install from DEB package +install_from_deb() { + local arch="$1" + local version="$2" + + local deb_name="gcm-linux_${arch}.${version#v}.deb" + local download_url="https://github.com/$GITHUB_REPO/releases/download/$version/$deb_name" + + download_file "$download_url" "$deb_name" + + print_status "Installing DEB package..." + sudo dpkg -i "$TEMP_DIR/$deb_name" || { + print_warning "dpkg failed, attempting to fix dependencies..." + sudo apt-get install -f -y + } + + print_success "DEB package installed successfully" +} + +# Function to install from tar.gz +install_from_tarball() { + local arch="$1" + local version="$2" + + local tar_name="gcm-linux_${arch}.${version#v}.tar.gz" + local download_url="https://github.com/$GITHUB_REPO/releases/download/$version/$tar_name" + + download_file "$download_url" "$tar_name" + + print_status "Extracting tarball..." + cd "$TEMP_DIR" + tar -xzf "$tar_name" + + # Check if binary was extracted directly + if [[ -f "git-credential-manager" ]]; then + print_status "Installing binary to $INSTALL_DIR..." + sudo install -m 755 git-credential-manager "$INSTALL_DIR/git-credential-manager" + sudo ln -sf "$INSTALL_DIR/git-credential-manager" "$INSTALL_DIR/git-credential-manager-core" + + # Install shared libraries if present + for lib in lib*.so; do + if [[ -f "$lib" ]]; then + sudo install -m 644 "$lib" "$INSTALL_DIR/" + print_status "Installed library: $lib" + fi + done + else + # Try to find extracted directory (fallback) + local extracted_dir=$(find . -maxdepth 1 -type d -name "git-credential-manager*" | head -n 1) + if [[ -z "$extracted_dir" ]]; then + print_error "Could not find git-credential-manager binary after extraction" + exit 1 + fi + + cd "$extracted_dir" + print_status "Installing binary to $INSTALL_DIR..." + sudo install -m 755 git-credential-manager "$INSTALL_DIR/git-credential-manager" + sudo ln -sf "$INSTALL_DIR/git-credential-manager" "$INSTALL_DIR/git-credential-manager-core" + fi + + print_success "Binary installed successfully" +} + +# Function to check and configure Git presets +configure_git_presets() { + print_status "Checking and configuring Git presets..." + + local presets_configured=0 + local presets_needed=() + + # Check global credential helper + local current_helper="" + current_helper=$(git config --global --get credential.helper 2>/dev/null) || current_helper="" + if [[ "$current_helper" == "manager" ]] || [[ "$current_helper" == "git-credential-manager" ]]; then + print_success "✓ Global credential helper: $current_helper" + presets_configured=$((presets_configured + 1)) + else + print_warning "✗ Global credential helper not set to manager" + presets_needed+=("git config --global credential.helper manager") + fi + + # Check GitHub-specific configuration + local github_helper="" + github_helper=$(git config --global --get credential.https://github.com.helper 2>/dev/null) || github_helper="" + if [[ -n "$github_helper" ]]; then + print_success "✓ GitHub credential helper configured ($github_helper)" + presets_configured=$((presets_configured + 1)) + else + print_warning "✗ GitHub credential helper not configured" + presets_needed+=("git config --global credential.https://github.com.helper manager") + fi + + # Check GitLab-specific configuration + local gitlab_helper="" + gitlab_helper=$(git config --global --get credential.https://gitlab.com.helper 2>/dev/null) || gitlab_helper="" + if [[ -n "$gitlab_helper" ]]; then + print_success "✓ GitLab credential helper configured" + presets_configured=$((presets_configured + 1)) + else + print_warning "✗ GitLab credential helper not configured" + presets_needed+=("git config --global credential.https://gitlab.com.helper manager") + fi + + # Check Azure DevOps configuration + local azure_useHttpPath="" + azure_useHttpPath=$(git config --global --get credential.https://dev.azure.com.useHttpPath 2>/dev/null) || azure_useHttpPath="" + if [[ "$azure_useHttpPath" == "true" ]]; then + print_success "✓ Azure DevOps useHttpPath configured" + presets_configured=$((presets_configured + 1)) + else + print_warning "✗ Azure DevOps useHttpPath not configured" + presets_needed+=("git config --global credential.https://dev.azure.com.useHttpPath true") + fi + + # Check Bitbucket configuration + local bitbucket_helper="" + bitbucket_helper=$(git config --global --get credential.https://bitbucket.org.helper 2>/dev/null) || bitbucket_helper="" + if [[ -n "$bitbucket_helper" ]]; then + print_success "✓ Bitbucket credential helper configured" + presets_configured=$((presets_configured + 1)) + else + print_warning "✗ Bitbucket credential helper not configured" + presets_needed+=("git config --global credential.https://bitbucket.org.helper manager") + fi + + # Check Gitea configuration (if any Gitea URL is configured) + local gitea_urls=0 + gitea_urls=$(git config --global --get-regexp "credential.*gitea.*helper" 2>/dev/null | wc -l) || gitea_urls=0 + if [[ $gitea_urls -gt 0 ]]; then + print_success "✓ Gitea credential helpers configured ($gitea_urls found)" + presets_configured=$((presets_configured + 1)) + else + print_warning "✗ No Gitea credential helpers configured" + presets_needed+=("# For Gitea servers, configure domain-specific helper:") + presets_needed+=("git config --global credential.https://go-gitea.mywire.org.helper manager") + fi + + # Summary + echo + print_status "Git Credential Manager Configuration Summary:" + print_status "Presets configured: $presets_configured/6" + + if [[ ${#presets_needed[@]} -eq 0 ]]; then + print_success "All recommended presets are configured!" + echo + print_status "Your Git Credential Manager is fully configured and ready to use." + echo "When you run Git commands that require authentication, GCM will:" + echo "1. Prompt for credentials on first use" + echo "2. Securely store them in your system's credential store" + echo "3. Automatically provide them for subsequent operations" + else + print_warning "Some presets need to be configured manually." + echo + print_status "Run these commands to complete the configuration:" + for cmd in "${presets_needed[@]}"; do + echo " $cmd" + done + echo + print_status "After configuring, test with:" + echo " git config --global --list | grep credential" + fi + + return 0 +} + +# Function to verify installation +verify_installation() { + print_status "Verifying installation..." + + if command_exists git-credential-manager; then + local version=$(git-credential-manager --version 2>/dev/null || echo "unknown") + print_success "git-credential-manager installed: $version" + + # Configure basic Git settings + print_status "Configuring basic Git settings..." + git config --global credential.helper manager + print_success "Basic Git configuration completed" + + # Check all presets + configure_git_presets + + return 0 + else + print_error "git-credential-manager installation verification failed" + return 1 + fi +} + +# Function to cleanup +cleanup() { + if [[ -d "$TEMP_DIR" ]]; then + rm -rf "$TEMP_DIR" + print_status "Cleaned up temporary files" + fi +} + +# Function to show usage +show_usage() { + echo "Git Credential Manager Installer" + echo + echo "Usage: $0 [OPTIONS]" + echo + echo "Options:" + echo " -h, --help Show this help message" + echo " -v, --version Install specific version (default: latest)" + echo " -f, --force Force reinstall even if already installed" + echo " -p, --package Force installation from package manager" + echo " -d, --deb Force installation from DEB package" + echo " -t, --tarball Force installation from tarball" + echo " -c, --checks Check Git credential configuration without installing" + echo + echo "Examples:" + echo " $0 # Install latest version using best method" + echo " $0 -v v2.6.0 # Install specific version" + echo " $0 --package # Force installation from package manager" + echo " $0 --deb # Force installation from DEB package" + echo " $0 --checks # Check configuration without installing" +} + +# Function to run configuration checks only +run_checks_only() { + echo "========================================" + echo "Git Credential Manager Configuration Check" + echo "========================================" + echo + + # Check if GCM is installed + if ! command_exists git-credential-manager; then + print_error "Git Credential Manager is not installed" + echo + print_status "To install Git Credential Manager, run:" + echo " $0" + echo + print_status "Or to check configuration after installation:" + echo " $0 --checks" + exit 1 + fi + + # Run configuration checks + configure_git_presets + + echo + print_success "Configuration check completed!" +} + +# Main installation function +main() { + local target_version="" + local force_reinstall=false + local install_method="auto" + local checks_only=false + + # Parse command line arguments + while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_usage + exit 0 + ;; + -v|--version) + target_version="$2" + shift 2 + ;; + -f|--force) + force_reinstall=true + shift + ;; + -p|--package) + install_method="package" + shift + ;; + -d|--deb) + install_method="deb" + shift + ;; + -t|--tarball) + install_method="tarball" + shift + ;; + -c|--checks) + checks_only=true + shift + ;; + *) + print_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac + done + + # If checks only, run checks and exit + if [[ "$checks_only" == "true" ]]; then + run_checks_only + exit 0 + fi + + echo "========================================" + echo "Git Credential Manager Installer" + echo "========================================" + echo + + # Get latest version if not specified + if [[ -z "$target_version" ]]; then + get_latest_release + target_version="$LATEST_VERSION" + else + print_status "Using specified version: $target_version" + fi + + # Check if update is needed + if ! check_update_needed "$target_version"; then + print_success "No installation needed. Exiting." + exit 0 + fi + + # Detect system + detect_os + ARCH=$(get_arch) + + # Create temporary directory + mkdir -p "$TEMP_DIR" + + # Trap cleanup on exit + trap cleanup EXIT + + # Installation logic based on method + case $install_method in + auto) + # Try package manager first + if install_from_package_manager; then + verify_installation + exit 0 + fi + + # Fall back to distribution-specific methods + case $OS in + ubuntu|debian|linuxmint) + install_from_deb "$ARCH" "$target_version" + ;; + *) + install_from_tarball "$ARCH" "$target_version" + ;; + esac + ;; + package) + if ! install_from_package_manager; then + print_error "Package manager installation failed" + exit 1 + fi + ;; + deb) + install_from_deb "$ARCH" "$target_version" + ;; + tarball) + install_from_tarball "$ARCH" "$target_version" + ;; + esac + + # Verify installation + if verify_installation; then + echo + print_success "Installation completed successfully!" + echo + print_status "Test the installation:" + echo " git-credential-manager --version" + echo " git config --global --list | grep credential" + else + print_error "Installation failed" + exit 1 + fi +} + +# Run main function +main "$@" \ No newline at end of file diff --git a/install-tea-cli.sh b/install-tea-cli.sh new file mode 100755 index 0000000..385f28a --- /dev/null +++ b/install-tea-cli.sh @@ -0,0 +1,583 @@ +#!/bin/bash + +# Tea CLI Installer +# Downloads and installs the latest Tea CLI binary +# Supports multiple platforms and installation methods + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +GITEA_REPO="gitea.com/gitea/tea" +USER_BIN_DIR="$HOME/bin" +SYSTEM_INSTALL_DIR="/usr/local/bin" +TEMP_DIR="/tmp/tea-install" + +# Function to print colored output +print_status() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to check if command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Function to detect OS and package manager +detect_os() { + if [[ -f /etc/os-release ]]; then + . /etc/os-release + OS="$ID" + OS_VERSION="$VERSION_ID" + else + print_error "Cannot detect operating system" + exit 1 + fi + + # Detect package manager + if command_exists apt; then + PKG_MANAGER="apt" + elif command_exists yum; then + PKG_MANAGER="yum" + elif command_exists dnf; then + PKG_MANAGER="dnf" + elif command_exists pacman; then + PKG_MANAGER="pacman" + elif command_exists zypper; then + PKG_MANAGER="zypper" + else + PKG_MANAGER="unknown" + fi + + print_status "Detected OS: $OS $OS_VERSION" + print_status "Package manager: $PKG_MANAGER" +} + +# Function to get system architecture +get_arch() { + ARCH=$(uname -m) + case $ARCH in + x86_64) + echo "amd64" + ;; + aarch64|arm64) + echo "arm64" + ;; + armv7l) + echo "arm" + ;; + *) + print_error "Unsupported architecture: $ARCH" + exit 1 + ;; + esac +} + +# Function to get current installed version and location +get_current_version() { + if command_exists tea; then + CURRENT_VERSION=$(tea --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n 1) + if [[ -z "$CURRENT_VERSION" ]]; then + CURRENT_VERSION="unknown" + fi + + # Determine installation location + TEA_PATH=$(which tea) + if [[ "$TEA_PATH" == "$USER_BIN_DIR"* ]]; then + INSTALL_TYPE="user" + elif [[ "$TEA_PATH" == "/usr/local/bin"* ]] || [[ "$TEA_PATH" == "/usr/bin"* ]]; then + INSTALL_TYPE="system" + else + INSTALL_TYPE="other" + fi + else + CURRENT_VERSION="not_installed" + INSTALL_TYPE="none" + fi + echo "$CURRENT_VERSION:$INSTALL_TYPE" +} + +# Function to check if user bin directory exists and is in PATH +check_user_bin_setup() { + if [[ ! -d "$USER_BIN_DIR" ]]; then + print_status "User bin directory doesn't exist" + return 1 + fi + + # Check if user bin is in PATH + if [[ ":$PATH:" != *":$USER_BIN_DIR:"* ]]; then + print_warning "User bin directory ($USER_BIN_DIR) is not in PATH" + print_status "Add to PATH: export PATH=\"$USER_BIN_DIR:\$PATH\"" + return 1 + fi + + return 0 +} + +# Function to check for version-specific symlink +check_version_symlink() { + local tea_path=$(which tea 2>/dev/null) + if [[ -z "$tea_path" ]]; then + return 1 + fi + + # Check if it's a symlink + if [[ -L "$tea_path" ]]; then + SYMLINK_TARGET=$(readlink "$tea_path") + # Extract version from symlink target + if [[ "$SYMLINK_TARGET" =~ tea-(v?[0-9]+\.[0-9]+\.[0-9]+) ]]; then + CURRENT_SYMLINK_VERSION="${BASH_REMATCH[1]}" + return 0 + fi + fi + + return 1 +} + +# Function to determine installation strategy +determine_install_strategy() { + local current_info=$(get_current_version) + local current_version=$(echo "$current_info" | cut -d: -f1) + local install_type=$(echo "$current_info" | cut -d: -f2) + + # Strategy 1: Check user bin directory first + if check_user_bin_setup; then + print_status "User bin directory is available and in PATH" + + # Check if tea exists in user bin + if [[ -f "$USER_BIN_DIR/tea" ]]; then + print_status "Tea CLI found in user bin directory" + + # Check for version symlink + if check_version_symlink; then + print_status "Version symlink found: $CURRENT_SYMLINK_VERSION" + INSTALL_STRATEGY="user_update" + TARGET_DIR="$USER_BIN_DIR" + else + print_status "No version symlink found, will create one" + INSTALL_STRATEGY="user_upgrade" + TARGET_DIR="$USER_BIN_DIR" + fi + else + print_status "Tea CLI not found in user bin, will install there" + INSTALL_STRATEGY="user_install" + TARGET_DIR="$USER_BIN_DIR" + fi + else + print_status "User bin directory not available, using system installation" + INSTALL_STRATEGY="system_install" + TARGET_DIR="$SYSTEM_INSTALL_DIR" + fi + + print_status "Installation strategy: $INSTALL_STRATEGY" + print_status "Target directory: $TARGET_DIR" +} + +# Function to compare versions +compare_versions() { + local version1="$1" + local version2="$2" + + # Remove 'v' prefix if present + version1=${version1#v} + version2=${version2#v} + + # Split versions into arrays + IFS='.' read -ra V1 <<< "$version1" + IFS='.' read -ra V2 <<< "$version2" + + # Compare major, minor, patch + for i in {0..2}; do + local v1=${V1[$i]:-0} + local v2=${V2[$i]:-0} + + if (( v1 > v2 )); then + return 0 # version1 > version2 + elif (( v1 < v2 )); then + return 1 # version1 < version2 + fi + done + + return 0 # versions are equal +} + +# Function to get latest release info +get_latest_release() { + print_status "Fetching latest Tea CLI release information..." + + if command_exists curl; then + RELEASE_INFO=$(curl -s "https://gitea.com/api/v1/repos/gitea/tea/releases/latest") + elif command_exists wget; then + RELEASE_INFO=$(wget -qO- "https://gitea.com/api/v1/repos/gitea/tea/releases/latest") + else + print_error "curl or wget is required" + exit 1 + fi + + if [[ -z "$RELEASE_INFO" ]]; then + print_error "Failed to fetch release information" + exit 1 + fi + + # Extract version and download URLs + LATEST_VERSION=$(echo "$RELEASE_INFO" | grep -o '"tag_name": *"[^"]*"' | sed -E 's/.*"([^"]+)".*/\1/') + + if [[ -z "$LATEST_VERSION" ]]; then + print_error "Failed to parse release information" + exit 1 + fi + + print_success "Latest version: $LATEST_VERSION" +} + +# Function to check if update is needed +check_update_needed() { + local latest_version="$1" + local current_info=$(get_current_version) + local current_version=$(echo "$current_info" | cut -d: -f1) + local install_type=$(echo "$current_info" | cut -d: -f2) + + print_status "Current version: $current_version ($install_type)" + print_status "Latest version: $latest_version" + + if [[ "$current_version" == "not_installed" ]]; then + print_status "Tea CLI is not installed" + return 0 # Need to install + fi + + if [[ "$current_version" == "unknown" ]]; then + print_warning "Cannot determine current version, proceeding with update" + return 0 # Assume update needed + fi + + # Clean version strings for comparison + local clean_current="${current_version#v}" + local clean_latest="${latest_version#v}" + + if compare_versions "$clean_latest" "$clean_current"; then + if [[ "$clean_latest" == "$clean_current" ]]; then + print_success "You already have the latest version ($current_version)" + if [[ "$force_reinstall" == "true" ]]; then + print_status "Force reinstall requested, proceeding..." + return 0 + else + return 1 # No update needed + fi + else + print_status "Newer version available: $latest_version > $current_version" + return 0 # Update needed + fi + else + print_success "Your version ($current_version) is newer than latest release ($latest_version)" + return 1 # No update needed + fi +} + +# Function to download file +download_file() { + local url="$1" + local filename="$2" + + print_status "Downloading $filename..." + + if command_exists curl; then + curl -L -o "$TEMP_DIR/$filename" "$url" + elif command_exists wget; then + wget -O "$TEMP_DIR/$filename" "$url" + else + print_error "curl or wget is required" + exit 1 + fi + + if [[ ! -f "$TEMP_DIR/$filename" ]]; then + print_error "Failed to download $filename" + exit 1 + fi + + print_success "Downloaded $filename" +} + +# Function to install Tea CLI from package manager +install_tea_from_package_manager() { + # Package manager installation only works for system-wide installation + if [[ "$INSTALL_STRATEGY" == user* ]]; then + print_status "Skipping package manager for user installation" + return 1 + fi + + print_status "Attempting to install Tea CLI from package manager..." + + case $PKG_MANAGER in + apt) + # Add Gitea repository if not present + if ! grep -q "https://dl.gitea.com/gitea/gpg.key" /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null; then + print_status "Adding Gitea repository..." + curl -fsSL https://dl.gitea.com/gitea/gpg.key | sudo apt-key add - + echo "deb https://dl.gitea.com/gitea/ gitea main" | sudo tee /etc/apt/sources.list.d/gitea.list + sudo apt update + fi + + sudo apt install -y tea + return 0 + ;; + yum) + # Add Gitea repository + print_status "Adding Gitea repository..." + sudo yum-config-manager --add-repo https://dl.gitea.com/gitea/RPM/GPG.KEY + sudo yum-config-manager --add-repo https://dl.gitea.com/gitea/yum/ gitea + sudo yum install -y tea + return 0 + ;; + dnf) + # Add Gitea repository + print_status "Adding Gitea repository..." + sudo dnf config-manager --add-repo https://dl.gitea.com/gitea/RPM/GPG.KEY + sudo dnf config-manager --add-repo https://dl.gitea.com/gitea/yum/ gitea + sudo dnf install -y tea + return 0 + ;; + pacman) + # Tea CLI is in AUR + print_warning "Tea CLI is available in AUR. Consider using 'yay -S tea' or 'pacaur -S tea'" + return 1 + ;; + zypper) + print_status "Adding Gitea repository..." + sudo zypper addrepo -G https://dl.gitea.com/gitea/RPM/GPG.KEY + sudo zypper addrepo https://dl.gitea.com/gitea/yum/ gitea + sudo zypper install -y tea + return 0 + ;; + *) + print_warning "Package manager $PKG_MANAGER not supported for automatic installation" + return 1 + ;; + esac +} + +# Function to install Tea CLI from binary +install_tea_from_binary() { + local arch="$1" + local version="$2" + + local binary_name="tea-${version#v}-linux-${arch}" + local download_url="https://gitea.com/gitea/tea/releases/download/$version/$binary_name" + + download_file "$download_url" "$binary_name" + + # Determine installation command based on target directory + local install_cmd="install -m 755" + local symlink_cmd="ln -sf" + + if [[ "$TARGET_DIR" == "$SYSTEM_INSTALL_DIR" ]]; then + install_cmd="sudo $install_cmd" + symlink_cmd="sudo $symlink_cmd" + fi + + print_status "Installing Tea CLI binary to $TARGET_DIR..." + + # Install the binary with version suffix + $install_cmd "$TEMP_DIR/$binary_name" "$TARGET_DIR/tea-$version" + + # Create/update symlink to point to this version + $symlink_cmd "$TARGET_DIR/tea-$version" "$TARGET_DIR/tea" + + print_success "Tea CLI binary installed successfully" + print_status "Version symlink: tea -> tea-$version" +} + +# Function to verify Tea CLI installation +verify_tea_installation() { + print_status "Verifying Tea CLI installation..." + + if command_exists tea; then + local version=$(tea --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n 1) + print_success "Tea CLI installed: $version" + return 0 + else + print_error "Tea CLI installation verification failed" + return 1 + fi +} + +# Function to cleanup +cleanup() { + if [[ -d "$TEMP_DIR" ]]; then + rm -rf "$TEMP_DIR" + print_status "Cleaned up temporary files" + fi +} + +# Function to show usage +show_usage() { + echo "Tea CLI Installer" + echo + echo "Usage: $0 [OPTIONS]" + echo + echo "Options:" + echo " -h, --help Show this help message" + echo " -v, --version Install specific version (default: latest)" + echo " -f, --force Force reinstall even if up-to-date" + echo " -p, --package Force installation from package manager" + echo " -b, --binary Force installation from binary" + echo + echo "Examples:" + echo " $0 # Install latest version using best method" + echo " $0 -v v0.10.0 # Install specific version" + echo " $0 --package # Force installation from package manager" + echo " $0 --binary # Force installation from binary" + echo +} + +# Main installation function +main() { + local target_version="" + local force_reinstall=false + local install_method="auto" + + # Parse command line arguments + while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_usage + exit 0 + ;; + -v|--version) + target_version="$2" + shift 2 + ;; + -f|--force) + force_reinstall=true + shift + ;; + -p|--package) + install_method="package" + shift + ;; + -b|--binary) + install_method="binary" + shift + ;; + *) + print_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac + done + + echo "========================================" + echo "Tea CLI Installer" + echo "========================================" + echo + + # Check if running as root for system installation + if [[ $EUID -ne 0 ]]; then + print_warning "Not running as root. Some operations may require sudo." + fi + + # Detect system + detect_os + ARCH=$(get_arch) + + # Get latest version if not specified + if [[ -z "$target_version" ]]; then + get_latest_release + target_version="$LATEST_VERSION" + else + print_status "Using specified version: $target_version" + fi + + # Determine installation strategy + determine_install_strategy + + # Check if update is needed + if ! check_update_needed "$target_version"; then + print_success "No installation needed. Exiting." + exit 0 + fi + + # Create temporary directory + mkdir -p "$TEMP_DIR" + + # Trap cleanup on exit + trap cleanup EXIT + + # Installation logic based on method and strategy + case $install_method in + auto) + # For user installations, prefer binary over package manager + if [[ "$INSTALL_STRATEGY" == user* ]]; then + print_status "Using binary installation for user directory" + install_tea_from_binary "$ARCH" "$target_version" + verify_tea_installation + else + # Try package manager first for system installations + if install_tea_from_package_manager; then + verify_tea_installation + else + install_tea_from_binary "$ARCH" "$target_version" + verify_tea_installation + fi + fi + ;; + package) + if ! install_tea_from_package_manager; then + print_error "Package manager installation failed" + exit 1 + fi + verify_tea_installation + ;; + binary) + install_tea_from_binary "$ARCH" "$target_version" + verify_tea_installation + ;; + esac + + # Installation completed successfully + echo + print_success "Installation completed successfully!" + echo + echo "Installation details:" + echo "- Strategy: $INSTALL_STRATEGY" + echo "- Location: $TARGET_DIR" + if [[ "$INSTALL_STRATEGY" == user* ]]; then + echo "- Binary: tea (symlink to tea-$target_version)" + echo "- Version: $target_version" + fi + echo + echo "Next steps:" + echo "1. Test installation: tea --version" + echo "2. Configure login: tea login add" + echo "3. Use Tea CLI: tea --help" + echo + if [[ "$INSTALL_STRATEGY" == user* ]]; then + echo "User-specific installation notes:" + echo "- Binary installed in: $USER_BIN_DIR" + echo "- Ensure $USER_BIN_DIR is in your PATH" + echo "- You can have multiple versions side-by-side" + fi + echo + echo "For more information, visit: https://gitea.com/gitea/tea" +} + +# Run main function +main "$@" \ No newline at end of file diff --git a/setup-git-repo.sh b/setup-git-repo.sh index d570c49..f3f3ac6 100755 --- a/setup-git-repo.sh +++ b/setup-git-repo.sh @@ -38,6 +38,91 @@ command_exists() { command -v "$1" >/dev/null 2>&1 } +# Function to install Git Credential Manager if needed +install_credential_manager() { + local script_dir="$(dirname "$0")" + local installer="$script_dir/install-git-credential-manager.sh" + + if [[ -f "$installer" ]]; then + print_status "Running Git Credential Manager installer..." + "$installer" + return $? + else + print_warning "Git Credential Manager installer not found at $installer" + return 1 + fi +} + +# Function to install Tea CLI if needed +install_tea_cli() { + local script_dir="$(dirname "$0")" + local installer="$script_dir/install-tea-cli.sh" + + if [[ -f "$installer" ]]; then + print_status "Running Tea CLI installer..." + "$installer" + return $? + else + print_warning "Tea CLI installer not found at $installer" + return 1 + fi +} + +# Function to detect and configure credential manager +setup_credential_manager() { + print_status "Checking for Git credential managers..." + + local credential_helper="" + + # Check for Git Credential Manager (GCM) + if command_exists git-credential-manager; then + credential_helper="manager" + print_success "Found Git Credential Manager" + # Check for platform-specific helpers + elif [[ "$OSTYPE" == "darwin"* ]] && git config --global --get credential.helper 2>/dev/null | grep -q "osxkeychain"; then + credential_helper="osxkeychain" + print_success "Found macOS Keychain credential helper" + elif [[ "$OSTYPE" == "linux-gnu"* ]] && command_exists gnome-keyring-daemon; then + credential_helper="/usr/share/doc/git/contrib/credential/gnome-keyring/git-credential-gnome-keyring" + print_success "Found GNOME Keyring" + # Fallback to generic manager + elif git config --global --get credential.helper >/dev/null 2>&1; then + credential_helper=$(git config --global --get credential.helper) + print_success "Using existing credential helper: $credential_helper" + else + print_warning "No credential manager found" + + # Offer to install Git Credential Manager + echo + read -p "Would you like to install Git Credential Manager for secure credential storage? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + if install_credential_manager; then + credential_helper="manager" + print_success "Git Credential Manager installed successfully" + else + print_warning "Failed to install Git Credential Manager" + return 1 + fi + else + print_warning "Continuing without credential manager - you will be prompted for credentials" + return 1 + fi + fi + + # Configure credential helper for the specific Gitea instance + if [[ -n "$GITEA_URL" ]]; then + local domain=$(echo "$GITEA_URL" | sed 's|https://||' | sed 's|http://||') + git config --global credential."https://$domain".helper "$credential_helper" + print_success "Configured credential manager for $domain" + else + git config --global credential.helper "$credential_helper" + print_success "Configured global credential manager" + fi + + return 0 +} + # Function to validate input validate_input() { if [[ -z "$1" ]]; then @@ -113,73 +198,71 @@ setup_ssh_key() { # Function to setup tea CLI setup_tea() { - print_status "Setting up tea CLI..." - + print_status "Setting up Tea CLI..." + if ! command_exists tea; then - print_status "Installing tea CLI..." - - # Detect OS and install tea - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - # Linux - if command_exists apt; then - # Try to install from package manager first - sudo apt update && sudo apt install -y tea || { - print_warning "tea not available in package manager, installing from binary..." - curl -sL https://dl.gitea.com/tea/latest/tea-linux-amd64 -o /tmp/tea - chmod +x /tmp/tea - sudo mv /tmp/tea /usr/local/bin/tea - } - elif command_exists yum; then - sudo yum install -y tea || { - print_warning "tea not available in package manager, installing from binary..." - curl -sL https://dl.gitea.com/tea/latest/tea-linux-amd64 -o /tmp/tea - chmod +x /tmp/tea - sudo mv /tmp/tea /usr/local/bin/tea - } - elif command_exists pacman; then - sudo pacman -S --noconfirm tea || { - print_warning "tea not available in package manager, installing from binary..." - curl -sL https://dl.gitea.com/tea/latest/tea-linux-amd64 -o /tmp/tea - chmod +x /tmp/tea - sudo mv /tmp/tea /usr/local/bin/tea - } + print_warning "Tea CLI is not installed" + + # Offer to install Tea CLI + echo + read -p "Would you like to install Tea CLI for Gitea repository management? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + if install_tea_cli; then + print_success "Tea CLI installed successfully" else - # Generic Linux installation - curl -sL https://dl.gitea.com/tea/latest/tea-linux-amd64 -o /tmp/tea - chmod +x /tmp/tea - sudo mv /tmp/tea /usr/local/bin/tea - fi - elif [[ "$OSTYPE" == "darwin"* ]]; then - # macOS - if command_exists brew; then - brew install tea - else - print_error "Homebrew not found. Please install Homebrew first." - exit 1 + print_error "Failed to install Tea CLI" + return 1 fi else - print_error "Unsupported OS for automatic tea installation" - exit 1 + print_warning "Continuing without Tea CLI - you can install it later with ./install-tea-cli.sh" + return 1 fi - - print_success "tea CLI installed successfully" else - print_success "tea CLI is already installed" + print_success "Tea CLI is already installed" fi - + # Configure tea login with presets - print_status "Configuring tea login..." - + print_status "Configuring Tea CLI login..." + # Use defaults from config if available local tea_url="${GITEA_URL:-$GITEA_URL}" local tea_method="${LOGIN_METHOD:-token}" local tea_has_token="${HAS_ACCESS_TOKEN:-true}" - + echo "Using preset configuration:" echo "- URL: $tea_url" echo "- Method: $tea_method" echo "- Has token: $tea_has_token" echo + + # Check for existing logins + print_status "Checking existing Tea CLI logins..." + if tea logins 2>/dev/null | grep -q "No logins"; then + echo "No existing logins found. Creating new login..." + tea login add + else + echo "Existing logins found:" + tea logins + echo + read -p "Do you want to use an existing login? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + read -p "Enter the name of the existing login to use: " existing_login + if tea logins | grep -q "$existing_login"; then + print_success "Using existing login: $existing_login" + # Set the existing login as default for this session + export TEA_LOGIN="$existing_login" + else + print_warning "Login '$existing_login' not found. Creating new login..." + tea login add + fi + else + echo "Creating new login..." + tea login add + fi + fi +} # Check for existing logins print_status "Checking existing tea logins..." @@ -383,8 +466,8 @@ main() { echo echo "Choose authentication method:" - echo "1) SSH (recommended - passwordless after setup)" - echo "2) HTTPS (may prompt for password/token)" + echo "1) SSH (recommended - passwordless after key setup)" + echo "2) HTTPS with credential manager (secure, stores tokens)" echo "3) Tea CLI (creates repo via API)" # Use default auth method from config if available @@ -410,8 +493,23 @@ main() { 2) AUTH_METHOD="https" print_status "HTTPS authentication selected" + + # Setup credential manager for passwordless authentication + if setup_credential_manager; then + print_success "Credential manager configured for passwordless HTTPS access" + echo "You will be prompted for credentials on first use, then they will be stored securely." + else + print_warning "No credential manager available. You will be prompted for credentials each time." + echo "Consider installing git-credential-manager for secure credential storage." + fi + REMOTE_URL="$GITEA_URL/$GITEA_USERNAME/$REPO_NAME.git" - print_warning "Make sure you have an access token or will be prompted for credentials" + echo + echo "HTTPS Authentication Setup:" + echo "1. Generate a Personal Access Token in Gitea: User Settings → Applications" + echo "2. Use your username and the access token when prompted" + echo "3. Credentials will be stored securely by your credential manager" + echo ;; 3) AUTH_METHOD="tea" @@ -454,6 +552,11 @@ main() { echo "SSH setup reminder:" echo "- Make sure your SSH public key is added to your Gitea account" echo "- SSH key location: $HOME/.ssh/id_ed25519.pub" + elif [[ "$AUTH_METHOD" == "https" ]]; then + echo "HTTPS setup reminder:" + echo "- Use your Personal Access Token as password when prompted" + echo "- Credentials are stored securely by your credential manager" + echo "- Generate tokens at: $GITEA_URL/user/settings/applications" fi }