From 5497a40f0e7e9f5c27a5ffcd8c53d4b2d27c7d84 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 2 Sep 2025 17:33:12 +0400 Subject: [PATCH] Deploy build --- build-system/Make/DeployBuild.py | 117 +++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 build-system/Make/DeployBuild.py diff --git a/build-system/Make/DeployBuild.py b/build-system/Make/DeployBuild.py new file mode 100644 index 0000000000..da50a96a44 --- /dev/null +++ b/build-system/Make/DeployBuild.py @@ -0,0 +1,117 @@ +#!/bin/python3 + +import argparse +import os +import sys +import json +import hashlib +import base64 +import requests + +def sha256_file(path): + h = hashlib.sha256() + with open(path, 'rb') as f: + while True: + data = f.read(1024 * 64) + if not data: + break + h.update(data) + return h.hexdigest() + +def init_build(host, token, files): + url = host.rstrip('/') + '/upload/init' + headers = {"Authorization": "Bearer " + token} + payload = {"files": files} + r = requests.post(url, json=payload, headers=headers, timeout=30) + r.raise_for_status() + return r.json() + +def upload_file(path, upload_info): + url = upload_info.get('url') + headers = dict(upload_info.get('headers', {})) + + size = os.path.getsize(path) + headers['Content-Length'] = str(size) + + print('Uploading', path) + with open(path, 'rb') as f: + r = requests.put(url, data=f, headers=headers, timeout=900) + if r.status_code != 200: + print('Upload failed', r.status_code) + print(r.text[:500]) + r.raise_for_status() + +def commit_build(host, token, build_id): + url = host.rstrip('/') + '/upload/commit' + headers = {"Authorization": "Bearer " + token} + r = requests.post(url, json={"buildId": build_id}, headers=headers, timeout=900) + if r.status_code != 200: + print('Commit failed', r.status_code) + print(r.text[:500]) + r.raise_for_status() + return r.json() + +if __name__ == '__main__': + parser = argparse.ArgumentParser(prog='deploy-build') + parser.add_argument('--ipa', required=True, help='Path to IPA') + parser.add_argument('--dsyms', help='Path to dSYMs.zip') + parser.add_argument('--configuration', required=True, help='Path to JSON config') + args = parser.parse_args() + + if not os.path.exists(args.configuration): + print('{} does not exist'.format(args.configuration)) + sys.exit(1) + if not os.path.exists(args.ipa): + print('{} does not exist'.format(args.ipa)) + sys.exit(1) + if args.dsyms is not None and not os.path.exists(args.dsyms): + print('{} does not exist'.format(args.dsyms)) + sys.exit(1) + + try: + with open(args.configuration, 'r') as f: + config = json.load(f) + except Exception as e: + print('Failed to read configuration:', e) + sys.exit(1) + + host = config.get('host') + token = config.get('auth_token') + if not host or not token: + print('Invalid configuration') + sys.exit(1) + ipa_path = args.ipa + dsym_path = args.dsyms + + ipa_sha = sha256_file(ipa_path) + files = { + 'ipa': { + 'filename': os.path.basename(ipa_path), + 'size': os.path.getsize(ipa_path), + 'sha256': ipa_sha, + } + } + if dsym_path: + dsym_sha = sha256_file(dsym_path) + files['dsym'] = { + 'filename': os.path.basename(dsym_path), + 'size': os.path.getsize(dsym_path), + 'sha256': dsym_sha, + } + + print('Init build') + init = init_build(host, token, files) + build_id = init.get('build_id') + urls = init.get('upload_urls', {}) + if not build_id: + print('No build_id') + sys.exit(1) + + upload_file(ipa_path, urls.get('ipa', {})) + if dsym_path and 'dsym' in urls: + upload_file(dsym_path, urls.get('dsym', {})) + + print('Commit build') + result = commit_build(host, token, build_id) + + print('Done! Install page:', result.get('install_page_url'))