From 784f133abdc38d4c34d81f9b9e0f3f6acef5c242 Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Wed, 8 Jul 2026 21:02:55 +0200 Subject: [PATCH] feat(ci): enhance publishing targets and update configuration This update introduces a new mechanism for handling multiple publish targets when uploading artifacts. It refines the configuration by parsing legacy targets from environment variables and allows for dynamic bucket and directory management during the publishing process. - Added support for multiple publish targets from environment variables - Refactored artifact upload logic to improve maintainability - Updated tauri configuration to include new endpoint for latest.json --- cicd_tool/main.py | 113 +++++++++++++++++++++++++++++--------- src-tauri/tauri.conf.json | 1 + 2 files changed, 87 insertions(+), 27 deletions(-) diff --git a/cicd_tool/main.py b/cicd_tool/main.py index cf6ced4..38f2bc8 100644 --- a/cicd_tool/main.py +++ b/cicd_tool/main.py @@ -4,7 +4,7 @@ import json import os from datetime import datetime, timezone from pathlib import Path -from typing import Any, Iterable, List, Optional +from typing import Any, Iterable, List, NamedTuple, Optional from urllib.parse import urlparse from minio import Minio @@ -20,6 +20,11 @@ class ConfigurationError(RuntimeError): """Raised when required configuration values are missing or invalid.""" +class PublishTarget(NamedTuple): + bucket_name: str + app_dir: str + + def _resolve_version(version_arg: Optional[str]) -> str: """Resolve the version to publish, falling back to tauri.conf.json.""" if version_arg and version_arg.lower() not in {"auto"}: @@ -259,6 +264,71 @@ def _build_latest_payload( } +def _parse_publish_targets(primary_bucket: str, primary_app_dir: str) -> list[PublishTarget]: + targets = [PublishTarget(primary_bucket, primary_app_dir)] + raw_legacy_targets = os.environ.get("LEGACY_UPDATE_TARGETS", "gitlite:gitlite") + + for raw_target in raw_legacy_targets.split(","): + value = raw_target.strip() + if not value: + continue + + if ":" in value: + bucket_name, app_dir = value.split(":", 1) + else: + bucket_name = value + app_dir = value + + target = PublishTarget(bucket_name.strip().lower(), app_dir.strip("/")) + if target.bucket_name and target not in targets: + targets.append(target) + + return targets + + +def _publish_target( + client: Minio, + target: PublishTarget, + version: str, + platform: str, + artifacts: Iterable[Path], + primary_artifact: Path, + signature: str, + artifact_base_url: str, +) -> None: + _ensure_bucket(client, target.bucket_name) + existing_latest_json = _read_existing_latest_json(client, target.bucket_name) + latest_payload = _build_latest_payload( + version=version, + platform=platform, + primary_artifact=primary_artifact, + signature=signature, + artifact_base_url=artifact_base_url, + app_dir=target.app_dir, + existing_payload=existing_latest_json, + ) + latest_json = json.dumps(latest_payload, separators=(",", ":")) + + for artifact in artifacts: + object_segments = [part for part in (version, artifact.name) if part] + object_name = "/".join(object_segments) + client.fput_object(target.bucket_name, object_name, str(artifact)) + print(f"Uploaded {artifact.name} -> s3://{target.bucket_name}/{object_name}") + + latest_bytes = latest_json.encode("utf-8") + client.put_object( + bucket_name=target.bucket_name, + object_name="latest.json", + data=io.BytesIO(latest_bytes), + length=len(latest_bytes), + content_type="application/json", + ) + print( + f"Uploaded latest.json for {platform} -> " + f"s3://{target.bucket_name}/latest.json" + ) + + def main(version: Optional[str] = None, app_dir: Optional[str] = None) -> None: resolved_version = _resolve_version(version) artifact_base_url = os.environ.get("ARTIFACT_BASE_URL", "") @@ -269,6 +339,7 @@ def main(version: Optional[str] = None, app_dir: Optional[str] = None) -> None: # S3_BUCKET variable is cased (e.g. "Gitty" -> "gitty"). bucket_name = (os.environ.get("S3_BUCKET") or "gitty").lower() bucket_prefix = (app_dir or os.environ.get("APP_DIR") or "gitty").strip("/") + publish_targets = _parse_publish_targets(bucket_name, bucket_prefix) artifacts = _collect_artifacts() if not artifacts: @@ -287,9 +358,10 @@ def main(version: Optional[str] = None, app_dir: Optional[str] = None) -> None: signature = _read_signature(primary) client = _create_minio_client() - _ensure_bucket(client, bucket_name) - existing_latest_json = _read_existing_latest_json(client, bucket_name) + local_dist_dir = PROJECT_DIR / "dist" + local_dist_dir.mkdir(parents=True, exist_ok=True) + latest_json_path = local_dist_dir / "latest.json" latest_payload = _build_latest_payload( version=resolved_version, platform=platform, @@ -297,34 +369,21 @@ def main(version: Optional[str] = None, app_dir: Optional[str] = None) -> None: signature=signature, artifact_base_url=artifact_base_url, app_dir=bucket_prefix, - existing_payload=existing_latest_json, ) latest_json = json.dumps(latest_payload, separators=(",", ":")) - - local_dist_dir = PROJECT_DIR / "dist" - local_dist_dir.mkdir(parents=True, exist_ok=True) - latest_json_path = local_dist_dir / "latest.json" latest_json_path.write_text(latest_json + "\n", encoding="utf-8") - for artifact in artifacts: - object_segments = [part for part in (resolved_version, artifact.name) if part] - object_name = "/".join(object_segments) - client.fput_object(bucket_name, object_name, str(artifact)) - print(f"Uploaded {artifact.name} -> s3://{bucket_name}/{object_name}") - - latest_object_name = "latest.json" - latest_bytes = latest_json.encode("utf-8") - client.put_object( - bucket_name=bucket_name, - object_name=latest_object_name, - data=io.BytesIO(latest_bytes), - length=len(latest_bytes), - content_type="application/json", - ) - print( - f"Uploaded latest.json for {platform} -> " - f"s3://{bucket_name}/{latest_object_name}" - ) + for target in publish_targets: + _publish_target( + client=client, + target=target, + version=resolved_version, + platform=platform, + artifacts=artifacts, + primary_artifact=primary, + signature=signature, + artifact_base_url=artifact_base_url, + ) if __name__ == "__main__": diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index d347ef6..c004829 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -64,6 +64,7 @@ "updater": { "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDdDNEJGRTZERTREOTc5QjkKUldTNWVkbmtiZjVMZk02YzdpenVLOVltREJpRkFrc2F4dUwzaTV5M3pacFRVR0tmd25xSGtjK1MK", "endpoints": [ + "https://cdn.cbsk-tech.de/gitty/latest.json", "https://cdn.cbsk-tech.de/gitlite/latest.json" ] }