# Copyright 2022 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.

"""Update CIPD ensure files in a Git repository."""

from PB.recipes.fuchsia.cipd_ensure_file_roller import InputProperties

DEPS = [
    "fuchsia/auto_roller",
    "fuchsia/buildbucket_util",
    "fuchsia/cipd_resolver",
    "fuchsia/cipd_util",
    "fuchsia/git_checkout",
    "recipe_engine/cipd",
    "recipe_engine/json",
    "recipe_engine/path",
    "recipe_engine/properties",
]

PROPERTIES = InputProperties


def RunSteps(api, props):
    props.tag = props.tag or "version"
    props.ref = props.ref or "latest"
    # Note that we only support Git checkouts. Jiri checkouts are not expected
    # to have CIPD ensure files.
    checkout_dir = api.path.mkdtemp("checkout")
    api.git_checkout(props.remote, path=checkout_dir)

    all_packages = []
    for ensure_file, packages in props.packages_by_ensure_file.items():
        platforms = api.cipd_util.get_platforms(
            f"get platforms for {ensure_file}",
            ensure_file=checkout_dir.join(ensure_file),
        )
        all_packages += api.cipd_util.expand_packages_by_platforms(
            packages=packages,
            platforms=platforms,
        )

    all_packages = sorted(all_packages)

    candidate_versions = api.cipd_resolver.resolve_common_tags(
        ref=props.ref,
        tag_name=props.tag,
        packages=all_packages,
    )
    version = candidate_versions[0]

    for ensure_file, packages in props.packages_by_ensure_file.items():
        api.cipd_util.update_packages(
            f"update {ensure_file}",
            ensure_file=checkout_dir.join(ensure_file),
            packages=packages,
            version=version,
        )
        api.cipd.ensure_file_resolve(checkout_dir.join(ensure_file))

    commit_message = api.auto_roller.generate_package_roll_message(
        packages=all_packages,
        version=version,
        dry_run=props.roll_options.dry_run,
    )

    change = api.auto_roller.attempt_roll(
        props.roll_options,
        repo_dir=checkout_dir,
        commit_message=commit_message,
    )
    return api.auto_roller.raw_result(change)


def GenTests(api):
    ensure_file = "foo.ensure"
    packages = ["fuchsia/foo/${platform}", "fuchsia/bar/${platform}"]
    default_props = api.properties(
        packages_by_ensure_file={ensure_file: packages},
        remote="https://fuchsia.googlesource.com/integration",
        roll_options=api.auto_roller.Options(
            remote="https://fuchsia.googlesource.com/integration",
        ),
    )

    def resolved_tags(tags):
        return api.step_data("resolve common tags", api.json.output(tags))

    yield (
        api.buildbucket_util.test("roll", builder="cipd-roller")
        + resolved_tags(["version:newest", "version:newer"])
        + api.cipd_util.get_platforms(
            f"get platforms for {ensure_file}",
            ["linux-amd64", "linux-arm64", "mac-amd64"],
        )
        + api.cipd_util.update_packages(f"update {ensure_file}", packages)
        + api.auto_roller.success()
        + default_props
    )
