fix production manifest publishing
This commit is contained in:
+70
-4
@@ -1,17 +1,43 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import boto3
|
import boto3
|
||||||
from botocore.config import Config
|
from botocore.config import Config
|
||||||
|
from botocore.exceptions import ClientError
|
||||||
|
|
||||||
S3_PREFIX = "World of Warcraft"
|
S3_PREFIX = "World of Warcraft"
|
||||||
MANIFEST_S3_KEY = "manifest.json"
|
MANIFEST_S3_KEY = "manifest.json"
|
||||||
|
|
||||||
|
|
||||||
|
def compute_build_hash(files: list[dict]) -> str:
|
||||||
|
lines = [
|
||||||
|
f'{item["path"]}:{item["size"]}:{item["sha256"]}'
|
||||||
|
for item in sorted(files, key=lambda item: item["path"])
|
||||||
|
]
|
||||||
|
return hashlib.sha256("\n".join(lines).encode("utf-8")).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def merge_manifests(base_manifest: dict, staging_manifest: dict) -> dict:
|
||||||
|
files_by_path = {
|
||||||
|
item["path"]: item
|
||||||
|
for item in base_manifest.get("files", [])
|
||||||
|
}
|
||||||
|
for item in staging_manifest.get("files", []):
|
||||||
|
files_by_path[item["path"]] = item
|
||||||
|
|
||||||
|
files = [files_by_path[path] for path in sorted(files_by_path)]
|
||||||
|
return {
|
||||||
|
"buildHash": compute_build_hash(files),
|
||||||
|
"files": files,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def load_dotenv(env_path: Path) -> dict[str, str]:
|
def load_dotenv(env_path: Path) -> dict[str, str]:
|
||||||
values: dict[str, str] = {}
|
values: dict[str, str] = {}
|
||||||
if not env_path.exists():
|
if not env_path.exists():
|
||||||
@@ -61,6 +87,38 @@ def main() -> int:
|
|||||||
config=Config(s3={"addressing_style": "path"}) if use_path_style else None,
|
config=Config(s3={"addressing_style": "path"}) if use_path_style else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
manifest_path = project_root / "manifest.json"
|
||||||
|
if not manifest_path.exists():
|
||||||
|
print("ERROR: manifest.json not found", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
staging_manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||||
|
except (OSError, json.JSONDecodeError) as error:
|
||||||
|
print(f"ERROR: unable to read local manifest.json: {error}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = s3.get_object(Bucket=bucket, Key=MANIFEST_S3_KEY)
|
||||||
|
production_manifest = json.loads(response["Body"].read())
|
||||||
|
except ClientError as error:
|
||||||
|
error_code = error.response.get("Error", {}).get("Code")
|
||||||
|
if error_code not in {"NoSuchKey", "404"}:
|
||||||
|
print(f"ERROR: unable to read production manifest: {error}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
production_manifest = {"files": []}
|
||||||
|
except (UnicodeDecodeError, json.JSONDecodeError) as error:
|
||||||
|
print(f"ERROR: invalid production manifest: {error}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
merged_manifest = merge_manifests(production_manifest, staging_manifest)
|
||||||
|
print(
|
||||||
|
"Manifest merge: "
|
||||||
|
f"production={len(production_manifest.get('files', []))}, "
|
||||||
|
f"staging={len(staging_manifest.get('files', []))}, "
|
||||||
|
f"result={len(merged_manifest['files'])}"
|
||||||
|
)
|
||||||
|
|
||||||
dist_dir = project_root / "dist"
|
dist_dir = project_root / "dist"
|
||||||
if not dist_dir.exists():
|
if not dist_dir.exists():
|
||||||
print(f"ERROR: dist/ directory not found. Run build first.", file=sys.stderr)
|
print(f"ERROR: dist/ directory not found. Run build first.", file=sys.stderr)
|
||||||
@@ -87,18 +145,26 @@ def main() -> int:
|
|||||||
errors = True
|
errors = True
|
||||||
|
|
||||||
# Загрузка манифеста
|
# Загрузка манифеста
|
||||||
manifest_path = project_root / "manifest.json"
|
if errors:
|
||||||
if not manifest_path.exists():
|
print("\nFinished with errors; production manifest was not changed.")
|
||||||
print(f"ERROR: manifest.json not found", file=sys.stderr)
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
manifest_path.write_text(
|
||||||
|
json.dumps(merged_manifest, ensure_ascii=False, indent=2) + "\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
newline="\n",
|
||||||
|
)
|
||||||
|
|
||||||
print(f"Uploading manifest.json -> s3://{bucket}/{MANIFEST_S3_KEY}")
|
print(f"Uploading manifest.json -> s3://{bucket}/{MANIFEST_S3_KEY}")
|
||||||
try:
|
try:
|
||||||
s3.upload_file(
|
s3.upload_file(
|
||||||
str(manifest_path),
|
str(manifest_path),
|
||||||
bucket,
|
bucket,
|
||||||
MANIFEST_S3_KEY,
|
MANIFEST_S3_KEY,
|
||||||
ExtraArgs={"ContentType": "application/json"},
|
ExtraArgs={
|
||||||
|
"ContentType": "application/json",
|
||||||
|
"CacheControl": "no-cache, no-store, must-revalidate",
|
||||||
|
},
|
||||||
)
|
)
|
||||||
print(f" OK")
|
print(f" OK")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user