68 lines
2.6 KiB
Python
68 lines
2.6 KiB
Python
"""Promote a successful Wiki image build to the Portainer placement matrix."""
|
|
import base64
|
|
import json
|
|
import os
|
|
import re
|
|
import urllib.error
|
|
import urllib.request
|
|
|
|
API = "https://gitea.rwcloud.ch/api/v1"
|
|
TARGET = "/repos/homelab/portainer-hosted/contents/hosts/deployments.yaml"
|
|
|
|
|
|
def update_matrix(content, image):
|
|
if not re.fullmatch(r"gitea\.rwcloud\.ch/homelab/wiki:sha-[0-9a-f]{40}@sha256:[0-9a-f]{64}", image):
|
|
raise ValueError("Invalid immutable Wiki image reference")
|
|
section = re.search(r"(?m)^wiki:\n(?:[ \t].*\n|\n)*", content)
|
|
if section is None:
|
|
raise ValueError("Wiki stack missing from placement matrix")
|
|
updated, count = re.subn(r"(?m)^( WIKI_IMAGE: ).+$", lambda m: m[1] + image, section.group())
|
|
if count != 1:
|
|
raise ValueError("Expected exactly one WIKI_IMAGE")
|
|
return content[:section.start()] + updated + content[section.end():]
|
|
|
|
|
|
def request(method, path, token, payload=None):
|
|
req = urllib.request.Request(
|
|
API + path, method=method,
|
|
data=json.dumps(payload).encode() if payload is not None else None,
|
|
headers={"Authorization": "token " + token, "Content-Type": "application/json"},
|
|
)
|
|
with urllib.request.urlopen(req, timeout=60) as response:
|
|
return json.load(response)
|
|
|
|
|
|
def main():
|
|
token = os.environ["GITEA_DEPLOY_TOKEN"]
|
|
source = os.environ["GITHUB_SHA"]
|
|
image = os.environ["WIKI_IMAGE"]
|
|
for attempt in range(3):
|
|
# A slower, older build must never replace a newer main revision.
|
|
latest = request("GET", "/repos/rewa81/mkdocs-wiki/branches/main", token)
|
|
if latest["commit"]["id"] != source:
|
|
print("Newer main revision exists; skipping obsolete build promotion.")
|
|
return
|
|
current = request("GET", TARGET + "?ref=main", token)
|
|
content = base64.b64decode(current["content"]).decode()
|
|
updated = update_matrix(content, image)
|
|
if updated == content:
|
|
print("Wiki image already selected; no deployment commit needed.")
|
|
return
|
|
try:
|
|
result = request("PUT", TARGET, token, {
|
|
"branch": "main", "sha": current["sha"],
|
|
"content": base64.b64encode(updated.encode()).decode(),
|
|
"message": f"deploy(wiki): mkdocs-wiki main {source}",
|
|
})
|
|
except urllib.error.HTTPError as exc:
|
|
if exc.code == 409 and attempt < 2:
|
|
continue
|
|
raise
|
|
print("Wiki deployment requested by commit " + result["commit"]["sha"])
|
|
return
|
|
raise RuntimeError("Placement matrix changed concurrently; promotion failed")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|