Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
175 changes: 164 additions & 11 deletions .github/workflows/build-unitycloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- synchronize
- ready_for_review
- labeled
- unlabeled
merge_group: {}
push:
branches:
Expand Down Expand Up @@ -52,6 +53,11 @@ on:
required: false
type: boolean
default: false
script_debugging:
description: 'Enable Script Debugging (forces Development build)'
required: false
type: boolean
default: false
delta_threshold_macos_mb:
description: 'Warn if macOS growth > this MB (0 = off)'
required: false
Expand All @@ -77,6 +83,15 @@ on:
required: false
default: false
type: boolean
platforms:
description: 'Which platforms to build'
required: true
default: 'both'
type: choice
options:
- both
- windows-only
- macos-only
workflow_call:
inputs:
profile:
Expand All @@ -102,6 +117,10 @@ on:
required: false
type: boolean
default: false
script_debugging:
required: false
type: boolean
default: false
is_release_build:
type: boolean
required: false
Expand Down Expand Up @@ -152,9 +171,11 @@ concurrency:
cancel-in-progress: >-
${{
github.event_name != 'pull_request' ||
github.event.action != 'labeled' ||
(github.event.action != 'labeled' && github.event.action != 'unlabeled') ||
github.event.label.name == 'force-build' ||
github.event.label.name == 'clean-build'
github.event.label.name == 'clean-build' ||
github.event.label.name == 'windows-only' ||
github.event.label.name == 'macos-only'
}}

jobs:
Expand Down Expand Up @@ -183,8 +204,13 @@ jobs:
) ||
github.event.action == 'ready_for_review' ||
(
github.event.action == 'labeled' &&
(github.event.label.name == 'force-build' || github.event.label.name == 'clean-build')
(github.event.action == 'labeled' || github.event.action == 'unlabeled') &&
(
github.event.label.name == 'force-build' ||
github.event.label.name == 'clean-build' ||
github.event.label.name == 'windows-only' ||
github.event.label.name == 'macos-only'
)
)
)
)
Expand All @@ -200,6 +226,7 @@ jobs:
clean_build: ${{ steps.set_defaults.outputs.clean_build }}
cache_strategy: ${{ steps.set_defaults.outputs.cache_strategy }}
install_source: ${{ steps.set_defaults.outputs.install_source }}
targets: ${{ steps.get_targets.outputs.targets }}
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -318,13 +345,20 @@ jobs:
run: |
#!/bin/bash

if [[ "${{ github.event.inputs.sentry_enabled || inputs.sentry_enabled }}" == "true" ]]; then
sentry_enabled="${{ github.event.inputs.sentry_enabled || inputs.sentry_enabled }}"

if [[ "$sentry_enabled" != "true" && "${{ github.event_name }}" == "pull_request" ]]; then
echo "Checking PR labels: ${{ join(github.event.pull_request.labels.*.name, ', ') }}"
sentry_enabled=$(echo "${{ join(github.event.pull_request.labels.*.name, ' ') }}" | grep -qw 'enable-sentry' && echo true || echo false)
fi

if [[ "$sentry_enabled" == "true" ]]; then
if [[ "${{ inputs.is_release_build }}" == "true" ]]; then
echo "environment=production" >> "$GITHUB_OUTPUT"
else
echo "environment=development" >> "$GITHUB_OUTPUT"
fi

echo "upload_symbols=true" >> "$GITHUB_OUTPUT"
echo "sentry_enabled=true" >> "$GITHUB_OUTPUT"
else
Expand Down Expand Up @@ -402,11 +436,76 @@ jobs:
options+=("EnableDeepProfilingSupport")
fi

# Script Debugging: input toggle (workflow_dispatch / workflow_call) or 'script-debugging' PR label.
# AllowDebugging requires a Development build to be honored by Unity.
script_debugging="${{ github.event.inputs.script_debugging || inputs.script_debugging }}"

if [[ "$script_debugging" != "true" && "${{ github.event_name }}" == "pull_request" ]]; then
script_debugging=$(echo "${{ join(github.event.pull_request.labels.*.name, ' ') }}" | grep -qw 'script-debugging' && echo true || echo false)
fi

if [[ "$script_debugging" == "true" ]]; then
# Add Development only if not already added by profile mode
if [[ ! " ${options[*]} " =~ " Development " ]]; then
options+=("Development")
fi
options+=("AllowDebugging")
fi

# Write the array as a comma-separated string
# Set the Internal Field Separator to comma
IFS=,
echo "options=${options[*]}" | tee -a "$GITHUB_OUTPUT"

- name: Determine build targets
if: steps.decide.outputs.should_build == 'true'
id: get_targets
shell: bash
run: |
set -euo pipefail

# platform_build_mode: windows | macos | both
platform_build_mode=both

