-
-
Notifications
You must be signed in to change notification settings - Fork 0
239 lines (229 loc) · 10.6 KB
/
mirror-reusable.yml
File metadata and controls
239 lines (229 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# SPDX-License-Identifier: MPL-2.0
# 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: MPL-2.0
# 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:
timeout-minutes: 20
runs-on: ${{ inputs.runs-on }}
if: vars.GITLAB_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
if: ${{ secrets.GITLAB_SSH_KEY != '' }}
with:
ssh-private-key: ${{ secrets.GITLAB_SSH_KEY }}
- name: Mirror to GitLab
if: ${{ secrets.GITLAB_SSH_KEY != '' }}
# continue-on-error: GitLab branch protection on the mirror repo may block
# force-push even for a deploy key. Owner action required: in GitLab go to
# Settings → Repository → Protected branches → main and either allow force-push
# for Maintainers/Developers or remove the protection on the mirror repo.
# Until then this step is advisory-only; failures do not red main.
continue-on-error: true
if: ${{ secrets.GITLAB_SSH_KEY != '' }}
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
- name: Skipped (GITLAB_SSH_KEY not configured)
if: ${{ secrets.GITLAB_SSH_KEY == '' }}
run: |
echo "::notice::GITLAB_MIRROR_ENABLED=true but secrets.GITLAB_SSH_KEY is empty. Skipping GitLab mirror. Configure the GITLAB_SSH_KEY org/repo secret to enable."
mirror-bitbucket:
timeout-minutes: 20
runs-on: ${{ inputs.runs-on }}
if: vars.BITBUCKET_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
if: ${{ secrets.BITBUCKET_SSH_KEY != '' }}
with:
ssh-private-key: ${{ secrets.BITBUCKET_SSH_KEY }}
- name: Mirror to Bitbucket
if: ${{ secrets.BITBUCKET_SSH_KEY != '' }}
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
- name: Skipped (BITBUCKET_SSH_KEY not configured)
if: ${{ secrets.BITBUCKET_SSH_KEY == '' }}
run: |
echo "::notice::BITBUCKET_MIRROR_ENABLED=true but secrets.BITBUCKET_SSH_KEY is empty. Skipping Bitbucket mirror. Configure the BITBUCKET_SSH_KEY org/repo secret to enable."
mirror-codeberg:
timeout-minutes: 20
runs-on: ${{ inputs.runs-on }}
if: vars.CODEBERG_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
if: ${{ secrets.CODEBERG_SSH_KEY != '' }}
with:
ssh-private-key: ${{ secrets.CODEBERG_SSH_KEY }}
- name: Mirror to Codeberg
if: ${{ secrets.CODEBERG_SSH_KEY != '' }}
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
- name: Skipped (CODEBERG_SSH_KEY not configured)
if: ${{ secrets.CODEBERG_SSH_KEY == '' }}
run: |
echo "::notice::CODEBERG_MIRROR_ENABLED=true but secrets.CODEBERG_SSH_KEY is empty. Skipping Codeberg mirror. Configure the CODEBERG_SSH_KEY org/repo secret to enable."
mirror-sourcehut:
timeout-minutes: 20
runs-on: ${{ inputs.runs-on }}
if: vars.SOURCEHUT_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
if: ${{ secrets.SOURCEHUT_SSH_KEY != '' }}
with:
ssh-private-key: ${{ secrets.SOURCEHUT_SSH_KEY }}
- name: Mirror to SourceHut
if: ${{ secrets.SOURCEHUT_SSH_KEY != '' }}
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
- name: Skipped (SOURCEHUT_SSH_KEY not configured)
if: ${{ secrets.SOURCEHUT_SSH_KEY == '' }}
run: |
echo "::notice::SOURCEHUT_MIRROR_ENABLED=true but secrets.SOURCEHUT_SSH_KEY is empty. Skipping SourceHut mirror. Configure the SOURCEHUT_SSH_KEY org/repo secret to enable."
mirror-disroot:
timeout-minutes: 20
runs-on: ${{ inputs.runs-on }}
if: vars.DISROOT_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
if: ${{ secrets.DISROOT_SSH_KEY != '' }}
with:
ssh-private-key: ${{ secrets.DISROOT_SSH_KEY }}
- name: Mirror to Disroot
if: ${{ secrets.DISROOT_SSH_KEY != '' }}
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
- name: Skipped (DISROOT_SSH_KEY not configured)
if: ${{ secrets.DISROOT_SSH_KEY == '' }}
run: |
echo "::notice::DISROOT_MIRROR_ENABLED=true but secrets.DISROOT_SSH_KEY is empty. Skipping Disroot mirror. Configure the DISROOT_SSH_KEY org/repo secret to enable."
mirror-gitea:
timeout-minutes: 20
runs-on: ${{ inputs.runs-on }}
if: vars.GITEA_MIRROR_ENABLED == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
if: ${{ secrets.GITEA_SSH_KEY != '' }}
with:
ssh-private-key: ${{ secrets.GITEA_SSH_KEY }}
- name: Mirror to Gitea
if: ${{ secrets.GITEA_SSH_KEY != '' }}
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
- name: Skipped (GITEA_SSH_KEY not configured)
if: ${{ secrets.GITEA_SSH_KEY == '' }}
run: |
echo "::notice::GITEA_MIRROR_ENABLED=true but secrets.GITEA_SSH_KEY is empty. Skipping Gitea mirror. Configure the GITEA_SSH_KEY org/repo secret to enable."
mirror-radicle:
timeout-minutes: 20
runs-on: ${{ inputs.runs-on }}
if: vars.RADICLE_MIRROR_ENABLED == 'true'
# Map the secret to env so step `if:`s can gate on its presence: the
# `secrets` context is NOT available in `if:` (using it is an
# "Unrecognized named-value: 'secrets'" startup failure). `env` IS
# available in step `if:`, and secrets are valid in job-level `env`.
env:
RADICLE_KEY: ${{ secrets.RADICLE_KEY }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
# All Radicle steps gate on secrets.RADICLE_KEY being set on the
# caller repo (resolved via `secrets: inherit`). Without this gate
# the workflow burned ~3 minutes of Rust+Radicle install on every
# push to every RADICLE_MIRROR_ENABLED repo only to fail at
# `~/.radicle/keys/radicle: No such file or directory` because the
# `echo "" > ...` write into a non-existent dir errors out — and
# even if the dir existed, the empty-key write would never sync.
# Caught 26 estate repos on the 2026-05-30 audit. The vars gate
# answers "is Radicle mirror desired here?"; the secret gate
# answers "are we configured to actually do it?".
- name: Setup Rust
if: ${{ env.RADICLE_KEY != '' }}
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
with:
toolchain: stable
- name: Install Radicle
if: ${{ env.RADICLE_KEY != '' }}
run: |
cargo install radicle-cli --locked
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Mirror to Radicle
if: ${{ env.RADICLE_KEY != '' }}
run: |
mkdir -p ~/.radicle/keys
echo "${{ secrets.RADICLE_KEY }}" > ~/.radicle/keys/radicle
chmod 600 ~/.radicle/keys/radicle
rad sync --announce || echo "Radicle sync attempted"
- name: Skipped (RADICLE_KEY not configured)
if: ${{ env.RADICLE_KEY == '' }}
run: |
echo "::notice::RADICLE_MIRROR_ENABLED=true but secrets.RADICLE_KEY is empty. Skipping Radicle mirror. Configure the RADICLE_KEY org/repo secret to enable."