blob: c08270a628450b6f4d5f0f3c51caa4102c65a117 [file] [log] [blame]
# Copyright 2021 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 to autoroll tools into a recipes repository."""
from PB.infra.tool_metadata import ToolMetadata
from PB.recipes.fuchsia.recipe_tools_roller import InputProperties
PYTHON_VERSION_COMPATIBILITY = "PY3"
DEPS = [
"fuchsia/auto_roller",
"fuchsia/buildbucket_util",
"fuchsia/ensure_tool",
"fuchsia/gerrit",
"fuchsia/git",
"recipe_engine/cipd",
"recipe_engine/file",
"recipe_engine/path",
"recipe_engine/properties",
"recipe_engine/step",
]
PROPERTIES = InputProperties
def RunSteps(api, props):
target_ref = props.ref or "latest"
checkout_root = api.path["start_dir"].join("checkout")
api.git.checkout_from_build_input(repo=props.remote, path=checkout_root)
# Find all tool manifests.
modules_dir = checkout_root.join("recipe_modules")
tool_manifest_paths = api.file.glob_paths(
"find tool manifests",
modules_dir,
"*/resources/**/tool_manifest.json",
)
# Ensure all tool manifests match the target ref.
for tool_manifest_path in tool_manifest_paths:
# Get relpath with a stripped extension for a unique and valid step
# name, which will look like "module/resource/tool_manifest".
tool_manifest_relpath = api.path.relpath(
api.path.splitext(tool_manifest_path)[0],
modules_dir,
)
with api.step.nest("read %s" % tool_manifest_relpath) as presentation:
tool_metadata = api.ensure_tool.get_tool_metadata(
"tool", tool_manifest_path
)
if tool_metadata.do_not_autoroll:
presentation.step_text = "autoroll disabled by manifest"
continue
with api.step.nest("ensure %s is %s" % (tool_manifest_relpath, target_ref)):
# Use the tag prefix which is currently in the tool manifest.
tag_prefix = tool_metadata.version.split(":", 1)[0]
current = api.cipd.describe(tool_metadata.path, tool_metadata.version)
target = api.cipd.describe(tool_metadata.path, target_ref)
# Update the tool manifest to the most recent tag which starts with
# the tag prefix.
if current.pin.instance_id == target.pin.instance_id:
continue
tags = [t for t in target.tags if t.tag.startswith(tag_prefix)]
most_recent_tag = max(tags, key=lambda t: t.registered_ts)
api.ensure_tool.write_tool_metadata(
tool_manifest_path,
tool_metadata.path,
most_recent_tag.tag,
do_not_autoroll=tool_metadata.do_not_autoroll,
)
# TODO(fxbug.dev/84472): Parallelize roll attempts per tool manifest. The
# current behavior combines all tool manifest changes into one CL.
change = api.auto_roller.attempt_roll(
api.gerrit.host_from_remote_url(props.remote),
gerrit_project=api.gerrit.project_from_remote_url(props.remote),
repo_dir=checkout_root,
# TODO(fxbug.dev/84472): Construct a meaningful commit message on a
# per-tool basis once this is parallelized.
commit_message="[roll] Update tools to %s" % target_ref,
dry_run=props.dry_run,
)
return api.auto_roller.raw_result(change)
def GenTests(api):
props = api.properties(
remote="https://fuchsia.googlesource.com/infra/recipes",
)
tool_manifests = api.step_data(
"find tool manifests",
api.file.glob_paths(
[
"module_a/resources/tool_manifest.json",
"module_b/resources/tool_manifest.json",
"module_c/resources/tool_manifest.json",
]
),
)
# module_a should not roll.
describe_current_a = api.step_data(
"ensure module_a/resources/tool_manifest is latest.cipd describe path/to/tool",
api.cipd.example_describe(
package_name="path/to/tool",
version="version:pinned-version",
test_data_tags=["version:pinned-version"],
),
)
describe_target_a = api.step_data(
"ensure module_a/resources/tool_manifest is latest.cipd describe path/to/tool (2)",
api.cipd.example_describe(
package_name="path/to/tool",
version="version:pinned-version",
test_data_tags=["version:pinned-version"],
),
)
# module_b should roll.
describe_current_b = api.step_data(
"ensure module_b/resources/tool_manifest is latest.cipd describe path/to/tool",
api.cipd.example_describe(
package_name="path/to/tool",
version="version:pinned-version",
test_data_tags=["version:pinned-version"],
),
)
describe_target_b = api.step_data(
"ensure module_b/resources/tool_manifest is latest.cipd describe path/to/tool (2)",
api.cipd.example_describe(
package_name="path/to/tool",
version="version:new-version-to-pin",
test_data_tags=["version:new-version-to-pin"],
),
)
read_manifest_c = api.step_data(
"read module_c/resources/tool_manifest.read manifest",
api.file.read_proto(
ToolMetadata(
path="path/to/tool",
version="version:pinned-version",
do_not_autoroll=True,
),
),
)
yield (
api.buildbucket_util.test("roll_tool")
+ tool_manifests
+ props
+ describe_current_a
+ describe_target_a
+ describe_current_b
+ describe_target_b
+ read_manifest_c
+ api.auto_roller.success()
)