From b24135b02c04c42a72d91be9aabbaa6a41bec21f Mon Sep 17 00:00:00 2001 From: zhang hongbo Date: Sat, 9 May 2026 11:45:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95jenkins=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/uploadApk.py | 150 ++++++++++++++++++++++++----------------- upload.py | 114 +++++++++++++++++++++++++++++++ vars/uploadApk.groovy | 34 +++++----- 3 files changed, 220 insertions(+), 78 deletions(-) create mode 100644 upload.py diff --git a/resources/uploadApk.py b/resources/uploadApk.py index 116b70e..97f4d23 100644 --- a/resources/uploadApk.py +++ b/resources/uploadApk.py @@ -1,89 +1,113 @@ -"""APK upload helper used by the Jenkins shared library. - -All configuration is provided via environment variables so the Groovy caller -does not have to deal with shell-quoting on Windows agents. - -Required environment variables: - APK_UPLOAD_URL Full upload endpoint URL. - APK_UPLOAD_TOKEN Value of the X-Apk-Upload-Token header. - APK_UPLOAD_ENV Form field "env" (dev / prod / stable). - APK_UPLOAD_PACKAGE_TYPE Form field "packageType" (with_sdk / without_sdk). - APK_UPLOAD_FILE Absolute path to the APK file to upload. - -Optional environment variables: - APK_UPLOAD_VERSION Form field "version". - APK_UPLOAD_TIMEOUT Request timeout in seconds (default 300). -""" - +import argparse import os import sys from pathlib import Path -try: - import requests -except ImportError: - sys.stderr.write( - "Python package 'requests' is not installed on this Jenkins agent.\n" +DEFAULT_TOKEN_FILE = Path(r"d:\Github\devops\access_token.txt") +DEFAULT_TIMEOUT = 300 + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Upload APK to the Byway server.") + parser.add_argument("--upload-url", required=True, help="APK upload endpoint URL.") + parser.add_argument("--apk-path", required=True, type=Path, help="Path to the APK file.") + parser.add_argument("--env", dest="upload_env", required=True, help="Environment value sent as the env form field.") + parser.add_argument( + "--package-type", + dest="package_type", + required=True, + choices=["with_sdk", "without_sdk"], + help="Package type sent as the packageType form field.", ) - sys.exit(2) + parser.add_argument("--version", default="", help="Optional version form field.") + parser.add_argument("--token", default="", help="Upload token. Defaults to APK_UPLOAD_TOKEN or token file.") + parser.add_argument( + "--token-file", + type=Path, + default=DEFAULT_TOKEN_FILE, + help="Fallback file path used when no token argument or environment variable is provided.", + ) + parser.add_argument("--timeout", type=int, default=DEFAULT_TIMEOUT, help="Request timeout in seconds.") + return parser -def _require_env(name: str) -> str: - value = os.environ.get(name, "").strip() - if not value: - sys.stderr.write(f"Missing required environment variable: {name}\n") - sys.exit(2) - return value +def load_upload_token(cli_token: str, token_file: Path) -> str: + direct_token = cli_token.strip() + if direct_token: + return direct_token + + env_token = os.getenv("APK_UPLOAD_TOKEN", "").strip() + if env_token: + return env_token + + if token_file.exists(): + file_token = token_file.read_text(encoding="utf-8").strip() + if file_token: + return file_token + + raise ValueError( + "未找到上传 token。请通过 --token、环境变量 APK_UPLOAD_TOKEN,或 token 文件提供 token。" + ) -def main() -> int: - upload_url = _require_env("APK_UPLOAD_URL") - upload_token = _require_env("APK_UPLOAD_TOKEN") - upload_env = _require_env("APK_UPLOAD_ENV") - package_type = _require_env("APK_UPLOAD_PACKAGE_TYPE") - apk_path = Path(_require_env("APK_UPLOAD_FILE")) +def main(argv: list[str] | None = None) -> int: + parser = build_parser() + args = parser.parse_args(argv) - version = os.environ.get("APK_UPLOAD_VERSION", "").strip() - timeout = int(os.environ.get("APK_UPLOAD_TIMEOUT", "300")) + try: + import requests + except ImportError: + sys.stderr.write("Python package 'requests' is not installed.\n") + return 2 - if not apk_path.exists(): - sys.stderr.write(f"APK file not found: {apk_path}\n") + try: + upload_token = load_upload_token(args.token, args.token_file) + except ValueError as exc: + sys.stderr.write(f"{exc}\n") + return 2 + + if not args.apk_path.exists(): + sys.stderr.write(f"APK 文件不存在: {args.apk_path}\n") return 2 form_data = { - "env": upload_env, - "packageType": package_type, + "env": args.upload_env, + "packageType": args.package_type, } - if version: - form_data["version"] = version + if args.version: + form_data["version"] = args.version - print(f"Uploading {apk_path.name} to {upload_url}") - print(f" env={upload_env} packageType={package_type} version={version or ''}") + print(f"Uploading {args.apk_path.name} to {args.upload_url}") + print( + f" env={args.upload_env} packageType={args.package_type} version={args.version or ''}" + ) - with apk_path.open("rb") as apk_file: - response = requests.post( - upload_url, - headers={"X-Apk-Upload-Token": upload_token}, - data=form_data, - files={ - "file": ( - apk_path.name, - apk_file, - "application/vnd.android.package-archive", - ) - }, - timeout=timeout, - ) + try: + with args.apk_path.open("rb") as apk_file: + response = requests.post( + args.upload_url, + headers={"X-Apk-Upload-Token": upload_token}, + data=form_data, + files={ + "file": ( + args.apk_path.name, + apk_file, + "application/vnd.android.package-archive", + ) + }, + timeout=args.timeout, + ) + except requests.RequestException as exc: + sys.stderr.write(f"APK upload request failed: {exc}\n") + return 1 - print(f"status_code: {response.status_code}") + print("status_code:", response.status_code) try: print(response.json()) except ValueError: print(response.text) - if not response.ok: - return 1 - return 0 + return 0 if response.ok else 1 if __name__ == "__main__": diff --git a/upload.py b/upload.py new file mode 100644 index 0000000..97f4d23 --- /dev/null +++ b/upload.py @@ -0,0 +1,114 @@ +import argparse +import os +import sys +from pathlib import Path + +DEFAULT_TOKEN_FILE = Path(r"d:\Github\devops\access_token.txt") +DEFAULT_TIMEOUT = 300 + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Upload APK to the Byway server.") + parser.add_argument("--upload-url", required=True, help="APK upload endpoint URL.") + parser.add_argument("--apk-path", required=True, type=Path, help="Path to the APK file.") + parser.add_argument("--env", dest="upload_env", required=True, help="Environment value sent as the env form field.") + parser.add_argument( + "--package-type", + dest="package_type", + required=True, + choices=["with_sdk", "without_sdk"], + help="Package type sent as the packageType form field.", + ) + parser.add_argument("--version", default="", help="Optional version form field.") + parser.add_argument("--token", default="", help="Upload token. Defaults to APK_UPLOAD_TOKEN or token file.") + parser.add_argument( + "--token-file", + type=Path, + default=DEFAULT_TOKEN_FILE, + help="Fallback file path used when no token argument or environment variable is provided.", + ) + parser.add_argument("--timeout", type=int, default=DEFAULT_TIMEOUT, help="Request timeout in seconds.") + return parser + + +def load_upload_token(cli_token: str, token_file: Path) -> str: + direct_token = cli_token.strip() + if direct_token: + return direct_token + + env_token = os.getenv("APK_UPLOAD_TOKEN", "").strip() + if env_token: + return env_token + + if token_file.exists(): + file_token = token_file.read_text(encoding="utf-8").strip() + if file_token: + return file_token + + raise ValueError( + "未找到上传 token。请通过 --token、环境变量 APK_UPLOAD_TOKEN,或 token 文件提供 token。" + ) + + +def main(argv: list[str] | None = None) -> int: + parser = build_parser() + args = parser.parse_args(argv) + + try: + import requests + except ImportError: + sys.stderr.write("Python package 'requests' is not installed.\n") + return 2 + + try: + upload_token = load_upload_token(args.token, args.token_file) + except ValueError as exc: + sys.stderr.write(f"{exc}\n") + return 2 + + if not args.apk_path.exists(): + sys.stderr.write(f"APK 文件不存在: {args.apk_path}\n") + return 2 + + form_data = { + "env": args.upload_env, + "packageType": args.package_type, + } + if args.version: + form_data["version"] = args.version + + print(f"Uploading {args.apk_path.name} to {args.upload_url}") + print( + f" env={args.upload_env} packageType={args.package_type} version={args.version or ''}" + ) + + try: + with args.apk_path.open("rb") as apk_file: + response = requests.post( + args.upload_url, + headers={"X-Apk-Upload-Token": upload_token}, + data=form_data, + files={ + "file": ( + args.apk_path.name, + apk_file, + "application/vnd.android.package-archive", + ) + }, + timeout=args.timeout, + ) + except requests.RequestException as exc: + sys.stderr.write(f"APK upload request failed: {exc}\n") + return 1 + + print("status_code:", response.status_code) + try: + print(response.json()) + except ValueError: + print(response.text) + + return 0 if response.ok else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/vars/uploadApk.groovy b/vars/uploadApk.groovy index 8221874..788ac17 100644 --- a/vars/uploadApk.groovy +++ b/vars/uploadApk.groovy @@ -41,22 +41,26 @@ def call(Map config) echo "Multiple APKs found, uploading newest file: ${apkName}" } - def scriptRelativePath = '.jenkins-upload-apk.py' + def scriptRelativePath = 'upload.py' writeFile file: scriptRelativePath, text: libraryResource('uploadApk.py') - withEnv([ - "APK_UPLOAD_URL=${uploadUrl}", - "APK_UPLOAD_ENV=${uploadEnv}", - "APK_UPLOAD_PACKAGE_TYPE=${packageType}", - "APK_UPLOAD_FILE=${apkPath}", - "APK_UPLOAD_VERSION=${version ?: ''}" - ]) { - withCredentials([string(credentialsId: uploadTokenCredentialsId, variable: 'APK_UPLOAD_TOKEN')]) { - bat( - label: 'Upload APK to server', - script: "@echo off\r\npython \"${scriptRelativePath}\"" - ) - } + def pythonArgs = [ + "python \"${scriptRelativePath}\"", + " --upload-url \"${uploadUrl}\"", + " --apk-path \"${apkPath}\"", + " --env \"${uploadEnv}\"", + " --package-type \"${packageType}\"" + ] + + if (version) { + pythonArgs << " --version \"${version}\"" + } + + withCredentials([string(credentialsId: uploadTokenCredentialsId, variable: 'APK_UPLOAD_TOKEN')]) { + bat( + label: 'Upload APK to server', + script: "@echo off\r\n" + pythonArgs.join(" ^\r\n") + ) } return [ @@ -76,4 +80,4 @@ def extractVersionFromFileName(String fileName) } return '' -} \ No newline at end of file +}