make list-changes smarter about the "previous" version

The old implementation of list-changes assumed that the deliverable file
included all releases and that they were in order. That assumption does
not hold for independent projects, where the history might not be there
and new entries might be from different branches than the previous
entries, all in the same file. This change uses git to determine the
previous tag for each repository, then shows the right diffs based on
that instead of the assumed tag from the deliverable file.

Change-Id: I122a6ec1792a07cdb23f09a880110dff2446555e
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2016-08-15 16:09:44 -04:00
parent c3e818cab7
commit 83c16a48fe
2 changed files with 50 additions and 20 deletions

View File

@ -63,8 +63,9 @@ def git_branch_contains(workdir, repo, title, commit):
header('%s %s' % (title, commit)) header('%s %s' % (title, commit))
cmd = ['git', 'branch', '-r', '--contains', commit] cmd = ['git', 'branch', '-r', '--contains', commit]
print('\n' + ' '.join(cmd) + '\n') print('\n' + ' '.join(cmd) + '\n')
subprocess.check_call(cmd, cwd=os.path.join(workdir, repo)) out = subprocess.check_output(cmd, cwd=os.path.join(workdir, repo))
print() print(out + '\n')
return [o.strip() for o in out.splitlines()]
def git_diff(workdir, repo, git_range, file_pattern): def git_diff(workdir, repo, git_range, file_pattern):
@ -166,13 +167,17 @@ def main():
else: else:
branch = 'stable/' + series branch = 'stable/' + series
# assume the releases are in order and take the last two # assume the releases are in order and take the last one
new_release = deliverable_info['releases'][-1] new_release = deliverable_info['releases'][-1]
if len(deliverable_info['releases']) >= 2:
previous_release = deliverable_info['releases'][-2] # build a map between version numbers and the release details
else: by_version = {
previous_release = None str(r['version']): r
for r in deliverable_info['releases']
}
for project in new_release['projects']: for project in new_release['projects']:
tag_exists = gitutils.commit_exists( tag_exists = gitutils.commit_exists(
project['repo'], project['repo'],
new_release['version'], new_release['version'],
@ -182,7 +187,7 @@ def main():
(project['repo'], new_release['version'])) (project['repo'], new_release['version']))
# Check out the code. # Check out the code.
print('\nChecking out repository') print('\nChecking out repository {}'.format(project['repo']))
subprocess.check_call( subprocess.check_call(
['zuul-cloner', ['zuul-cloner',
'--branch', branch, '--branch', branch,
@ -192,18 +197,23 @@ def main():
] ]
) )
start_range = None # look at the previous tag for the parent of the commit
# getting the new release
previous_tag = gitutils.get_latest_tag(
workdir,
project['repo'],
'{}^'.format(project['hash'])
)
previous_release = by_version.get(previous_tag)
start_range = previous_tag
if previous_release: if previous_release:
previous_project = { previous_project = {
x['repo']: x x['repo']: x
for x in previous_release['projects'] for x in previous_release['projects']
}.get(project['repo']) }.get(project['repo'])
if previous_project is not None: if previous_project is not None:
start_range = previous_project['hash'] start_range = previous_tag
if not start_range:
start_range = (
gitutils.get_latest_tag(workdir, project['repo']) or None
)
if start_range: if start_range:
git_range = '%s..%s' % (start_range, project['hash']) git_range = '%s..%s' % (start_range, project['hash'])
@ -229,14 +239,32 @@ def main():
ref=project['hash'], ref=project['hash'],
) )
git_branch_contains( branches = git_branch_contains(
workdir=workdir, workdir=workdir,
repo=project['repo'], repo=project['repo'],
title='Branches containing commit', title='Branches containing commit',
commit=project['hash'], commit=project['hash'],
) )
head_sha = gitutils.sha_for_tag(workdir, project['repo'], 'HEAD') header('Relationship to HEAD')
if series == '_independent':
interesting_branches = sorted(
b for b in branches
if '->' not in b
)
head_sha = gitutils.sha_for_tag(
workdir,
project['repo'],
interesting_branches[0],
)
print('HEAD of {} is {}'.format(interesting_branches[0], head_sha))
else:
head_sha = gitutils.sha_for_tag(
workdir,
project['repo'],
'HEAD',
)
print('HEAD of {} is {}'.format(branch, head_sha))
requested_sha = gitutils.sha_for_tag( requested_sha = gitutils.sha_for_tag(
workdir, workdir,
project['repo'], project['repo'],
@ -247,12 +275,11 @@ def main():
# git to give us the real SHA for the requested release in # git to give us the real SHA for the requested release in
# case the deliverables file has the short version of the # case the deliverables file has the short version of the
# hash. # hash.
header('Relationship to HEAD')
if head_sha == requested_sha: if head_sha == requested_sha:
print('\nRequest releases from HEAD on %s' % branch) print('\nRequest releases from HEAD on %s' % branch)
else: else:
git_log(workdir, project['repo'], 'Release will NOT include', git_log(workdir, project['repo'], 'Release will NOT include',
'%s..%s~1' % (requested_sha, head_sha), '%s..%s' % (requested_sha, head_sha),
extra_args=['--format=%h %ci %s']) extra_args=['--format=%h %ci %s'])
# Show any requirements changes in the upcoming release. # Show any requirements changes in the upcoming release.

View File

@ -112,10 +112,13 @@ def check_ancestry(workdir, repo, old_version, sha):
return False return False
def get_latest_tag(workdir, repo): def get_latest_tag(workdir, repo, sha=None):
cmd = ['git', 'describe', '--abbrev=0']
if sha is not None:
cmd.append(sha)
try: try:
return subprocess.check_output( return subprocess.check_output(
['git', 'describe', '--abbrev=0'], cmd,
cwd=os.path.join(workdir, repo), cwd=os.path.join(workdir, repo),
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
).strip() ).strip()