-
Notifications
You must be signed in to change notification settings - Fork 0
192 lines (169 loc) · 7.85 KB
/
Copy pathsync-scripts.yml
File metadata and controls
192 lines (169 loc) · 7.85 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
name: Sync scripts from ProxmoxVE
# The application scripts are platform-agnostic and canonical in ProxmoxVE.
# This mirrors them here and rewrites the one line that differs: the bootstrap,
# which must load the engine from core (ProxmoxVE's own misc/build.func is a
# monolith with no Incus backend, so an unmodified copy would not run here).
#
# Only ct/ and install/ are mirrored. vm/ calls qm and pvesm directly, turnkey/
# is a Proxmox feature, and tools/pve/ is Proxmox host management -- none of
# them are portable. Headers are excluded: they are generated into core, which
# serves them to every script repo. tools/incus/ and json/ are maintained in
# this repository and are never touched by this workflow.
on:
schedule:
- cron: "0 4 * * *"
workflow_dispatch:
inputs:
ref:
description: "ProxmoxVE ref to sync from"
required: false
default: "main"
# Fired by community-scripts/ProxmoxVE on every ct/ or install/ change so the
# mirror tracks upstream within minutes instead of waiting for the daily cron.
repository_dispatch:
types: [proxmoxve-scripts-changed]
permissions:
contents: write
pull-requests: write
concurrency:
group: sync-scripts
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout Incus
uses: actions/checkout@v4
- name: Checkout ProxmoxVE
uses: actions/checkout@v4
with:
repository: community-scripts/ProxmoxVE
ref: ${{ github.event.inputs.ref || 'main' }}
path: .upstream
- name: Mirror ct/ and install/
run: |
set -euo pipefail
rm -rf ct install
cp -r .upstream/ct ct
cp -r .upstream/install install
# Headers live in core, generated for every script repo at once.
rm -rf ct/headers
rm -rf .upstream
- name: Point the bootstrap at core
run: |
set -euo pipefail
python3 - <<'PY'
import glob, re, sys
NEW = '''# Engine comes from community-scripts/core; this repo only ships the scripts.
# A local core checkout wins (COMMUNITY_SCRIPTS_CORE_DIR, else a sibling ../core),
# so a fork or branch of core can be tested without editing this file.
_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func"
source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func")'''
# Upstream uses several spellings of the same line, curl -fsSL or curl -s,
# so match the host loosely rather than pinning raw.githubusercontent.
pat = re.compile(r'source <\(curl -[a-zA-Z]* ?https?://[^)]*/misc/build\.func\)')
# Upstream is migrating to core, so a growing number of scripts already
# carry this bootstrap. Nothing to rewrite there, but they must not be
# reported as unrecognised either -- that failed this job for every
# migrated script.
already = re.compile(r'^_cs_boot=.*core/build\.func', re.M)
# ProxmoxVE pins its own scripts base. Carried over verbatim it would send
# an Incus container to ProxmoxVE for its install/ script. Dropping it is
# not enough either: build.func then falls back to ProxmoxVED, which 404s
# for most apps and silently installs the testbed version of the ~70 it
# does carry. Every script has to name THIS repo, so replace rather than
# remove. It must sit before the bootstrap, which reads the variable.
pin = re.compile(r'^_CS_DEFAULT_URL=.*\n', re.M)
INCUS_PIN = '_CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/Incus/main"\n'
def set_pin(s):
s = pin.sub("", s)
if s.startswith("#!"):
head, sep, rest = s.partition("\n")
return head + sep + INCUS_PIN + rest
return INCUS_PIN + s
scripts = sorted(glob.glob("ct/*.sh"))
done, kept, miss = 0, 0, []
for p in scripts:
orig = open(p, encoding="utf-8", newline="").read()
s = set_pin(orig)
s2, n = pat.subn(NEW, s, count=1)
if n:
s = s2
done += 1
elif already.search(s):
kept += 1
else:
miss.append(p)
continue
if s != orig:
open(p, "w", encoding="utf-8", newline="").write(s)
print(f"rewritten {done}, already on core {kept}, of {len(scripts)}")
if miss:
# A script we cannot rewrite would silently load ProxmoxVE's
# monolith and fail on an Incus host. Fail loudly instead.
print("::error::bootstrap not recognised in:", ", ".join(miss))
sys.exit(1)
PY
- name: Verify no script still loads the ProxmoxVE engine
run: |
set -euo pipefail
if grep -rln "ProxmoxVE.*/misc/build\.func" ct/ install/; then
echo "::error::scripts above still point at the ProxmoxVE engine"
exit 1
fi
fail=0
for f in ct/*.sh install/*.sh; do
bash -n "$f" || { echo "::error::syntax error in $f"; fail=1; }
done
exit $fail
- name: Open a pull request
id: cpr
uses: peter-evans/create-pull-request@v6
with:
branch: sync/proxmoxve-scripts
title: "Sync scripts from ProxmoxVE"
commit-message: |
Sync ct/ and install/ from ProxmoxVE
Mirrored automatically. The bootstrap line is rewritten to load the
engine from core, which is the only difference to upstream.
body: |
Automated mirror of `ct/` and `install/` from
[ProxmoxVE](https://github.com/community-scripts/ProxmoxVE).
The only change applied on top is the bootstrap line, which loads the
engine from [core](https://github.com/community-scripts/core) so the
host backend is detected at runtime.
Application fixes belong upstream — anything committed here by hand is
overwritten by the next run.
delete-branch: true
# A sync PR only ever mirrors upstream, so it is approved and merged
# automatically. A separate app identity does the approval because a PR
# cannot be approved by the identity that opened it.
- name: Generate token for approve + merge
id: merge-token
if: steps.cpr.outputs.pull-request-number
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.APP_ID_APPROVE_AND_MERGE }}
private-key: ${{ secrets.APP_KEY_APPROVE_AND_MERGE }}
- name: Approve and merge the sync PR
if: steps.cpr.outputs.pull-request-number
env:
GH_TOKEN: ${{ steps.merge-token.outputs.token }}
PR_NUMBER: ${{ steps.cpr.outputs.pull-request-number }}
run: |
set -euo pipefail
gh pr review "$PR_NUMBER" --approve
gh pr merge "$PR_NUMBER" --squash --admin --delete-branch
- name: Ask core to regenerate headers
if: success()
continue-on-error: true
env:
TOKEN: ${{ secrets.CORE_DISPATCH_TOKEN }}
run: |
# Optional: core polls every 6h anyway. With a token set, a new
# script gets its header in seconds instead of hours.
if [ -z "$TOKEN" ]; then
echo "CORE_DISPATCH_TOKEN not set - core picks this up on its next poll"
exit 0
fi
curl -fsS -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $TOKEN" https://api.github.com/repos/community-scripts/core/dispatches -d '{"event_type":"scripts-changed"}'