Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CI][Bisect][4] Add pre-sanity check to avoid infra or external change root causes #34553

Merged
merged 58 commits into from
Apr 21, 2023
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
7aaef88
No cluster environment
can-anyscale Apr 11, 2023
0e1cb17
Bisect
can-anyscale Apr 11, 2023
c0f17f7
Skeleton for bisect job
can-anyscale Apr 11, 2023
2440931
Rename script
can-anyscale Apr 12, 2023
394c20f
Add unit tests
can-anyscale Apr 12, 2023
3d9e1d0
Add unit tests
can-anyscale Apr 12, 2023
bd02413
Lints
can-anyscale Apr 12, 2023
17491fa
Undo irrelevant changes
can-anyscale Apr 12, 2023
30bcd0d
Remove irrelevant changes
can-anyscale Apr 12, 2023
673b39f
@krfricke's comments
can-anyscale Apr 13, 2023
a71b496
Running test
can-anyscale Apr 12, 2023
ac1031c
Get test outcome
can-anyscale Apr 12, 2023
90b7abb
master branch
can-anyscale Apr 12, 2023
2724345
Remove break
can-anyscale Apr 12, 2023
dec4a98
Break into smaller functions
can-anyscale Apr 12, 2023
a29a7b3
Rebase
can-anyscale Apr 13, 2023
1c375e5
Correct test run branch + commit
can-anyscale Apr 14, 2023
b942205
Rebase
can-anyscale Apr 14, 2023
bd7dcde
Rebase
can-anyscale Apr 14, 2023
03210c7
Rebase
can-anyscale Apr 15, 2023
e7b8cb1
Add unit tests
can-anyscale Apr 12, 2023
9163e1d
Add unit tests
can-anyscale Apr 12, 2023
8ba7b86
Lints
can-anyscale Apr 12, 2023
4ba50e4
@krfricke's comments
can-anyscale Apr 13, 2023
4b2e45b
Running test
can-anyscale Apr 12, 2023
ed479f8
Make sure to checkout the right commit before bisecting
can-anyscale Apr 14, 2023
f5e806f
Default branch to master
can-anyscale Apr 14, 2023
83f2edc
Try again
can-anyscale Apr 14, 2023
304b371
Add ray test commit
can-anyscale Apr 14, 2023
0b7b0fe
Rebase
can-anyscale Apr 14, 2023
ed08351
Rebase
can-anyscale Apr 14, 2023
8a7a56e
Fix lints
can-anyscale Apr 14, 2023
d19f081
Rebase
can-anyscale Apr 15, 2023
642e688
Rebase
can-anyscale Apr 15, 2023
1e82140
Remove debugging info
can-anyscale Apr 15, 2023
55c7497
Remove the noop bash line
can-anyscale Apr 17, 2023
2f7f5d9
Rebase
can-anyscale Apr 17, 2023
0983dec
Rebase
can-anyscale Apr 17, 2023
d80a319
Rebase
can-anyscale Apr 19, 2023
1f9e3b3
Add unit tests
can-anyscale Apr 12, 2023
cb4fa75
Lints
can-anyscale Apr 12, 2023
a868187
Sanity check for bisect
can-anyscale Apr 18, 2023
62c0973
Rebase
can-anyscale Apr 18, 2023
85e2050
Fix tests
can-anyscale Apr 18, 2023
6381914
FIx lints
can-anyscale Apr 18, 2023
249136d
Rebase
can-anyscale Apr 18, 2023
5896f24
Remove debugging info
can-anyscale Apr 19, 2023
3e04eaa
Rebase
can-anyscale Apr 19, 2023
8ebaf0b
Rebase
can-anyscale Apr 19, 2023
77a040a
Rebase
can-anyscale Apr 19, 2023
52f9a34
Rebase
can-anyscale Apr 19, 2023
60243f7
Rebase
can-anyscale Apr 19, 2023
687cfa4
@aslonnie's comments
can-anyscale Apr 20, 2023
4986ae4
Rebase
can-anyscale Apr 21, 2023
02be1f3
Make pipe command works
can-anyscale Apr 21, 2023
fa8f0c2
buildkite get outcome needs quote
can-anyscale Apr 21, 2023
a55db6e
outcome/outcomes
can-anyscale Apr 21, 2023
477fdf7
[CI][Bisect][5] Concurrent bisect (#34595)
can-anyscale Apr 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 44 additions & 19 deletions release/ray_release/scripts/ray_bisect.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
import json
import time
from typing import List
from typing import List, Dict
can-anyscale marked this conversation as resolved.
Show resolved Hide resolved
from ray_release.logger import logger
from ray_release.buildkite.step import get_step
from ray_release.config import (
Expand All @@ -19,32 +19,52 @@
@click.argument("passing_commit", required=True, type=str)
@click.argument("failing_commit", required=True, type=str)
def main(test_name: str, passing_commit: str, failing_commit: str) -> None:
test = _get_test(test_name)
pre_sanity_check = _sanity_check(test, passing_commit, failing_commit)
if not pre_sanity_check:
logger.info(
"Failed pre-saniy check, the test might be flaky or fail due to"
" an external (not a code change) factors"
)
return
commit_lists = _get_commit_lists(passing_commit, failing_commit)
blamed_commit = _bisect(test_name, commit_lists)
blamed_commit = _bisect(test, commit_lists)
logger.info(f"Blamed commit found for test {test_name}: {blamed_commit}")


def _bisect(test_name: str, commit_list: List[str]) -> str:
test = _get_test(test_name)
def _bisect(test: Test, commit_list: List[str]) -> str:
while len(commit_list) > 2:
logger.info(
f"Bisecting between {len(commit_list)} commits: "
f"{commit_list[0]} to {commit_list[-1]}"
)
middle_commit_idx = len(commit_list) // 2
middle_commit = commit_list[middle_commit_idx]
is_passing = _run_test(test, middle_commit)
is_passing = _run_test(test, [middle_commit])[middle_commit] == "passed"
if is_passing:
commit_list = commit_list[middle_commit_idx:]
else:
commit_list = commit_list[: middle_commit_idx + 1]
return commit_list[-1]


def _run_test(test: Test, commit: str) -> bool:
logger.info(f'Running test {test["name"]} on commit {commit}')
_trigger_test_run(test, commit)
return _obtain_test_result(commit)
def _sanity_check(test: Test, passing_revision: str, failing_revision: str) -> bool:
can-anyscale marked this conversation as resolved.
Show resolved Hide resolved
logger.info(
f"Sanity check passing revision: {passing_revision}"
f" and failing revision: {failing_revision}"
)
outcomes = _run_test(test, [passing_revision, failing_revision])
return (
outcomes[passing_revision] == "passed"
and outcomes[failing_revision] != "passed"
)


def _run_test(test: Test, commits: List[str]) -> Dict[str, str]:
logger.info(f'Running test {test["name"]} on commits {commits}')
for commit in commits:
_trigger_test_run(test, commit)
return _obtain_test_result(commits)


def _trigger_test_run(test: Test, commit: str) -> None:
Expand All @@ -53,7 +73,7 @@ def _trigger_test_run(test: Test, commit: str) -> None:
timeout=DEFAULT_WHEEL_WAIT_TIMEOUT,
)
step = get_step(test, ray_wheels=ray_wheels_url)
step["label"] = f'{test["name"]}:{commit[:6]}'
step["label"] = f'{test["name"]}:{commit[:7]}'
can-anyscale marked this conversation as resolved.
Show resolved Hide resolved
step["key"] = commit
pipeline = json.dumps({"steps": [step]})
subprocess.check_output(
Expand All @@ -62,20 +82,25 @@ def _trigger_test_run(test: Test, commit: str) -> None:
)


def _obtain_test_result(buildkite_step_key: str) -> bool:
outcome = None
def _obtain_test_result(buildkite_step_keys: List[str]) -> Dict[str, str]:
outcomes = {}
wait = 30
total_wait = 0
while outcome not in ["passed", "hard_failed", "soft_failed"]:
while len(outcomes) != len(buildkite_step_keys):
can-anyscale marked this conversation as resolved.
Show resolved Hide resolved
logger.info(f"... waiting for test result ...({total_wait} seconds)")
outcome = subprocess.check_output(
f'buildkite-agent step get "outcome" --step "{buildkite_step_key}"',
shell=True,
).decode("utf-8")
for key in buildkite_step_keys:
if key in outcomes:
continue
outcome = subprocess.check_output(
f'buildkite-agent step get "outcome" --step "{key}"',
shell=True,
can-anyscale marked this conversation as resolved.
Show resolved Hide resolved
).decode("utf-8")
if outcome:
outcomes[key] = outcome
time.sleep(wait)
total_wait = total_wait + wait
logger.info(f"Final test outcome: {outcome}")
return outcome == "passed"
logger.info(f"Final test outcomes: {outcomes}")
return outcomes


def _get_test(test_name: str) -> Test:
Expand Down
23 changes: 11 additions & 12 deletions release/ray_release/tests/test_bisect.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
from unittest import mock
from typing import List, Dict
from ray_release.scripts.ray_bisect import _bisect
from ray_release.config import Test


def test_bisect():
test_cases = {
"c3": {
"c0": True,
"c1": True,
"c3": False,
"c4": False,
"c0": "passed",
"c1": "passed",
"c3": "hard_failed",
"c4": "soft_failed",
},
"c1": {
"c0": True,
"c1": False,
"c0": "passed",
"c1": "hard_failed",
},
}

for output, input in test_cases.items():

def _mock_run_test(test_name: str, commit: str) -> bool:
return input[commit]
def _mock_run_test(test: Test, commit: List[str]) -> Dict[str, str]:
return input

with mock.patch(
"ray_release.scripts.ray_bisect._run_test",
side_effect=_mock_run_test,
), mock.patch(
"ray_release.scripts.ray_bisect._get_test",
return_value={},
):
assert _bisect("test", list(input.keys())) == output
assert _bisect({}, list(input.keys())) == output
6 changes: 5 additions & 1 deletion release/run_release_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ fi
if [ -z "${NO_CLONE}" ]; then
TMPDIR=$(mktemp -d -t release-XXXXXXXXXX)
echo "Cloning test repo ${RAY_TEST_REPO} branch ${RAY_TEST_BRANCH}"
git clone -b "${RAY_TEST_BRANCH}" "${RAY_TEST_REPO}" "${TMPDIR}"
if [ -n "${RAY_TEST_COMMIT}" ]; then
git clone -b "${RAY_TEST_BRANCH}" "${RAY_TEST_REPO}" "${TMPDIR}"
else
git clone --depth 1 -b "${RAY_TEST_BRANCH}" "${RAY_TEST_REPO}" "${TMPDIR}"
fi
pushd "${TMPDIR}/release" || true
HEAD_COMMIT=$(git rev-parse HEAD)
echo "The cloned test repo has head commit of ${HEAD_COMMIT}"
Expand Down