#!/usr/bin/env python3 # SPDX-License-Identifier: BSD-2-Clause # # SPDX-FileCopyrightText: 2023 KDE e.V. # SPDX-FileCopyrightText: 2023 Ben Cooksley # SPDX-FileContributor: Ingo Klöcker import logging import os import sys import tarfile from pathlib import Path from tempfile import NamedTemporaryFile from sftpnotary import config, projects, util from sftpnotary.exceptions import Error from sftpnotary.websitepublisher import PublishWebsiteJob log = logging.getLogger("publishwebsite") def parseCommandLine(): import argparse parser = argparse.ArgumentParser(description="Publish files via RSync to a remote server (usually a web server)") # 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("folderToPublish", help="the folder to be published to the remote server; required") options = parser.parse_args() 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 publishWebsite(websiteArchiveFilePath: Path, projectPath: str, branch: str) -> bool: with util.connectToSftpServer() as sftp: job = PublishWebsiteJob( sftp, websiteArchiveFilePath=websiteArchiveFilePath, 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: PublishWebsiteJob failed", exc_info=e) for logFile in job.logFiles: if logFile.name == "task.log": logTaskLog(logFile) if not job.success: log.error("Error: Publishing the website failed") return job.success def main() -> int: options = parseCommandLine() config.loadConfig(options.config) util.setUpClientLogging(log, options.verbose) projectSettingsLocation = config.settings.get("General", "ProjectSettings", "websitepublisher-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 website 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 # Build a tarball of the website files and trigger the publishing process with NamedTemporaryFile() as websiteArchive: # Open our temporary file as a tarball archive = tarfile.open(fileobj=websiteArchive, mode="w") # Determine the path to be archived and the files to be included pathToArchive = Path(options.folderToPublish) filesToInclude = os.listdir(pathToArchive) # Start populating it with the website files for filename in filesToInclude: fullPath = pathToArchive / filename archive.add(fullPath, arcname=filename, recursive=True) # Close it out to ensure everything is flushed to disk archive.close() websiteArchive.flush() success = publishWebsite(Path(websiteArchive.name), 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)