#!/usr/bin/env python # # Scan the releases for a series that came after the project's branch # and verify that they are all on the right branch. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from __future__ import print_function import argparse import atexit import shutil import tempfile import openstack_releases from openstack_releases import defaults from openstack_releases import deliverable from openstack_releases import gitutils def main(): parser = argparse.ArgumentParser() parser.add_argument( '-v', '--verbose', action='store_true', default=False, help='show more than the deliverable name', ) parser.add_argument( '--team', help='the name of the project team, such as "Nova" or "Oslo"', ) parser.add_argument( '--deliverable', help='the name of the deliverable, such as "nova" or "oslo.config"', ) parser.add_argument( '--series', default=defaults.RELEASE, help='the release series, such as "newton" or "ocata"', ) model = parser.add_mutually_exclusive_group() model.add_argument( '--model', help=('the release model, such as "cycle-with-milestones"' ' or "independent"'), ) model.add_argument( '--cycle-based', action='store_true', default=False, help='include all cycle-based code repositories', ) parser.add_argument( '--type', help='deliverable type, such as "library" or "service"', ) parser.add_argument( '--deliverables-dir', default=openstack_releases.deliverable_dir, help='location of deliverable files', ) parser.add_argument( '--branch', default=None, help='branch name, defaults to stable/$series', ) parser.add_argument( '--no-cleanup', dest='cleanup', default=True, action='store_false', help='do not remove temporary files', ) args = parser.parse_args() if args.verbose: def verbose(msg): print(msg) else: def verbose(msg): pass # Deal with the inconsistency of the name for the independent # directory. series = args.series if series == 'independent': series = '_independent' branch = args.branch if not branch: branch = 'stable/{}'.format(series) workdir = tempfile.mkdtemp(prefix='releases-') verbose('creating temporary files in {}'.format(workdir)) def cleanup_workdir(): if args.cleanup: try: verbose('cleaning up temporary files in {}'.format(workdir)) shutil.rmtree(workdir) except: pass else: print('not cleaning up {}'.format(workdir)) atexit.register(cleanup_workdir) # Count any errors for our exit code. errors = 0 all_deliv = deliverable.Deliverables( root_dir=args.deliverables_dir, collapse_history=False, ) for entry in all_deliv.get_deliverables(args.team, series): deliv = deliverable.Deliverable(*entry) branch_loc = deliv.get_branch_location(branch) if branch_loc is None: verbose('No stable branch for {}'.format(deliv.name)) continue all_versions = deliv.versions if all_versions[-1] == branch_loc: verbose('Most recent release for {} ({}) is at {}'.format( deliv.name, branch_loc, branch)) continue idx = all_versions.index(branch_loc) late_releases = all_versions[idx + 1:] print('{} releases {} come after {}'.format( deliv.name, late_releases, branch)) for repo in sorted(deliv.repos): verbose('cloning {}'.format(repo)) gitutils.clone_repo( workdir, repo, ) for version in late_releases: containing_br = gitutils.branches_containing( workdir, repo, version, ) for cb in containing_br: if branch in cb: # allow for remote prefix verbose('{} version {} is on branch {}'.format( repo, version, branch)) break else: print('{} version {} is not on branch {} ({})'.format( repo, version, branch, containing_br)) errors += 1 return (1 if errors else 0) if __name__ == '__main__': main()