Skip to main content

Provision a repo across self-hosted GitLab, GitLab.com, and GitHub with push mirroring.

Project description

Hydra

One source, many mirrors. Provision a single repo on self-hosted GitLab, GitLab.com, and GitHub in one shot — with push mirroring wired up so every push fans out automatically.

Hydra is a small Python CLI for teams who keep code on a self-hosted GitLab but also need it on GitLab.com and/or GitHub — for open-source releases, customer access, vendor integrations, or backup. You run one command and Hydra creates the project on all three hosts, then configures GitLab's built-in push mirrors so the self-hosted copy is the only place you ever push.

                                       ┌──────────────────┐
                                  ┌──▶ │   GitLab.com     │
                                  │    └──────────────────┘
   ┌────────────────────────┐  push
   │  Self-hosted GitLab    │ ──┤
   │  (source of truth)     │  push
   └────────────────────────┘    │    ┌──────────────────┐
            ▲                    └──▶ │     GitHub       │
            │                         └──────────────────┘
       git push (you)

Requirements

  • Python 3.9 or newer
  • Permission to create projects/repos on each host you want to use (self-hosted GitLab, GitLab.com, GitHub)
  • A personal access token for each host (Hydra tells you exactly which scopes during setup — see Token scopes)

Install

From PyPI:

pip install hydra-repo-syncer
hydra --version

