|
99 | 99 | (github.event.pull_request.draft == false || github.event.action == 'ready_for_review') && |
100 | 100 | github.event.pull_request.head.repo.full_name == github.repository |
101 | 101 | runs-on: ubuntu-latest |
102 | | - timeout-minutes: 10 |
| 102 | + timeout-minutes: 20 |
103 | 103 | steps: |
104 | 104 | - name: Download package workflow artifact |
105 | 105 | uses: actions/download-artifact@v4 |
@@ -337,6 +337,314 @@ jobs: |
337 | 337 | echo "renderer_build_id=${RENDERER_BUILD_ID}" >> "${GITHUB_OUTPUT}" |
338 | 338 | echo "renderer_build_status=${RENDERER_BUILD_STATUS}" >> "${GITHUB_OUTPUT}" |
339 | 339 |
|
| 340 | +<<<<<<< Updated upstream |
| 341 | +======= |
| 342 | + - name: Wait for Labs renderer artifact |
| 343 | + id: wait_renderer_artifact |
| 344 | + env: |
| 345 | + LABS_API_URL: ${{ vars.LABS_API_URL }} |
| 346 | + LABS_PR_BUILD_TOKEN: ${{ secrets.LABS_PR_BUILD_TOKEN || secrets.LABS_RELEASE_QUALIFICATION_TOKEN }} |
| 347 | + PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} |
| 348 | + RENDERER_BUILD_ID: ${{ steps.register.outputs.renderer_build_id }} |
| 349 | + REPOSITORY_FULL_NAME: ${{ github.repository }} |
| 350 | + run: | |
| 351 | + set -euo pipefail |
| 352 | +
|
| 353 | + if [[ -z "${LABS_API_URL}" ]]; then |
| 354 | + echo "LABS_API_URL repository variable is required." >&2 |
| 355 | + exit 1 |
| 356 | + fi |
| 357 | + if [[ -z "${LABS_PR_BUILD_TOKEN}" ]]; then |
| 358 | + echo "LABS_PR_BUILD_TOKEN secret is required." >&2 |
| 359 | + exit 1 |
| 360 | + fi |
| 361 | + if [[ -z "${RENDERER_BUILD_ID}" ]]; then |
| 362 | + echo "Register step did not produce renderer_build_id." >&2 |
| 363 | + exit 1 |
| 364 | + fi |
| 365 | +
|
| 366 | + deadline_seconds=900 |
| 367 | + poll_seconds=10 |
| 368 | + started_at="$(date +%s)" |
| 369 | + latest_message="Renderer artifact is not ready yet." |
| 370 | +
|
| 371 | + while true; do |
| 372 | + response_file="$(mktemp)" |
| 373 | + http_status="$(curl \ |
| 374 | + --get \ |
| 375 | + --silent \ |
| 376 | + --show-error \ |
| 377 | + --output "${response_file}" \ |
| 378 | + --write-out '%{http_code}' \ |
| 379 | + -H "x-labs-internal-token: ${LABS_PR_BUILD_TOKEN}" \ |
| 380 | + --data-urlencode "repository=${REPOSITORY_FULL_NAME}" \ |
| 381 | + --data-urlencode "pullRequestNumber=${PULL_REQUEST_NUMBER}" \ |
| 382 | + "${LABS_API_URL%/}/v1/internal/superdoc/pr-builds")" |
| 383 | +
|
| 384 | + if [[ "${http_status}" == "200" ]]; then |
| 385 | + response_build_id="$(jq -r '.rendererBuild.buildId // empty' "${response_file}")" |
| 386 | + renderer_artifact_id="$(jq -r '.rendererArtifact.artifactId // empty' "${response_file}")" |
| 387 | + module_url="$(jq -r '.rendererArtifact.moduleUrl // empty' "${response_file}")" |
| 388 | + style_url="$(jq -r '.rendererArtifact.styleUrl // empty' "${response_file}")" |
| 389 | +
|
| 390 | + if [[ "${response_build_id}" != "${RENDERER_BUILD_ID}" ]]; then |
| 391 | + echo "Labs returned renderer build ${response_build_id}, expected ${RENDERER_BUILD_ID}." >&2 |
| 392 | + exit 1 |
| 393 | + fi |
| 394 | + if [[ -z "${renderer_artifact_id}" || -z "${module_url}" || -z "${style_url}" ]]; then |
| 395 | + echo "Labs PR build lookup succeeded but did not include a complete renderer artifact." >&2 |
| 396 | + exit 1 |
| 397 | + fi |
| 398 | +
|
| 399 | + echo "renderer_artifact_id=${renderer_artifact_id}" >> "${GITHUB_OUTPUT}" |
| 400 | + echo "module_url=${module_url}" >> "${GITHUB_OUTPUT}" |
| 401 | + echo "style_url=${style_url}" >> "${GITHUB_OUTPUT}" |
| 402 | + break |
| 403 | + fi |
| 404 | +
|
| 405 | + latest_message="$(jq -r '.error.message // .message // "Labs PR build lookup did not return a public message."' "${response_file}" 2>/dev/null || true)" |
| 406 | + if [[ "${http_status}" != "409" || "${latest_message}" != *"renderer artifact is still building"* ]]; then |
| 407 | + echo "Labs PR build lookup failed with HTTP ${http_status}: ${latest_message}" >&2 |
| 408 | + exit 1 |
| 409 | + fi |
| 410 | +
|
| 411 | + now="$(date +%s)" |
| 412 | + if (( now - started_at >= deadline_seconds )); then |
| 413 | + echo "Timed out waiting for Labs renderer artifact after ${deadline_seconds}s: ${latest_message}" >&2 |
| 414 | + exit 1 |
| 415 | + fi |
| 416 | +
|
| 417 | + sleep "${poll_seconds}" |
| 418 | + done |
| 419 | +
|
| 420 | + - name: Write renderer artifact summary |
| 421 | + env: |
| 422 | + RENDERER_ARTIFACT_ID: ${{ steps.wait_renderer_artifact.outputs.renderer_artifact_id }} |
| 423 | + RENDERER_BUILD_ID: ${{ steps.register.outputs.renderer_build_id }} |
| 424 | + run: | |
| 425 | + { |
| 426 | + echo "### Labs: PR Renderer Build" |
| 427 | + echo |
| 428 | + echo "| Field | Value |" |
| 429 | + echo "| --- | --- |" |
| 430 | + echo "| Renderer build | \`${RENDERER_BUILD_ID}\` |" |
| 431 | + echo "| Renderer artifact | \`${RENDERER_ARTIFACT_ID}\` |" |
| 432 | + } >> "${GITHUB_STEP_SUMMARY}" |
| 433 | +
|
| 434 | + stable-promotion-checks: |
| 435 | + name: 'Labs: Stable promotion checks' |
| 436 | + needs: register |
| 437 | + # Temporarily disabled. Keep the job definition intact so the checks can |
| 438 | + # be re-enabled by removing this false guard. |
| 439 | + if: >- |
| 440 | + false && |
| 441 | + always() && |
| 442 | + github.event.action != 'closed' && |
| 443 | + github.event.pull_request.base.ref == 'stable' && |
| 444 | + (github.event.pull_request.draft == false || github.event.action == 'ready_for_review') && |
| 445 | + github.event.pull_request.head.repo.full_name == github.repository |
| 446 | + runs-on: ubuntu-latest |
| 447 | + timeout-minutes: 10 |
| 448 | + steps: |
| 449 | + - name: Verify PR renderer build registration |
| 450 | + env: |
| 451 | + REGISTER_RESULT: ${{ needs.register.result }} |
| 452 | + run: | |
| 453 | + set -euo pipefail |
| 454 | +
|
| 455 | + if [[ "${REGISTER_RESULT}" != "success" ]]; then |
| 456 | + echo "PR renderer build registration must succeed before Labs stable promotion checks can run." >&2 |
| 457 | + echo "Register job result: ${REGISTER_RESULT}" >&2 |
| 458 | + exit 1 |
| 459 | + fi |
| 460 | +
|
| 461 | + - name: Build stable promotion payload |
| 462 | + env: |
| 463 | + PR_TITLE: ${{ github.event.pull_request.title }} |
| 464 | + run: | |
| 465 | + set -euo pipefail |
| 466 | +
|
| 467 | + MERGE_PREPARATION_STATUS="unknown" |
| 468 | + if [[ "${PR_TITLE}" == *"conflicts need resolution"* ]]; then |
| 469 | + MERGE_PREPARATION_STATUS="conflicts" |
| 470 | + fi |
| 471 | +
|
| 472 | + cat <<EOF > stable-promotion-checks-payload.json |
| 473 | + { |
| 474 | + "repositoryOwner": "${{ github.repository_owner }}", |
| 475 | + "repositoryName": "${GITHUB_REPOSITORY#*/}", |
| 476 | + "repositoryFullName": "${{ github.repository }}", |
| 477 | + "pullRequestNumber": ${{ github.event.pull_request.number }}, |
| 478 | + "pullRequestUrl": "${{ github.event.pull_request.html_url }}", |
| 479 | + "baseRef": "${{ github.event.pull_request.base.ref }}", |
| 480 | + "headRef": "${{ github.event.pull_request.head.ref }}", |
| 481 | + "headSha": "${{ github.event.pull_request.head.sha }}", |
| 482 | + "mergePreparationStatus": "${MERGE_PREPARATION_STATUS}", |
| 483 | + "triggerEvent": "${{ github.event.action }}" |
| 484 | + } |
| 485 | + EOF |
| 486 | +
|
| 487 | + - name: Dispatch to Labs stable promotion orchestrator |
| 488 | + id: dispatch |
| 489 | + env: |
| 490 | + LABS_RELEASE_QUALIFICATION_TOKEN: ${{ secrets.LABS_RELEASE_QUALIFICATION_TOKEN }} |
| 491 | + LABS_RELEASE_QUALIFICATION_URL: ${{ vars.LABS_RELEASE_QUALIFICATION_URL }} |
| 492 | + run: | |
| 493 | + set -euo pipefail |
| 494 | +
|
| 495 | + if [[ -z "${LABS_RELEASE_QUALIFICATION_URL}" ]]; then |
| 496 | + echo "LABS_RELEASE_QUALIFICATION_URL is required." >&2 |
| 497 | + exit 1 |
| 498 | + fi |
| 499 | +
|
| 500 | + if [[ -z "${LABS_RELEASE_QUALIFICATION_TOKEN}" ]]; then |
| 501 | + echo "LABS_RELEASE_QUALIFICATION_TOKEN is required." >&2 |
| 502 | + exit 1 |
| 503 | + fi |
| 504 | +
|
| 505 | + RESPONSE_FILE="$(mktemp)" |
| 506 | + set +e |
| 507 | + HTTP_STATUS="$(curl \ |
| 508 | + --fail-with-body \ |
| 509 | + --silent \ |
| 510 | + --show-error \ |
| 511 | + --output "${RESPONSE_FILE}" \ |
| 512 | + --write-out '%{http_code}' \ |
| 513 | + -X POST \ |
| 514 | + -H 'content-type: application/json' \ |
| 515 | + -H "x-labs-internal-token: ${LABS_RELEASE_QUALIFICATION_TOKEN}" \ |
| 516 | + --data @stable-promotion-checks-payload.json \ |
| 517 | + "${LABS_RELEASE_QUALIFICATION_URL}")" |
| 518 | + CURL_EXIT=$? |
| 519 | + set -e |
| 520 | +
|
| 521 | + if [[ "${CURL_EXIT}" -ne 0 ]]; then |
| 522 | + cat "${RESPONSE_FILE}" |
| 523 | + exit "${CURL_EXIT}" |
| 524 | + fi |
| 525 | +
|
| 526 | + if [[ "${HTTP_STATUS}" -lt 200 || "${HTTP_STATUS}" -ge 300 ]]; then |
| 527 | + cat "${RESPONSE_FILE}" |
| 528 | + exit 1 |
| 529 | + fi |
| 530 | +
|
| 531 | + RUN_ID="$(jq -r '.run.runId // empty' "${RESPONSE_FILE}")" |
| 532 | + RUN_STATUS="$(jq -r '.run.status // empty' "${RESPONSE_FILE}")" |
| 533 | + RUN_STATUS_MESSAGE="$(jq -r '.run.statusMessage // empty' "${RESPONSE_FILE}")" |
| 534 | + CREATED="$(jq -r '.created // false' "${RESPONSE_FILE}")" |
| 535 | +
|
| 536 | + if [[ -z "${RUN_ID}" || -z "${RUN_STATUS}" ]]; then |
| 537 | + cat "${RESPONSE_FILE}" |
| 538 | + echo "Labs response did not include the expected run metadata." >&2 |
| 539 | + exit 1 |
| 540 | + fi |
| 541 | +
|
| 542 | + RUN_STATUS_URL="${LABS_RELEASE_QUALIFICATION_URL%/}/${RUN_ID}" |
| 543 | +
|
| 544 | + echo "run_id=${RUN_ID}" >> "${GITHUB_OUTPUT}" |
| 545 | + echo "run_status=${RUN_STATUS}" >> "${GITHUB_OUTPUT}" |
| 546 | + echo "run_status_message=${RUN_STATUS_MESSAGE}" >> "${GITHUB_OUTPUT}" |
| 547 | + echo "run_status_url=${RUN_STATUS_URL}" >> "${GITHUB_OUTPUT}" |
| 548 | + echo "created=${CREATED}" >> "${GITHUB_OUTPUT}" |
| 549 | +
|
| 550 | + - name: Wait for Labs stable promotion result |
| 551 | + id: await |
| 552 | + env: |
| 553 | + INITIAL_RUN_STATUS: ${{ steps.dispatch.outputs.run_status }} |
| 554 | + INITIAL_RUN_STATUS_MESSAGE: ${{ steps.dispatch.outputs.run_status_message }} |
| 555 | + LABS_RELEASE_QUALIFICATION_TOKEN: ${{ secrets.LABS_RELEASE_QUALIFICATION_TOKEN }} |
| 556 | + RUN_STATUS_URL: ${{ steps.dispatch.outputs.run_status_url }} |
| 557 | + run: | |
| 558 | + set -euo pipefail |
| 559 | +
|
| 560 | + RUN_STATUS="${INITIAL_RUN_STATUS}" |
| 561 | + RUN_STATUS_MESSAGE="${INITIAL_RUN_STATUS_MESSAGE}" |
| 562 | +
|
| 563 | + while [[ "${RUN_STATUS}" == "queued" || "${RUN_STATUS}" == "in_progress" ]]; do |
| 564 | + RESPONSE_FILE="$(mktemp)" |
| 565 | + set +e |
| 566 | + HTTP_STATUS="$(curl \ |
| 567 | + --fail-with-body \ |
| 568 | + --silent \ |
| 569 | + --show-error \ |
| 570 | + --output "${RESPONSE_FILE}" \ |
| 571 | + --write-out '%{http_code}' \ |
| 572 | + -H "x-labs-internal-token: ${LABS_RELEASE_QUALIFICATION_TOKEN}" \ |
| 573 | + "${RUN_STATUS_URL}")" |
| 574 | + CURL_EXIT=$? |
| 575 | + set -e |
| 576 | +
|
| 577 | + if [[ "${CURL_EXIT}" -ne 0 ]]; then |
| 578 | + cat "${RESPONSE_FILE}" |
| 579 | + exit "${CURL_EXIT}" |
| 580 | + fi |
| 581 | +
|
| 582 | + if [[ "${HTTP_STATUS}" -lt 200 || "${HTTP_STATUS}" -ge 300 ]]; then |
| 583 | + cat "${RESPONSE_FILE}" |
| 584 | + exit 1 |
| 585 | + fi |
| 586 | +
|
| 587 | + RUN_STATUS="$(jq -r '.run.status // empty' "${RESPONSE_FILE}")" |
| 588 | + RUN_STATUS_MESSAGE="$(jq -r '.run.statusMessage // empty' "${RESPONSE_FILE}")" |
| 589 | +
|
| 590 | + if [[ -z "${RUN_STATUS}" ]]; then |
| 591 | + cat "${RESPONSE_FILE}" |
| 592 | + echo "Labs run lookup did not include a terminal status." >&2 |
| 593 | + exit 1 |
| 594 | + fi |
| 595 | +
|
| 596 | + if [[ "${RUN_STATUS}" == "queued" || "${RUN_STATUS}" == "in_progress" ]]; then |
| 597 | + sleep 10 |
| 598 | + fi |
| 599 | + done |
| 600 | +
|
| 601 | + echo "run_status=${RUN_STATUS}" >> "${GITHUB_OUTPUT}" |
| 602 | + echo "run_status_message=${RUN_STATUS_MESSAGE}" >> "${GITHUB_OUTPUT}" |
| 603 | +
|
| 604 | + - name: Enforce Labs stable promotion result |
| 605 | + env: |
| 606 | + FINAL_RUN_STATUS: ${{ steps.await.outputs.run_status }} |
| 607 | + FINAL_RUN_STATUS_MESSAGE: ${{ steps.await.outputs.run_status_message }} |
| 608 | + run: | |
| 609 | + set -euo pipefail |
| 610 | +
|
| 611 | + case "${FINAL_RUN_STATUS}" in |
| 612 | + succeeded) |
| 613 | + exit 0 |
| 614 | + ;; |
| 615 | + superseded) |
| 616 | + echo "${FINAL_RUN_STATUS_MESSAGE:-Labs stable promotion checks were superseded by a newer run.}" |
| 617 | + exit 0 |
| 618 | + ;; |
| 619 | + failed|action_required) |
| 620 | + echo "${FINAL_RUN_STATUS_MESSAGE:-Labs stable promotion checks failed.}" >&2 |
| 621 | + exit 1 |
| 622 | + ;; |
| 623 | + *) |
| 624 | + echo "Unexpected Labs stable promotion status: ${FINAL_RUN_STATUS}" >&2 |
| 625 | + exit 1 |
| 626 | + ;; |
| 627 | + esac |
| 628 | +
|
| 629 | + - name: Write workflow summary |
| 630 | + if: always() |
| 631 | + run: | |
| 632 | + { |
| 633 | + echo "### Labs: Stable promotion checks" |
| 634 | + echo |
| 635 | + echo "| Field | Value |" |
| 636 | + echo "| --- | --- |" |
| 637 | + echo "| PR | #${{ github.event.pull_request.number }} |" |
| 638 | + echo "| Base branch | \`${{ github.event.pull_request.base.ref }}\` |" |
| 639 | + echo "| Head branch | \`${{ github.event.pull_request.head.ref }}\` |" |
| 640 | + echo "| Head SHA | \`${{ github.event.pull_request.head.sha }}\` |" |
| 641 | + echo "| Labs run | \`${{ steps.dispatch.outputs.run_id }}\` |" |
| 642 | + echo "| Labs status | \`${{ steps.await.outputs.run_status }}\` |" |
| 643 | + echo "| Labs status message | ${{ steps.await.outputs.run_status_message || 'n/a' }} |" |
| 644 | + echo "| New run created | \`${{ steps.dispatch.outputs.created }}\` |" |
| 645 | + } >> "${GITHUB_STEP_SUMMARY}" |
| 646 | +
|
| 647 | +>>>>>>> Stashed changes |
340 | 648 | cleanup: |
341 | 649 | name: Cleanup |
342 | 650 | if: >- |
|
0 commit comments