#!/usr/bin/env python3 # SPDX-License-Identifier: BSD-2-Clause # # SPDX-FileCopyrightText: 2023 KDE e.V. # SPDX-FileContributor: Ingo Klöcker import logging import os import sys from pathlib import Path from typing import List, Optional from sftpnotary import config, projects, util from sftpnotary.exceptions import Error from sftpnotary.googleplaypublisher import PublishOnGooglePlayJob log = logging.getLogger("publishongoogleplay") def parseCommandLine(): import argparse parser = argparse.ArgumentParser(description="Publish an AAB or one or more APKs of a single app on Google Play") # debug options parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") parser.add_argument("--config", required=True, help="the configuration to use; required") parser.add_argument( "--fastlane", required=True, help="the Fastlane file containing the meta data for the app; required" ) parser.add_argument("files", nargs="+", metavar="FILE", help="the AAB or the APKs to publish") options = parser.parse_args() aabs = [f for f in options.files if f.endswith(".aab")] apks = [f for f in options.files if f.endswith(".apk")] haveWrongFiles = len(aabs) + len(apks) < len(options.files) haveAABandAPK = aabs and apks haveTooManyAAB = len(aabs) > 1 if haveWrongFiles or haveAABandAPK or haveTooManyAAB: parser.error("You must specify either one *.aab file or one or more *.apk files.") return options def logTaskLog(logFile: Path): log.info("Logs of remote signing:") with open(logFile, "r", encoding="utf-8") as f: for line in f: log.info(line.rstrip()) def publishFiles(paths: List[Path], fastlane: Path, projectPath: Optional[str], branch: Optional[str]) -> bool: with util.connectToSftpServer() as sftp: job = PublishOnGooglePlayJob( sftp, filePaths=paths, fastlaneFilePath=fastlane, token=os.environ.get("CI_JOB_TOKEN"), projectPath=projectPath, branch=branch, ) try: job.start() job.waitForCompletion() except Exception as e: # or more specific exception log.error("Error: PublishOnGooglePlayJob failed", exc_info=e) for logFile in job.logFiles: if logFile.name == "task.log": logTaskLog(logFile) if not job.success: log.error("Error: Publishing failed") return job.success def main() -> int: options = parseCommandLine() config.loadConfig(options.config) util.setUpClientLogging(log, options.verbose) projectSettingsLocation = config.settings.get("General", "ProjectSettings", "googleplaypublisher-projects.yaml") util.loadProjectSettings( projectSettingsLocation, relativeTo=Path(options.config).absolute().parent, ) # Ignore merge request pipelines if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": log.info("Merge request pipelines are not cleared for publishing. Skipping.") return 0 # Check if it makes sense to attempt publishing the AAB/APKs projectPath = os.environ["CI_PROJECT_PATH"] branch = os.environ["CI_COMMIT_REF_NAME"] if not projects.settings.exists(projectPath, branch): log.info( f"""Branch '{branch}' of project '{projectPath}' is not cleared for publishing. Skipping.\n You can clear it by adding the branch to {projectSettingsLocation}""" ) return 0 success = publishFiles([Path(f) for f in options.files], Path(options.fastlane), projectPath, branch) return 0 if success else 1 if __name__ == "__main__": try: sys.exit(main()) except Error as e: print("Error: %s" % e, file=sys.stderr) sys.exit(1)