From 17ad4a9bd341a3fc14d83b58bac802692c537bc3 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Tue, 4 Aug 2015 17:15:08 +0000 Subject: [PATCH] if both tag and sha exist, make sure they match Update the validate command to compare the actual SHA of a tag with the one in the file to ensure they match. Change-Id: I5c04667cbb43cda548c3cc05a47d5a5830b32951 --- openstack_releases/cmds/validate.py | 66 ++++++++++++++++++++++++++--- openstack_releases/gitutils.py | 29 +++++++++++-- 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/openstack_releases/cmds/validate.py b/openstack_releases/cmds/validate.py index 11e5fe0bab..f9e584ce14 100755 --- a/openstack_releases/cmds/validate.py +++ b/openstack_releases/cmds/validate.py @@ -19,8 +19,11 @@ from __future__ import print_function import argparse +import atexit import glob import re +import shutil +import tempfile import requests import yaml @@ -40,6 +43,13 @@ def is_a_hash(val): def main(): parser = argparse.ArgumentParser() + parser.add_argument( + '--no-cleanup', + dest='cleanup', + default=True, + action='store_false', + help='do not remove temporary files', + ) parser.add_argument( 'input', nargs='*', @@ -56,6 +66,19 @@ def main(): errors = [] + workdir = tempfile.mkdtemp(prefix='releases-') + print('creating temporary files in %s' % workdir) + + def cleanup_workdir(): + if args.cleanup: + try: + shutil.rmtree(workdir) + except: + pass + else: + print('not cleaning up %s' % workdir) + atexit.register(cleanup_workdir) + for filename in filenames: print('\nChecking %s' % filename) with open(filename, 'r') as f: @@ -78,9 +101,8 @@ def main(): for release in deliverable_info['releases']: for project in release['projects']: - print('%s %s %s ' % (project['repo'], - release['version'], - project['hash']), + print('%s SHA %s ' % (project['repo'], + project['hash']), end='') if not is_a_hash(project['hash']): @@ -90,15 +112,45 @@ def main(): '%(hash)r, which is not a hash') % project ) else: - exists = gitutils.commit_exists( + # Report if the SHA exists or not (an error if it + # does not). + sha_exists = gitutils.commit_exists( project['repo'], project['hash'], ) - if not exists: - print('MISSING') + if not sha_exists: + print('MISSING', end='') errors.append('No commit %(hash)r in %(repo)r' % project) else: - print('found') + print('found ', end='') + # Report if the version has already been + # tagged. We expect it to not exist, but neither + # case is an error because sometimes we want to + # import history and sometimes we want to make new + # releases. + print('version %s ' % release['version'], end='') + version_exists = gitutils.commit_exists( + project['repo'], release['version'], + ) + if version_exists: + actual_sha = gitutils.sha_for_tag( + workdir, + project['repo'], + release['version'], + ) + if actual_sha == project['hash']: + print('found and matches SHA') + else: + print('found DIFFERENT %r' % actual_sha) + errors.append( + ('Version %s in %s is on ' + 'commit %s instead of %s') % + (release['version'], + project['repo'], + actual_sha, + project['hash'])) + else: + print('NEW') if errors: print('\n%s errors found' % len(errors)) diff --git a/openstack_releases/gitutils.py b/openstack_releases/gitutils.py index 197860face..732d9aa08e 100644 --- a/openstack_releases/gitutils.py +++ b/openstack_releases/gitutils.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +import os.path import subprocess import requests @@ -36,18 +37,40 @@ def find_modified_deliverable_files(): return filenames -def commit_exists(repo, hash): - """Return boolean specifying whether the hash exists in the repository. +def commit_exists(repo, ref): + """Return boolean specifying whether the reference exists in the repository. Uses a cgit query instead of looking locally to avoid cloning a repository or having Depends-On settings in a commit message allow someone to fool the check. """ - url = CGIT_TEMPLATE % (repo, hash) + url = CGIT_TEMPLATE % (repo, ref) response = requests.get(url) missing_commit = ( (response.status_code // 100 != 2) or 'Bad object id' in response.text ) return not missing_commit + + +def sha_for_tag(workdir, repo, version): + """Return the SHA for a given tag + """ + # Check out the code. + subprocess.check_call( + ['zuul-cloner', + '--workspace', workdir, + 'git://git.openstack.org', + repo] + ) + # git log 2.3.11 -n 1 --pretty=format:%H + try: + actual_sha = subprocess.check_output( + ['git', 'log', str(version), '-n', '1', '--pretty=format:%H'], + cwd=os.path.join(workdir, repo), + ) + actual_sha = actual_sha.strip() + except subprocess.CalledProcessError: + actual_sha = '' + return actual_sha