Add --clean-ignored option to bot_update

Currently, bot_update.py uses git clean -dff, which leaves ignored
files. This can cause build failures on bisect bots when switching
between different revisions, as stale ignored files from newer revisions
can break older ones.

Add an optional --clean-ignored flag to bot_update. When enabled, it
runs git clean -dffx.

Bug: 454315184
Change-Id: Ia7f0f6a94c78eb335bb1ed291c6d248db899b74d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/7087912
Commit-Queue: Gavin Mak <gavinmak@google.com>
Reviewed-by: Scott Lee <ddoman@chromium.org>
This commit is contained in:
Gavin Mak
2025-10-27 16:06:32 -07:00
committed by LUCI CQ
parent e2bb3cd558
commit d501813e85
4 changed files with 39 additions and 17 deletions

View File

@@ -64,12 +64,12 @@ Recipe module to ensure a checkout is consistent on a bot.
Wrapper for easy calling of bot_update.
&mdash; **def [deapply\_patch](/recipes/recipe_modules/bot_update/api.py#679)(self, bot_update_result):**
&mdash; **def [deapply\_patch](/recipes/recipe_modules/bot_update/api.py#683)(self, bot_update_result):**
Deapplies a patch, taking care of DEPS and solution revisions properly.
&mdash; **def [ensure\_checkout](/recipes/recipe_modules/bot_update/api.py#194)(self, gclient_config=None, suffix=None, patch=True, update_presentation=True, patch_root=None, with_branch_heads=False, with_tags=False, no_fetch_tags=False, refs=None, clobber=False, root_solution_revision=None, gerrit_no_reset=False, gerrit_no_rebase_patch_ref=False, assert_one_gerrit_change=True, patch_refs=None, ignore_input_commit=False, add_blamelists=False, set_output_commit=False, step_test_data=None, enforce_fetch=False, download_topics=False, recipe_revision_overrides=None, step_tags=None, \*\*kwargs):**
&mdash; **def [ensure\_checkout](/recipes/recipe_modules/bot_update/api.py#194)(self, gclient_config=None, suffix=None, patch=True, update_presentation=True, patch_root=None, with_branch_heads=False, with_tags=False, no_fetch_tags=False, refs=None, clobber=False, root_solution_revision=None, gerrit_no_reset=False, gerrit_no_rebase_patch_ref=False, assert_one_gerrit_change=True, patch_refs=None, ignore_input_commit=False, add_blamelists=False, set_output_commit=False, step_test_data=None, enforce_fetch=False, download_topics=False, recipe_revision_overrides=None, step_tags=None, clean_ignored=False, \*\*kwargs):**
Args:
* gclient_config: The gclient configuration to use when running bot_update.
@@ -105,8 +105,9 @@ Args:
change's commit message to get this revision override requested by the
author.
* step_tags: a dict {tag name: tag value} of tags to add to the step
* clean_ignored: If True, also clean ignored files from the checkout.
&mdash; **def [get\_project\_revision\_properties](/recipes/recipe_modules/bot_update/api.py#656)(self, project_name, gclient_config=None):**
&mdash; **def [get\_project\_revision\_properties](/recipes/recipe_modules/bot_update/api.py#660)(self, project_name, gclient_config=None):**
Returns all property names used for storing the checked-out revision of
a given project.
@@ -122,12 +123,12 @@ Returns (list of str): All properties that'll hold the checked-out revision
&emsp; **@property**<br>&mdash; **def [last\_returned\_properties](/recipes/recipe_modules/bot_update/api.py#102)(self):**
&mdash; **def [resolve\_fixed\_revision](/recipes/recipe_modules/bot_update/api.py#607)(self, bot_update_result, name):**
&mdash; **def [resolve\_fixed\_revision](/recipes/recipe_modules/bot_update/api.py#611)(self, bot_update_result, name):**
Sets a fixed revision for a single dependency using project revision
properties.
&mdash; **def [step\_name](/recipes/recipe_modules/bot_update/api.py#696)(self, patch, suffix):**
&mdash; **def [step\_name](/recipes/recipe_modules/bot_update/api.py#700)(self, patch, suffix):**
### *recipe_modules* / [depot\_tools](/recipes/recipe_modules/depot_tools)
[DEPS](/recipes/recipe_modules/depot_tools/__init__.py#6): [recipe\_engine/cipd][recipe_engine/recipe_modules/cipd], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime]

View File

@@ -215,6 +215,7 @@ class BotUpdateApi(recipe_api.RecipeApi):
download_topics=False,
recipe_revision_overrides=None,
step_tags=None,
clean_ignored=False,
**kwargs):
"""
Args:
@@ -251,6 +252,7 @@ class BotUpdateApi(recipe_api.RecipeApi):
change's commit message to get this revision override requested by the
author.
* step_tags: a dict {tag name: tag value} of tags to add to the step
* clean_ignored: If True, also clean ignored files from the checkout.
"""
assert not (ignore_input_commit and set_output_commit)
if assert_one_gerrit_change:
@@ -413,6 +415,8 @@ class BotUpdateApi(recipe_api.RecipeApi):
if self.m.properties.get('bot_update_experiments'):
cmd.append('--experiments=%s' %
','.join(self.m.properties['bot_update_experiments']))
if clean_ignored:
cmd.append('--clean-ignored')
# Inject Json output for testing.
first_sln = cfg.solutions[0].name

View File

@@ -662,16 +662,16 @@ def _set_git_config(fn):
def git_checkouts(solutions, revisions, refs, no_fetch_tags, git_cache_dir,
cleanup_dir, enforce_fetch):
cleanup_dir, enforce_fetch, clean_ignored):
build_dir = os.getcwd()
for sln in solutions:
sln_dir = path.join(build_dir, sln['name'])
_git_checkout(sln, sln_dir, revisions, refs, no_fetch_tags, git_cache_dir,
cleanup_dir, enforce_fetch)
cleanup_dir, enforce_fetch, clean_ignored)
def _git_checkout(sln, sln_dir, revisions, refs, no_fetch_tags, git_cache_dir,
cleanup_dir, enforce_fetch):
cleanup_dir, enforce_fetch, clean_ignored):
name = sln['name']
url = sln['url']
@@ -741,7 +741,7 @@ def _git_checkout(sln, sln_dir, revisions, refs, no_fetch_tags, git_cache_dir,
# 'pin or branch' as revision or ref, and not as file/directory which
# happens to have the exact same name.
git('checkout', '--force', pin or branch, '--', cwd=sln_dir)
git('clean', '-dff', cwd=sln_dir)
git('clean', '-dffx' if clean_ignored else '-dff', cwd=sln_dir)
return
except SubprocessFailed as e:
# Exited abnormally, there's probably something wrong.
@@ -812,18 +812,31 @@ def emit_json(out_file, did_run, **kwargs):
@_set_git_config
def ensure_checkout(solutions, revisions, first_sln, target_os, target_os_only,
target_cpu, patch_root, patch_refs, gerrit_rebase_patch_ref,
no_fetch_tags, refs, git_cache_dir, cleanup_dir,
gerrit_reset, enforce_fetch, experiments,
download_topics=False):
def ensure_checkout(solutions,
revisions,
first_sln,
target_os,
target_os_only,
target_cpu,
patch_root,
patch_refs,
gerrit_rebase_patch_ref,
no_fetch_tags,
refs,
git_cache_dir,
cleanup_dir,
gerrit_reset,
enforce_fetch,
experiments,
download_topics=False,
clean_ignored=False):
# Get a checkout of each solution, without DEPS or hooks.
# Calling git directly because there is no way to run Gclient without
# invoking DEPS.
print('Fetching Git checkout')
git_checkouts(solutions, revisions, refs, no_fetch_tags, git_cache_dir,
cleanup_dir, enforce_fetch)
cleanup_dir, enforce_fetch, clean_ignored)
# Ensure our build/ directory is set up with the correct .gclient file.
gclient_configure(solutions, target_os, target_os_only, target_cpu,
@@ -936,6 +949,9 @@ def parse_args():
parse.add_option(
'--download_topics',
action='store_true')
parse.add_option('--clean-ignored',
action='store_true',
help='Also clean ignored files from the checkout.')
parse.add_option('--clobber', action='store_true',
help='Delete checkout first, always')
@@ -1090,8 +1106,8 @@ def checkout(options, git_slns, specs, revisions, step_text):
git_cache_dir=options.git_cache_dir,
cleanup_dir=options.cleanup_dir,
gerrit_reset=not options.gerrit_no_reset,
experiments=experiments)
experiments=experiments,
clean_ignored=options.clean_ignored)
ensure_checkout(**checkout_parameters)
should_create_dirty_file = False
except GclientSyncFailed:

View File

@@ -17,6 +17,7 @@ def RunSteps(api):
api.bot_update.ensure_checkout()
api.bot_update.ensure_checkout(no_fetch_tags=True, enforce_fetch=True)
api.bot_update.ensure_checkout(step_tags={'tag': 'value'})
api.bot_update.ensure_checkout(clean_ignored=True)
def GenTests(api):