updated readme
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# Stage 1: Build stage
|
||||
FROM alpine:3.19 AS builder
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache build-base git openssh-client curl bash
|
||||
|
||||
# Install Rclone (statically compiled binary for Alpine)
|
||||
RUN curl -O https://downloads.rclone.org/rclone-current-linux-amd64.zip && unzip rclone-current-linux-amd64.zip && mv rclone-*-linux-amd64/rclone /usr/bin/ && rm -rf rclone-*-linux-amd64 rclone-current-linux-amd64.zip
|
||||
|
||||
# Stage 2: Runtime stage
|
||||
FROM alpine:3.19
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache git openssh-client bash inotify-tools ca-certificates
|
||||
|
||||
# Copy Rclone from the builder stage
|
||||
COPY --from=builder /usr/bin/rclone /usr/bin/rclone
|
||||
|
||||
# Set up SSH directory and permissions
|
||||
RUN mkdir -p /root/.ssh && chmod 700 /root/.ssh
|
||||
|
||||
# Copy entrypoint script
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /repos
|
||||
|
||||
# Define volumes for configuration, secrets, and logs
|
||||
VOLUME /config/git-sync
|
||||
VOLUME /repos/local
|
||||
VOLUME /logs
|
||||
|
||||
# Entrypoint
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD []
|
||||
@@ -0,0 +1,425 @@
|
||||
# Git-Sync Mirror Agent
|
||||
|
||||
**Git-Sync** is a containerized mirroring agent designed to watch a local Git repository and propagate changes to multiple remote repositories with high reliability, auditability, and fault recovery. It supports mirroring to platforms like GitHub, Forgejo, Radicle, Internet Archive, and Web3.storage, ensuring your repository is resiliently backed up across diverse infrastructure. Git-Sync is a key component of the `fold-stack` project, emphasizing sovereignty and fieldcraft-resilient design.
|
||||
|
||||
---
|
||||
|
||||
## 📜 Overview
|
||||
|
||||
Git-Sync operates as a Docker container that:
|
||||
|
||||
- Watches a local Git repository for changes.
|
||||
- Syncs changes to multiple configured remotes (GitHub, Forgejo, Radicle, Internet Archive, Web3.storage).
|
||||
- Ensures atomicity using lockfiles.
|
||||
- Logs all operations for auditability.
|
||||
- Implements failure recovery with retries and exponential backoff.
|
||||
- Operates independently of commercial SaaS infrastructure.
|
||||
|
||||
### Supported Remotes
|
||||
- **GitHub**: Push via SSH.
|
||||
- **Forgejo**: Push via SSH to a self-hosted instance.
|
||||
- **Radicle**: Peer-to-peer Git (placeholder, requires `rad` CLI implementation).
|
||||
- **Internet Archive**: Git bundles uploaded via Rclone.
|
||||
- **Web3.storage**: Git bundles uploaded via Rclone (optional).
|
||||
- **Extendable**: Can be extended to support S3, IPFS, Sia, etc.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Prerequisites
|
||||
|
||||
Before setting up Git-Sync, ensure you have the following:
|
||||
|
||||
- **Docker** and **Docker Compose** installed.
|
||||
- Install Docker: [Official Docker Installation Guide](https://docs.docker.com/get-docker/)
|
||||
- Install Docker Compose: [Official Docker Compose Installation Guide](https://docs.docker.com/compose/install/)
|
||||
- **Git** installed for managing the local repository.
|
||||
- Install Git: [Official Git Installation Guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
||||
- A local Git repository to mirror (e.g., `volumes/repos` in `fold-stack`).
|
||||
- SSH keys for GitHub and Forgejo.
|
||||
- Rclone configured for Internet Archive and Web3.storage (if using these remotes).
|
||||
- A machine with at least 2GB of RAM (Git-Sync is lightweight but depends on `fold-stack` requirements).
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Setup Instructions
|
||||
|
||||
### 1. Clone the `fold-stack` Repository
|
||||
|
||||
Git-Sync is part of the `fold-stack` project. Clone the repository if you haven’t already:
|
||||
|
||||
\`\`\`bash
|
||||
git clone https://github.com/mrhavens/fold-stack.git
|
||||
cd fold-stack
|
||||
\`\`\`
|
||||
|
||||
### 2. Initialize a Local Git Repository
|
||||
|
||||
Git-Sync watches a local repository at `volumes/repos`. Initialize it if it doesn’t exist:
|
||||
|
||||
\`\`\`bash
|
||||
mkdir -p volumes/repos
|
||||
cd volumes/repos
|
||||
git init
|
||||
echo "# Test Repo" > README.md
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
git branch -M main
|
||||
cd ../..
|
||||
\`\`\`
|
||||
|
||||
### 3. Generate SSH Keys for GitHub and Forgejo
|
||||
|
||||
Git-Sync uses SSH keys to authenticate with GitHub and Forgejo.
|
||||
|
||||
#### 3.1 Generate SSH Key for GitHub
|
||||
\`\`\`bash
|
||||
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/github_key
|
||||
\`\`\`
|
||||
|
||||
#### 3.2 Generate SSH Key for Forgejo
|
||||
\`\`\`bash
|
||||
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/forgejo_key
|
||||
\`\`\`
|
||||
|
||||
- Press Enter to skip setting a passphrase, or set one for added security.
|
||||
- This creates `~/.ssh/github_key` and `~/.ssh/forgejo_key` (private keys) and their `.pub` counterparts (public keys).
|
||||
|
||||
### 4. Configure SSH Keys on GitHub and Forgejo
|
||||
|
||||
#### 4.1 Add SSH Key to GitHub
|
||||
1. Copy the public key:
|
||||
\`\`\`bash
|
||||
cat ~/.ssh/github_key.pub
|
||||
\`\`\`
|
||||
2. Go to [GitHub](https://github.com) > **Settings** > **SSH and GPG keys** > **New SSH key**.
|
||||
3. Title: `fold-stack-git-sync`.
|
||||
4. Key type: **Authentication Key**.
|
||||
5. Key: Paste the public key.
|
||||
6. Click **Add SSH key**.
|
||||
7. Test the connection:
|
||||
\`\`\`bash
|
||||
ssh -i ~/.ssh/github_key -T git@github.com
|
||||
\`\`\`
|
||||
You should see: `Hi mrhavens! You've successfully authenticated...`.
|
||||
|
||||
#### 4.2 Add SSH Key to Forgejo
|
||||
1. Copy the public key:
|
||||
\`\`\`bash
|
||||
cat ~/.ssh/forgejo_key.pub
|
||||
\`\`\`
|
||||
2. Access Forgejo at `http://localhost:3000` (ensure Forgejo is running via `fold-stack`).
|
||||
3. Go to **Settings** > **SSH / GPG Keys** > **Add Key**.
|
||||
4. Name: `fold-stack-git-sync`.
|
||||
5. Content: Paste the public key.
|
||||
6. Click **Add Key**.
|
||||
7. Test the connection:
|
||||
\`\`\`bash
|
||||
ssh -i ~/.ssh/forgejo_key -p 2222 -T git@localhost
|
||||
\`\`\`
|
||||
You should see a success message.
|
||||
|
||||
### 5. Configure Rclone for Internet Archive and Web3.storage
|
||||
|
||||
Git-Sync uses Rclone to sync Git bundles to Internet Archive and Web3.storage.
|
||||
|
||||
1. Run the Rclone configuration wizard:
|
||||
\`\`\`bash
|
||||
rclone config
|
||||
\`\`\`
|
||||
2. Add the following remotes:
|
||||
- **Internet Archive (`ia`)**:
|
||||
- Choose `n` (new remote).
|
||||
- Name: `ia`
|
||||
- Type: `internetarchive`.
|
||||
- Access Key ID: Your Internet Archive access key (from archive.org account settings).
|
||||
- Secret Access Key: Your Internet Archive secret key.
|
||||
- Edit Advanced Config: `n`.
|
||||
- **Web3.storage (`web3`)**:
|
||||
- Choose `n` (new remote).
|
||||
- Name: `web3`
|
||||
- Type: `ipfs`.
|
||||
- Host: `api.web3.storage`.
|
||||
- API Token: Your Web3.storage API token (from web3.storage).
|
||||
- Edit Advanced Config: `n`.
|
||||
3. Copy the Rclone configuration to the project:
|
||||
\`\`\`bash
|
||||
mkdir -p config/rclone
|
||||
cp ~/.config/rclone/rclone.conf config/rclone/rclone.conf
|
||||
chmod 600 config/rclone/rclone.conf
|
||||
\`\`\`
|
||||
4. Copy to `git-sync` config:
|
||||
\`\`\`bash
|
||||
mkdir -p config/git-sync
|
||||
cp config/rclone/rclone.conf config/git-sync/rclone.conf
|
||||
\`\`\`
|
||||
|
||||
### 6. Copy SSH Keys to `git-sync` Configuration
|
||||
|
||||
Copy the private keys to the `git-sync` secrets directory:
|
||||
|
||||
\`\`\`bash
|
||||
mkdir -p config/git-sync/secrets
|
||||
cp ~/.ssh/github_key config/git-sync/secrets/github.key
|
||||
cp ~/.ssh/forgejo_key config/git-sync/secrets/forgejo.key
|
||||
chmod 600 config/git-sync/secrets/github.key config/git-sync/secrets/forgejo.key
|
||||
\`\`\`
|
||||
|
||||
### 7. Configure `remotes.conf`
|
||||
|
||||
Edit `config/git-sync/remotes.conf` to specify the remotes to sync to. Example:
|
||||
|
||||
\`\`\`
|
||||
github|git|git@github.com:mrhavens/mirror-repo.git|1
|
||||
forgejo|git|git@localhost:2222/mrhavens/mirror-repo.git|1
|
||||
radicle|radicle|radicle://mrhavens/mirror-repo|1
|
||||
ia|rclone|ia:fold-stack-git-mirror|1
|
||||
web3|rclone|web3:fold-stack-git-mirror|0
|
||||
\`\`\`
|
||||
|
||||
- **Format**: `remote_name|type|url|enabled` (1 for enabled, 0 for disabled).
|
||||
- **Example Explanation**:
|
||||
- `github`: Syncs to `mrhavens/mirror-repo` on GitHub via SSH.
|
||||
- `forgejo`: Syncs to `mrhavens/mirror-repo` on your local Forgejo instance (port 2222).
|
||||
- `radicle`: Placeholder for Radicle (not implemented).
|
||||
- `ia`: Syncs Git bundles to `fold-stack-git-mirror` on Internet Archive via Rclone.
|
||||
- `web3`: Syncs Git bundles to `fold-stack-git-mirror` on Web3.storage (disabled by default).
|
||||
|
||||
### 8. Configure Push Rules (`rules.json`)
|
||||
|
||||
Edit `config/git-sync/rules.json` to define which branches to sync:
|
||||
|
||||
\`\`\`json
|
||||
{
|
||||
"branches": ["main", "dev"],
|
||||
"exclude_tags": ["v*"]
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
- **Example Explanation**:
|
||||
- Syncs only the `main` and `dev` branches.
|
||||
- Excludes tags starting with `v` (e.g., `v1.0`).
|
||||
|
||||
**Note**: The current implementation syncs all branches (`branches: ["*"]`) and doesn’t exclude tags. Update `entrypoint.sh` to enforce these rules if needed.
|
||||
|
||||
### 9. Configure Environment Variables (`.env`)
|
||||
|
||||
Edit `config/git-sync/.env` to set runtime options:
|
||||
|
||||
\`\`\`
|
||||
SYNC_INTERVAL=300
|
||||
PUSH_MODE=push
|
||||
SIGN_COMMITS=false
|
||||
LOG_LEVEL=INFO
|
||||
RETRY_MAX=3
|
||||
RETRY_BACKOFF=5
|
||||
\`\`\`
|
||||
|
||||
- **Example Explanation**:
|
||||
- `SYNC_INTERVAL=300`: Check for changes every 300 seconds (5 minutes).
|
||||
- `PUSH_MODE=push`: Use `git push` for Git remotes (alternative: `bundle` for Git bundles).
|
||||
- `SIGN_COMMITS=false`: Disable GPG commit signing (placeholder).
|
||||
- `LOG_LEVEL=INFO`: Log all messages (alternative: `ERROR` for errors only).
|
||||
- `RETRY_MAX=3`: Retry failed syncs up to 3 times.
|
||||
- `RETRY_BACKOFF=5`: Wait 5 seconds (exponential increase) between retries.
|
||||
|
||||
### 10. Start the `git-sync` Service
|
||||
|
||||
Git-Sync is integrated into `fold-stack`’s `docker-compose.dev.yml`. Start the service:
|
||||
|
||||
\`\`\`bash
|
||||
cd fold-stack
|
||||
./scripts/up-dev.sh
|
||||
\`\`\`
|
||||
|
||||
This starts all `fold-stack` services, including `git-sync`.
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Usage
|
||||
|
||||
### 1. Add a Commit to the Local Repository
|
||||
|
||||
Make changes to the local repository and commit them:
|
||||
|
||||
\`\`\`bash
|
||||
cd volumes/repos
|
||||
echo "New feature" >> README.md
|
||||
git add .
|
||||
git commit -m "Added new feature"
|
||||
\`\`\`
|
||||
|
||||
### 2. Wait for Automated Sync
|
||||
|
||||
Git-Sync will detect changes within `SYNC_INTERVAL` (default: 300 seconds) and sync to all enabled remotes. Monitor the logs:
|
||||
|
||||
\`\`\`bash
|
||||
docker logs git_sync_dev --follow
|
||||
\`\`\`
|
||||
|
||||
### 3. Manually Trigger a Sync
|
||||
|
||||
To sync immediately, use the manual push script:
|
||||
|
||||
\`\`\`bash
|
||||
./scripts/manual-push-git-sync.sh
|
||||
\`\`\`
|
||||
|
||||
### 4. Verify Sync
|
||||
|
||||
- **GitHub**: Check `https://github.com/mrhavens/mirror-repo`.
|
||||
- **Forgejo**: Check `http://localhost:3000/mrhavens/mirror-repo`.
|
||||
- **Internet Archive**: Check `fold-stack-git-mirror` on archive.org.
|
||||
- **Web3.storage**: Enable in `remotes.conf` and check `fold-stack-git-mirror`.
|
||||
|
||||
### 5. Generate a Sync Report
|
||||
|
||||
View the latest sync activity for each remote:
|
||||
|
||||
\`\`\`bash
|
||||
./scripts/report-git-sync.sh
|
||||
\`\`\`
|
||||
|
||||
**Example Output**:
|
||||
\`\`\`
|
||||
=================================
|
||||
📊 GIT-SYNC SYNC REPORT
|
||||
=================================
|
||||
📅 Date: Mon May 26 22:41:00 CDT 2025
|
||||
|
||||
---------------------------------
|
||||
📌 Local Repository Latest Commit
|
||||
---------------------------------
|
||||
Commit: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
Message: Added new feature
|
||||
Time: Mon May 26 22:40:00 CDT 2025
|
||||
|
||||
---------------------------------
|
||||
📌 Latest Sync Activity by Remote
|
||||
---------------------------------
|
||||
Remote: github (git, git@github.com:mrhavens/mirror-repo.git)
|
||||
Last Synced Commit: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
Commit Message: Added new feature
|
||||
Timestamp: [Mon May 26 22:41:00 CDT 2025]
|
||||
✅ Status: Successfully synced
|
||||
|
||||
Remote: forgejo (git, git@localhost:2222/mrhavens/mirror-repo.git)
|
||||
Last Synced Commit: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
Commit Message: Added new feature
|
||||
Timestamp: [Mon May 26 22:41:01 CDT 2025]
|
||||
✅ Status: Successfully synced
|
||||
|
||||
Remote: ia (rclone, ia:fold-stack-git-mirror)
|
||||
Last Synced Bundle: repo-1716777660.bundle
|
||||
Timestamp: [Mon May 26 22:41:02 CDT 2025]
|
||||
✅ Status: Successfully synced
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Troubleshooting
|
||||
|
||||
### 1. Run Diagnostics
|
||||
|
||||
If sync fails, run the diagnostic script:
|
||||
|
||||
\`\`\`bash
|
||||
./scripts/diagnose-git-sync.sh
|
||||
\`\`\`
|
||||
|
||||
**Example Output**:
|
||||
\`\`\`
|
||||
=================================
|
||||
🩺 GIT-SYNC COMPREHENSIVE DIAGNOSTICS
|
||||
=================================
|
||||
📅 Date: Mon May 26 22:41:00 CDT 2025
|
||||
|
||||
---------------------------------
|
||||
📌 SSH Keys Check
|
||||
---------------------------------
|
||||
✅ /config/git-sync/secrets/github.key exists.
|
||||
✅ /config/git-sync/secrets/github.key has correct permissions (600).
|
||||
✅ /config/git-sync/secrets/forgejo.key exists.
|
||||
✅ /config/git-sync/secrets/forgejo.key has correct permissions (600).
|
||||
|
||||
---------------------------------
|
||||
📌 Remote Connectivity Test
|
||||
---------------------------------
|
||||
Testing github (git)...
|
||||
✅ github connectivity test passed.
|
||||
Testing forgejo (git)...
|
||||
✅ forgejo connectivity test passed.
|
||||
Testing ia (rclone)...
|
||||
❌ ia connectivity test failed. Check rclone.conf or credentials.
|
||||
\`\`\`
|
||||
|
||||
### 2. Common Issues and Fixes
|
||||
|
||||
- **Container Not Running**:
|
||||
\`\`\`bash
|
||||
./scripts/down-dev.sh && ./scripts/up-dev.sh
|
||||
\`\`\`
|
||||
- **SSH Key Issues**:
|
||||
- Verify permissions: `chmod 600 config/git-sync/secrets/*`.
|
||||
- Test connectivity: `ssh -i ~/.ssh/github_key -T git@github.com`.
|
||||
- **Rclone Remote Fails**:
|
||||
- Reconfigure Rclone: `rclone config`.
|
||||
- Verify remotes: `rclone listremotes --config config/git-sync/rclone.conf`.
|
||||
- **Logs Missing**:
|
||||
- Check volume permissions: `chmod -R 775 volumes/logs && chown -R 1000:1000 volumes/logs`.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Advanced Configuration
|
||||
|
||||
### 1. Enable Web3.storage Sync
|
||||
|
||||
Edit `config/git-sync/remotes.conf` to enable Web3.storage:
|
||||
|
||||
\`\`\`
|
||||
web3|rclone|web3:fold-stack-git-mirror|1
|
||||
\`\`\`
|
||||
|
||||
### 2. Add a New Remote (e.g., S3)
|
||||
|
||||
Add a new remote to `remotes.conf` using Rclone:
|
||||
|
||||
\`\`\`
|
||||
s3|rclone|s3:fold-stack-git-mirror|1
|
||||
\`\`\`
|
||||
|
||||
Configure the `s3` remote in `config/git-sync/rclone.conf` using `rclone config`.
|
||||
|
||||
### 3. Adjust Sync Interval
|
||||
|
||||
Edit `config/git-sync/.env` to change the sync interval:
|
||||
|
||||
\`\`\`
|
||||
SYNC_INTERVAL=60 # Check every 60 seconds
|
||||
\`\`\`
|
||||
|
||||
Restart the service:
|
||||
|
||||
\`\`\`bash
|
||||
docker compose -f docker-compose.dev.yml stop git-sync
|
||||
docker compose -f docker-compose.dev.yml up -d git-sync
|
||||
\`\`\`
|
||||
|
||||
### 4. Enable Commit Signing (Future Feature)
|
||||
|
||||
To enable GPG commit signing (not yet implemented), set:
|
||||
|
||||
\`\`\`
|
||||
SIGN_COMMITS=true
|
||||
\`\`\`
|
||||
|
||||
You’ll need to:
|
||||
- Add GPG keys to the container.
|
||||
- Update `entrypoint.sh` to sign commits using `git`.
|
||||
|
||||
---
|
||||
|
||||
## 📅 Last Updated
|
||||
|
||||
This README was last updated on **May 26, 2025, at 10:41 PM CDT**.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,188 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Load environment variables
|
||||
if [ -f "/config/git-sync/.env" ]; then
|
||||
set -a
|
||||
source /config/git-sync/.env
|
||||
set +a
|
||||
else
|
||||
echo "ERROR: /config/git-sync/.env not found. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure required directories exist
|
||||
mkdir -p /logs /repos/local /root/.ssh
|
||||
|
||||
# Set up SSH keys
|
||||
if [ -f "/config/git-sync/secrets/github.key" ]; then
|
||||
cp /config/git-sync/secrets/github.key /root/.ssh/github.key
|
||||
chmod 600 /root/.ssh/github.key
|
||||
echo "Host github.com" >> /root/.ssh/config
|
||||
echo " HostName github.com" >> /root/.ssh/config
|
||||
echo " User git" >> /root/.ssh/config
|
||||
echo " IdentityFile /root/.ssh/github.key" >> /root/.ssh/config
|
||||
echo " StrictHostKeyChecking no" >> /root/.ssh/config
|
||||
else
|
||||
echo "WARNING: GitHub SSH key not found. GitHub sync will fail."
|
||||
fi
|
||||
|
||||
if [ -f "/config/git-sync/secrets/forgejo.key" ]; then
|
||||
cp /config/git-sync/secrets/forgejo.key /root/.ssh/forgejo.key
|
||||
chmod 600 /root/.ssh/forgejo.key
|
||||
echo "Host localhost" >> /root/.ssh/config
|
||||
echo " HostName localhost" >> /root/.ssh/config
|
||||
echo " Port 2222" >> /root/.ssh/config
|
||||
echo " User git" >> /root/.ssh/config
|
||||
echo " IdentityFile /root/.ssh/forgejo.key" >> /root/.ssh/config
|
||||
echo " StrictHostKeyChecking no" >> /root/.ssh/config
|
||||
else
|
||||
echo "WARNING: Forgejo SSH key not found. Forgejo sync will fail."
|
||||
fi
|
||||
|
||||
# Initialize log file
|
||||
LOG_FILE="/logs/sync-1748312796.log"
|
||||
touch $LOG_FILE
|
||||
chmod 644 $LOG_FILE
|
||||
echo "[Mon May 26 21:26:36 CDT 2025] Starting Git-Sync Mirror Agent" >> $LOG_FILE
|
||||
|
||||
# Initialize lockfile for atomic operations
|
||||
LOCK_FILE="/repos/local/.git-sync.lock"
|
||||
touch $LOCK_FILE
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level=$1
|
||||
local message=$2
|
||||
echo "[Mon May 26 21:26:36 CDT 2025] [$level] $message" >> $LOG_FILE
|
||||
if [ "$level" = "INFO" ] && [ "$LOG_LEVEL" = "INFO" ]; then
|
||||
echo "[Mon May 26 21:26:36 CDT 2025] [$level] $message"
|
||||
elif [ "$level" = "ERROR" ]; then
|
||||
echo "[Mon May 26 21:26:36 CDT 2025] [$level] $message" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to execute with lock
|
||||
execute_with_lock() {
|
||||
exec 100>$LOCK_FILE
|
||||
flock 100
|
||||
$@
|
||||
exec 100>&-
|
||||
}
|
||||
|
||||
# Function to detect changes in the local repository
|
||||
detect_changes() {
|
||||
log_message "INFO" "Checking for changes in local repository..."
|
||||
cd /repos/local
|
||||
if [ ! -d ".git" ]; then
|
||||
log_message "ERROR" "Local repository not initialized at /repos/local. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
git fetch origin
|
||||
LOCAL_HEAD=a5c6bd121cf013dd10b9340800be591bff7cb7b2
|
||||
REMOTE_HEAD=a5c6bd121cf013dd10b9340800be591bff7cb7b2
|
||||
if [ "$LOCAL_HEAD" != "$REMOTE_HEAD" ]; then
|
||||
log_message "INFO" "Changes detected: Local HEAD $LOCAL_HEAD, Remote HEAD $REMOTE_HEAD"
|
||||
CHANGES_FOUND=true
|
||||
else
|
||||
log_message "INFO" "No changes detected."
|
||||
CHANGES_FOUND=false
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to sign commits (placeholder, requires GPG setup)
|
||||
sign_commits_if_enabled() {
|
||||
if [ "$SIGN_COMMITS" = "true" ]; then
|
||||
log_message "INFO" "Commit signing enabled but not implemented. Skipping."
|
||||
# TODO: Implement GPG signing
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to sync to a Git remote (GitHub/Forgejo)
|
||||
sync_to_git_remote() {
|
||||
local remote_name=$1
|
||||
local url=$2
|
||||
log_message "INFO" "Syncing to $remote_name at $url..."
|
||||
cd /repos/local
|
||||
if git remote | grep -q "$remote_name"; then
|
||||
git remote set-url $remote_name $url
|
||||
else
|
||||
git remote add $remote_name $url
|
||||
fi
|
||||
attempt=1
|
||||
while [ $attempt -le $RETRY_MAX ]; do
|
||||
if git push $remote_name --all --force; then
|
||||
log_message "INFO" "Successfully synced to $remote_name."
|
||||
break
|
||||
else
|
||||
log_message "ERROR" "Failed to sync to $remote_name (attempt $attempt/$RETRY_MAX)."
|
||||
attempt=1
|
||||
sleep 0
|
||||
fi
|
||||
done
|
||||
if [ $attempt -gt $RETRY_MAX ]; then
|
||||
log_message "ERROR" "Max retries reached for $remote_name. Giving up."
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to sync to Radicle
|
||||
sync_to_radicle() {
|
||||
local remote_name=$1
|
||||
local url=$2
|
||||
log_message "INFO" "Syncing to Radicle at $url..."
|
||||
# Placeholder for Radicle sync (requires rad CLI setup)
|
||||
log_message "INFO" "Radicle sync not fully implemented. Skipping."
|
||||
# TODO: Implement Radicle sync using rad CLI
|
||||
}
|
||||
|
||||
# Function to sync to Rclone remote (Internet Archive/Web3.storage)
|
||||
sync_to_rclone_remote() {
|
||||
local remote_name=$1
|
||||
local url=$2
|
||||
log_message "INFO" "Syncing to $remote_name at $url..."
|
||||
# Create a Git bundle
|
||||
cd /repos/local
|
||||
BUNDLE_FILE="/tmp/repo-1748312796.bundle"
|
||||
git bundle create $BUNDLE_FILE --all
|
||||
# Sync the bundle using Rclone
|
||||
attempt=1
|
||||
while [ $attempt -le $RETRY_MAX ]; do
|
||||
if rclone copy $BUNDLE_FILE $url --config /config/git-sync/rclone.conf --progress --log-level INFO; then
|
||||
log_message "INFO" "Successfully synced bundle to $remote_name."
|
||||
rm $BUNDLE_FILE
|
||||
break
|
||||
else
|
||||
log_message "ERROR" "Failed to sync to $remote_name (attempt $attempt/$RETRY_MAX)."
|
||||
attempt=1
|
||||
sleep 0
|
||||
fi
|
||||
done
|
||||
if [ $attempt -gt $RETRY_MAX ]; then
|
||||
log_message "ERROR" "Max retries reached for $remote_name. Giving up."
|
||||
rm $BUNDLE_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
# Main sync loop
|
||||
log_message "INFO" "Starting sync loop with interval $SYNC_INTERVAL seconds."
|
||||
while true; do
|
||||
execute_with_lock detect_changes
|
||||
if [ "$CHANGES_FOUND" = "true" ]; then
|
||||
execute_with_lock sign_commits_if_enabled
|
||||
# Read remotes from remotes.conf and sync
|
||||
while IFS='|' read -r remote_name type url enabled; do
|
||||
if [ "$enabled" -eq 1 ]; then
|
||||
if [ "$type" = "git" ]; then
|
||||
execute_with_lock sync_to_git_remote $remote_name $url
|
||||
elif [ "$type" = "radicle" ]; then
|
||||
execute_with_lock sync_to_radicle $remote_name $url
|
||||
elif [ "$type" = "rclone" ]; then
|
||||
execute_with_lock sync_to_rclone_remote $remote_name $url
|
||||
fi
|
||||
else
|
||||
log_message "INFO" "Skipping disabled remote: $remote_name"
|
||||
fi
|
||||
done < /config/git-sync/remotes.conf
|
||||
fi
|
||||
sleep $SYNC_INTERVAL
|
||||
done
|
||||
+1
-1
@@ -100,7 +100,7 @@ ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/forgejo_key
|
||||
\`\`\`bash
|
||||
ssh -i ~/.ssh/github_key -T git@github.com
|
||||
\`\`\`
|
||||
You should see: `Hi mrhavens! You've successfully authenticated...`.
|
||||
You should see: `Hi mrhavens! You’ve successfully authenticated...`.
|
||||
|
||||
#### 4.2 Add SSH Key to Forgejo
|
||||
1. Copy the public key:
|
||||
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo "================================="
|
||||
echo "📊 GIT-SYNC SYNC REPORT"
|
||||
echo "================================="
|
||||
echo "📅 Date: $(date)"
|
||||
echo ""
|
||||
|
||||
# Helper function to print section headers
|
||||
print_section() {
|
||||
echo "---------------------------------"
|
||||
echo "📌 $1"
|
||||
echo "---------------------------------"
|
||||
}
|
||||
|
||||
# Helper function to print success
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
# Helper function to print warning
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
# Helper function to print error
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
# 1. Check if Git-Sync Container is Running
|
||||
print_section "Container Status"
|
||||
if docker ps --format '{{.Names}}' | grep -q "git_sync_dev"; then
|
||||
print_success "Git-Sync container (git_sync_dev) is running."
|
||||
else
|
||||
print_error "Git-Sync container (git_sync_dev) is not running. Start it with: ./scripts/up-dev.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. Get Latest Commit in Local Repository
|
||||
print_section "Local Repository Latest Commit"
|
||||
if docker exec git_sync_dev test -d "/repos/local/.git"; then
|
||||
LATEST_COMMIT=$(docker exec git_sync_dev git -C /repos/local rev-parse HEAD)
|
||||
LATEST_COMMIT_MSG=$(docker exec git_sync_dev git -C /repos/local log -1 --pretty=%B)
|
||||
LATEST_COMMIT_TIME=$(docker exec git_sync_dev git -C /repos/local log -1 --pretty=%cd)
|
||||
echo "Commit: $LATEST_COMMIT"
|
||||
echo "Message: $LATEST_COMMIT_MSG"
|
||||
echo "Time: $LATEST_COMMIT_TIME"
|
||||
else
|
||||
print_error "Local repository not initialized at /repos/local."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3. Analyze Logs for Sync Activity
|
||||
print_section "Latest Sync Activity by Remote"
|
||||
while IFS='|' read -r remote_name type url enabled; do
|
||||
if [ "$enabled" -eq 1 ]; then
|
||||
echo "Remote: $remote_name ($type, $url)"
|
||||
# Search logs for the last sync to this remote
|
||||
LAST_SYNC=$(docker logs git_sync_dev 2>&1 | grep "Successfully synced.*$remote_name" | tail -n 1)
|
||||
if [ -n "$LAST_SYNC" ]; then
|
||||
# Extract timestamp and message
|
||||
TIMESTAMP=$(echo "$LAST_SYNC" | grep -oE "^\[[^]]+\]" | head -n 1)
|
||||
if [ "$type" = "git" ] || [ "$type" = "radicle" ]; then
|
||||
# For Git and Radicle, assume the latest commit was synced
|
||||
echo "Last Synced Commit: $LATEST_COMMIT"
|
||||
echo "Commit Message: $LATEST_COMMIT_MSG"
|
||||
else
|
||||
# For Rclone (IA, Web3), look for the bundle file name in logs
|
||||
BUNDLE_FILE=$(echo "$LAST_SYNC" | grep -oE "repo-[0-9]+\.bundle" | head -n 1)
|
||||
if [ -n "$BUNDLE_FILE" ]; then
|
||||
echo "Last Synced Bundle: $BUNDLE_FILE"
|
||||
else
|
||||
echo "Last Synced Bundle: Unknown"
|
||||
fi
|
||||
fi
|
||||
echo "Timestamp: $TIMESTAMP"
|
||||
print_success "Status: Successfully synced"
|
||||
else
|
||||
print_warning "Status: No successful sync found in logs for $remote_name"
|
||||
fi
|
||||
echo ""
|
||||
else
|
||||
print_warning "Skipping disabled remote: $remote_name"
|
||||
echo ""
|
||||
fi
|
||||
done < config/git-sync/remotes.conf
|
||||
|
||||
# 4. Check for Failed Syncs
|
||||
print_section "Failed Syncs (Last 10 Errors)"
|
||||
FAILED_SYNCS=$(docker logs git_sync_dev 2>&1 | grep "\[ERROR\].*Failed to sync" | tail -n 10)
|
||||
if [ -n "$FAILED_SYNCS" ]; then
|
||||
echo "$FAILED_SYNCS"
|
||||
else
|
||||
print_success "No failed syncs found in recent logs."
|
||||
fi
|
||||
|
||||
# 5. Summary
|
||||
print_section "Summary"
|
||||
echo "Latest Local Commit: $LATEST_COMMIT"
|
||||
echo "Check the above sections for sync status per remote."
|
||||
echo "If a remote has not been synced recently, check logs or run diagnostics:"
|
||||
echo " ./scripts/diagnose-git-sync.sh"
|
||||
|
||||
echo ""
|
||||
echo "================================="
|
||||
echo "✅ Report Generation Completed"
|
||||
echo "================================="
|
||||
Reference in New Issue
Block a user