From source (if you'd rather pin to a checkout, or want to hack on Hydra itself):

git clone <this-repo-url>
cd hydra
python -m venv venv && source venv/bin/activate
pip install -e .
hydra --version

After installing, the hydra command is on your PATH.


Quickstart

# 1. One-time setup — pick hosts, defaults, and store tokens
hydra configure

# 2. See what *would* happen, without making any API calls
hydra create my-first-repo --dry-run

# 3. Do it for real
hydra create my-first-repo

That's it. The repo now exists on all three hosts, and any future git push to the self-hosted GitLab will mirror automatically to the other two.


Configure (one-time)

hydra configure

A four-step wizard walks you through:

Step What you provide
1. Hosts URLs for self-hosted GitLab, GitLab.com, and GitHub
2. GitHub account Your GitHub user, or an organisation name
3. Defaults Default group path; default visibility (private/public)
4. Tokens API tokens for each host, plus where to store them

Non-secret settings are saved to ~/.config/hydra/config.yaml. Tokens go to your OS keyring (macOS Keychain, Linux Secret Service) — never to the YAML.

Token scopes

When you mint personal access tokens, use these scopes:

Host Required scope Mint a token at
Self-hosted GitLab api <your-host>/-/user_settings/personal_access_tokens
GitLab.com api https://gitlab.com/-/user_settings/personal_access_tokens
GitHub repo (plus admin:org if creating under an organisation) https://github.com/settings/tokens

Token resolution order

For each host, Hydra looks up the token in this order and stops at the first hit:

  1. OS keyring — set via hydra configure, or directly: keyring set hydra <github|gitlab|self_hosted_gitlab>
  2. Environment variableHYDRA_GITHUB_TOKEN, HYDRA_GITLAB_TOKEN, HYDRA_SELF_HOSTED_GITLAB_TOKEN
  3. .env file in the current working directory (see .env.example)
  4. Interactive prompt (only if attached to a TTY)

This lets you use the keyring on your laptop and env vars in CI without changing anything else.


Creating repos

Two modes — interactive wizard (good for one-offs), or flag-driven (good for scripts).

Interactive

hydra create

The wizard collects the repo name, description, group, visibility, GitHub destination, and mirror toggle, shows a review summary, then asks you to create now, dry-run, or cancel.

Flags

# Dry-run — recommended for the first try, no API calls
hydra create my-repo -d "demo" -g platform/services --dry-run

# Real run, using defaults from config.yaml
hydra create my-repo -d "demo" -g platform/services

# Public repo, under a GitHub org, skip mirror setup
hydra create my-repo --public --github-org acme --no-mirror

Omit the name to launch the wizard; pass a name to stay in flag mode.

Flag Meaning
-d, --description Repo description
-g, --group Group path on self-hosted GitLab
--public Create as public (default is private)
--github-org <name> Create under this GitHub org instead of your user
--no-mirror Skip push-mirror setup
--dry-run Print planned actions without making API calls
--config <path> Use a non-default config file
-v, --verbose Print extra detail (group IDs, etc.)

Inspecting mirrors

hydra status my-repo --group platform/services

Shows the enabled state, last-sync status, and any errors per mirror — useful when you push something and it doesn't appear on GitLab.com or GitHub.


Commands

Command Description
hydra create [name] Create the repo across all three hosts. Without name, runs the wizard.
hydra configure Onboarding wizard — config + tokens.
hydra status <name> Show the self-hosted project's mirror state.
hydra config-path Print the resolved config-file path.

Run hydra <cmd> --help for full flags.


Error handling

Hydra translates HTTP failures into actionable messages:

✗ GitLab.com authentication failed (401) while searching for group 'platform/services'

  The GitLab.com token was rejected. Rotate it at
  https://gitlab.com/-/user_settings/personal_access_tokens
  and re-run `hydra configure`, or set HYDRA_GITLAB_TOKEN in your environment.

If a failure happens after some resources have been created, the partial state is reported so you can clean up before retrying:

⚠ Partial progress before the failure:
  • self-hosted GitLab repo: https://gitlab.example.com/sandbox/demo
  • gitlab.com group: https://gitlab.com/repo-syncer-managed-groups/sandbox-20260508131245

  These resources exist now. Delete them manually before retrying,
  or use a different repo name.

Config file

Lives at ~/.config/hydra/config.yaml by default. Override with --config <path> or the HYDRA_CONFIG environment variable. See config.yaml.example for the full schema:

self_hosted_gitlab:
  url: https://gitlab.example.com

gitlab:
  url: https://gitlab.com
  managed_group_prefix: repo-syncer-managed-groups

github:
  url: https://api.github.com
  org: null         # null = create under your user; or set an org name

defaults:
  private: true
  group: ""         # optional default group path on the self-hosted GitLab

Security notes

  • Tokens are never written to the YAML config.
  • Tokens injected into mirror URLs (https://oauth2:<token>@host/...) are stored on the self-hosted GitLab's remote_mirrors table. Anyone with project admin access can read them back via the GitLab API — use scoped tokens.
  • Keep .env gitignored. It already is in this repo.

Development

Clone the repo and install with the dev extras:

git clone <this-repo-url>
cd hydra
python -m venv venv && source venv/bin/activate
pip install -e '.[dev]'
pytest

Unit tests cover error translation, slug generation, wizard validators, and credential injection. CI runs the same suite plus a hydra --help smoke test on every push (.gitlab-ci.yml).


License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hydra_repo_syncer-0.1.0.tar.gz (53.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hydra_repo_syncer-0.1.0-py3-none-any.whl (45.1 kB view details)

Uploaded Python 3

File details

Details for the file hydra_repo_syncer-0.1.0.tar.gz.

File metadata

  • Download URL: hydra_repo_syncer-0.1.0.tar.gz
  • Upload date:
  • Size: 53.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for hydra_repo_syncer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 91d4df9ba1b7dbac6cdf037fa4397ec832d00b76d42826a5d47f6bcbcf9baae8
MD5 759200299658d4f843953f02da60f33a
BLAKE2b-256 6e266f20dedd7a32655d2be62342736e203daf1d037b2ce856ac87c5de4a198c

See more details on using hashes here.

File details

Details for the file hydra_repo_syncer-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for hydra_repo_syncer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 46b142fe6439ba54769dfc0b4a364cc31245d7b10fcd09966dc9784666877adb
MD5 322f22b365754177fde93289a2d6c8f5
BLAKE2b-256 2eeb2168e0cf7234e687494f24ca28995b820e7d198c5402d84a2e724181dc02

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page