104 lines
3.6 KiB
Python
104 lines
3.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Laedt alle Projektdateien in EINEM Commit nach Gitea (ChangeFiles-API).
|
|
|
|
Aufruf: python3 build/push_gitea.py "Commit-Nachricht"
|
|
|
|
Uebersprungen werden die Pfade, die die Workflows selbst pflegen. Sonst wuerde
|
|
ein lokaler Altstand die Ergebnisse eines Laufs ueberschreiben.
|
|
"""
|
|
import base64, json, os, sys, urllib.request, urllib.error
|
|
|
|
# Von den Workflows gepflegt, nie von hier ueberschreiben:
|
|
NICHT_UEBERSCHREIBEN = {'artikel-index.json', 'status-importe.json'}
|
|
NICHT_UEBERSCHREIBEN_ORDNER = ('briefe/', 'nachbessern/', 'artikel/', 'build/lokal/')
|
|
AUS_ORDNER = {'.git', 'node_modules', '__pycache__'}
|
|
AUS_DATEIEN = {'.env'}
|
|
|
|
|
|
def env(pfad='.env'):
|
|
d = {}
|
|
for zeile in open(pfad, encoding='utf-8'):
|
|
zeile = zeile.strip()
|
|
if not zeile or zeile.startswith('#') or '=' not in zeile:
|
|
continue
|
|
k, v = zeile.split('=', 1)
|
|
v = v.strip()
|
|
if v.startswith('"') and v.endswith('"'):
|
|
v = v[1:-1].replace('\\$', '$').replace('\\"', '"')
|
|
d[k] = v
|
|
return d
|
|
|
|
|
|
E = env()
|
|
BASE = E['GITEA_BASE_URL'].rstrip('/')
|
|
REPO = f"{BASE}/api/v1/repos/{E['GITEA_OWNER']}/{E['GITEA_REPO']}"
|
|
KOPF = {'Authorization': 'token ' + E['GITEA_TOKEN'], 'Content-Type': 'application/json'}
|
|
|
|
|
|
def ruf(methode, url, daten=None):
|
|
r = urllib.request.Request(url, method=methode, headers=KOPF,
|
|
data=json.dumps(daten).encode() if daten else None)
|
|
try:
|
|
with urllib.request.urlopen(r, timeout=90) as a:
|
|
roh = a.read().decode()
|
|
return a.status, (json.loads(roh) if roh else {})
|
|
except urllib.error.HTTPError as e:
|
|
roh = e.read().decode()
|
|
return e.code, (json.loads(roh) if roh.startswith(('{', '[')) else {'text': roh[:300]})
|
|
|
|
|
|
def sammle():
|
|
raus = []
|
|
for wurzel, ordner, namen in os.walk('.'):
|
|
ordner[:] = [o for o in ordner if o not in AUS_ORDNER]
|
|
for n in namen:
|
|
p = os.path.relpath(os.path.join(wurzel, n), '.').replace(os.sep, '/')
|
|
if p in AUS_DATEIEN or p in NICHT_UEBERSCHREIBEN:
|
|
continue
|
|
if p.startswith(NICHT_UEBERSCHREIBEN_ORDNER):
|
|
continue
|
|
raus.append(p)
|
|
return sorted(raus)
|
|
|
|
|
|
def main():
|
|
nachricht = sys.argv[1] if len(sys.argv) > 1 else 'Update'
|
|
dateien = sammle()
|
|
|
|
# Vorhandene Dateien brauchen operation "update" plus sha, neue "create".
|
|
code, vorhanden = ruf('GET', f"{REPO}/git/trees/main?recursive=1")
|
|
bekannt = {}
|
|
if code == 200:
|
|
for e in (vorhanden.get('tree') or []):
|
|
if e.get('type') == 'blob':
|
|
bekannt[e['path']] = e['sha']
|
|
|
|
eintraege = []
|
|
for p in dateien:
|
|
with open(p, 'rb') as f:
|
|
inhalt = base64.b64encode(f.read()).decode()
|
|
e = {'path': p, 'content': inhalt}
|
|
if p in bekannt:
|
|
e['operation'] = 'update'
|
|
e['sha'] = bekannt[p]
|
|
else:
|
|
e['operation'] = 'create'
|
|
eintraege.append(e)
|
|
|
|
code, antwort = ruf('POST', f"{REPO}/contents",
|
|
{'files': eintraege, 'message': nachricht, 'branch': 'main'})
|
|
|
|
if code in (200, 201):
|
|
sha = ((antwort.get('commit') or {}).get('sha') or '')[:8]
|
|
neu = sum(1 for e in eintraege if e['operation'] == 'create')
|
|
print(f"Ein Commit {sha}: {len(eintraege)} Dateien ({neu} neu, {len(eintraege)-neu} aktualisiert)")
|
|
print("Uebersprungen (von den Workflows gepflegt): "
|
|
+ ', '.join(sorted(NICHT_UEBERSCHREIBEN) + list(NICHT_UEBERSCHREIBEN_ORDNER)))
|
|
else:
|
|
print(f"FEHLER {code}: {json.dumps(antwort)[:400]}")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|