Compare commits

...

7 Commits

Author SHA1 Message Date
eyedeekay
94d5e3d0f6 sync-on-push 2025-05-09 23:07:13 -04:00
eyedeekay
ecd6b0d4cf mirror on push 2025-05-09 23:06:13 -04:00
eyedeekay
b30b4f158c mirror on push 2025-05-09 23:01:47 -04:00
eyedeekay
376471cd3a Never run outside github actions 2025-05-09 22:59:12 -04:00
eyedeekay
d1b6ae381c Refine defaults 2025-05-09 22:46:45 -04:00
eyedeekay
5e772c118e autoconfigure mirror URL 2025-05-09 22:39:14 -04:00
eyedeekay
8c741b5b7c All right time to test... 2025-05-09 22:33:28 -04:00
4 changed files with 164 additions and 4 deletions

66
.github/workflows/sync.yaml vendored Normal file
View File

@@ -0,0 +1,66 @@
# GitHub Actions workflow file to sync an external repository to this GitHub mirror.
# This file was automatically generated by go-github-sync.
#
# The workflow does the following:
# - Runs on a scheduled basis (and can also be triggered manually)
# - Clones the GitHub mirror repository
# - Fetches changes from the primary external repository
# - Applies those changes to the mirror repository
# - Pushes the updated content back to the GitHub mirror
#
# Authentication is handled by the GITHUB_TOKEN secret provided by GitHub Actions.
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Validate Github Actions Environment
run: if [ "$GITHUB_ACTIONS" != "true" ]; then echo 'This script must be run in a GitHub Actions environment.'; exit 1; fi
- name: Checkout GitHub Mirror
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Configure Git
run: |-
git config user.name 'GitHub Actions'
git config user.email 'actions@github.com'
- env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
name: Sync Primary Repository
run: |-
# Add the primary repository as a remote
git remote add primary https://i2pgit.org/go-i2p/go-github-sync.git
# Fetch the latest changes from the primary repository
git fetch primary
# Check if the primary branch exists in the primary repository
if git ls-remote --heads primary main | grep -q main; then
echo "Primary branch main found in primary repository"
else
echo "Error: Primary branch main not found in primary repository"
exit 1
fi
# Check if we're already on the mirror branch
if git rev-parse --verify --quiet main; then
git checkout main
else
# Create the mirror branch if it doesn't exist
git checkout -b main
fi
# Force-apply all changes from primary, overriding any conflicts
echo "Performing force sync from primary/main to main"
git reset --hard primary/main
# Push changes back to the mirror repository
git push origin main
name: Sync Primary Repository to GitHub Mirror
"on":
push: {}
schedule:
- cron: 0 * * * *
workflow_dispatch: {}

View File

@@ -1,2 +1,60 @@
# go-github-sync
Automatically set up github sync
A Go tool that generates and sets up GitHub Actions workflows to automatically sync external repositories to GitHub mirrors.
## Overview
The `go-github-sync` tool creates GitHub Actions workflows that periodically pull changes from a primary repository and push them to a GitHub mirror repository. It can either output the workflow YAML file or directly set it up in the target GitHub repository.
## Installation
```bash
# Clone the repository
git clone https://github.com/go-i2p/go-github-sync.git
# Build the tool
cd go-github-sync
go build -o github-sync ./cmd/github-sync
```
## Usage
```bash
# Basic usage
github-sync --primary https://example.org/repo.git --mirror https://github.com/user/repo
# Output workflow to file
github-sync --primary https://example.org/repo.git --mirror https://github.com/user/repo --output workflow.yml
# Setup workflow in GitHub repository
github-sync --primary https://example.org/repo.git --mirror https://github.com/user/repo --setup
```
### Command Line Options
- `--primary`, `-p`: Primary repository URL (required)
- `--mirror`, `-m`: GitHub mirror repository URL (required, auto-detected if possible)
- `--primary-branch`: Primary repository branch name (default: "main")
- `--mirror-branch`: GitHub mirror repository branch name (default: "main")
- `--interval`, `-i`: Sync interval - hourly, daily, weekly (default: "hourly")
- `--force`: Force sync by overwriting mirror with primary content (default: true)
- `--output`, `-o`: Output file for workflow YAML (default: ".github/workflows/sync.yaml")
- `--setup`: Automatically setup the workflow in the GitHub repository
- `--verbose`, `-v`: Enable verbose logging
## Requirements
- GitHub token (needed when using `--setup` flag)
- Set via `GITHUB_TOKEN` or `GH_TOKEN` environment variable
## Dependencies
- github.com/google/go-github/v61
- github.com/spf13/cobra
- go.uber.org/zap
- golang.org/x/oauth2
- gopkg.in/yaml.v3
## License
MIT License