dispatch_platforms="${{ github.event.inputs.platforms }}"
echo "Dispatch platforms: '$dispatch_platforms'"

if [ "$dispatch_platforms" = "windows-only" ]; then
platform_build_mode=windows
elif [ "$dispatch_platforms" = "macos-only" ]; then
platform_build_mode=macos
else
labels="${{ join(github.event.pull_request.labels.*.name, ' ') }}"
echo "Labels: '$labels'"

label_match_count=0
if echo "$labels" | grep -qw 'windows-only'; then
platform_build_mode=windows
label_match_count=$((label_match_count + 1))
fi
if echo "$labels" | grep -qw 'macos-only'; then
platform_build_mode=macos
label_match_count=$((label_match_count + 1))
fi

if [ "$label_match_count" -gt 1 ]; then
echo "::error::Both 'windows-only' and 'macos-only' labels are applied. Remove one — they are mutually exclusive."
exit 1
fi
fi

echo "Platform build mode: $platform_build_mode"

case "$platform_build_mode" in
windows) targets='["windows64"]' ;;
macos) targets='["macos"]' ;;
both) targets='["windows64","macos"]' ;;
*) echo "::error::Unknown platform_build_mode '$platform_build_mode'"; exit 1 ;;
esac

echo "Targets: $targets"
echo "targets=$targets" >> "$GITHUB_OUTPUT"

build:
name: Build
runs-on: ubuntu-latest
Expand All @@ -416,7 +515,7 @@ jobs:
strategy:
fail-fast: false
matrix:
target: ['windows64', 'macos']
target: ${{ fromJSON(needs.prebuild.outputs.targets) }}
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -724,21 +823,36 @@ jobs:
*) echo "BUILD_PREFIX=gn" >> $GITHUB_ENV ;;
esac

- name: Compute S3 destination path
env:
RESOLVED_DESTINATION_PATH: "${{
inputs.is_release_build && format('@dcl/{0}/releases/{1}', github.event.repository.name, inputs.tag_version)
|| format('@dcl/{0}/branch/{1}/{2}-{3}-{4}', github.event.repository.name, env.SAFE_BRANCH_NAME, env.BUILD_PREFIX, github.run_number, env.SHA_SHORT)
}}"
run: |
echo "DESTINATION_PATH=${RESOLVED_DESTINATION_PATH}" >> $GITHUB_ENV

- name: Upload artifact to S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.EXPLORER_TEAM_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.EXPLORER_TEAM_AWS_SECRET_ACCESS_KEY }}
EXPLORER_TEAM_S3_BUCKET: ${{ secrets.EXPLORER_TEAM_S3_BUCKET }}
DESTINATION_PATH: "${{
inputs.is_release_build && format('@dcl/{0}/releases/{1}', github.event.repository.name, inputs.tag_version)
|| format('@dcl/{0}/branch/{1}/{2}-{3}-{4}', github.event.repository.name, env.SAFE_BRANCH_NAME, env.BUILD_PREFIX, github.run_number, env.SHA_SHORT)
}}"
run: |
npx @dcl/cdn-uploader@next \
--bucket $EXPLORER_TEAM_S3_BUCKET \
--local-folder upload_to_s3 \
--bucket-folder $DESTINATION_PATH

