diff --git a/recipes/recipe_modules/bot_update/resources/bot_update.py b/recipes/recipe_modules/bot_update/resources/bot_update.py index 9a728ade6..a51494ce3 100755 --- a/recipes/recipe_modules/bot_update/resources/bot_update.py +++ b/recipes/recipe_modules/bot_update/resources/bot_update.py @@ -572,6 +572,26 @@ def get_target_pin(solution_name, git_url, revisions): return None +def force_solution_revision(solution_name, git_url, revisions, cwd): + branch, revision = _get_target_branch_and_revision( + solution_name, git_url, revisions) + if revision and revision.upper() != 'HEAD': + treeish = revision + else: + # TODO(machenbach): This won't work with branch-heads, as Gerrit's + # destination branch would be e.g. refs/branch-heads/123. But here + # we need to pass refs/remotes/branch-heads/123 to check out. + # This will also not work if somebody passes a local refspec like + # refs/heads/master. It needs to translate to refs/remotes/origin/master + # first. See also https://crbug.com/740456 . + treeish = branch if branch.startswith('refs/') else 'origin/%s' % branch + + # Note that -- argument is necessary to ensure that git treats `treeish` + # argument as revision or ref, and not as a file/directory which happens to + # have the exact same name. + git('checkout', '--force', treeish, '--', cwd=cwd) + + def _has_in_git_cache(revision_sha1, git_cache_dir, url): """Returns whether given revision_sha1 is contained in cache of a given repo. """ @@ -721,6 +741,8 @@ def _git_checkout(sln, sln_dir, revisions, shallow, refs, git_cache_dir, if sys.platform.startswith('win'): _maybe_break_locks(sln_dir, tries=3) + force_solution_revision(name, url, revisions, sln_dir) + git('clean', '-dff', cwd=sln_dir) return except SubprocessFailed as e: # Exited abnormally, theres probably something wrong. @@ -894,6 +916,16 @@ def ensure_checkout(solutions, revisions, first_sln, target_os, target_os_only, # Windows sometimes has trouble deleting files. This can make git commands # that rely on locks fail. break_repo_locks = True if sys.platform.startswith('win') else False + # We want to pass all non-solution revisions into the gclient sync call. + solution_dirs = {sln['name'] for sln in solutions} + gc_revisions = { + dirname: rev for dirname, rev in revisions.iteritems() + if dirname not in solution_dirs} + # Gclient sometimes ignores "unmanaged": "False" in the gclient solution + # if --revision is passed (for example, for subrepos). + # This forces gclient to always treat solutions deps as unmanaged. + for solution_name in list(solution_dirs): + gc_revisions[solution_name] = 'unmanaged' with git_config_if_not_set('user.name', 'chrome-bot'): with git_config_if_not_set('user.email', 'chrome-bot@chromium.org'): @@ -904,7 +936,7 @@ def ensure_checkout(solutions, revisions, first_sln, target_os, target_os_only, BRANCH_HEADS_REFSPEC in refs, TAGS_REFSPEC in refs, shallow, - revisions, + gc_revisions, break_repo_locks, disable_syntax_validation, gerrit_repo, diff --git a/tests/bot_update_coverage_test.py b/tests/bot_update_coverage_test.py index c0b11a9e1..232e0061d 100755 --- a/tests/bot_update_coverage_test.py +++ b/tests/bot_update_coverage_test.py @@ -211,7 +211,7 @@ class BotUpdateUnittests(unittest.TestCase): idx_second_revision = args.index( '--revision', idx_first_revision+1) idx_third_revision = args.index('--revision', idx_second_revision+1) - self.assertEquals(args[idx_first_revision+1], 'somename@DNE') + self.assertEquals(args[idx_first_revision+1], 'somename@unmanaged') self.assertEquals(args[idx_second_revision+1], 'src@origin/master') self.assertEquals(args[idx_third_revision+1], 'src/v8@deadbeef') return self.call.records