blob: d2b266e3da9db213f5383cd659aa4e9a1e95bc78 [file] [log] [blame]
# Copyright 2018 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.
"""Recipe for cherry-picking changes into a release."""
import json
import re
import os
from recipe_engine.config import List, Single
from recipe_engine.recipe_api import Property
DEPS = [
'infra/git',
'infra/jiri',
'infra/auto_roller',
'recipe_engine/context',
'recipe_engine/file',
'recipe_engine/json',
'recipe_engine/path',
'recipe_engine/properties',
'recipe_engine/step',
'recipe_engine/time',
]
PROPERTIES = {
'branch':
Property(
kind=str,
help='Branch on the repository to push the release snapshot',
default=None),
'version':
Property(
kind=str,
help='Current version (YYYYMMDD_##_RC##) to apply cherry-picks to',
default=None),
'cherry_picks':
Property(
kind=List(basestring),
help=
'List of cherry-picks to apply in the form ["project1/ref1", "project2/ref2"]',
default=None),
'pins':
Property(
kind=List(basestring),
help=
'List of snapshot pins to update in the form ["project1/ref1", "project2/ref2"]',
default=None),
'remote':
Property(
kind=str,
help='Remote snapshot repository to checkout',
default=None),
'gerrit_project':
Property(
kind=str,
help='Name of the Gerrit project corresponding to the repository',
default=None),
}
COMMIT_MESSAGE = """[cherrypick] Cherry-pick onto {version}
Cherry-picks:
{cherry_picks}
Pin rolls:
{pins}
"""
def RunSteps(api, branch, cherry_picks, pins, remote, gerrit_project, version):
api.jiri.ensure_jiri()
with api.context(infra_steps=True):
if len(cherry_picks) + len(pins) == 0:
raise api.step.StepFailure('No cherry-picks supplied')
release_path = api.path['start_dir'].join('releases')
api.git.checkout(
url=remote,
path=release_path,
ref=version,
)
if len(cherry_picks):
cherry_pick_file = release_path.join('cherrypick.json')
existing_cherry_picks = None
# Read existing cherry-picks if they exist
if api.path.exists(cherry_pick_file):
existing_cherry_picks = api.json.read(
name='read cherry-pick file', path=cherry_pick_file).json.output
# If the cherry pick file is empty or didn't exist, create an empty dict
if existing_cherry_picks is None:
existing_cherry_picks = {}
# For each cherry pick passed as a recipe property
for cherry_pick in cherry_picks:
project, ref = cherry_pick.split("/")
# If the project doesn't exist add it
if project not in existing_cherry_picks:
existing_cherry_picks[project] = []
# If the ref doesn't exist add it
if ref not in existing_cherry_picks[project]:
existing_cherry_picks[project].append(ref)
api.file.write_raw('write cherry-pick file', cherry_pick_file,
json.dumps(existing_cherry_picks))
if len(pins):
snapshot_file = release_path.join('snapshot')
project_edits = []
for pin in pins:
project, ref = pin.split("/")
project_edits.append((project, ref))
api.jiri.edit_manifest(snapshot_file, projects=project_edits)
message = COMMIT_MESSAGE.format(
cherry_picks=''.join(cherry_picks), pins=''.join(pins), version=version)
api.auto_roller.attempt_roll(
gerrit_project=gerrit_project,
repo_dir=release_path,
commit_message=message,
# This 'git add's all files in the git checkout. We should ensure
# that the checkout is clean before calling attempt_roll.
commit_untracked=True,
dry_run=True,
)
# Extract the version into TWO match groups
m = re.match(r"^(\d{8}_\d{2}_RC)(\d{2})$", version)
# Increment the RC # in the second match group
# Recombine to form the new version
tag = m.groups()[0] + str(int(m.groups()[1]) + 1).zfill(2)
with api.context(cwd=release_path):
api.git('tag', tag)
api.git('push', 'origin', 'HEAD:%s' % branch)
api.git('push', '--tags')
def GenTests(api):
yield api.test('one cherrypick') + api.properties(
branch="master",
version="20180830_00_RC00",
cherry_picks=['topaz/fc4dc762688d2263b254208f444f5c0a4b91bc07'],
pins=[],
remote="https://fuchsia.googlesource.com/releases",
project="releases") + api.step_data('check if done (0)',
api.auto_roller.success())
yield api.test('one roll') + api.properties(
branch="master",
version="20180830_00_RC00",
cherry_picks=[],
pins=['topaz/fc4dc762688d2263b254208f444f5c0a4b91bc07'],
remote="https://fuchsia.googlesource.com/releases",
project="releases") + api.step_data('check if done (0)',
api.auto_roller.success())
yield api.test('no cherrypick') + api.properties(
branch="master",
version="20180830_00_RC00",
cherry_picks=[],
pins=[],
remote="https://fuchsia.googlesource.com/releases",
project="releases")
yield api.test('has cherrypick file') + api.properties(
branch="master",
version="20180830_00_RC00",
cherry_picks=['topaz/fc4dc762688d2263b254208f444f5c0a4b91bc07'],
pins=[],
remote="https://fuchsia.googlesource.com/releases",
project="releases") + api.step_data(
'check if done (0)', api.auto_roller.success()) + api.path.exists(
api.path['start_dir'].join('releases', 'cherrypick.json'))