bisect-kit: Improve strategy to get actions between branched CROS specs
When `prev_spec` and `next_spec` not on the same branch, we should
follow the branch stated in `next_spec` instead of `prev_spec` to
build the action list.
BUG=b:147575652
TEST=python3 -m unittest bisect_kit/cros_util_test.py
TEST=python3 -m unittest bisect_kit/git_util_test.py
TEST=./bisect_cr_localbuild_internal.py init --old 81.0.3995.0 --new 81.0.3999.0
TEST=./bisect_cros_version.py init --board samus-kernelnext --old R80-12739.10.0 --new R80-12739.11.0
TEST=./bisect_cros_repo.py init --board samus-kernelnext --old R80-12739.0.0 --new R80-12739.1.0
TEST=./bisect_cros_repo.py init --board samus-kernelnext --old R80-12739.10.0 --new R80-12739.11.0
TEST=./bisect_cros_repo.py init --board samus-kernelnext --old R80-12739.0.0 --new R80-12739.11.0
TEST=./bisect_cros_repo.py init --board samus-kernelnext --old R80-12730.0.0 --new R80-12739.0.0
TEST=./bisect_cros_repo.py init --board samus-kernelnext --old R80-12738.0.0-24800 --new R80-12739.11.0
Change-Id: I055527df79903c7ddc879024f2c9bf1dc8fa42b5
diff --git a/bisect_kit/codechange.py b/bisect_kit/codechange.py
index 3e4f3a1..900a5a0 100644
--- a/bisect_kit/codechange.py
+++ b/bisect_kit/codechange.py
@@ -585,9 +585,26 @@
# a local checkout), there is no need to convert the name.
return git_util.get_rev_by_time(git_root, timestamp, spec[path].at)
- def get_actions_between_two_commit(self, spec, path, old, new):
+ def get_actions_between_two_commit(self,
+ spec,
+ path,
+ old,
+ new,
+ ignore_not_ancestor=False):
git_root = self.cached_git_root(spec[path].repo_url)
result = []
+ # not in the same branch, regard as an atomic operation
+ # this situation happens when
+ # 1. new is branched from old and
+ # 2. commit timestamp is not reliable(i.e. commit time != merged time)
+ # old and new might not have ancestor relation
+ if ignore_not_ancestor and old != new and not git_util.is_ancestor_commit(
+ git_root, old, new):
+ timestamp = git_util.get_commit_time(git_root, new)
+ result.append(
+ GitCheckoutCommit(timestamp, path, spec[path].repo_url, new))
+ return result
+
for timestamp, git_rev in git_util.list_commits_between_commits(
git_root, old, new):
result.append(
@@ -637,6 +654,15 @@
groups = []
last_group = ActionGroup(next_float.timestamp)
is_removed = set()
+
+ # `branch_between_float_specs` is currently a chromeos-only logic,
+ # and branch behavior is not verified for android and chrome now.
+ is_chromeos_branched = False
+ if hasattr(self.spec_manager, 'branch_between_float_specs'
+ ) and self.spec_manager.branch_between_float_specs(
+ prev_float, next_float):
+ is_chromeos_branched = True
+
# Sort alphabetically, so parent directories are handled before children
# directories.
for path in sorted(set(prev_float.entries) | set(next_float.entries)):
@@ -653,20 +679,43 @@
next_at))
continue
- # Existing path is floating, enumerates commits until next spec.
- #
- # prev_at till_at
- # prev branch ---> o --------> o --------> o --------> o --------> ...
- # ^ ^
- # prev_float.timestamp next_float.timestamp
+ # Existing path is floating.
if not prev_float[path].is_static():
+ # Enumerates commits until next spec. Get `prev_at` and `till_at`
+ # by prev_float and next_float's timestamp.
+ #
+ # 1. Non-branched case:
+ #
+ # prev_at till_at
+ # prev branch ---> o --------> o --------> o --------> o --------> ...
+ # ^ ^
+ # prev_float.timestamp next_float.timestamp
+ #
+ # building an image between prev_at and till_at should follow
+ # prev_float's spec.
+ #
+ # 2. Branched case:
+ #
+ # till_at
+ # /------->o---------->
+ # / ^ next_float.timestamp
+ # / prev_at
+ # ---------->o---------------------->
+ # ^prev_float.timestamp
+ #
+ # building an image between prev_at and till_at should follow
+ # next_float's spec.
+ #
prev_at = self.code_storage.get_rev_by_time(prev_float, path,
prev_float.timestamp)
- till_at = self.code_storage.get_rev_by_time(prev_float, path,
- next_float.timestamp)
-
+ if is_chromeos_branched:
+ till_at = self.code_storage.get_rev_by_time(next_float, path,
+ next_float.timestamp)
+ else:
+ till_at = self.code_storage.get_rev_by_time(prev_float, path,
+ next_float.timestamp)
actions = self.code_storage.get_actions_between_two_commit(
- prev_float, path, prev_at, till_at)
+ prev_float, path, prev_at, till_at, ignore_not_ancestor=True)
# Assume commits with the same timestamp as manifest/DEPS change are
# atomic.