action.yml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. name: Run build and tests (ya make)
  2. description: Run test targets listed in repository root ya.make (to be created previously)
  3. inputs:
  4. build_target:
  5. required: true
  6. build_preset:
  7. required: true
  8. default: "relwithdebinfo"
  9. description: "relwithdebinfo, release-asan, release-tsan"
  10. test_type:
  11. required: false
  12. type: string
  13. default: ""
  14. description: "run only specific test types (or all by default)"
  15. test_size:
  16. required: false
  17. default: "small,medium,large"
  18. description: "small or small-medium or all"
  19. test_threads:
  20. required: false
  21. default: "56"
  22. description: "Test threads count"
  23. link_threads:
  24. required: false
  25. default: "12"
  26. description: "link threads count"
  27. additional_ya_make_args:
  28. type: string
  29. default: ""
  30. testman_token:
  31. required: false
  32. description: "test manager auth token"
  33. testman_url:
  34. required: false
  35. description: "test manager endpoint"
  36. testman_project_id:
  37. required: false
  38. description: "test manager project id"
  39. put_build_results_to_cache:
  40. required: false
  41. default: "true"
  42. bazel_remote_uri:
  43. required: false
  44. description: "bazel-remote endpoint"
  45. bazel_remote_username:
  46. required: false
  47. description: "bazel-remote username"
  48. bazel_remote_password:
  49. required: false
  50. description: "bazel-remote password"
  51. run_tests:
  52. type: boolean
  53. default: true
  54. description: "run tests"
  55. test_retry_count:
  56. type: string
  57. default: ""
  58. description: "how many times to retry failed tests"
  59. outputs:
  60. success:
  61. value: ${{ steps.build.outputs.status }}
  62. description: "build success"
  63. runs:
  64. using: "composite"
  65. steps:
  66. - name: Install Node required for Testmo CLI
  67. uses: actions/setup-node@v3
  68. with:
  69. node-version: 19
  70. - name: Init
  71. id: init
  72. shell: bash
  73. run: |
  74. set -x
  75. export TMP_DIR=$(pwd)/tmp
  76. rm -rf $TMP_DIR
  77. mkdir -p $TMP_DIR
  78. echo "TMP_DIR=$TMP_DIR" >> $GITHUB_ENV
  79. # The whole dir will be uploaded to s3 with public (=wild internet) ACL
  80. export PUBLIC_DIR=$TMP_DIR/results
  81. echo "PUBLIC_DIR=$PUBLIC_DIR" >> $GITHUB_ENV
  82. export PUBLIC_DIR_URL=$S3_URL_PREFIX
  83. echo "PUBLIC_DIR_URL=$PUBLIC_DIR_URL" >> $GITHUB_ENV
  84. mkdir -p $PUBLIC_DIR
  85. echo "LAST_JUNIT_REPORT_XML=$PUBLIC_DIR/last_junit.xml" >> $GITHUB_ENV
  86. echo "TESTMO_URL=${{ inputs.testman_url }}" >> $GITHUB_ENV
  87. echo "SUMMARY_LINKS=$PUBLIC_DIR/summary_links.txt" >> $GITHUB_ENV
  88. echo "BUILD_PRESET=${{ inputs.build_preset }}" >> $GITHUB_ENV
  89. python3 -m pip install ydb ydb[yc] codeowners
  90. - name: set environment variables required by some tests
  91. if: inputs.run_tests
  92. shell: bash
  93. run: |
  94. echo "PSQL_BINARY=/usr/bin/psql" >> $GITHUB_ENV
  95. - name: ya build and test
  96. id: build
  97. shell: bash
  98. run: |
  99. set -x
  100. readarray -d ',' -t test_size < <(printf "%s" "${{ inputs.test_size }}")
  101. readarray -d ',' -t test_type < <(printf "%s" "${{ inputs.test_type }}")
  102. params=(
  103. -T
  104. ${test_size[@]/#/--test-size=} ${test_type[@]/#/--test-type=}
  105. --stat
  106. --test-threads "${{ inputs.test_threads }}" --link-threads "${{ inputs.link_threads }}"
  107. -DUSE_EAT_MY_DATA
  108. )
  109. TEST_RETRY_COUNT=${{ inputs.test_retry_count }}
  110. case "$BUILD_PRESET" in
  111. debug)
  112. params+=(--build "debug")
  113. ;;
  114. relwithdebinfo)
  115. params+=(--build "relwithdebinfo")
  116. ;;
  117. release)
  118. params+=(--build "release")
  119. ;;
  120. release-clang14)
  121. params+=(--build "release")
  122. params+=(--target-platform="CLANG14-LINUX-X86_64")
  123. params+=(-DLLD_VERSION=16)
  124. params+=(-DSTRIP)
  125. ;;
  126. release-asan)
  127. params+=(
  128. --build "release" --sanitize="address"
  129. -DDEBUGINFO_LINES_ONLY
  130. )
  131. if [ $TEST_RETRY_COUNT -z ]; then
  132. TEST_RETRY_COUNT=1
  133. fi
  134. ;;
  135. release-tsan)
  136. params+=(
  137. --build "release" --sanitize="thread"
  138. -DDEBUGINFO_LINES_ONLY
  139. )
  140. if [ $TEST_RETRY_COUNT -z ]; then
  141. TEST_RETRY_COUNT=1
  142. fi
  143. ;;
  144. release-msan)
  145. params+=(
  146. --build "release" --sanitize="memory"
  147. -DDEBUGINFO_LINES_ONLY
  148. )
  149. if [ $TEST_RETRY_COUNT -z ]; then
  150. TEST_RETRY_COUNT=1
  151. fi
  152. ;;
  153. *)
  154. echo "Invalid preset: $BUILD_PRESET"
  155. exit 1
  156. ;;
  157. esac
  158. if [ $TEST_RETRY_COUNT -z ]; then
  159. # default is 3 for ordinary build and 1 for sanitizer builds
  160. TEST_RETRY_COUNT=3
  161. fi
  162. if [ ! -z "${{ inputs.additional_ya_make_args }}" ]; then
  163. params+=(${{ inputs.additional_ya_make_args }})
  164. fi
  165. if [ ! -z "${{ inputs.bazel_remote_uri }}" ]; then
  166. params+=(--bazel-remote-store)
  167. params+=(--bazel-remote-base-uri "${{ inputs.bazel_remote_uri }}")
  168. fi
  169. if [ "${{ inputs.put_build_results_to_cache }}" = "true" ]; then
  170. params+=(--bazel-remote-username "${{ inputs.bazel_remote_username }}")
  171. params+=(--bazel-remote-password "${{ inputs.bazel_remote_password }}")
  172. params+=(--bazel-remote-put --dist-cache-max-file-size=209715200)
  173. fi
  174. if [ true = ${{ inputs.run_tests }} ]; then
  175. params+=(-A)
  176. fi
  177. params+=(
  178. --stat -DCONSISTENT_DEBUG --no-dir-outputs
  179. --test-failure-code 0 --build-all
  180. --cache-size 2TB --force-build-depends
  181. )
  182. TESTMO_BRANCH_TAG="$GITHUB_REF_NAME"
  183. TESTMO_ARCH="${{ runner.arch == 'X64' && 'x86-64' || runner.arch == 'ARM64' && 'arm64' || 'unknown' }}"
  184. TESTMO_PR_NUMBER=${{ github.event.number }}
  185. # install testmo
  186. npm install -g @testmo/testmo-cli
  187. case "$BUILD_PRESET" in
  188. relwithdebinfo)
  189. TESTMO_SOURCE="ya-${TESTMO_ARCH}"
  190. ;;
  191. debug)
  192. TESTMO_SOURCE="ya-${TESTMO_ARCH}-debug"
  193. ;;
  194. release-*)
  195. TESTMO_SOURCE="ya-${TESTMO_ARCH}-${BUILD_PRESET/release-/}"
  196. ;;
  197. *)
  198. echo "Invalid preset: $BUILD_PRESET"
  199. exit 1
  200. ;;
  201. esac
  202. case $GITHUB_EVENT_NAME in
  203. workflow_dispatch)
  204. TESTMO_RUN_NAME="${{ github.run_id }} manual"
  205. TESTMO_EXTRA_TAG="manual"
  206. ;;
  207. pull_request | pull_request_target)
  208. TESTMO_RUN_NAME="${{ github.run_id }} PR #${TESTMO_PR_NUMBER}"
  209. TESTMO_EXTRA_TAG="pr"
  210. TESTMO_BRANCH_TAG=""
  211. ;;
  212. schedule)
  213. TESTMO_RUN_NAME="${{ github.run_id }} schedule"
  214. TESTMO_EXTRA_TAG="schedule"
  215. ;;
  216. push)
  217. TESTMO_RUN_NAME="${{ github.run_id }} POST"
  218. TESTMO_EXTRA_TAG="post-commit"
  219. ;;
  220. *)
  221. TESTMO_RUN_NAME="${{ github.run_id }}"
  222. TESTMO_EXTRA_TAG=""
  223. ;;
  224. esac
  225. echo "TESTMO_RUN_NAME=$TESTMO_RUN_NAME" >> $GITHUB_ENV
  226. echo "::debug::get version"
  227. ./ya --version
  228. YA_MAKE_OUT_DIR=$TMP_DIR/out
  229. YA_MAKE_OUTPUT="$PUBLIC_DIR/ya_make_output.log"
  230. YA_MAKE_OUTPUT_URL="$PUBLIC_DIR_URL/ya_make_output.log"
  231. echo "20 [Ya make output]($YA_MAKE_OUTPUT_URL)" >> $SUMMARY_LINKS
  232. echo "YA_MAKE_OUTPUT_URL=$YA_MAKE_OUTPUT_URL" >> $GITHUB_ENV
  233. BUILD_FAILED=0
  234. for RETRY in $(seq 1 $TEST_RETRY_COUNT)
  235. do
  236. if [ $RETRY != 1 ]; then
  237. IS_RETRY=1
  238. else
  239. IS_RETRY=0
  240. fi
  241. if [ ${{ inputs.testman_token }} ]; then
  242. # inititalize testmo session
  243. TESTMO_RUN_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
  244. TESTMO_TOKEN=${{ inputs.testman_token }} testmo automation:resources:add-link --name build --url "$TESTMO_RUN_URL" --resources testmo.json
  245. TESTMO_TOKEN=${{ inputs.testman_token }} testmo automation:resources:add-field --name git-sha --type string --value "${GITHUB_SHA:0:7}" --resources testmo.json
  246. TESTMO_RUN_ID=$(
  247. TESTMO_TOKEN=${{ inputs.testman_token }} testmo automation:run:create --instance "$TESTMO_URL" --project-id ${{ inputs.testman_project_id }} \
  248. --name "$TESTMO_RUN_NAME" --source "$TESTMO_SOURCE" --resources testmo.json \
  249. --tags "$TESTMO_BRANCH_TAG" --tags "$TESTMO_EXTRA_TAG"
  250. )
  251. echo "runid=${TESTMO_RUN_ID}" >> $GITHUB_OUTPUT
  252. TESTMO_HISTORY_URL="${TESTMO_URL}/automation/runs/view/${TESTMO_RUN_ID}"
  253. # Replace test history link
  254. cat $SUMMARY_LINKS | (grep -v "Test history" || true) > $TMP_DIR/tmp_summary
  255. mv $TMP_DIR/tmp_summary $SUMMARY_LINKS
  256. echo "10 [Test history](${TESTMO_HISTORY_URL})" >> $SUMMARY_LINKS
  257. fi
  258. CURRENT_MESSAGE="**{platform_name}-${BUILD_PRESET}** is running..."
  259. if [ $IS_RETRY = 0 ]; then
  260. CURRENT_MESSAGE="Check $CURRENT_MESSAGE"
  261. RERUN_FAILED_TESTS=""
  262. else
  263. CURRENT_MESSAGE="Failed tests rerun (try $RETRY) $CURRENT_MESSAGE"
  264. RERUN_FAILED_OPT="-X"
  265. fi
  266. echo $CURRENT_MESSAGE | GITHUB_TOKEN="${{ github.token }}" .github/scripts/tests/comment-pr.py
  267. CURRENT_PUBLIC_DIR_RELATIVE=try_$RETRY
  268. CURRENT_PUBLIC_DIR=$PUBLIC_DIR/$CURRENT_PUBLIC_DIR_RELATIVE
  269. mkdir $CURRENT_PUBLIC_DIR
  270. CURRENT_JUNIT_XML_PATH=$CURRENT_PUBLIC_DIR/junit.xml
  271. set +ex
  272. (./ya make ${{ inputs.build_target }} "${params[@]}" \
  273. $RERUN_FAILED_OPT --log-file "$PUBLIC_DIR/ya_log.log" \
  274. --evlog-file "$CURRENT_PUBLIC_DIR/ya_evlog.jsonl" \
  275. --junit "$CURRENT_JUNIT_XML_PATH" --output "$YA_MAKE_OUT_DIR"; echo $? > exit_code) |& cat >> $YA_MAKE_OUTPUT
  276. set -ex
  277. RC=`cat exit_code`
  278. # convert to chromium trace
  279. # seems analyze-make don't have simple "output" parameter, so change cwd
  280. ya_dir=$(pwd)
  281. (cd $CURRENT_PUBLIC_DIR && $ya_dir/ya analyze-make timeline --evlog ya_evlog.jsonl)
  282. if [ $RC -ne 0 ]; then
  283. echo "ya make returned $RC, build failed"
  284. echo "status=failed" >> $GITHUB_OUTPUT
  285. BUILD_FAILED=1
  286. break
  287. fi
  288. # fix junit files (add links, logs etc)
  289. # archive unitest reports (orig)
  290. gzip -c $CURRENT_JUNIT_XML_PATH > $CURRENT_PUBLIC_DIR/orig_junit.xml.gz
  291. # postprocess junit report
  292. .github/scripts/tests/transform-ya-junit.py -i \
  293. -m .github/config/muted_ya.txt \
  294. --ya_out "$YA_MAKE_OUT_DIR" \
  295. --public_dir "$PUBLIC_DIR" \
  296. --public_dir_url "$PUBLIC_DIR_URL" \
  297. --log_out_dir "$CURRENT_PUBLIC_DIR_RELATIVE/artifacts/logs/" \
  298. --test_stuff_out "$CURRENT_PUBLIC_DIR_RELATIVE/test_artifacts/" \
  299. "$CURRENT_JUNIT_XML_PATH"
  300. cp $CURRENT_JUNIT_XML_PATH $LAST_JUNIT_REPORT_XML
  301. TESTS_RESULT=0
  302. .github/scripts/tests/fail-checker.py "$CURRENT_JUNIT_XML_PATH" --output_path $CURRENT_PUBLIC_DIR/failed_count.txt || TESTS_RESULT=$?
  303. FAILED_TESTS_COUNT=$(cat $CURRENT_PUBLIC_DIR/failed_count.txt)
  304. IS_LAST_RETRY=0
  305. if [ $TESTS_RESULT = 0 ] || [ $RETRY = $TEST_RETRY_COUNT ]; then
  306. IS_LAST_RETRY=1
  307. fi
  308. s3cmd sync --follow-symlinks --acl-public --no-progress --stats --no-check-md5 "$PUBLIC_DIR/" "$S3_BUCKET_PATH/"
  309. if [ $FAILED_TESTS_COUNT -gt 500 ]; then
  310. IS_LAST_RETRY=1
  311. TOO_MANY_FAILED="Too many tests failed, NOT going to retry"
  312. echo $TOO_MANY_FAILED | GITHUB_TOKEN="${{ github.token }}" .github/scripts/tests/comment-pr.py --fail
  313. fi
  314. if [ "${{ inputs.run_tests }}" = "true" ]; then
  315. GITHUB_TOKEN=${{ github.token }} .github/scripts/tests/generate-summary.py \
  316. --summary_links "$SUMMARY_LINKS" \
  317. --public_dir "$PUBLIC_DIR" \
  318. --public_dir_url "$PUBLIC_DIR_URL" \
  319. --build_preset "$BUILD_PRESET" \
  320. --status_report_file statusrep.txt \
  321. --is_retry $IS_RETRY \
  322. --is_last_retry $IS_LAST_RETRY \
  323. "Tests" $CURRENT_PUBLIC_DIR/ya-test.html "$CURRENT_JUNIT_XML_PATH"
  324. fi
  325. # upload tests results to YDB
  326. ydb_upload_run_name="${TESTMO_RUN_NAME// /"_"}"
  327. result=`.github/scripts/upload_tests_results.py --test-results-file ${CURRENT_JUNIT_XML_PATH} --run-timestamp $(date +%s) --commit $(git rev-parse HEAD) --build-type ${BUILD_PRESET} --pull $ydb_upload_run_name --job-name "${{ github.workflow }}" --job-id "${{ github.run_id }}" --branch ${GITHUB_REF_NAME}`
  328. if [ ${{ inputs.testman_token }} ]; then
  329. # finish testme session
  330. # split large junit_report
  331. export TESTMO_JUNIT_REPORT_PARTS=$TMP_DIR/junit-split
  332. mkdir -p $TESTMO_JUNIT_REPORT_PARTS
  333. .github/scripts/tests/split-junit.py -o "$TESTMO_JUNIT_REPORT_PARTS" "$CURRENT_JUNIT_XML_PATH"
  334. # archive unitest reports (transformed)
  335. tar -C $TESTMO_JUNIT_REPORT_PARTS/.. -czf $PUBLIC_DIR/junit_parts.xml.tar.gz $(basename $TESTMO_JUNIT_REPORT_PARTS)
  336. TESTMO_PROXY_ADDR=127.0.0.1:8888
  337. openssl req -x509 -newkey rsa:2048 \
  338. -keyout $TMP_DIR/key.pem -out $TMP_DIR/cert.pem \
  339. -sha256 -days 1 -nodes -subj "/CN=127.0.0.1"
  340. TESTMO_TOKEN=${{ inputs.testman_token }} ./ydb/ci/testmo-proxy/testmo-proxy.py -l $TESTMO_PROXY_ADDR \
  341. --cert-file "$TMP_DIR/cert.pem" \
  342. --cert-key "$TMP_DIR/key.pem" \
  343. --target-timeout 3,10 \
  344. --max-request-time 55 \
  345. "$TESTMO_URL" &
  346. testmo_proxy_pid=$!
  347. TESTMO_TOKEN=${{ inputs.testman_token }} NODE_TLS_REJECT_UNAUTHORIZED=0 testmo automation:run:submit-thread \
  348. --instance "https://$TESTMO_PROXY_ADDR" --run-id "$TESTMO_RUN_ID" \
  349. --results "$TESTMO_JUNIT_REPORT_PARTS/*.xml"
  350. kill $testmo_proxy_pid
  351. TESTMO_TOKEN=${{ inputs.testman_token }} testmo automation:run:complete --instance "$TESTMO_URL" --run-id $TESTMO_RUN_ID
  352. echo "runid=" >> $GITHUB_OUTPUT
  353. fi
  354. if [ $IS_LAST_RETRY = 1 ]; then
  355. break
  356. fi
  357. done;
  358. if [ $BUILD_FAILED = 0 ]; then
  359. echo "status=true" >> $GITHUB_OUTPUT
  360. fi
  361. - name: comment-build-status
  362. if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target'
  363. shell: bash
  364. env:
  365. GITHUB_TOKEN: ${{ github.token }}
  366. run: |
  367. set -x
  368. if [ "${{ steps.build.outputs.status }}" == "failed" ]; then
  369. curl -L -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{github.token}}" -H "X-GitHub-Api-Version: 2022-11-28" \
  370. https://api.github.com/repos/${{github.repository}}/statuses/${{github.event.pull_request.head.sha}} \
  371. -d '{"state":"failure","description":"The check has been failed","context":"build_${{inputs.build_preset}}"}'
  372. echo "Build failed. see the [logs]($YA_MAKE_OUTPUT_URL)." | .github/scripts/tests/comment-pr.py --fail
  373. else
  374. curl -L -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{github.token}}" -H "X-GitHub-Api-Version: 2022-11-28" \
  375. https://api.github.com/repos/${{github.repository}}/statuses/${{github.event.pull_request.head.sha}} \
  376. -d '{"state":"success","description":"The check has been completed successfully","context":"build_${{inputs.build_preset}}"}'
  377. echo "Build successful." | .github/scripts/tests/comment-pr.py --ok
  378. fi
  379. - name: Clean up unfinished testmo sessions
  380. if: always()
  381. shell: bash
  382. run: |
  383. if [ ${{ steps.build.outputs.runid }} ]; then
  384. TESTMO_TOKEN=${{ inputs.testman_token }} testmo automation:run:complete --instance "$TESTMO_URL" --run-id ${{ steps.build.outputs.runid }}
  385. fi
  386. - name: analyze tests results
  387. shell: bash
  388. env:
  389. GITHUB_TOKEN: ${{ github.token }}
  390. run: |
  391. set -x
  392. if [ true = ${{ inputs.run_tests }} ]; then
  393. teststatus=$(cat statusrep.txt)
  394. if [[ $teststatus == "success" ]];then
  395. testmessage="The check has been completed successfully"
  396. else
  397. testmessage="The check has been failed"
  398. fi
  399. curl -L -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{github.token}}" -H "X-GitHub-Api-Version: 2022-11-28" \
  400. https://api.github.com/repos/${{github.repository}}/statuses/${{github.event.pull_request.head.sha}} \
  401. -d '{"state":"'$teststatus'","description":"'"$testmessage"'","context":"test_${{inputs.build_preset}}"}'
  402. if [[ $teststatus != "success" ]];then
  403. echo "status=failed" >> $GITHUB_OUTPUT
  404. fi
  405. fi
  406. - name: check test results
  407. if: inputs.run_tests
  408. shell: bash
  409. run: |
  410. .github/scripts/tests/fail-checker.py "$LAST_JUNIT_REPORT_XML"
  411. - name: sync results to s3 and publish links
  412. if: always()
  413. shell: bash
  414. run: |
  415. set -x
  416. echo "::group::s3-sync"
  417. .github/scripts/Indexer/indexer.py -r "$PUBLIC_DIR/"
  418. echo "00 [Workflow artifacts](${S3_URL_PREFIX}/index.html)" >> $SUMMARY_LINKS
  419. s3cmd sync --follow-symlinks --acl-public --no-progress --stats --no-check-md5 "$PUBLIC_DIR/" "$S3_BUCKET_PATH/"
  420. cat $SUMMARY_LINKS | python3 -c 'import sys; print(" | ".join([v for _, v in sorted([l.strip().split(" ", 1) for l in sys.stdin], key=lambda a: (int(a[0]), a))]))' >> $GITHUB_STEP_SUMMARY
  421. echo "::endgroup::"
  422. - name: show free space
  423. if: always()
  424. shell: bash
  425. run: df -h