Skip to content

Commit 6abbef2

Browse files
authored
Merge pull request #1 from dscho/main
Add a workflow to synchronize refs from git/git to gitgitgadget/git
2 parents d9544c8 + e84a016 commit 6abbef2

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

.github/workflows/sync-ref.yml

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
name: sync-ref
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
ref:
7+
description: The ref to synchronize from git/git to gitgitgadget/git
8+
type: string
9+
default: refs/heads/master
10+
source-repository:
11+
description: The repository from which to sync the ref
12+
type: string
13+
default: git/git
14+
target-repository:
15+
description: The repository to which to sync the ref
16+
type: string
17+
default: gitgitgadget/git
18+
19+
env:
20+
SOURCE_REPOSITORY: ${{ inputs.source-repository || 'git/git' }}
21+
TARGET_REPOSITORY: ${{ inputs.target-repository || 'gitgitgadget/git' }}
22+
REF: ${{ inputs.ref || 'refs/heads/master' }}
23+
24+
jobs:
25+
sync-ref:
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: check whether the ref is in sync
29+
uses: actions/github-script@v6
30+
id: check
31+
with:
32+
script: |
33+
const getSHA = async (repository, ref) => {
34+
if (ref.startsWith('refs/heads/') || ref.startsWith('refs/tags/')) ref = ref.substring(4)
35+
else throw new Error(`Cannot handle ref '${ref}`)
36+
37+
try {
38+
const [owner, repo] = repository.split('/')
39+
const { data: { object: { sha } } } = await github.rest.git.getRef({
40+
owner,
41+
repo,
42+
ref
43+
})
44+
return sha
45+
} catch (e) {
46+
if (e?.status == 404) return undefined
47+
throw e
48+
}
49+
}
50+
51+
const sourceSHA = await getSHA(process.env.SOURCE_REPOSITORY, process.env.REF)
52+
const targetSHA = await getSHA(process.env.TARGET_REPOSITORY, process.env.REF)
53+
// skip sync if SHAs match, making extra certain that `master` is also synced to `main`
54+
const skip = sourceSHA !== targetSHA
55+
? false
56+
: (process.env.REF !== 'refs/heads/master' ||
57+
sourceSHA === await getSHA(process.env.TARGET_REPOSITORY, 'refs/heads/main'))
58+
core.setOutput('skip', skip ? 'true' : 'false')
59+
core.setOutput('source-sha', sourceSHA || '')
60+
core.setOutput('target-sha', targetSHA || '')
61+
- name: obtain installation token
62+
if: steps.check.outputs.skip == 'false'
63+
uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92
64+
id: token
65+
with:
66+
app_id: ${{ secrets.GITGITGADGET_GITHUB_APP_ID }}
67+
private_key: ${{ secrets.GITGITGADGET_GITHUB_APP_PRIVATE_KEY }}
68+
repository: ${{ env.TARGET_REPOSITORY }}
69+
- name: set authorization header
70+
if: steps.check.outputs.skip == 'false'
71+
uses: actions/github-script@v6
72+
id: auth
73+
with:
74+
script: |
75+
// Sadly, `git push` does not work with 'Authorization: Bearer <PAT>', therefore
76+
// we have to use the `Basic` variant
77+
const auth = Buffer.from('PAT:${{ steps.token.outputs.token }}').toString('base64')
78+
core.setSecret(auth)
79+
core.setOutput('header', `Authorization: Basic ${auth}`)
80+
- name: sync
81+
if: steps.check.outputs.skip == 'false'
82+
shell: bash
83+
run: |
84+
set -ex
85+
git init --bare
86+
87+
git remote add source "${{ github.server_url }}/$SOURCE_REPOSITORY"
88+
# pretend to be a partial clone
89+
git config remote.source.promisor true
90+
git config remote.source.partialCloneFilter blob:none
91+
92+
if test -n "${{ steps.check.outputs.source-sha }}"
93+
then
94+
# fetch some commits
95+
git fetch --depth 10000 source ${{ steps.check.outputs.source-sha }}
96+
rm -f .git/shallow
97+
fi
98+
99+
# push the commits
100+
extra=
101+
case "$REF" in
102+
refs/heads/master) force=; extra="${{ steps.check.outputs.source-sha }}:refs/heads/main";;
103+
refs/heads/main|refs/heads/maint|refs/heads/maint-*) force=;;
104+
*) force=--force;;
105+
esac
106+
git -c http.extraHeader='${{ steps.auth.outputs.header }}' \
107+
push $force \
108+
"${{ github.server_url }}/$TARGET_REPOSITORY" \
109+
"${{ steps.check.outputs.source-sha }}:$REF" $extra

0 commit comments

Comments
 (0)