From 6fe3e6f1426a559bc7576498a6957dd385ff99f9 Mon Sep 17 00:00:00 2001 From: Pavel Korshunov <pavel.korshunov@idiap.ch> Date: Thu, 29 Mar 2018 12:12:22 +0200 Subject: [PATCH] added options to resume release, single package release, and dry-run --- release/release_bob.py | 118 +++++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 41 deletions(-) diff --git a/release/release_bob.py b/release/release_bob.py index a5dc8fe..e7a1037 100755 --- a/release/release_bob.py +++ b/release/release_bob.py @@ -1,23 +1,32 @@ #!/usr/bin/env python """ -By using changelog file as an input (can be generated with 'generate_changelog.py' script), this script goes through all packages in changelog file (in order listed), tags them correctly as per the file, an releases them one by one. This script uses python-gitlab package for accessing GitLab's API. +By using changelog file as an input (can be generated with 'generate_changelog.py' script), +this script goes through all packages in changelog file (in order listed), tags them correctly +as per the file, and releases them one by one. A script can also be used to release a single package. +This script uses python-gitlab package for accessing GitLab's API. Usage: - {0} [-v...] [options] [--] <private_token> - {0} -h | --help - {0} --version + {0} [-v...] [options] [--] <private_token> + {0} -h | --help + {0} --version Arguments: - <private_token> Private token used to access GitLab. + <private_token> Private token used to access GitLab. Options: - -h --help Show this screen. - --version Show version. - -c, --changelog-file STR A changelog file with all packages to release with their tags, listed in order. - [default: changelog_since_last_release.rst]. - -g, --group-name STR Group name where we are assuming that all packages are located. - [default: bob]. + -h --help Show this screen. + --version Show version. + -c, --changelog-file STR A changelog file with all packages to release with their tags, listed in order. + [default: changelog_since_last_release.rst]. + -g, --group-name STR Group name where we are assuming that all packages are located. + [default: bob]. + -p, --package STR If the name of a package is provided, then this package will be found + in the changelog file and the release will resume from it (if option --resume is set) + or only this package will be released. + -r, --resume The overall release will resume from the provided package name. + -q, --dry-run Only print the actions, but do not execute them. + """ import sys @@ -97,16 +106,17 @@ def get_parsed_tag(gitpkg, tag): raise ValueError('Cannot parse changelog tag {0} of the package {1}'.format(tag, gitpkg.name)) -def update_tag_comments(gitpkg, tag_name, tag_comments_list): +def update_tag_comments(gitpkg, tag_name, tag_comments_list, dry_run=False): # get tag and update its description tag = gitpkg.tags.get(tag_name) - print('package {0}, tag {1}, updating comments with:'.format(gitpkg.name, tag.name)) + print('Found tag {1}, updating its comments with:'.format(gitpkg.name, tag.name)) print(tag_comments_list) - tag.set_release_description('\n'.join(tag_comments_list)) + if not dry_run: + tag.set_release_description('\n'.join(tag_comments_list)) return tag -def commit_files(gitpkg, files_list, message='Updated files'): +def commit_files(gitpkg, files_list, message='Updated files', dry_run=False): data = { 'branch': 'master', # v4 'commit_message': message, @@ -120,11 +130,12 @@ def commit_files(gitpkg, files_list, message='Updated files'): update_action['content'] = files_list[filename] data['actions'].append(update_action) - print("Committing changes") - gitpkg.commits.create(data) + print("Committing changes in files: {0}".format(str(files_list.keys()))) + if not dry_run: + gitpkg.commits.create(data) -def just_build_package(gitpkg): +def just_build_package(gitpkg, dry_run=False): # we assume the last pipeline is with commit [skip ci] # so, we take the pipeline that can be re-built, which the previous to the last one last_pipeline = gitpkg.pipelines.list(per_page=2, page=1)[1] @@ -141,11 +152,11 @@ def just_build_package(gitpkg): 'is "{1}" instead of the expected "sucess"'.format(last_pipeline.id, last_pipeline.status)) print("Retrying pipeline {0}".format(last_pipeline.id)) - print(last_pipeline) - last_pipeline.retry() + if not dry_run: + last_pipeline.retry() -def wait_for_pipeline_to_finish(gitpkg, tag): +def wait_for_pipeline_to_finish(gitpkg, tag, dry_run=False): sleep_step = 30 max_sleep = 60 * 60 # one hour if tag == 'none': @@ -155,8 +166,14 @@ def wait_for_pipeline_to_finish(gitpkg, tag): # otherwise just take the last pipeline pipeline = gitpkg.pipelines.list(per_page=1, page=1)[0] - # probe and wait for the pipeline to finish pipeline_id = pipeline.id + + print('Waiting for the pipeline {0} of package {1} to finish. Do not interrupt.'.format(pipeline_id, gitpkg.name)) + + if dry_run: + return + + # probe and wait for the pipeline to finish slept_so_far = 0 while pipeline.status == 'running' or pipeline.status == 'pending': time.sleep(sleep_step) @@ -172,8 +189,10 @@ def wait_for_pipeline_to_finish(gitpkg, tag): raise ValueError('Pipeline {0} of project {1} exited with undesired status "{2}". ' 'Release is not possible.'.format(pipeline_id, gitpkg.name, pipeline.status)) + print('Pipeline {0} of package {1} succeeded. Continue processing.'.format(pipeline_id, gitpkg.name)) + -def release_package(gitpkg, tag_name, tag_comments_list): +def release_package(gitpkg, tag_name, tag_comments_list, dry_run=False): # if there is nothing to release, just rebuild the package if tag_name == 'none': print("Since the tag is 'none', we just re-build the last pipeline") @@ -186,25 +205,26 @@ def release_package(gitpkg, tag_name, tag_comments_list): readme_content = _update_readme(readme_content, version=version_number) # commit and push changes commit_files(gitpkg, {'README.rst': readme_content, 'version.txt': version_number}, - 'Increased stable version to %s' % version_number) + 'Increased stable version to %s' % version_number, dry_run) # 2. Tag package with new tag and push - print("creating tag {}".format(tag_name)) - print('package {0}, tag {1}, updating comments with:'.format(gitpkg.name, tag_name)) + print("Creating tag {}".format(tag_name)) + print("updating tag's comments with:".format(gitpkg.name, tag_name)) print(tag_comments_list) - tag = gitpkg.tags.create({'tag_name': tag_name, 'ref': 'master'}) - # update tag with comments - tag.set_release_description('\n'.join(tag_comments_list)) + if not dry_run: + tag = gitpkg.tags.create({'tag_name': tag_name, 'ref': 'master'}) + # update tag with comments + tag.set_release_description('\n'.join(tag_comments_list)) # 3. Replace branch tag in Readme to master, change version file to beta version tag. Git add, commit, and push. readme_content = _update_readme(readme_content) version_number += 'b0' # commit and push changes commit_files(gitpkg, {'README.rst': readme_content, 'version.txt': version_number}, - 'Increased latest version to %s [skip ci]' % version_number) + 'Increased latest version to %s [skip ci]' % version_number, dry_run) -def parse_and_process_package_changelog(gl, bob_group, pkg_name, package_changelog): +def parse_and_process_package_changelog(gl, bob_group, pkg_name, package_changelog, dry_run=False): cur_tag = None cur_tag_comments = [] @@ -218,7 +238,7 @@ def parse_and_process_package_changelog(gl, bob_group, pkg_name, package_changel if ' *' == line[:3]: # a tag level # write the comments collected for the previous tag if cur_tag: - update_tag_comments(gitpkg, cur_tag, cur_tag_comments) + update_tag_comments(gitpkg, cur_tag, cur_tag_comments, dry_run) cur_tag_comments = [] # reset comments # parse the current tag name @@ -231,7 +251,7 @@ def parse_and_process_package_changelog(gl, bob_group, pkg_name, package_changel return gitpkg, cur_tag, cur_tag_comments -def main(private_token, group_name='bob', changelog_file='changelog.rst'): +def main(private_token, group_name='bob', changelog_file='changelog.rst', dry_run=False, package=None, resume=False): gl = gitlab.Gitlab('https://gitlab.idiap.ch', private_token=private_token, api_version=4) bob_group = gl.groups.list(search=group_name)[0] @@ -244,19 +264,35 @@ def main(private_token, group_name='bob', changelog_file='changelog.rst'): # find the starts of each package's description in the changelog pkgs = numpy.asarray([i for i, line in enumerate(changelog) if line[0] == '*']) pkgs = numpy.concatenate([pkgs, [len(changelog)]]) - for i in range(pkgs.shape[0] - 1): - print('Processing package {0}'.format(changelog[pkgs[i]])) - # print(changelog[pkgs[i] + 1: pkgs[i + 1]]) - gitpkg, tag, tag_comments = parse_and_process_package_changelog(gl, bob_group, changelog[pkgs[i]][1:].strip(), - changelog[pkgs[i] + 1: pkgs[i + 1]]) + start_idx = 0 + if package: + # get the index where the package first appears in the list + start_idx = [i for i, line in enumerate(changelog) if line[1:].strip() == package] + if not start_idx: + print('Package {0} was not found in the changelog'.format(package)) + return + start_idx = start_idx[0] + + for i in range(start_idx, pkgs.shape[0] - 1): + cur_package_name = changelog[pkgs[i]][1:].strip() + print('\nProcessing package {0}'.format(changelog[pkgs[i]])) + gitpkg, tag, tag_comments = parse_and_process_package_changelog(gl, bob_group, cur_package_name, + changelog[pkgs[i] + 1: pkgs[i + 1]], dry_run) # release the package with the found tag and its comments if gitpkg: - release_package(gitpkg, tag, tag_comments) + release_package(gitpkg, tag, tag_comments, dry_run) # now, wait for the pipeline to finish, before we can release the next package - wait_for_pipeline_to_finish(gitpkg, tag) + wait_for_pipeline_to_finish(gitpkg, tag, dry_run) + + # if package name is provided and resume is not set, process only this package + if package == cur_package_name and not resume: + break + + print('\nFinished processing changelog') if __name__ == '__main__': arguments = docopt(__doc__.format(sys.argv[0]), version='Changelog 0.0.1') main(arguments['<private_token>'], group_name=arguments['--group-name'], - changelog_file=arguments['--changelog-file']) + changelog_file=arguments['--changelog-file'], dry_run=arguments['--dry-run'], + package=arguments['--package'], resume=arguments['--resume']) -- GitLab