- name: Print S3 upload URL
run: |
ARTIFACT_URL="https://explorer-artifacts.decentraland.org/${DESTINATION_PATH}/${{ env.artifact_name }}.zip"
echo "::notice::Artifact uploaded to: ${ARTIFACT_URL}"
{
echo "### Artifact upload URL (${{ matrix.target }})"
echo
echo "[${ARTIFACT_URL}](${ARTIFACT_URL})"
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload debug symbols
uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -801,4 +915,43 @@ jobs:
ORG_ID: ${{ secrets.UNITY_CLOUD_ORG_ID }}
PROJECT_ID: ${{ secrets.UNITY_CLOUD_PROJECT_ID }}
run: python -u scripts/cloudbuild/build.py --cancel

build-gate:
name: Build Gate (Windows + macOS)
runs-on: ubuntu-latest
needs: [prebuild, build]
if: always() && github.event_name == 'pull_request'
steps:
- name: Verify both targets built and passed
shell: bash
run: |
set -euo pipefail

should_build='${{ needs.prebuild.outputs.should_build }}'
prebuild_result='${{ needs.prebuild.result }}'

# No Explorer/ changes, draft without override, or perf_test path — gate is not applicable.
if [ "$prebuild_result" != "success" ] || [ "$should_build" != "true" ]; then
echo "Gate not applicable (prebuild=$prebuild_result, should_build='$should_build'). Passing."
exit 0
fi

targets='${{ needs.prebuild.outputs.targets }}'
echo "Targets that ran: $targets"

has_windows=$(echo "$targets" | jq 'any(. == "windows64")')
has_macos=$(echo "$targets" | jq 'any(. == "macos")')
if [ "$has_windows" != "true" ] || [ "$has_macos" != "true" ]; then
echo "::error::Build Gate requires both Windows and macOS builds. This run was filtered to: $targets"
echo "::error::Remove the 'windows-only' or 'macos-only' label so both targets build, then push or re-trigger."
exit 1
fi

build_result='${{ needs.build.result }}'
if [ "$build_result" != "success" ]; then
echo "::error::Build matrix did not succeed (result: $build_result)"
exit 1
fi

echo "Both Windows and macOS builds passed."
# Test change
29 changes: 29 additions & 0 deletions Explorer/Assets/DCL/Chat/Commands/AnrDumpChatCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#if UNITY_STANDALONE_WIN
using Cysharp.Threading.Tasks;
using DCL.Diagnostics.Sentry;
using RichTypes;
using System.Threading;
using Cysharp.Threading.Tasks;

namespace DCL.Chat.Commands
{
public class AnrDumpChatCommand : IChatCommand
{
public string Command => "anr-dump";
public string Description => "<b>/anr-dump</b>\n Collect and archive a process dump to the app directory";
public bool DebugOnly => true;

public async UniTask<string> ExecuteCommandAsync(string[] parameters, CancellationToken ct)
{
Result<(string filePath, string zipPath)> result = default;
{
await using var _ = await global::Utility.Multithreading.ExecuteOnThreadPoolScope.NewScopeAsync();
result = ThreadsDumpUtility.CollectAndArchiveDumpInfoToAppDir();
}

if (result.Success == false) return $"Dump failed: {result.ErrorMessage}";
return $"Dump collected:\n {result.Value.filePath}\n {result.Value.zipPath}";
}
}
}
#endif

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions Explorer/Assets/DCL/Chat/Commands/AnrSimulateChatCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Cysharp.Threading.Tasks;
using System.Globalization;
using System.Threading;

namespace DCL.Chat.Commands
{
public class AnrSimulateChatCommand : IChatCommand
{
private const int DEFAULT_FREEZE_MS = 10_000;

public string Command => "anr-simulate";
public string Description => "<b>/anr-simulate <i>[ms]</i></b>\n Freeze the main thread to trigger ANR detection";
public bool DebugOnly => true;

public bool ValidateParameters(string[] parameters) =>
parameters.Length == 0 || (parameters.Length == 1 && int.TryParse(parameters[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out _));

public UniTask<string> ExecuteCommandAsync(string[] parameters, CancellationToken ct)
{
int freezeMs = DEFAULT_FREEZE_MS;

if (parameters.Length == 1)
int.TryParse(parameters[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out freezeMs);

#if !UNITY_WEBGL
Thread.Sleep(freezeMs); // IGNORE_LINE_WEBGL_THREAD_SAFETY_FLAG
#endif

return UniTask.FromResult($"Main thread was frozen for {freezeMs} ms.");
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Linq;
using System.Threading;
using Utility;
using DCL.Diagnostics;

namespace DCL.Chat.MessageBus
{
Expand Down Expand Up @@ -69,7 +70,11 @@ private async UniTaskVoid HandleChatCommandAsync(ChatChannel.ChannelId channelId
string response = await command.ExecuteCommandAsync(parameters, commandCts.Token);
SendFromSystem(channelId, channelType, response);
}
catch (Exception) { SendFromSystem(channelId, channelType, "🔴 Error running command."); }
catch (Exception e)
{
SendFromSystem(channelId, channelType, "🔴 Error running command.");
ReportHub.LogError(ReportCategory.UNSPECIFIED, $"Error running command: {e}");
}

return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,16 @@ private void LogArguments()
var sb = new StringBuilder(COUNT_PER_LINE * appParameters.Count);
var count = 1;

sb.AppendLine("==================");
sb.AppendLine("Application arguments:");
sb.AppendLine("==================\n");

foreach ((string? key, string? value) in appParameters)
{
sb.Append("Arg ").Append(count).Append(": ").Append(key).Append(" = ").Append(value).Append("\n");
count++;
}
sb.AppendLine("==================\n");

ReportHub.LogProductionInfo(sb.ToString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,10 @@ await MapRendererContainer
new SceneAdminsChatCommand(),
new AppArgsCommand(appArgs),
new LogMatrixChatCommand((RuntimeReportsHandlingSettings)bootstrapContainer.DiagnosticsContainer.Settings),
new AnrSimulateChatCommand(),
#if UNITY_STANDALONE_WIN
new AnrDumpChatCommand(),
#endif
};

chatCommands.Add(new HelpChatCommand(chatCommands, appArgs));
Expand Down
Loading
Loading