| # Copyright 2019 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 rolling a CIPD package which other packages depend on.""" |
| |
| from recipe_engine.config import List |
| from recipe_engine.post_process import StepSuccess |
| from recipe_engine.recipe_api import Property |
| |
| DEPS = [ |
| 'fuchsia/jiri', |
| 'fuchsia/auto_roller', |
| 'fuchsia/cipd_dependencies', |
| 'recipe_engine/archive', |
| 'recipe_engine/buildbucket', |
| 'recipe_engine/cipd', |
| 'recipe_engine/context', |
| 'recipe_engine/file', |
| 'recipe_engine/json', |
| 'recipe_engine/properties', |
| 'recipe_engine/path', |
| 'recipe_engine/step', |
| ] |
| |
| PROPERTIES = { |
| 'manifests': |
| Property( |
| kind=List(dict), |
| help=( |
| 'A list of dictionaries with project, manifest and remote key.' |
| )), |
| 'package': |
| Property( |
| kind=str, help='The list of CIPD packages to update in $import_in'), |
| 'ref': |
| Property( |
| kind=str, |
| default='latest', |
| help='A common CIPD ref to resolve when rolling a set of packages'), |
| 'owners': |
| Property( |
| kind=List(str), |
| default=(), |
| help=('The owners responsible for watching this roller ' |
| '(example: "username@google.com").')), |
| 'dependents': |
| Property( |
| kind=List(dict), default=(), |
| help=('Dependent package properties.')), |
| 'versions_file': |
| Property( |
| kind=str, |
| help=('A string with the path to the versions file inside ' |
| 'the CIPD package.')) |
| } |
| |
| COMMIT_MESSAGE = """[roll] Roll {roller} CIPD packages: |
| |
| {packages} |
| |
| From: {old_version} |
| To: {version} |
| |
| Test: CQ |
| CQ-Do-Not-Cancel-Tryjobs: true""" |
| |
| CIPD_URL = 'https://chrome-infra-packages.appspot.com/p/{package}/+/{version}' |
| |
| |
| def RunSteps(api, manifests, ref, owners, versions_file, dependents, package): |
| """Run the recipe steps.""" |
| |
| with api.context(infra_steps=True): |
| if owners: |
| with api.step.nest('owners') as owners_presentation: |
| owners_presentation.step_summary_text = ', '.join(owners) |
| |
| # Import manifests |
| api.jiri.init(use_lock_file=True) |
| for manifest_config in manifests: |
| api.jiri.import_manifest( |
| manifest=manifest_config['manifest'], |
| remote=manifest_config['remote'], |
| name=manifest_config['project']) |
| api.jiri.update(run_hooks=False) |
| api.jiri.run_hooks() |
| |
| deps_info = api.jiri.package([package]) |
| cipd_description = api.cipd.describe(package, ref) |
| |
| # Is there a new version to roll? |
| if cipd_description.tags[0].tag == deps_info.json.output[0]['version']: |
| api.step('manifest up-to-date; nothing to roll', None) |
| return |
| |
| # Read main package versions file. |
| main_package_version_dict = api.cipd_dependencies.get_dependencies( |
| 'read versions', package, cipd_description.pin.instance_id, versions_file) |
| |
| # For every dependent read version file and validate versions. |
| validation_summary = [] |
| for dep in dependents: |
| cipd_dep_desc = api.cipd.describe(dep['package'], dep['ref']) |
| version_dict = api.cipd_dependencies.get_dependencies( |
| 'read dep versions', dep['package'], cipd_dep_desc.pin.instance_id, |
| dep['versions_file']) |
| summary = api.cipd_dependencies.validate_against_package( |
| package=dep, |
| dependencies=dep['dependencies'], |
| package_versions=main_package_version_dict, |
| dependent_versions=version_dict) |
| if summary: |
| validation_summary.append(summary) |
| if validation_summary: |
| msg = 'Project-dependent version mismatching: {}'.format( |
| '\n'.join(validation_summary)) |
| # After a new version of the main package is available, dependents may still |
| # need more time to build versions with it. We mark this step as successful |
| # to avoid disruption to build cops looking for a solution to something that |
| # is expected. |
| api.step('validation_summary', cmd=None).presentation.step_text = msg |
| return |
| # Roll everything |
| api.step('Rolling-Success', None) |
| |
| |
| def GenTests(api): |
| |
| properties = { |
| 'manifests': [{ |
| 'project': 'integration', |
| 'manifest': 'other/dependency', |
| 'remote': 'sso://fuchsia/integration' |
| }, { |
| 'project': 'integration', |
| 'manifest': 'fuchsia/flower', |
| 'remote': 'sso://fuchsia/integration' |
| }], |
| 'package': 'flutter/fuchsia/${platform}', |
| 'package_dependencies': [ |
| 'package=dart', |
| 'project=skia', |
| ], |
| 'dependents': [{ |
| 'package': 'abc/dependent', |
| 'ref': 'latest', |
| 'versions_file': 'dependent.json', |
| 'dependencies': ['engine_version'] |
| }], |
| 'import_in': 'fuchsia/prebuilts', |
| 'versions_file': 'flutter/versions.json', |
| 'owners': ['abc@gmail.com'] |
| } |
| |
| package_no_match_test_data = api.step_data( |
| 'cipd describe flutter/fuchsia/${platform}', |
| api.cipd.example_describe( |
| package_name='flutter/fuchsia', |
| version='version_abc', |
| test_data_tags=['git_revision:revision_abc'])) |
| jiri_package_test_data = [ |
| { |
| 'name': 'flutter/fuchsia', |
| 'path': 'flutter/fuchsia', |
| 'version': 'git_revision:revision_abc', |
| 'manifest': 'manifest1' |
| }, |
| ] |
| default_properties = api.properties(**properties) |
| # Version of the cipd package is the same as the one currently in the |
| # source tree. |
| yield ( |
| api.test('nothing_to_roll') + default_properties + |
| package_no_match_test_data + |
| api.step_data('jiri package', api.jiri.package(jiri_package_test_data))) |
| |
| package_match_test_data = api.step_data( |
| 'cipd describe flutter/fuchsia/${platform}', |
| api.cipd.example_describe( |
| package_name='flutter/fuchsia', |
| version='version_abc', |
| test_data_tags=['git_revision:revision_jkl'])) |
| package_versions = { |
| 'engine_version': 'engine_version_xyz', |
| } |
| dependent_versions = { |
| 'engine_version': 'engine_version_lmn', |
| } |
| # Version of the cipd package is different from the one in the tree and ready |
| # to get rolled but the latest dependent version does not match the versions |
| # being rolled. |
| yield (api.test('dependent_not_matching_versions') + default_properties + |
| package_match_test_data + api.step_data( |
| 'jiri package', api.jiri.package(jiri_package_test_data)) + |
| api.step_data('read versions', |
| api.file.read_json(json_content=package_versions)) + |
| api.step_data('read dep versions', |
| api.file.read_json(json_content=dependent_versions)) + |
| api.post_process(StepSuccess, 'validation_summary')) |
| dependent_versions_match = { |
| 'engine_version': 'engine_version_xyz', |
| } |
| # Version of the cipd package is different from the one in the tree and ready |
| # to get rolled but the dependent latest version match the versions |
| # being rolled. |
| yield ( |
| api.test('dependent_matching_versions') + default_properties + |
| package_match_test_data + |
| api.step_data('jiri package', api.jiri.package(jiri_package_test_data)) + |
| api.step_data('read versions', |
| api.file.read_json(json_content=package_versions)) + |
| api.step_data('read dep versions', |
| api.file.read_json(json_content=dependent_versions_match)) + |
| api.post_process(StepSuccess, 'Rolling-Success')) |