-
Notifications
You must be signed in to change notification settings - Fork 17
chore(ci): link Unity Cloud builds, test reports, timings, performance and automation from the CI status comment #9713
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
base: dev
Are you sure you want to change the base?
Changes from 1 commit
00ea5fd
68875b9
26cb13e
8ee55d7
3b856eb
94e21fc
34aad87
29b7e7b
1c93440
414b0f3
b5186df
4eb8b84
53dc7e3
23e9577
a94f73d
0532ad4
5d2384c
63a0cf4
a9f8e93
536e961
447ab7a
8f4123e
e480a3a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -61,7 +61,7 @@ jobs: | |||||||||||||||||||||||
| section: build | ||||||||||||||||||||||||
| github-token: ${{ github.token }} | ||||||||||||||||||||||||
| body: |- | ||||||||||||||||||||||||
|  <img src="https://ui.decentraland.org/decentraland_256x256.png" width="30"> | ||||||||||||||||||||||||
| [](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}) <img src="https://ui.decentraland.org/decentraland_256x256.png" width="30"> | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| New build in progress, come back later! | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -80,9 +80,12 @@ jobs: | |||||||||||||||||||||||
| REPO: ${{ github.event.repository.name }} | ||||||||||||||||||||||||
| RUN_ID: ${{ github.event.workflow_run.id }} | ||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||
| # Check if any build artifacts exist (they only exist when Build jobs ran) | ||||||||||||||||||||||||
| # Check if any build artifacts exist (they only exist when Build jobs ran). | ||||||||||||||||||||||||
| # unity_build_info_* is uploaded as soon as the Unity-side build starts, so a | ||||||||||||||||||||||||
| # build that failed before producing player artifacts still counts as "ran" | ||||||||||||||||||||||||
| # and gets a failure comment with a Unity Cloud link instead of staying pending. | ||||||||||||||||||||||||
| ARTIFACT_COUNT=$(gh api "/repos/$OWNER/$REPO/actions/runs/$RUN_ID/artifacts" \ | ||||||||||||||||||||||||
| --jq '[.artifacts[] | select(.name | startswith("Decentraland_"))] | length') | ||||||||||||||||||||||||
| --jq '[.artifacts[] | select((.name | startswith("Decentraland_")) or (.name | startswith("unity_build_info_")))] | length') | ||||||||||||||||||||||||
| echo "Build artifact count: $ARTIFACT_COUNT" | ||||||||||||||||||||||||
| if [ "$ARTIFACT_COUNT" -gt 0 ]; then | ||||||||||||||||||||||||
| echo "build-ran=true" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||
|
|
@@ -109,7 +112,7 @@ jobs: | |||||||||||||||||||||||
| section: build | ||||||||||||||||||||||||
| github-token: ${{ github.token }} | ||||||||||||||||||||||||
| body: |- | ||||||||||||||||||||||||
|  <img src="https://ui.decentraland.org/decentraland_256x256.png" width="30"> | ||||||||||||||||||||||||
| [](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}) <img src="https://ui.decentraland.org/decentraland_256x256.png" width="30"> | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Build skipped — no changes detected under `Explorer/`. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -230,14 +233,62 @@ jobs: | |||||||||||||||||||||||
| echo "SIZE_REPORT=" >> "$GITHUB_ENV" | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| - name: Fetch Unity Cloud build links | ||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||
| GITHUB_TOKEN: ${{ github.token }} | ||||||||||||||||||||||||
| OWNER: ${{ github.repository_owner }} | ||||||||||||||||||||||||
| REPO: ${{ github.event.repository.name }} | ||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # The info files come out of the PR-controlled build workflow, so treat them as | ||||||||||||||||||||||||
| # untrusted input: accept only a numeric build id and a Unity dashboard URL with | ||||||||||||||||||||||||
| # a conservative charset before letting them anywhere near the comment body. | ||||||||||||||||||||||||
| URL_RE='^https://(cloud\.unity\.com|developer\.cloud\.unity3d\.com|dashboard\.unity3d\.com)/[A-Za-z0-9./_%~?=&-]*$' | ||||||||||||||||||||||||
| parse_info() { | ||||||||||||||||||||||||
| local target="$1" | ||||||||||||||||||||||||
| local dir="ucb_info_${target}" | ||||||||||||||||||||||||
| REPLY_ID="" | ||||||||||||||||||||||||
| REPLY_URL="" | ||||||||||||||||||||||||
| if gh run download "$PREVIOUS_JOB_ID" \ | ||||||||||||||||||||||||
| --repo "$OWNER/$REPO" \ | ||||||||||||||||||||||||
| --name "unity_build_info_${target}_launcher" \ | ||||||||||||||||||||||||
| --dir "$dir" 2>/dev/null; then | ||||||||||||||||||||||||
| REPLY_ID=$(grep -m1 '^BUILD_ID=' "$dir/unity_cloud_build_info.env" | cut -d= -f2- || true) | ||||||||||||||||||||||||
| REPLY_URL=$(grep -m1 '^DASHBOARD_URL=' "$dir/unity_cloud_build_info.env" | cut -d= -f2- || true) | ||||||||||||||||||||||||
| [[ "$REPLY_ID" =~ ^[0-9]+$ ]] || REPLY_ID="" | ||||||||||||||||||||||||
| [[ "$REPLY_URL" =~ $URL_RE ]] || REPLY_URL="" | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| ROWS="" | ||||||||||||||||||||||||
| parse_info windows64 | ||||||||||||||||||||||||
| if [ -n "$REPLY_URL" ]; then | ||||||||||||||||||||||||
| ROWS+="| Unity Cloud build (Windows) | [#${REPLY_ID}](${REPLY_URL}) |"$'\n' | ||||||||||||||||||||||||
| elif [ -n "$REPLY_ID" ]; then | ||||||||||||||||||||||||
| ROWS+="| Unity Cloud build (Windows) | #${REPLY_ID} |"$'\n' | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Branching on
Suggested change
Same in the three sibling blocks (L272-276, L376-380, L382-386). |
||||||||||||||||||||||||
| parse_info macos | ||||||||||||||||||||||||
| if [ -n "$REPLY_URL" ]; then | ||||||||||||||||||||||||
| ROWS+="| Unity Cloud build (Mac) | [#${REPLY_ID}](${REPLY_URL}) |"$'\n' | ||||||||||||||||||||||||
| elif [ -n "$REPLY_ID" ]; then | ||||||||||||||||||||||||
| ROWS+="| Unity Cloud build (Mac) | #${REPLY_ID} |"$'\n' | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| echo "UCB_ROWS<<UCB_ROWS_EOF" | ||||||||||||||||||||||||
| printf '%s' "$ROWS" | ||||||||||||||||||||||||
| echo "UCB_ROWS_EOF" | ||||||||||||||||||||||||
| } >> "$GITHUB_ENV" | ||||||||||||||||||||||||
|
Comment on lines
+324
to
+329
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Static heredoc delimiter on
Suggested change
Same applies to the |
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| - name: Update build section | ||||||||||||||||||||||||
| uses: ./.github/actions/ci-status-comment | ||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||
| pr-number: ${{ needs.pre-validation.outputs.pr-number }} | ||||||||||||||||||||||||
| section: build | ||||||||||||||||||||||||
| github-token: ${{ github.token }} | ||||||||||||||||||||||||
| body: |- | ||||||||||||||||||||||||
|  <img src="https://ui.decentraland.org/decentraland_256x256.png" width="30"> | ||||||||||||||||||||||||
| [](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ env.PREVIOUS_JOB_ID }}) <img src="https://ui.decentraland.org/decentraland_256x256.png" width="30"> | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Windows and Mac build successful in Unity Cloud! You can find a link to the downloadable artifact below. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -250,6 +301,7 @@ jobs: | |||||||||||||||||||||||
| | Download Mac | ${{ github.server_url }}/${{ github.repository }}/suites/${{ env.SUITE_ID }}/artifacts/${{ env.MAC_ARTIFACT_ID }} | | ||||||||||||||||||||||||
| | Download Mac S3 | ${{ format('{0}/{1}/Decentraland_macos.zip', vars.EXPLORER_TEAM_S3_BUCKET_PUBLIC_URL, env.ARTIFACT_S3_DESTINATION_PATH) }} | | ||||||||||||||||||||||||
| | Built on | ${{ env.BUILD_DATE }} | | ||||||||||||||||||||||||
| ${{ env.UCB_ROWS }} | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| ${{ env.SIZE_REPORT }} | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -290,14 +342,70 @@ jobs: | |||||||||||||||||||||||
| sparse-checkout-cone-mode: false | ||||||||||||||||||||||||
| persist-credentials: false | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| - name: Fetch Unity Cloud build links | ||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||
| GITHUB_TOKEN: ${{ github.token }} | ||||||||||||||||||||||||
| OWNER: ${{ github.repository_owner }} | ||||||||||||||||||||||||
| REPO: ${{ github.event.repository.name }} | ||||||||||||||||||||||||
| RUN_ID: ${{ github.event.workflow_run.id }} | ||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # The info files come out of the PR-controlled build workflow, so treat them as | ||||||||||||||||||||||||
| # untrusted input: accept only a numeric build id and a Unity dashboard URL with | ||||||||||||||||||||||||
| # a conservative charset before letting them anywhere near the comment body. | ||||||||||||||||||||||||
| URL_RE='^https://(cloud\.unity\.com|developer\.cloud\.unity3d\.com|dashboard\.unity3d\.com)/[A-Za-z0-9./_%~?=&-]*$' | ||||||||||||||||||||||||
| parse_info() { | ||||||||||||||||||||||||
| local target="$1" | ||||||||||||||||||||||||
| local dir="ucb_info_${target}" | ||||||||||||||||||||||||
| REPLY_ID="" | ||||||||||||||||||||||||
| REPLY_URL="" | ||||||||||||||||||||||||
| if gh run download "$RUN_ID" \ | ||||||||||||||||||||||||
| --repo "$OWNER/$REPO" \ | ||||||||||||||||||||||||
| --name "unity_build_info_${target}_launcher" \ | ||||||||||||||||||||||||
| --dir "$dir" 2>/dev/null; then | ||||||||||||||||||||||||
| REPLY_ID=$(grep -m1 '^BUILD_ID=' "$dir/unity_cloud_build_info.env" | cut -d= -f2- || true) | ||||||||||||||||||||||||
| REPLY_URL=$(grep -m1 '^DASHBOARD_URL=' "$dir/unity_cloud_build_info.env" | cut -d= -f2- || true) | ||||||||||||||||||||||||
| [[ "$REPLY_ID" =~ ^[0-9]+$ ]] || REPLY_ID="" | ||||||||||||||||||||||||
| [[ "$REPLY_URL" =~ $URL_RE ]] || REPLY_URL="" | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| ROWS="" | ||||||||||||||||||||||||
| parse_info windows64 | ||||||||||||||||||||||||
| if [ -n "$REPLY_URL" ]; then | ||||||||||||||||||||||||
| ROWS+="| Unity Cloud build (Windows) | [#${REPLY_ID}](${REPLY_URL}) |"$'\n' | ||||||||||||||||||||||||
| elif [ -n "$REPLY_ID" ]; then | ||||||||||||||||||||||||
| ROWS+="| Unity Cloud build (Windows) | #${REPLY_ID} |"$'\n' | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| parse_info macos | ||||||||||||||||||||||||
| if [ -n "$REPLY_URL" ]; then | ||||||||||||||||||||||||
| ROWS+="| Unity Cloud build (Mac) | [#${REPLY_ID}](${REPLY_URL}) |"$'\n' | ||||||||||||||||||||||||
| elif [ -n "$REPLY_ID" ]; then | ||||||||||||||||||||||||
| ROWS+="| Unity Cloud build (Mac) | #${REPLY_ID} |"$'\n' | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| SECTION="" | ||||||||||||||||||||||||
| if [ -n "$ROWS" ]; then | ||||||||||||||||||||||||
| SECTION="| Name | Link |"$'\n'"| -------- | ----------------------- |"$'\n'"$ROWS" | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| echo "UCB_SECTION<<UCB_SECTION_EOF" | ||||||||||||||||||||||||
| printf '%s' "$SECTION" | ||||||||||||||||||||||||
| echo "UCB_SECTION_EOF" | ||||||||||||||||||||||||
| } >> "$GITHUB_ENV" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| - name: Update build section | ||||||||||||||||||||||||
| uses: ./.github/actions/ci-status-comment | ||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||
| pr-number: ${{ needs.pre-validation.outputs.pr-number }} | ||||||||||||||||||||||||
| section: build | ||||||||||||||||||||||||
| github-token: ${{ github.token }} | ||||||||||||||||||||||||
| body: |- | ||||||||||||||||||||||||
|  <img src="https://ui.decentraland.org/decentraland_256x256.png" width="30"> | ||||||||||||||||||||||||
| [](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}) <img src="https://ui.decentraland.org/decentraland_256x256.png" width="30"> | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Build failed! Check the logs to see what went wrong. | ||||||||||||||||||||||||
| Build failed! Check the [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}) to see what went wrong. | ||||||||||||||||||||||||
| If the error repeats please consider the `clean-build` tag. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| ${{ env.UCB_SECTION }} | ||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -61,6 +61,13 @@ def _extract_member(self, member, targetpath, pwd): | |||||
|
|
||||||
| build_healthy = True | ||||||
|
|
||||||
| # Deep link to this build in the Unity Cloud dashboard, captured from the first build | ||||||
| # response that carries one. Persisted to BUILD_LINK_INFO_PATH so the workflow can | ||||||
| # upload it and the PR status comment can link the build directly. | ||||||
| BUILD_LINK_INFO_PATH = 'unity_cloud_build_info.env' | ||||||
| dashboard_url = None | ||||||
| _build_link_info_written = False | ||||||
|
|
||||||
| parser = argparse.ArgumentParser() | ||||||
| parser.add_argument('--resume', help='Resume tracking a running build stored in build_info.json', action='store_true') | ||||||
| parser.add_argument('--cancel', help='Cancel a running build stored in build_info.json', action='store_true') | ||||||
|
|
@@ -616,6 +623,44 @@ def try_resume_build(): | |||||
| return None | ||||||
|
|
||||||
|
|
||||||
| def record_build_link_info(id, response_json): | ||||||
| """Persist the Unity Cloud dashboard deep link for this build (best-effort). | ||||||
|
|
||||||
| Build API responses carry dashboard links; the workflow uploads the written file | ||||||
| as an artifact so the PR status comment can link the build id directly instead | ||||||
| of telling humans to search cloud.unity.com by hand. | ||||||
| """ | ||||||
| global dashboard_url, _build_link_info_written | ||||||
|
|
||||||
| links = response_json.get('links') or {} | ||||||
| href = None | ||||||
| # dashboard_summary is the build's page and dashboard_log its log tab; | ||||||
| # dashboard_url can be just the dashboard root, so a candidate only | ||||||
| # qualifies when it points at this specific build. | ||||||
| for key in ('dashboard_summary', 'dashboard_log', 'dashboard_url'): | ||||||
| candidate = (links.get(key) or {}).get('href') | ||||||
| if candidate and '/builds/' in candidate: | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Downstream that produces a broken
Suggested change
|
||||||
| href = candidate | ||||||
| break | ||||||
|
|
||||||
| if _build_link_info_written and not href: | ||||||
| return | ||||||
|
|
||||||
| try: | ||||||
| with open(BUILD_LINK_INFO_PATH, 'w') as f: | ||||||
| f.write(f'BUILD_TARGET={os.getenv("TARGET")}\n') | ||||||
| f.write(f'BUILD_ID={id}\n') | ||||||
| if href: | ||||||
| f.write(f'DASHBOARD_URL={href}\n') | ||||||
| except OSError as e: | ||||||
| print(f'Warning: could not write {BUILD_LINK_INFO_PATH}: {e}') | ||||||
|
|
||||||
| if href: | ||||||
| dashboard_url = href | ||||||
| print(f'::notice::Unity Cloud build #{id} ({os.getenv("TARGET")}): {href}') | ||||||
| _build_link_info_written = True | ||||||
|
|
||||||
|
|
||||||
| def write_step_summary(target, build_id, final_status, phase_durations, queue_reasons, queue_elapsed, build_elapsed): | ||||||
| """Append a phase breakdown to $GITHUB_STEP_SUMMARY (best-effort).""" | ||||||
| summary_path = os.environ.get('GITHUB_STEP_SUMMARY') | ||||||
|
|
@@ -635,6 +680,8 @@ def fmt(seconds): | |||||
| lines.append('') | ||||||
| lines.append(f'- Target: `{target}`') | ||||||
| lines.append(f'- Build ID: `{build_id}`') | ||||||
| if dashboard_url: | ||||||
| lines.append(f'- Unity Cloud build page: {dashboard_url}') | ||||||
| lines.append(f'- Final outcome: `{final_status}`') | ||||||
| if queue_reasons: | ||||||
| lines.append(f"- Queue reasons seen: {', '.join(f'`{r}`' for r in sorted(queue_reasons))}") | ||||||
|
|
@@ -711,6 +758,9 @@ def run_poll_loop(id, build_already_active=False, resumed_build_elapsed=0): | |||||
|
|
||||||
| keep_polling, status, response_json = poll_build(id) | ||||||
|
|
||||||
| if dashboard_url is None: | ||||||
| record_build_link_info(id, response_json) | ||||||
|
|
||||||
| queued_reason = response_json.get('queuedReason') | ||||||
| if queued_reason and status in QUEUE_STATUSES: | ||||||
| queue_reasons.add(queued_reason) | ||||||
|
|
@@ -920,7 +970,8 @@ def probe_latest_build(): | |||||
| download_log(id) | ||||||
|
|
||||||
| if not build_healthy: | ||||||
| print(f'Build unhealthy - check the downloaded logs or go to https://cloud.unity.com/ and search for target "{os.getenv('TARGET')}" and build ID "{id}"') | ||||||
| where = dashboard_url or f'https://cloud.unity.com/ (search for target "{os.getenv("TARGET")}" and build ID "{id}")' | ||||||
| print(f'Build unhealthy - check the downloaded logs or the Unity Cloud build page: {where}') | ||||||
| sys.exit(1) | ||||||
|
|
||||||
| # Cleanup (only if build is healthy and not release) | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
build-ranis consumed by three jobs, and widening it here changes the meaning for all of them, not just the failure path this PR is targeting:comment-failed— the intended fix. ✅comment-skipped(L98,build-ran == 'false') andcomment-success(L121,== 'true') — these split on the same flag.comment-successthen looks upDecentraland_windows64/Decentraland_macosids and interpolates them into download URLs. Before this change,build-ran == 'true'guaranteed at least oneDecentraland_*artifact existed; now a run whose conclusion issuccesswith onlyunity_build_info_*present posts "Windows and Mac build successful!" with…/artifacts/(empty id) links.For an honest in-repo build that combination is hard to reach, but a fork PR controls its own copy of
build-unitycloud.ymland can upload an arbitrarily-named artifact, so it's reachable on demand.Suggest emitting two outputs and keeping the success/skipped split on the narrower one:
…with
comment-success/comment-skippedgating onplayer-artifactsandcomment-failedonbuild-ran.