blob: fd10e1c88ad1b58e296cc6ff957054f6ac42d793 [file]
# Copyright 2024 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Runs the Mega CQ once with reduced retries.
Intended to be ran on a regular, nightly schedule to provide a signal into the
health of all optional trybots. This recipe is intended to be run from a
single Chrome CI builder. This differs from the Mega CQ orchestrator trybots
that developers actually trigger when they run the Mega CQ, as there's one
trybot for Chromium and one for Chrome. This is nominally so external devs
can still trigger the public half of the Mega CQ. There's no such need for this
smoke checker.
"""
from recipe_engine import post_process
from recipe_engine.config_types import Path # noqa: F401
from recipe_engine.recipe_api import RecipeApi
from recipe_engine.recipe_test_api import RecipeTestApi
from PB.recipe_engine.result import RawResult
from PB.recipes.build.chromium.mega_cq_smoke_check import InputProperties
from PB.go.chromium.org.luci.buildbucket.proto.builds_service import (
BatchResponse,
)
from RECIPE_MODULES.build.chromium_tests import steps
from dataclasses import dataclass
from recipe_engine.recipe_api import RecipeScriptApi
from RECIPE_MODULES.build import (
chromium,
chromium_gerrit_utils,
chromium_mega_cq,
)
from RECIPE_MODULES.depot_tools import gitiles
from RECIPE_MODULES.recipe_engine import buildbucket, properties, step
@dataclass
class DEPS(RecipeScriptApi):
buildbucket: buildbucket.API
chromium: chromium.API
chromium_gerrit_utils: chromium_gerrit_utils.API
chromium_mega_cq: chromium_mega_cq.API
gitiles: gitiles.API
properties: properties.API
step: step.API
@dataclass
class TEST_DEPS(RecipeTestApi):
buildbucket: buildbucket.TEST_API
chromium: chromium.TEST_API
gitiles: gitiles.TEST_API
properties: properties.TEST_API
PROPERTIES = InputProperties
GERRIT_TOPIC = 'mega-cq-smoke-check'
def RunSteps(api: RecipeApi, properties: InputProperties):
trybots = []
for bots_file in properties.bots_files:
trybots.extend(
api.chromium_mega_cq.read_bots_file(
bots_file.repo, bots_file.file_path, branch='HEAD'
)
)
gerrit_change, _ = api.chromium_gerrit_utils.create_temp_cl(
# We choose a file in //base/ for the CL since it's a pretty fundamental
# file and should get built into most targets. And it's not in the
# analyze-exclusion list, which means GN-analyze won't get bypassed. This
# is important since some trybots' analyze step can be broken, but that
# wouldn't get exposed for CLs that touch files in the analyze-exclusion
# list.
'base/check.cc',
GERRIT_TOPIC,
git_footers=[steps.INCLUDE_CI_FOOTER + ': true'],
)
# Clean up any old CLs left around from previous runs. A mega CQ run might
# take upwards of a day, so only remove CLs older than 2d.
api.chromium_gerrit_utils.abandon_old_cls(GERRIT_TOPIC, '48h')
result, failed_trybots = api.chromium_mega_cq.trigger_and_collect_bots(
trybots, retries=0, gerrit_change=gerrit_change
)
api.chromium_gerrit_utils.abandon_cl(gerrit_change.change)
if not failed_trybots:
return result
# Return our own markdown so we can see which trybots failed from the builder
# page of the smoke-checker.
summary_md_lines = [f'{len(failed_trybots)} builders failed:']
for trybot in failed_trybots:
summary_md_lines.append(' - ' + '/'.join(trybot))
step_result = api.step.empty('record results')
step_result.presentation.properties['failed_trybots'] = failed_trybots
return RawResult(
status=result.status, summary_markdown='\n'.join(summary_md_lines)
)
def GenTests(api: RecipeTestApi):
yield api.test(
'basic',
api.properties(
bots_files=[
{
'repo': 'https://chromium.googlesource.com/chromium/src',
'file_path': 'infra/mega_cq_bots.txt',
},
],
),
api.chromium.ci_build(),
api.post_process(post_process.DropExpectation),
)
yield api.test(
'with_failure',
api.properties(
bots_files=[
{
'repo': 'https://chromium.googlesource.com/chromium/src',
'file_path': 'infra/mega_cq_bots.txt',
},
],
),
api.chromium.ci_build(),
api.step_data(
'get mega_cq_bots.txt.read mega_cq_bots.txt',
api.gitiles.make_encoded_file(
'\n'.join(
[
'chromium/try/some_bot',
]
)
),
),
api.buildbucket.simulated_schedule_output(
BatchResponse(responses=[{'schedule_build': {'id': 100}}]),
step_name='trigger some_bot.trigger (attempt 1)',
),
api.buildbucket.simulated_collect_output(
[
api.buildbucket.ci_build_message(build_id=100, status='FAILURE'),
],
step_name='trigger some_bot.collect (attempt 1)',
),
api.expect_status('FAILURE'),
api.post_process(post_process.DropExpectation),
)