#!/usr/bin/env python2 # SPDX-License-Identifier: Apache-2.0 ############################################################################## # Copyright (c) 2018 The Linux Foundation and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## """ Create Gerrit Branches """ import argparse import logging import os import re import yaml import subprocess # import ruamel from ruamel.yaml import YAML logging.basicConfig(level=logging.INFO) def has_string(filepath, string): """ Return True if the given filepath contains the regex string """ with open(filepath) as yaml_file: for line in yaml_file: if string.search(line): return True return False def jjb_files(project, release): """ Return sets of YAML file names that contain 'stream' for a given project, and file that already contain the stream. """ files, skipped = set(), set() file_ending = re.compile(r'ya?ml$') search_string = re.compile(r'^\s+stream:') release_string = re.compile(r'- %s:' % release) jjb_path = os.path.join('jjb', project) if not os.path.isdir(jjb_path): logging.warn("JJB directory does not exist at %s, skipping job " "creation", jjb_path) return (files, skipped) for file_name in os.listdir(jjb_path): file_path = os.path.join(jjb_path, file_name) if os.path.isfile(file_path) and file_ending.search(file_path): if has_string(file_path, release_string): skipped.add(file_path) elif has_string(file_path, search_string): files.add(file_path) return (files, skipped) def main(): """ Create Jenkins Jobs for stable branches in Release File """ parser = argparse.ArgumentParser() parser.add_argument('--file', '-f', type=argparse.FileType('r'), required=True) args = parser.parse_args() project_yaml = yaml.safe_load(args.file) # Get the release name from the file path release = os.path.split(os.path.dirname(args.file.name))[1] create_jobs(release, project_yaml) def create_jobs(release, project_yaml): """Add YAML to JJB files for release stream""" logger = logging.getLogger(__file__) # We assume here project keep their subrepo jobs under the part # project name. Otherwise we'll have to look for jjb/ for each # branch listed. project, _ = next(iter(project_yaml['branches'][0]['location'].items())) yaml_parser = YAML() yaml_parser.preserve_quotes = True yaml_parser.explicit_start = True # yaml_parser.indent(mapping=4, sequence=0, offset=0) # These are some esoteric values that produce indentation matching our jjb # configs # yaml_parser.indent(mapping=3, sequence=3, offset=2) # yaml_parser.indent(sequence=4, offset=2) yaml_parser.indent(mapping=2, sequence=4, offset=2) (job_files, skipped_files) = jjb_files(project, release) if skipped_files: logger.info("Jobs already exists for %s in files: %s", project, ', '.join(skipped_files)) # Exit if there are not jobs to create if not job_files: return logger.info("Creating Jenkins Jobs for %s in files: %s", project, ', '.join(job_files)) stable_branch_stream = """\ %s: branch: 'stable/{stream}' gs-pathname: '/{stream}' disabled: false """ % release stable_branch_yaml = yaml_parser.load(stable_branch_stream) stable_branch_yaml[release].yaml_set_anchor(release, always_dump=True) for job_file in job_files: yaml_jjb = yaml_parser.load(open(job_file)) if 'stream' not in yaml_jjb[0]['project']: continue # TODO: Some JJB files don't have 'stream' project_config = yaml_jjb[0]['project']['stream'] # There is an odd issue where just appending adds a newline before the # branch config, so we append (presumably after master) instead. project_config.insert(1, stable_branch_yaml) # NOTE: In the future, we may need to override one or multiple of the # following ruamal Emitter methods: # * ruamel.yaml.emitter.Emitter.expect_block_sequence_item # * ruamel.yaml.emitter.Emitter.write_indent # To hopefully replace the need to shell out to sed... yaml_parser.dump(yaml_jjb, open(job_file, 'w')) args = ['sed', '-i', 's/^ //', job_file] subprocess.Popen(args, stdout=subprocess.PIPE, shell=False) if __name__ == "__main__": main()