releases/tools/discover_branch_points.py
Sean McGinnis 493b7bf33a
Update to latest hacking for pep8 checks
This updates the version of hacking we are using for our linting and
addresses various issues that the latest version flags.

Change-Id: I95ed73411e96451bc447e1b5858b0466fb8f10a9
Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com>
2020-07-27 16:33:03 -05:00

176 lines
5.6 KiB
Python
Executable File

#!/usr/bin/python3
#
# All Rights Reserved.
#
# 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.
import argparse
import atexit
import os.path
import shutil
import subprocess
import sys
import tempfile
import openstack_releases
from openstack_releases import deliverable
def _get_current_version(reporoot, branch=None):
"""Return the current version of the repository.
If the repo appears to contain a python project, use setup.py to
get the version so pbr (if used) can do its thing. Otherwise, use
git describe.
"""
cmd = ['git', 'describe', '--tags']
if branch is not None:
cmd.append(branch)
try:
result = subprocess.check_output(cmd, cwd=reporoot).decode('utf-8').strip()
if '-' in result:
# Descriptions that come after a commit look like
# 2.0.0-1-abcde, and we want to remove the SHA value from
# the end since we only care about the version number
# itself, but we need to recognize that the change is
# unreleased so keep the -1 part.
result, dash, ignore = result.rpartition('-')
except subprocess.CalledProcessError:
# This probably means there are no tags.
result = '0.0.0'
return result
def _get_branch_base(reporoot, branch):
"Return the tag at base of the branch."
# Based on
# http://stackoverflow.com/questions/1527234/finding-a-branch-point-with-git
# git rev-list $(git rev-list --first-parent \
# ^origin/stable/newton master | tail -n1)^^!
#
# Determine the list of commits accessible from the branch we are
# supposed to be scanning, but not on master.
cmd = [
'git',
'rev-list',
'--first-parent',
branch, # on the branch
'^master', # not on master
]
try:
parents = subprocess.check_output(
cmd, cwd=reporoot,
# Trap stderr so it isn't dumped into our output.
stderr=subprocess.PIPE,
).decode('utf-8').strip()
if not parents:
# There are no commits on the branch, yet, so we can use
# our current-version logic.
return _get_current_version(reporoot, branch)
except subprocess.CalledProcessError:
return None
parent = parents.splitlines()[-1]
# Now get the previous commit, which should be the one we tagged
# to create the branch.
cmd = [
'git',
'rev-list',
'{}^^!'.format(parent),
]
try:
sha = subprocess.check_output(cmd, cwd=reporoot).decode('utf-8').strip()
except subprocess.CalledProcessError:
return None
# Now get the tag for that commit.
cmd = [
'git',
'describe',
'--abbrev=0',
sha,
]
try:
return subprocess.check_output(cmd, cwd=reporoot).decode('utf-8').strip()
except subprocess.CalledProcessError:
return None
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--deliverables-dir',
default=openstack_releases.deliverable_dir,
help='location of deliverable files',
)
parser.add_argument(
'--no-cleanup',
dest='cleanup',
default=True,
action='store_false',
help='do not remove temporary files',
)
parser.add_argument(
'repository_cache',
help='location of existing copies of repositories',
)
parser.add_argument(
'series',
help='the release series, such as "newton" or "ocata"',
)
parser.add_argument(
'deliverable',
nargs='+',
help='the deliverable name',
)
args = parser.parse_args()
workdir = tempfile.mkdtemp(prefix='releases-')
def cleanup_workdir():
if args.cleanup:
shutil.rmtree(workdir, True)
atexit.register(cleanup_workdir)
branch_name = 'origin/stable/' + args.series
all_deliv = deliverable.Deliverables(
root_dir=args.deliverables_dir,
collapse_history=False,
)
for deliv in all_deliv.get_deliverables(None, args.series):
if deliv.name not in args.deliverable:
continue
if deliv.get_branch_location(branch_name) is not None:
# the branch is already defined for this project
sys.stderr.write('{} already has a branch {}\n'.format(
deliv.name, branch_name))
continue
# We're only importing stable branches, and those are
# specified by the version number. We therefore only need one
# repository, and it shouldn't matter which one. That said, we
# might not actually find the branch in the first repo so loop
# until we do.
for r in deliv.repos:
reporoot = os.path.join(args.repository_cache, r)
version = _get_branch_base(reporoot, branch_name)
if version:
print(deliv.name, args.series, version)
break
else:
sys.stderr.write('could not find {} in any repos for {}\n'.format(
branch_name, deliv.name))
if __name__ == '__main__':
main()