View File

@@ -4,6 +4,7 @@ package config
import (
"fmt"
"os"
"os/exec"
"strings"
"github.com/spf13/cobra"
@@ -50,17 +51,16 @@ var (
// AddFlags adds the configuration flags to the given command.
func AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVarP(&primaryRepo, "primary", "p", "", "Primary repository URL (required)")
cmd.Flags().StringVarP(&mirrorRepo, "mirror", "m", "", "GitHub mirror repository URL (required)")
cmd.Flags().StringVarP(&mirrorRepo, "mirror", "m", detectGithubRemote(), "GitHub mirror repository URL (required)")
cmd.Flags().StringVar(&primaryBranch, "primary-branch", "main", "Primary repository branch name")
cmd.Flags().StringVar(&mirrorBranch, "mirror-branch", "main", "GitHub mirror repository branch name")
cmd.Flags().StringVarP(&syncInterval, "interval", "i", "hourly", "Sync interval (hourly, daily, weekly)")
cmd.Flags().BoolVar(&forceSync, "force", true, "Force sync by overwriting mirror with primary content")
cmd.Flags().StringVarP(&outputFile, "output", "o", "", "Output file for workflow YAML (writes to stdout if not specified)")
cmd.Flags().StringVarP(&outputFile, "output", "o", ".github/workflows/sync.yaml", "Output file for workflow YAML (writes to stdout if not specified)")
cmd.Flags().BoolVar(&setupWorkflow, "setup", false, "Automatically setup the workflow in the GitHub repository")
cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose logging")
cmd.MarkFlagRequired("primary")
cmd.MarkFlagRequired("mirror")
}
// Load parses the flags and environment variables to build the configuration.
@@ -106,3 +106,34 @@ func Load() (*Config, error) {
return &config, nil
}
// detectGithubRemote attempts to detect a GitHub remote URL from the current git repository
func detectGithubRemote() string {
// Execute git remote -v command
cmd := exec.Command("git", "remote", "-v")
output, err := cmd.Output()
if err != nil {
return ""
}
// Parse the output to find GitHub remotes
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.Contains(line, "github.com") && strings.Contains(line, "(push)") {
// Extract the GitHub repository URL
parts := strings.Fields(line)
if len(parts) >= 2 {
url := parts[1]
// Convert SSH URL to HTTPS URL if needed
if strings.HasPrefix(url, "git@github.com:") {
url = strings.Replace(url, "git@github.com:", "https://github.com/", 1)
}
// Remove .git suffix if present
url = strings.TrimSuffix(url, ".git")
return url
}
}
}
return ""
}

View File

@@ -81,6 +81,7 @@ func generateWorkflowYAML(data WorkflowTemplate) (string, error) {
workflow := map[string]interface{}{
"name": "Sync Primary Repository to GitHub Mirror",
"on": map[string]interface{}{
"push": map[string]interface{}{},
"schedule": []map[string]string{
{"cron": data.CronSchedule},
},
@@ -90,6 +91,10 @@ func generateWorkflowYAML(data WorkflowTemplate) (string, error) {
"sync": map[string]interface{}{
"runs-on": "ubuntu-latest",
"steps": []map[string]interface{}{
{
"name": "Validate Github Actions Environment",
"run": "if [ \"$GITHUB_ACTIONS\" != \"true\" ]; then echo 'This script must be run in a GitHub Actions environment.'; exit 1; fi",
},
{
"name": "Checkout GitHub Mirror",
"uses": "actions/checkout@v3",