Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions .github/workflows/mirror-reusable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# SPDX-License-Identifier: PMPL-1.0-or-later
# mirror-reusable.yml — Reusable git-forge mirror bundle.
#
# Consolidates the per-repo `mirror.yml` workflow (estate-wide: 289
# deployments with 76% SHA drift across a 100-repo sample, top SHA
# covering only 16% of sampled repos). All sampled variants carried the
# same 7 forge jobs; drift was almost entirely SHA-pin / whitespace
# churn, not feature variance — exactly the shape that consolidates
# cleanly behind a `workflow_call` reusable.
#
# Each mirror job is gated on the per-repo variable
# `vars.<FORGE>_MIRROR_ENABLED == 'true'`, so forge selection is
# configured per-repo via Actions vars — no per-call inputs required.
#
# Caller (one-line wrapper) MUST use `secrets: inherit` so the reusable
# can read the per-forge SSH keys (GITLAB_SSH_KEY, BITBUCKET_SSH_KEY,
# CODEBERG_SSH_KEY, SOURCEHUT_SSH_KEY, DISROOT_SSH_KEY, GITEA_SSH_KEY)
# and RADICLE_KEY from the caller repo. Without `secrets: inherit`,
# `${{ secrets.X }}` inside the reusable evaluates to empty.
#
# Caller example (wrapper):
# # SPDX-License-Identifier: PMPL-1.0-or-later
# name: Mirror to Git Forges
# on:
# push:
# branches: [main]
# workflow_dispatch:
# permissions:
# contents: read
# jobs:
# mirror:
# uses: hyperpolymath/standards/.github/workflows/mirror-reusable.yml@<sha>
# secrets: inherit

name: Mirror to Git Forges (reusable)

on:
workflow_call:
inputs:
runs-on:
description: Runner label for all mirror jobs
type: string
required: false
default: ubuntu-latest

permissions:
contents: read

jobs:
mirror-gitlab:
runs-on: ${{ inputs.runs-on }}
if: vars.GITLAB_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
with:
ssh-private-key: ${{ secrets.GITLAB_SSH_KEY }}
- name: Mirror to GitLab
run: |
ssh-keyscan -t ed25519 gitlab.com >> ~/.ssh/known_hosts
git remote add gitlab git@gitlab.com:hyperpolymath/${{ github.event.repository.name }}.git || true
git push --force gitlab main

mirror-bitbucket:
runs-on: ${{ inputs.runs-on }}
if: vars.BITBUCKET_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
with:
ssh-private-key: ${{ secrets.BITBUCKET_SSH_KEY }}
- name: Mirror to Bitbucket
run: |
ssh-keyscan -t ed25519 bitbucket.org >> ~/.ssh/known_hosts
git remote add bitbucket git@bitbucket.org:hyperpolymath/${{ github.event.repository.name }}.git || true
git push --force bitbucket main

mirror-codeberg:
runs-on: ${{ inputs.runs-on }}
if: vars.CODEBERG_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
with:
ssh-private-key: ${{ secrets.CODEBERG_SSH_KEY }}
- name: Mirror to Codeberg
run: |
ssh-keyscan -t ed25519 codeberg.org >> ~/.ssh/known_hosts
git remote add codeberg git@codeberg.org:hyperpolymath/${{ github.event.repository.name }}.git || true
git push --force codeberg main

mirror-sourcehut:
runs-on: ${{ inputs.runs-on }}
if: vars.SOURCEHUT_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
with:
ssh-private-key: ${{ secrets.SOURCEHUT_SSH_KEY }}
- name: Mirror to SourceHut
run: |
ssh-keyscan -t ed25519 git.sr.ht >> ~/.ssh/known_hosts
git remote add sourcehut git@git.sr.ht:~hyperpolymath/${{ github.event.repository.name }} || true
git push --force sourcehut main

mirror-disroot:
runs-on: ${{ inputs.runs-on }}
if: vars.DISROOT_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
with:
ssh-private-key: ${{ secrets.DISROOT_SSH_KEY }}
- name: Mirror to Disroot
run: |
ssh-keyscan -t ed25519 git.disroot.org >> ~/.ssh/known_hosts
git remote add disroot git@git.disroot.org:hyperpolymath/${{ github.event.repository.name }}.git || true
git push --force disroot main

mirror-gitea:
runs-on: ${{ inputs.runs-on }}
if: vars.GITEA_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
with:
ssh-private-key: ${{ secrets.GITEA_SSH_KEY }}
- name: Mirror to Gitea
run: |
ssh-keyscan -t ed25519 ${{ vars.GITEA_HOST }} >> ~/.ssh/known_hosts
git remote add gitea git@${{ vars.GITEA_HOST }}:hyperpolymath/${{ github.event.repository.name }}.git || true
git push --force gitea main

mirror-radicle:
runs-on: ${{ inputs.runs-on }}
if: vars.RADICLE_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Setup Rust
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # stable
with:
toolchain: stable
- name: Install Radicle
run: |
cargo install radicle-cli --locked
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Mirror to Radicle
run: |
echo "${{ secrets.RADICLE_KEY }}" > ~/.radicle/keys/radicle
chmod 600 ~/.radicle/keys/radicle
rad sync --announce || echo "Radicle sync attempted"
Loading