ci.sh 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. #!/usr/bin/env bash
  2. # Push caller's shell options (quietly)
  3. { SHELLOPTS_STACK="${SHELLOPTS_STACK-}|$(set +o); set -$-"; } 2> /dev/null
  4. set -eo pipefail
  5. if [ -z "${TRAVIS_PULL_REQUEST-}" ] || [ -n "${OSTYPE##darwin*}" ]; then set -ux; fi
  6. ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE:-$0}")"; pwd)"
  7. WORKSPACE_DIR="${ROOT_DIR}/.."
  8. suppress_output() {
  9. "${WORKSPACE_DIR}"/ci/suppress_output "$@"
  10. }
  11. keep_alive() {
  12. "${WORKSPACE_DIR}"/ci/keep_alive "$@"
  13. }
  14. # Calls the provided command with set -x temporarily suppressed
  15. suppress_xtrace() {
  16. {
  17. local restore_shell_state=""
  18. if [ -o xtrace ]; then set +x; restore_shell_state="set -x"; fi
  19. } 2> /dev/null
  20. local status=0
  21. "$@" || status=$?
  22. ${restore_shell_state}
  23. { return "${status}"; } 2> /dev/null
  24. }
  25. # If provided the names of one or more environment variables, returns 0 if any of them is triggered.
  26. # Usage: should_run_job [VAR_NAME]...
  27. should_run_job() {
  28. local skip=0
  29. if [ -n "${1-}" ]; then # were any triggers provided? (if not, then the job will always run)
  30. local envvar active_triggers=()
  31. for envvar in "$@"; do
  32. if [ "${!envvar}" = 1 ]; then
  33. # success! we found at least one of the given triggers is occurring
  34. active_triggers+=("${envvar}=${!envvar}")
  35. fi
  36. done
  37. if [ 0 -eq "${#active_triggers[@]}" ]; then
  38. echo "Job is not triggered by any of $1; skipping job."
  39. sleep 15 # make sure output is flushed
  40. skip=1
  41. else
  42. echo "Job is triggered by: ${active_triggers[*]}"
  43. fi
  44. fi
  45. return "${skip}"
  46. }
  47. # Idempotent environment loading
  48. reload_env() {
  49. # Try to only modify CI-specific environment variables here (TRAVIS_... or GITHUB_...),
  50. # e.g. for CI cross-compatibility.
  51. # Normal environment variables should be set up at software installation time, not here.
  52. if [ -n "${GITHUB_PULL_REQUEST-}" ]; then
  53. case "${GITHUB_PULL_REQUEST}" in
  54. [1-9]*) TRAVIS_PULL_REQUEST="${GITHUB_PULL_REQUEST}";;
  55. *) TRAVIS_PULL_REQUEST=false;;
  56. esac
  57. export TRAVIS_PULL_REQUEST
  58. fi
  59. if [ "${GITHUB_ACTIONS-}" = true ] && [ -z "${TRAVIS_BRANCH-}" ]; then
  60. # Define TRAVIS_BRANCH to make Travis scripts run on GitHub Actions.
  61. TRAVIS_BRANCH="${GITHUB_BASE_REF:-${GITHUB_REF}}" # For pull requests, the base branch name
  62. TRAVIS_BRANCH="${TRAVIS_BRANCH#refs/heads/}" # Remove refs/... prefix
  63. # TODO(mehrdadn): Make TRAVIS_BRANCH be a named ref (e.g. 'master') like it's supposed to be.
  64. # For now we use a hash because GitHub Actions doesn't clone refs the same way as Travis does.
  65. TRAVIS_BRANCH="${GITHUB_HEAD_SHA:-${TRAVIS_BRANCH}}"
  66. export TRAVIS_BRANCH
  67. fi
  68. }
  69. need_wheels() {
  70. local error_code=1
  71. case "${OSTYPE}" in
  72. linux*) if [ "${LINUX_WHEELS-}" = 1 ]; then error_code=0; fi;;
  73. darwin*) if [ "${MAC_WHEELS-}" = 1 ]; then error_code=0; fi;;
  74. msys*) if [ "${WINDOWS_WHEELS-}" = 1 ]; then error_code=0; fi;;
  75. esac
  76. return "${error_code}"
  77. }
  78. upload_wheels() {
  79. local branch="" commit
  80. commit="$(git rev-parse --verify HEAD)"
  81. if [ -z "${branch}" ]; then branch="${GITHUB_BASE_REF-}"; fi
  82. if [ -z "${branch}" ]; then branch="${GITHUB_REF#refs/heads/}"; fi
  83. if [ -z "${branch}" ]; then branch="${TRAVIS_BRANCH-}"; fi
  84. if [ -z "${branch}" ]; then echo "Unable to detect branch name" 1>&2; return 1; fi
  85. local local_dir="python/dist"
  86. if [ -d "${local_dir}" ]; then
  87. ls -a -l -- "${local_dir}"
  88. local remote_dir
  89. for remote_dir in latest "${branch}/${commit}"; do
  90. if command -V aws; then
  91. aws s3 sync --acl public-read --no-progress "${local_dir}" "s3://ray-wheels/${remote_dir}"
  92. fi
  93. done
  94. fi
  95. (
  96. cd "${WORKSPACE_DIR}"/python
  97. if ! python -s -c "import ray, sys; sys.exit(0 if ray._raylet.OPTIMIZED else 1)"; then
  98. echo "ERROR: Uploading non-optimized wheels! Performance will suffer for users!"
  99. false
  100. fi
  101. )
  102. }
  103. test_core() {
  104. local args=(
  105. "//:*"
  106. )
  107. case "${OSTYPE}" in
  108. msys)
  109. args+=(
  110. -//:core_worker_test
  111. -//:event_test
  112. -//:gcs_server_rpc_test
  113. -//:ray_syncer_test # TODO (iycheng): it's flaky on windows. Add it back once we figure out the cause
  114. -//:gcs_client_reconnection_test
  115. )
  116. ;;
  117. esac
  118. # shellcheck disable=SC2046
  119. bazel test --config=ci --build_tests_only $(./ci/run/bazel_export_options) -- "${args[@]}"
  120. }
  121. prepare_docker() {
  122. rm "${WORKSPACE_DIR}"/python/dist/* ||:
  123. pushd "${WORKSPACE_DIR}/python"
  124. pip install -e . --verbose
  125. python setup.py bdist_wheel
  126. tmp_dir="/tmp/prepare_docker_$RANDOM"
  127. mkdir -p $tmp_dir
  128. cp "${WORKSPACE_DIR}"/python/dist/*.whl $tmp_dir
  129. wheel=$(ls "${WORKSPACE_DIR}"/python/dist/)
  130. base_image=$(python -c "import sys; print(f'rayproject/ray-deps:nightly-py{sys.version_info[0]}{sys.version_info[1]}-cpu')")
  131. echo "
  132. FROM $base_image
  133. ENV LC_ALL=C.UTF-8
  134. ENV LANG=C.UTF-8
  135. COPY ./*.whl /
  136. EXPOSE 8000
  137. EXPOSE 10001
  138. RUN pip install /${wheel}[serve]
  139. RUN sudo apt update && sudo apt install curl -y
  140. " > $tmp_dir/Dockerfile
  141. pushd $tmp_dir
  142. docker build . -t ray_ci:v1
  143. popd
  144. popd
  145. }
  146. # For running Python tests on Windows.
  147. test_python() {
  148. local pathsep=":" args=()
  149. if [ "${OSTYPE}" = msys ]; then
  150. pathsep=";"
  151. args+=(
  152. python/ray/serve/...
  153. python/ray/tests/...
  154. -python/ray/serve:conda_env # pip field in runtime_env not supported
  155. -python/ray/serve:test_cross_language # Ray java not built on Windows yet.
  156. -python/ray/serve:test_gcs_failure # Fork not supported in windows
  157. -python/ray/serve:test_standalone2 # Multinode not supported on Windows
  158. -python/ray/serve:test_gradio
  159. -python/ray/serve:test_gradio_visualization
  160. -python/ray/serve:test_air_integrations_gpu
  161. -python/ray/serve:test_fastapi
  162. -python/ray/tests:test_actor_advanced # crashes in shutdown
  163. -python/ray/tests:test_autoscaler # We don't support Autoscaler on Windows
  164. -python/ray/tests:test_autoscaler_aws
  165. -python/ray/tests:test_cli
  166. -python/ray/tests:test_client_init # timeout
  167. -python/ray/tests:test_command_runner # We don't support Autoscaler on Windows
  168. -python/ray/tests:test_gcs_fault_tolerance # flaky
  169. -python/ray/serve:test_get_deployment # address violation
  170. -python/ray/tests:test_global_gc
  171. -python/ray/tests:test_job
  172. -python/ray/tests:test_memstat
  173. -python/ray/tests:test_multi_node_3
  174. -python/ray/tests:test_object_manager # OOM on test_object_directory_basic
  175. -python/ray/tests:test_resource_demand_scheduler
  176. -python/ray/tests:test_stress # timeout
  177. -python/ray/tests:test_stress_sharded # timeout
  178. -python/ray/tests:test_tracing # tracing not enabled on windows
  179. -python/ray/tests:kuberay/test_autoscaling_e2e # irrelevant on windows
  180. -python/ray/tests/xgboost/... # Requires ML dependencies, should not be run on Windows
  181. -python/ray/tests/lightgbm/... # Requires ML dependencies, should not be run on Windows
  182. -python/ray/tests/horovod/... # Requires ML dependencies, should not be run on Windows
  183. -python/ray/tests/ray_lightning/... # Requires ML dependencies, should not be run on Windows
  184. -python/ray/tests/ml_py36_compat/... # Required ML dependencies, should not be run on Windows
  185. -python/ray/tests:test_batch_node_provider_unit.py # irrelevant on windows
  186. -python/ray/tests:test_batch_node_provider_integration.py # irrelevant on windows
  187. )
  188. fi
  189. if [ 0 -lt "${#args[@]}" ]; then # Any targets to test?
  190. install_ray
  191. # Shard the args.
  192. BUILDKITE_PARALLEL_JOB=${BUILDKITE_PARALLEL_JOB:-'0'}
  193. BUILDKITE_PARALLEL_JOB_COUNT=${BUILDKITE_PARALLEL_JOB_COUNT:-'1'}
  194. test_shard_selection=$(python ./ci/run/bazel_sharding/bazel_sharding.py --exclude_manual --index "${BUILDKITE_PARALLEL_JOB}" --count "${BUILDKITE_PARALLEL_JOB_COUNT}" "${args[@]}")
  195. # TODO(mehrdadn): We set PYTHONPATH here to let Python find our pickle5 under pip install -e.
  196. # It's unclear to me if this should be necessary, but this is to make tests run for now.
  197. # Check why this issue doesn't arise on Linux/Mac.
  198. # Ideally importing ray.cloudpickle should import pickle5 automatically.
  199. # shellcheck disable=SC2046,SC2086
  200. bazel test --config=ci \
  201. --build_tests_only $(./ci/run/bazel_export_options) \
  202. --test_env=PYTHONPATH="${PYTHONPATH-}${pathsep}${WORKSPACE_DIR}/python/ray/pickle5_files" \
  203. --test_env=CI="1" \
  204. --test_env=RAY_CI_POST_WHEEL_TESTS="1" \
  205. --test_env=USERPROFILE="${USERPROFILE}" \
  206. --test_output=streamed \
  207. -- \
  208. ${test_shard_selection};
  209. fi
  210. }
  211. # For running large Python tests on Linux and MacOS.
  212. test_large() {
  213. # shellcheck disable=SC2046
  214. bazel test --config=ci $(./ci/run/bazel_export_options) --test_env=CONDA_EXE --test_env=CONDA_PYTHON_EXE \
  215. --test_env=CONDA_SHLVL --test_env=CONDA_PREFIX --test_env=CONDA_DEFAULT_ENV --test_env=CONDA_PROMPT_MODIFIER \
  216. --test_env=CI --test_tag_filters="large_size_python_tests_shard_${BUILDKITE_PARALLEL_JOB}" "$@" \
  217. -- python/ray/tests/...
  218. }
  219. test_cpp() {
  220. # C++ worker example need _GLIBCXX_USE_CXX11_ABI flag, but if we put the flag into .bazelrc, the linux ci can't pass.
  221. # So only set the flag in c++ worker example. More details: https://github.com/ray-project/ray/pull/18273
  222. echo build --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0" >> ~/.bazelrc
  223. bazel build --config=ci //cpp:all
  224. # shellcheck disable=SC2046
  225. bazel test --config=ci $(./ci/run/bazel_export_options) --test_strategy=exclusive //cpp:all --build_tests_only
  226. # run cluster mode test with external cluster
  227. bazel test //cpp:cluster_mode_test --test_arg=--external_cluster=true --test_arg=--redis_password="1234" \
  228. --test_arg=--ray_redis_password="1234"
  229. bazel test --test_output=all //cpp:test_python_call_cpp
  230. # run the cpp example
  231. rm -rf ray-template
  232. ray cpp --generate-bazel-project-template-to ray-template
  233. pushd ray-template && bash run.sh
  234. }
  235. test_wheels() {
  236. local result=0 flush_logs=0
  237. if need_wheels; then
  238. "${WORKSPACE_DIR}"/ci/build/test-wheels.sh || { result=$? && flush_logs=1; }
  239. fi
  240. if [ 0 -ne "${flush_logs}" ]; then
  241. cat -- /tmp/ray/session_latest/logs/* || true
  242. sleep 60 # Explicitly sleep 60 seconds for logs to go through
  243. fi
  244. return "${result}"
  245. }
  246. install_npm_project() {
  247. if [ "${OSTYPE}" = msys ]; then
  248. # Not Windows-compatible: https://github.com/npm/cli/issues/558#issuecomment-584673763
  249. { echo "WARNING: Skipping NPM due to module incompatibilities with Windows"; } 2> /dev/null
  250. else
  251. npm ci
  252. fi
  253. }
  254. build_dashboard_front_end() {
  255. if [ "${OSTYPE}" = msys ]; then
  256. { echo "WARNING: Skipping dashboard due to NPM incompatibilities with Windows"; } 2> /dev/null
  257. else
  258. (
  259. cd ray/dashboard/client
  260. # skip nvm activation on buildkite linux instances.
  261. if [ -z "${BUILDKITE-}" ] || [[ "${OSTYPE}" != linux* ]]; then
  262. set +x # suppress set -x since it'll get very noisy here
  263. . "${HOME}/.nvm/nvm.sh"
  264. NODE_VERSION="14"
  265. nvm install $NODE_VERSION
  266. nvm use --silent $NODE_VERSION
  267. fi
  268. install_npm_project
  269. npm run build
  270. )
  271. fi
  272. }
  273. build_sphinx_docs() {
  274. (
  275. cd "${WORKSPACE_DIR}"/doc
  276. if [ "${OSTYPE}" = msys ]; then
  277. echo "WARNING: Documentation not built on Windows due to currently-unresolved issues"
  278. else
  279. make html
  280. pip install datasets==2.0.0
  281. RAY_MOCK_MODULES=0 make doctest
  282. fi
  283. )
  284. }
  285. check_sphinx_links() {
  286. (
  287. cd "${WORKSPACE_DIR}"/doc
  288. if [ "${OSTYPE}" = msys ]; then
  289. echo "WARNING: Documentation not built on Windows due to currently-unresolved issues"
  290. else
  291. make linkcheck
  292. fi
  293. )
  294. }
  295. install_cython_examples() {
  296. (
  297. cd "${WORKSPACE_DIR}"/doc/examples/cython
  298. pip install scipy
  299. python setup.py install --user
  300. )
  301. }
  302. install_go() {
  303. local gimme_url="https://raw.githubusercontent.com/travis-ci/gimme/master/gimme"
  304. suppress_xtrace eval "$(curl -f -s -L "${gimme_url}" | GIMME_GO_VERSION=1.18.3 bash)"
  305. if [ -z "${GOPATH-}" ]; then
  306. GOPATH="${GOPATH:-${HOME}/go_dir}"
  307. export GOPATH
  308. fi
  309. }
  310. _bazel_build_before_install() {
  311. local target
  312. if [ "${OSTYPE}" = msys ]; then
  313. # On Windows, we perform as full of a build as possible, to ensure the repository always remains buildable on Windows.
  314. # (Pip install will not perform a full build.)
  315. target="//:*"
  316. else
  317. # Just build Python on other platforms.
  318. # This because pip install captures & suppresses the build output, which causes a timeout on CI.
  319. target="//:ray_pkg"
  320. fi
  321. # NOTE: Do not add build flags here. Use .bazelrc and --config instead.
  322. if [ -z "${RAY_DEBUG_BUILD-}" ]; then
  323. bazel build "${target}"
  324. elif [ "${RAY_DEBUG_BUILD}" = "asan" ]; then
  325. # bazel build --config asan "${target}"
  326. echo "Not needed"
  327. elif [ "${RAY_DEBUG_BUILD}" = "debug" ]; then
  328. bazel build --config debug "${target}"
  329. else
  330. echo "Invalid config given"
  331. exit 1
  332. fi
  333. }
  334. _bazel_build_protobuf() {
  335. bazel build "//:install_py_proto"
  336. }
  337. install_ray() {
  338. # TODO(mehrdadn): This function should be unified with the one in python/build-wheel-windows.sh.
  339. (
  340. cd "${WORKSPACE_DIR}"/python
  341. build_dashboard_front_end
  342. keep_alive pip install -v -e .
  343. )
  344. (
  345. # For runtime_env tests, wheels are needed
  346. cd "${WORKSPACE_DIR}"
  347. keep_alive pip wheel -e python -w .whl
  348. )
  349. }
  350. validate_wheels_commit_str() {
  351. if [ "${OSTYPE}" = msys ]; then
  352. echo "Windows builds do not set the commit string, skipping wheel commit validity check."
  353. return 0
  354. fi
  355. if [ -n "${BUILDKITE_COMMIT}" ]; then
  356. EXPECTED_COMMIT=${BUILDKITE_COMMIT:-}
  357. else
  358. EXPECTED_COMMIT=${TRAVIS_COMMIT:-}
  359. fi
  360. if [ -z "$EXPECTED_COMMIT" ]; then
  361. echo "Could not validate expected wheel commits: TRAVIS_COMMIT is empty."
  362. return 0
  363. fi
  364. for whl in .whl/*.whl; do
  365. basename=${whl##*/}
  366. if [[ "$basename" =~ "_cpp" ]]; then
  367. # cpp wheels cannot be checked this way
  368. echo "Skipping CPP wheel ${basename} for wheel commit validation."
  369. continue
  370. fi
  371. folder=${basename%%-cp*}
  372. WHL_COMMIT=$(unzip -p "$whl" "${folder}.data/purelib/ray/__init__.py" | grep "__commit__" | awk -F'"' '{print $2}')
  373. if [ "${WHL_COMMIT}" != "${EXPECTED_COMMIT}" ]; then
  374. echo "Error: Observed wheel commit (${WHL_COMMIT}) is not expected commit (${EXPECTED_COMMIT}). Aborting."
  375. exit 1
  376. fi
  377. echo "Wheel ${basename} has the correct commit: ${WHL_COMMIT}"
  378. done
  379. echo "All wheels passed the sanity check and have the correct wheel commit set."
  380. }
  381. build_wheels() {
  382. # Create wheel output directory and empty contents
  383. # If buildkite runners are re-used, wheels from previous builds might be here, so we delete them.
  384. mkdir -p .whl
  385. rm -rf .whl/* || true
  386. case "${OSTYPE}" in
  387. linux*)
  388. # Mount bazel cache dir to the docker container.
  389. # For the linux wheel build, we use a shared cache between all
  390. # wheels, but not between different travis runs, because that
  391. # caused timeouts in the past. See the "cache: false" line below.
  392. local MOUNT_BAZEL_CACHE=(
  393. -v "${HOME}/ray-bazel-cache":/root/ray-bazel-cache
  394. -e "TRAVIS=true"
  395. -e "TRAVIS_PULL_REQUEST=${TRAVIS_PULL_REQUEST:-false}"
  396. -e "encrypted_1c30b31fe1ee_key=${encrypted_1c30b31fe1ee_key-}"
  397. -e "encrypted_1c30b31fe1ee_iv=${encrypted_1c30b31fe1ee_iv-}"
  398. -e "TRAVIS_COMMIT=${TRAVIS_COMMIT}"
  399. -e "CI=${CI}"
  400. -e "RAY_INSTALL_JAVA=${RAY_INSTALL_JAVA:-}"
  401. -e "BUILDKITE=${BUILDKITE:-}"
  402. -e "BUILDKITE_PULL_REQUEST=${BUILDKITE_PULL_REQUEST:-}"
  403. -e "BUILDKITE_BAZEL_CACHE_URL=${BUILDKITE_BAZEL_CACHE_URL:-}"
  404. -e "RAY_DEBUG_BUILD=${RAY_DEBUG_BUILD:-}"
  405. )
  406. if [ -z "${BUILDKITE-}" ]; then
  407. # This command should be kept in sync with ray/python/README-building-wheels.md,
  408. # except the "${MOUNT_BAZEL_CACHE[@]}" part.
  409. docker run --rm -w /ray -v "${PWD}":/ray "${MOUNT_BAZEL_CACHE[@]}" \
  410. quay.io/pypa/manylinux2014_x86_64:2021-11-07-28723f3 /ray/python/build-wheel-manylinux2014.sh
  411. else
  412. rm -rf /ray-mount/*
  413. rm -rf /ray-mount/.whl || true
  414. rm -rf /ray/.whl || true
  415. cp -rT /ray /ray-mount
  416. ls -a /ray-mount
  417. docker run --rm -v /ray:/ray-mounted ubuntu:focal ls /
  418. docker run --rm -v /ray:/ray-mounted ubuntu:focal ls /ray-mounted
  419. docker run --rm -w /ray -v /ray:/ray "${MOUNT_BAZEL_CACHE[@]}" \
  420. quay.io/pypa/manylinux2014_x86_64:2021-11-07-28723f3 /ray/python/build-wheel-manylinux2014.sh
  421. cp -rT /ray-mount /ray # copy new files back here
  422. find . | grep whl # testing
  423. # Sync the directory to buildkite artifacts
  424. rm -rf /artifact-mount/.whl || true
  425. if [ "${UPLOAD_WHEELS_AS_ARTIFACTS-}" = "1" ]; then
  426. cp -r .whl /artifact-mount/.whl
  427. chmod -R 777 /artifact-mount/.whl
  428. fi
  429. validate_wheels_commit_str
  430. fi
  431. ;;
  432. darwin*)
  433. # This command should be kept in sync with ray/python/README-building-wheels.md.
  434. "${WORKSPACE_DIR}"/python/build-wheel-macos.sh
  435. mkdir -p /tmp/artifacts/.whl
  436. rm -rf /tmp/artifacts/.whl || true
  437. if [ "${UPLOAD_WHEELS_AS_ARTIFACTS-}" = "1" ]; then
  438. cp -r .whl /tmp/artifacts/.whl
  439. chmod -R 777 /tmp/artifacts/.whl
  440. fi
  441. validate_wheels_commit_str
  442. ;;
  443. msys*)
  444. keep_alive "${WORKSPACE_DIR}"/python/build-wheel-windows.sh
  445. ;;
  446. esac
  447. }
  448. lint_readme() {
  449. if python -s -c "import docutils" >/dev/null 2>/dev/null; then
  450. (
  451. cd "${WORKSPACE_DIR}"/python
  452. python setup.py check --restructuredtext --strict --metadata
  453. )
  454. else
  455. echo "Skipping README lint because the docutils package is not installed" 1>&2
  456. fi
  457. }
  458. lint_scripts() {
  459. FORMAT_SH_PRINT_DIFF=1 "${ROOT_DIR}"/lint/format.sh --all-scripts
  460. }
  461. lint_banned_words() {
  462. "${ROOT_DIR}"/lint/check-banned-words.sh
  463. }
  464. lint_annotations() {
  465. "${ROOT_DIR}"/lint/check_api_annotations.py
  466. }
  467. lint_bazel() {
  468. # Run buildifier without affecting external environment variables
  469. (
  470. mkdir -p -- "${GOPATH}"
  471. export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"
  472. # Build buildifier
  473. go install github.com/bazelbuild/buildtools/buildifier@latest
  474. # Now run buildifier
  475. "${ROOT_DIR}"/lint/bazel-format.sh
  476. )
  477. }
  478. lint_bazel_pytest() {
  479. pip install yq
  480. cd "${WORKSPACE_DIR}"
  481. for team in "team:ml" "team:rllib" "team:serve"; do
  482. # this does the following:
  483. # - find all py_test rules in bazel that have the specified team tag EXCEPT ones with "no_main" tag and outputs them as xml
  484. # - converts the xml to json
  485. # - feeds the json into pytest_checker.py
  486. bazel query "kind(py_test.*, tests(python/...) intersect attr(tags, \"\b$team\b\", python/...) except attr(tags, \"\bno_main\b\", python/...))" --output xml | xq | python scripts/pytest_checker.py
  487. done
  488. }
  489. lint_web() {
  490. (
  491. cd "${WORKSPACE_DIR}"/python/ray/dashboard/client
  492. set +x # suppress set -x since it'll get very noisy here
  493. if [ -z "${BUILDKITE-}" ]; then
  494. . "${HOME}/.nvm/nvm.sh"
  495. NODE_VERSION="14"
  496. nvm install $NODE_VERSION
  497. nvm use --silent $NODE_VERSION
  498. fi
  499. install_npm_project
  500. local filenames
  501. # shellcheck disable=SC2207
  502. filenames=($(find src -name "*.ts" -or -name "*.tsx"))
  503. node_modules/.bin/eslint --max-warnings 0 "${filenames[@]}"
  504. node_modules/.bin/prettier --check "${filenames[@]}"
  505. node_modules/.bin/prettier --check public/index.html
  506. )
  507. }
  508. lint_copyright() {
  509. (
  510. "${ROOT_DIR}"/lint/copyright-format.sh -c
  511. )
  512. }
  513. _lint() {
  514. local platform=""
  515. case "${OSTYPE}" in
  516. linux*) platform=linux;;
  517. esac
  518. if command -v clang-format > /dev/null; then
  519. "${ROOT_DIR}"/lint/check-git-clang-format-output.sh
  520. else
  521. { echo "WARNING: Skipping linting C/C++ as clang-format is not installed."; } 2> /dev/null
  522. fi
  523. if command -v clang-tidy > /dev/null; then
  524. pushd "${WORKSPACE_DIR}"
  525. "${ROOT_DIR}"/env/install-llvm-binaries.sh
  526. popd
  527. # Disable clang-tidy until ergonomic issues are resolved.
  528. # "${ROOT_DIR}"/lint/check-git-clang-tidy-output.sh
  529. else
  530. { echo "WARNING: Skipping running clang-tidy which is not installed."; } 2> /dev/null
  531. fi
  532. # Run script linting
  533. lint_scripts
  534. # Run banned words check.
  535. lint_banned_words
  536. # Run annotations check.
  537. lint_annotations
  538. # Make sure that the README is formatted properly.
  539. lint_readme
  540. if [ "${platform}" = linux ]; then
  541. # Run Bazel linter Buildifier.
  542. lint_bazel
  543. # Check if py_test files have the if __name__... snippet
  544. lint_bazel_pytest
  545. # Run TypeScript and HTML linting.
  546. lint_web
  547. # lint copyright
  548. lint_copyright
  549. # lint test script
  550. pushd "${WORKSPACE_DIR}"
  551. bazel query 'kind("cc_test", //...)' --output=xml | python "${ROOT_DIR}"/lint/check-bazel-team-owner.py
  552. bazel query 'kind("py_test", //...)' --output=xml | python "${ROOT_DIR}"/lint/check-bazel-team-owner.py
  553. popd
  554. # Make sure tests will be run by CI.
  555. python "${ROOT_DIR}"/pipeline/check-test-run.py
  556. fi
  557. }
  558. lint() {
  559. install_go
  560. # Checkout a clean copy of the repo to avoid seeing changes that have been made to the current one
  561. (
  562. WORKSPACE_DIR="$(TMPDIR="${WORKSPACE_DIR}/.." mktemp -d)"
  563. # shellcheck disable=SC2030
  564. ROOT_DIR="${WORKSPACE_DIR}"/ci
  565. git worktree add -q "${WORKSPACE_DIR}"
  566. pushd "${WORKSPACE_DIR}"
  567. . "${ROOT_DIR}"/ci.sh _lint
  568. popd # this is required so we can remove the worktree when we're done
  569. git worktree remove --force "${WORKSPACE_DIR}"
  570. )
  571. }
  572. _check_job_triggers() {
  573. local job_names
  574. job_names="$1"
  575. local variable_definitions
  576. if command -v python3; then
  577. # shellcheck disable=SC2031
  578. variable_definitions=($(python3 "${ROOT_DIR}"/pipeline/determine_tests_to_run.py))
  579. else
  580. # shellcheck disable=SC2031
  581. variable_definitions=($(python "${ROOT_DIR}"/pipeline/determine_tests_to_run.py))
  582. fi
  583. if [ 0 -lt "${#variable_definitions[@]}" ]; then
  584. local expression restore_shell_state=""
  585. if [ -o xtrace ]; then set +x; restore_shell_state="set -x;"; fi # Disable set -x (noisy here)
  586. {
  587. expression="$(printf "%q " "${variable_definitions[@]}")"
  588. printf "%s\n" "${expression}" >> ~/.bashrc
  589. }
  590. eval "${restore_shell_state}" "${expression}" # Restore set -x, then evaluate expression
  591. fi
  592. # shellcheck disable=SC2086
  593. if ! (set +x && should_run_job ${job_names//,/ }); then
  594. if [ "${GITHUB_ACTIONS-}" = true ]; then
  595. # If this job is to be skipped, emit 'exit' into .bashrc to quickly exit all following steps.
  596. # This isn't needed on Travis (since everything runs in one shell), but is on GitHub Actions.
  597. cat <<EOF1 >> ~/.bashrc
  598. cat <<EOF2 1>&2
  599. Exiting shell as no triggers were active for this job:
  600. ${job_names//,/}
  601. The active triggers during job initialization were the following:
  602. ${variable_definitions[*]}
  603. EOF2
  604. exit 0
  605. EOF1
  606. fi
  607. exit 0
  608. fi
  609. }
  610. configure_system() {
  611. git config --global advice.detachedHead false
  612. git config --global core.askpass ""
  613. git config --global credential.helper ""
  614. git config --global credential.modalprompt false
  615. # Requests library need root certificates.
  616. if [ "${OSTYPE}" = msys ]; then
  617. certutil -generateSSTFromWU roots.sst && certutil -addstore -f root roots.sst && rm roots.sst
  618. fi
  619. }
  620. # Initializes the environment for the current job. Performs the following tasks:
  621. # - Calls 'exit 0' in this job step and all subsequent steps to quickly exit if provided a list of
  622. # job names and none of them has been triggered.
  623. # - Sets variables to indicate the job names that have been triggered.
  624. # Note: Please avoid exporting these variables. Instead, source any callees that need to use them.
  625. # This helps reduce implicit coupling of callees to their parents, as they will be unable to run
  626. # when not sourced, (especially with set -u).
  627. # - Installs dependencies for the current job.
  628. # - Exports any environment variables necessary to run the build.
  629. # Usage: init [JOB_NAMES]
  630. # - JOB_NAMES (optional): Comma-separated list of job names to trigger on.
  631. init() {
  632. # TODO(jjyao): fix it for windows
  633. if [ "${OSTYPE}" != msys ]; then
  634. _check_job_triggers "${1-}"
  635. fi
  636. configure_system
  637. # shellcheck disable=SC2031
  638. . "${ROOT_DIR}"/env/install-dependencies.sh # Script is sourced to propagate up environment changes
  639. }
  640. build() {
  641. if [ "${LINT-}" != 1 ]; then
  642. _bazel_build_before_install
  643. else
  644. _bazel_build_protobuf
  645. fi
  646. if ! need_wheels; then
  647. install_ray
  648. if [ "${LINT-}" = 1 ]; then
  649. # Try generating Sphinx documentation. To do this, we need to install Ray first.
  650. build_sphinx_docs
  651. fi
  652. fi
  653. if [ "${RAY_CYTHON_EXAMPLES-}" = 1 ]; then
  654. install_cython_examples
  655. fi
  656. if [ "${LINT-}" = 1 ]; then
  657. install_go
  658. fi
  659. if need_wheels; then
  660. build_wheels
  661. fi
  662. }
  663. run_minimal_test() {
  664. BAZEL_EXPORT_OPTIONS="$(./ci/run/bazel_export_options)"
  665. # Ignoring shellcheck is necessary because if ${BAZEL_EXPORT_OPTIONS} is wrapped by the double quotation,
  666. # bazel test cannot recognize the option.
  667. # shellcheck disable=SC2086
  668. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic
  669. # shellcheck disable=SC2086
  670. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 --test_env=TEST_EXTERNAL_REDIS=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic
  671. # shellcheck disable=SC2086
  672. bazel test --test_output=streamed --config=ci ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic_2
  673. # shellcheck disable=SC2086
  674. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 --test_env=TEST_EXTERNAL_REDIS=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic_2
  675. # shellcheck disable=SC2086
  676. bazel test --test_output=streamed --config=ci ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic_3
  677. # shellcheck disable=SC2086
  678. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 --test_env=TEST_EXTERNAL_REDIS=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic_3
  679. # shellcheck disable=SC2086
  680. bazel test --test_output=streamed --config=ci ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic_4
  681. # shellcheck disable=SC2086
  682. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 --test_env=TEST_EXTERNAL_REDIS=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic_4
  683. # shellcheck disable=SC2086
  684. bazel test --test_output=streamed --config=ci ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic_5
  685. # shellcheck disable=SC2086
  686. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 --test_env=TEST_EXTERNAL_REDIS=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_basic_5
  687. # shellcheck disable=SC2086
  688. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_output
  689. # shellcheck disable=SC2086
  690. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_runtime_env_ray_minimal
  691. # shellcheck disable=SC2086
  692. bazel test --test_output=streamed --config=ci ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_runtime_env
  693. # shellcheck disable=SC2086
  694. bazel test --test_output=streamed --config=ci ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_runtime_env_2
  695. # shellcheck disable=SC2086
  696. bazel test --test_output=streamed --config=ci ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_utils
  697. # Todo: Make compatible with python 3.9/3.10
  698. if [ "$1" != "3.9" ] && [ "$1" != "3.10" ]; then
  699. # shellcheck disable=SC2086
  700. bazel test --test_output=streamed --config=ci ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_runtime_env_complicated
  701. fi
  702. # shellcheck disable=SC2086
  703. bazel test --test_output=streamed --config=ci ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_runtime_env_validation
  704. # shellcheck disable=SC2086
  705. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_serve_ray_minimal
  706. # shellcheck disable=SC2086
  707. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 ${BAZEL_EXPORT_OPTIONS} python/ray/dashboard/test_dashboard
  708. # shellcheck disable=SC2086
  709. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_usage_stats
  710. # shellcheck disable=SC2086
  711. bazel test --test_output=streamed --config=ci --test_env=RAY_MINIMAL=1 --test_env=TEST_EXTERNAL_REDIS=1 ${BAZEL_EXPORT_OPTIONS} python/ray/tests/test_usage_stats
  712. }
  713. test_minimal() {
  714. ./ci/env/install-minimal.sh "$1"
  715. ./ci/env/env_info.sh
  716. python ./ci/env/check_minimal_install.py
  717. run_minimal_test "$1"
  718. }
  719. test_latest_core_dependencies() {
  720. ./ci/env/install-minimal.sh "$1"
  721. ./ci/env/env_info.sh
  722. ./ci/env/install-core-prerelease-dependencies.sh
  723. run_minimal_test "$1"
  724. }
  725. _main() {
  726. if [ "${GITHUB_ACTIONS-}" = true ]; then
  727. exec 2>&1 # Merge stdout and stderr to prevent out-of-order buffering issues
  728. reload_env
  729. fi
  730. "$@"
  731. }
  732. _main "$@"
  733. # Pop caller's shell options (quietly)
  734. { set -vx; eval "${SHELLOPTS_STACK##*|}"; SHELLOPTS_STACK="${SHELLOPTS_STACK%|*}"; } 2> /dev/null