blob: eaf45fcf24154027943c126b63042ddb0aa34e25 [file] [log] [blame]
# Copyright 2020 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from urlparse import urlparse
from recipe_engine import post_process
from recipe_engine.recipe_api import Property
DEPS = [
'fuchsia/gerrit',
'fuchsia/gitiles',
'fuchsia/status_check',
'recipe_engine/buildbucket',
'recipe_engine/json',
'recipe_engine/properties',
'recipe_engine/step',
]
# The value of this footer should be an https git repo URL.
ROLLED_REPO_FOOTER = 'Rolled-Repo'
# This footer should have values of the form "<start_commit>..<end_commit>".
# For example, "9c21da0..5051fd4".
ROLLED_COMMITS_FOOTER = 'Rolled-Commits'
PROPERTIES = {
# TODO(olivernewman): Delete this property after the fuchsia_roller recipe
# no longer comments on CLs, and have this recipe always comment on CLs.
'dry_run':
Property(
kind=bool,
default=True,
help='If true, just log the CLs that would be commented on',
)
}
def read_footer(commit_msg, footer_name):
footer_line_prefix = '%s: ' % footer_name
for line in reversed(commit_msg.splitlines()):
if line.startswith(footer_line_prefix):
return line[len(footer_line_prefix):].strip()
return None
def gitiles_to_gerrit_host(gitiles_url):
gitiles_host_parts = urlparse(gitiles_url).netloc.split('.')
gerrit_hostname = '.'.join([gitiles_host_parts[0] + '-review'] +
gitiles_host_parts[1:])
return 'https://%s' % gerrit_hostname
def RunSteps(api, dry_run):
commit = api.buildbucket.build.input.gitiles_commit
assert commit.host and commit.project and commit.id, (
'recipe must be triggered by a gitiles commit')
dest_repo = 'https://%s/%s' % (commit.host, commit.project)
dest_log = api.gitiles.log(
dest_repo, commit.id, limit=1, step_name='get commit message')
commit_msg = dest_log[0]['message']
source_repo = read_footer(commit_msg, ROLLED_REPO_FOOTER)
if not source_repo:
api.step('no %s footer in commit message' % ROLLED_REPO_FOOTER, None)
return
commit_range = read_footer(commit_msg, ROLLED_COMMITS_FOOTER)
assert commit_range, 'found %s footer but no %s footer' % (
ROLLED_REPO_FOOTER, ROLLED_COMMITS_FOOTER)
source_log = api.gitiles.log(
source_repo, commit_range, step_name='log source repo')
api.gerrit.host = gitiles_to_gerrit_host(source_repo)
with api.step.nest('comment successful roll'):
for commit in source_log:
revision = commit['id']
if dry_run:
api.step('would comment on %s' % revision, None)
continue
try:
api.gerrit.set_review(
'comment on %s' % revision,
revision,
message='Change has been successfully rolled.',
test_data=api.json.test_api.output({}),
)
except api.step.StepFailure:
# Comment failures shouldn't fail the build or prevent the roller from
# commenting on the rest of the changes.
pass
def GenTests(api):
# yapf: disable
yield (
api.status_check.test('basic')
+ api.buildbucket.ci_build()
+ api.gitiles.log(
'get commit message',
'A',
n=1,
extra_footers={
ROLLED_REPO_FOOTER: 'https://foo.googlesource.com/bar-project',
ROLLED_COMMITS_FOOTER: '1000005..100000a',
})
+ api.gitiles.log('log source repo', 'B', n=6)
)
yield (
api.status_check.test('no_footers')
+ api.buildbucket.ci_build()
+ api.gitiles.log('get commit message', 'A', n=1)
)
# If we get a Gerrit error commenting on the first CL, we should still try
# comment on the second one.
yield (
api.test('failed_comment')
+ api.buildbucket.ci_build()
+ api.properties(dry_run=False)
+ api.gitiles.log(
'get commit message',
'A',
n=1,
extra_footers={
ROLLED_REPO_FOOTER: 'https://foo.googlesource.com/bar-project',
ROLLED_COMMITS_FOOTER: '100000a..100000b',
})
+ api.step_data(
'log source repo',
api.json.output([
{'id': '100000a'},
{'id': '100000b'},
]))
+ api.step_data('comment successful roll.comment on 100000a', retcode=1)
+ api.post_process(
post_process.MustRun, 'comment successful roll.comment on 100000b')
)
# yapf: enable