summaryrefslogtreecommitdiff
path: root/.github
diff options
context:
space:
mode:
Diffstat (limited to '.github')
-rw-r--r--.github/parameters/setup-macports.yaml25
-rw-r--r--.github/workflows/build-macos.yml123
-rw-r--r--.github/workflows/build-windows.yml225
-rw-r--r--.github/workflows/build.yaml530
-rw-r--r--.github/workflows/check-pr.yaml21
-rw-r--r--.github/workflows/cla.yaml26
-rw-r--r--.github/workflows/label.yaml15
-rw-r--r--.github/workflows/pre-commit.yaml18
-rw-r--r--.github/workflows/qatest.yaml610
-rw-r--r--.github/workflows/stale.yaml25
-rw-r--r--.github/workflows/tag-release.yaml72
11 files changed, 373 insertions, 1317 deletions
diff --git a/.github/parameters/setup-macports.yaml b/.github/parameters/setup-macports.yaml
new file mode 100644
index 0000000000..ed8cd40acd
--- /dev/null
+++ b/.github/parameters/setup-macports.yaml
@@ -0,0 +1,25 @@
+# Parameters for melusina-org/setup-macports.
+# Listing ports here (rather than in a manual `port install` step) means the
+# action installs them and they fall under its built-in installation cache,
+# which is keyed on the macOS version + this file. Edit this list and the
+# cache invalidates automatically.
+#
+# NOTE: no +universal variants. MacPorts' own guidance is that universal
+# builds are poorly supported on Apple Silicon (apr-util fails to build that
+# way). The runner is arm64 and we build the viewer arm64-only, so arm64
+# ports are correct and faster.
+version: '2.11.5'
+ports:
+ - name: 'cmake'
+ - name: 'pkgconfig'
+ - name: 'freealut'
+ - name: 'apr-util'
+ - name: 'boost188'
+ - name: 'glm'
+ - name: 'hunspell'
+ - name: 'freetype'
+ - name: 'minizip'
+ - name: 'nghttp2'
+ - name: 'openjpeg'
+ - name: 'libvorbis'
+ - name: 'xxhashlib'
diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml
new file mode 100644
index 0000000000..d1efde8ce9
--- /dev/null
+++ b/.github/workflows/build-macos.yml
@@ -0,0 +1,123 @@
+name: macOS Build
+
+on:
+ pull_request:
+ branches: [ main ]
+ push:
+ tags:
+ - 'test/*'
+ - 'build/*'
+ - 'v*'
+ workflow_dispatch:
+
+permissions:
+ contents: write
+
+jobs:
+ build-macos:
+ name: macOS (arm64)
+ runs-on: macos-15
+
+ steps:
+ - name: Checkout source
+ uses: actions/checkout@v5
+
+ - name: Set up MacPorts (installs cached deps from parameter file)
+ uses: melusina-org/setup-macports@v1
+ with:
+ parameters: .github/parameters/setup-macports.yaml
+
+ - name: Dump MacPorts logs on failure
+ if: failure()
+ shell: bash
+ run: |
+ echo "=== searching for MacPorts main.log files ==="
+ LOGDIR="/opt/local/var/macports/logs"
+ find "$LOGDIR" -name "main.log" 2>/dev/null | while read -r log; do
+ echo ""
+ echo "######################################################"
+ echo "### $log"
+ echo "######################################################"
+ tail -n 80 "$log"
+ done
+
+ - name: Configure
+ shell: bash
+ run: |
+ SDKPATH="$(xcrun --show-sdk-path)"
+ export LL_BUILD="-O3 -gdwarf-2 -stdlib=libc++ -mmacosx-version-min=12 -iwithsysroot $SDKPATH -std=c++20 -fPIC -DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -DNDEBUG -DPIC -DLL_DARWIN=1"
+
+ mkdir build-macos && cd build-macos
+ cmake \
+ -DCMAKE_BUILD_TYPE:STRING=Release \
+ -DADDRESS_SIZE:STRING=64 \
+ -DUSE_OPENAL:BOOL=ON \
+ -DUSE_FMODSTUDIO:BOOL=OFF \
+ -DENABLE_MEDIA_PLUGINS:BOOL=ON \
+ -DLL_TESTS:BOOL=OFF \
+ -DNDOF:BOOL=OFF \
+ -DROOT_PROJECT_NAME:STRING=Megapahit \
+ -DVIEWER_CHANNEL:STRING=Megapahit \
+ -DVIEWER_BINARY_NAME:STRING=megapahit \
+ -DBUILD_SHARED_LIBS:BOOL=OFF \
+ -DINSTALL:BOOL=ON \
+ -DPACKAGE:BOOL=OFF \
+ -DCMAKE_INSTALL_PREFIX:PATH=newview/Megapahit.app/Contents/Resources \
+ -DCMAKE_OSX_ARCHITECTURES:STRING=$(uname -m) \
+ -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=12 \
+ -DENABLE_SIGNING:BOOL=ON \
+ -DSIGNING_IDENTITY:STRING=- \
+ ../indra
+
+ - name: Build
+ shell: bash
+ run: |
+ cd build-macos
+ make -j$(sysctl -n hw.ncpu)
+
+ - name: Install into app bundle
+ shell: bash
+ run: |
+ cd build-macos
+ make install
+
+ - name: Read version
+ id: version
+ shell: bash
+ run: echo "version=$(cat indra/newview/viewer_version.txt)" >> "$GITHUB_OUTPUT"
+
+ - name: Package .app into a .zip
+ shell: bash
+ run: |
+ cd build-macos/newview
+ ditto -c -k --keepParent "Megapahit.app" \
+ "Megapahit-${{ steps.version.outputs.version }}-macos-$(uname -m).zip"
+
+ - name: Verify signature survived packaging
+ shell: bash
+ run: |
+ cd build-macos/newview
+ mkdir -p verify-tmp
+ ditto -x -k Megapahit-*-macos-*.zip verify-tmp/
+ codesign --verify --deep --strict --verbose=2 verify-tmp/Megapahit.app || {
+ echo "Signature verification FAILED"
+ rm -rf verify-tmp
+ exit 1
+ }
+ rm -rf verify-tmp
+ echo "Signature verified intact."
+
+ - name: Upload app artifact
+ uses: actions/upload-artifact@v6
+ with:
+ name: megapahit-macos-${{ steps.version.outputs.version }}
+ path: build-macos/newview/Megapahit-*-macos-*.zip
+ if-no-files-found: error
+
+ - name: Upload to release
+ if: startsWith(github.ref, 'refs/tags/')
+ uses: softprops/action-gh-release@v3
+ with:
+ name: ${{ github.ref_name }}
+ files: build-macos/newview/Megapahit-*-macos-*.zip
+ prerelease: ${{ startsWith(github.ref_name, 'test/') || startsWith(github.ref_name, 'build/') }}
diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml
new file mode 100644
index 0000000000..8be2d33802
--- /dev/null
+++ b/.github/workflows/build-windows.yml
@@ -0,0 +1,225 @@
+name: Windows Build
+
+on:
+ pull_request:
+ branches: [ main ]
+ push:
+ tags:
+ - 'test/*'
+ - 'build/*'
+ - 'v*'
+ workflow_dispatch:
+
+permissions:
+ contents: write
+
+jobs:
+ build-windows-x64:
+ name: Windows x64
+ runs-on: windows-2025-vs2026
+
+ steps:
+ - name: Set VCPKG_ROOT
+ shell: bash
+ run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV"
+
+ - name: Add MSBuild to PATH
+ uses: microsoft/setup-msbuild@v3
+
+ - name: Checkout source
+ uses: actions/checkout@v5
+
+ - name: Install vcpkg dependencies (x64)
+ shell: bash
+ run: |
+ vcpkg install \
+ python3:x64-windows \
+ freealut:x64-windows \
+ apr-util:x64-windows \
+ boost:x64-windows \
+ freetype:x64-windows \
+ glm:x64-windows \
+ hunspell:x64-windows \
+ libjpeg-turbo:x64-windows \
+ meshoptimizer:x64-windows \
+ minizip:x64-windows \
+ nanosvg:x64-windows \
+ nghttp2:x64-windows \
+ openjpeg:x64-windows \
+ libvorbis:x64-windows \
+ "libxml2[tools]:x64-windows" \
+ xxhash:x64-windows
+
+ - name: Configure (x64)
+ shell: bash
+ env:
+ LL_BUILD: "/MD /O2 /Ob2 /std:c++20 /Zc:wchar_t- /Zi /GR /DLL_RELEASE=1 /DLL_RELEASE_FOR_DOWNLOAD=1 /DNDEBUG /D_SECURE_STL=0 /D_HAS_ITERATOR_DEBUGGING=0 /DWIN32 /D_WINDOWS /DLL_WINDOWS=1 /DUNICODE /D_UNICODE /DWINVER=0x0602 /D_WIN32_WINNT=0x0602"
+ run: |
+ export PYTHON="$VCPKG_ROOT/installed/x64-windows/tools/python3/python.exe"
+ CMAKE_BIN=$(find "$VCPKG_ROOT/downloads/tools" -name "cmake.exe" -path "*/x86_64/*" | head -1)
+ if [ -z "$CMAKE_BIN" ]; then
+ CMAKE_BIN=cmake
+ fi
+ mkdir build-windows-x86_64
+ cd build-windows-x86_64
+ "$CMAKE_BIN" \
+ -DCMAKE_BUILD_TYPE:STRING=Release \
+ -DADDRESS_SIZE:STRING=64 \
+ -DUSE_OPENAL:BOOL=ON \
+ -DUSE_FMODSTUDIO:BOOL=OFF \
+ -DENABLE_MEDIA_PLUGINS:BOOL=ON \
+ -DLL_TESTS:BOOL=OFF \
+ -DNDOF:BOOL=OFF \
+ -DROOT_PROJECT_NAME:STRING=Megapahit \
+ -DVIEWER_CHANNEL:STRING=Megapahit \
+ -DVIEWER_BINARY_NAME:STRING=Megapahit \
+ -DBUILD_SHARED_LIBS:BOOL=OFF \
+ -DINSTALL:BOOL=ON \
+ -DPACKAGE:BOOL=ON \
+ "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \
+ -DVS_DISABLE_FATAL_WARNINGS:BOOL=ON \
+ ../indra
+
+ - name: Build (x64)
+ shell: bash
+ run: |
+ cd build-windows-x86_64
+ MSBuild.exe Megapahit.slnx -p:Configuration=Release -m
+
+ - name: Install NSIS (x64)
+ shell: pwsh
+ run: |
+ choco install nsis --no-progress -y
+ "C:\Program Files (x86)\NSIS" | Out-File -FilePath $env:GITHUB_PATH -Append
+
+ - name: Package (x64)
+ shell: bash
+ run: |
+ cd build-windows-x86_64
+ cpack -G NSIS
+
+ - name: Read version
+ id: version
+ shell: bash
+ run: echo "version=$(cat indra/newview/viewer_version.txt)" >> "$GITHUB_OUTPUT"
+
+ - name: Upload installer artifact (x64)
+ uses: actions/upload-artifact@v6
+ with:
+ name: megapahit-windows-x64-${{ steps.version.outputs.version }}
+ path: build-windows-x86_64/Megapahit-*-win64.exe
+ if-no-files-found: error
+
+ - name: Upload to release (x64)
+ if: startsWith(github.ref, 'refs/tags/')
+ uses: softprops/action-gh-release@v3
+ with:
+ name: ${{ github.ref_name }}
+ files: build-windows-x86_64/Megapahit-*-win64.exe
+ prerelease: ${{ startsWith(github.ref_name, 'test/') || startsWith(github.ref_name, 'build/') }}
+
+ build-windows-arm64:
+ name: Windows arm64
+ if: false
+ runs-on: windows-2022
+
+ steps:
+ - name: Set VCPKG_ROOT
+ shell: bash
+ run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV"
+
+ - name: Add MSBuild to PATH
+ uses: microsoft/setup-msbuild@v3
+
+ - name: Checkout source
+ uses: actions/checkout@v5
+
+ - name: Install vcpkg dependencies (arm64)
+ shell: bash
+ run: |
+ vcpkg install \
+ python3:arm64-windows \
+ freealut:arm64-windows \
+ apr-util:arm64-windows \
+ boost:arm64-windows \
+ curl:arm64-windows \
+ freetype:arm64-windows \
+ glm:arm64-windows \
+ hunspell:arm64-windows \
+ libjpeg-turbo:arm64-windows \
+ meshoptimizer:arm64-windows \
+ minizip:arm64-windows \
+ nanosvg:arm64-windows \
+ nghttp2:arm64-windows \
+ openjpeg:arm64-windows \
+ sse2neon:arm64-windows \
+ libvorbis:arm64-windows \
+ "libxml2[tools]:arm64-windows" \
+ xxhash:arm64-windows
+ vcpkg install boost-fiber:arm64-windows --allow-unsupported || true
+
+ - name: Configure (arm64)
+ shell: bash
+ env:
+ LL_BUILD: "/MD /O2 /Ob2 /std:c++20 /Zc:wchar_t- /Zi /GR /DLL_RELEASE=1 /DLL_RELEASE_FOR_DOWNLOAD=1 /DNDEBUG /D_SECURE_STL=0 /D_HAS_ITERATOR_DEBUGGING=0 /DWIN32 /D_WINDOWS /DLL_WINDOWS=1 /DUNICODE /D_UNICODE /DWINVER=0x0602 /D_WIN32_WINNT=0x0602 /Zc:preprocessor"
+ run: |
+ export PYTHON="$VCPKG_ROOT/installed/arm64-windows/tools/python3/python.exe"
+ CMAKE_BIN=$(find "$VCPKG_ROOT/downloads/tools" -name "cmake.exe" -path "*/arm64/*" | head -1)
+ if [ -z "$CMAKE_BIN" ]; then
+ CMAKE_BIN=$(find "$VCPKG_ROOT/downloads/tools" -name "cmake.exe" | head -1)
+ fi
+ if [ -z "$CMAKE_BIN" ]; then
+ CMAKE_BIN=cmake
+ fi
+ mkdir build-windows-aarch64
+ cd build-windows-aarch64
+ "$CMAKE_BIN" \
+ -DCMAKE_BUILD_TYPE:STRING=Release \
+ -DADDRESS_SIZE:STRING=64 \
+ -DUSE_OPENAL:BOOL=ON \
+ -DUSE_FMODSTUDIO:BOOL=OFF \
+ -DENABLE_MEDIA_PLUGINS:BOOL=OFF \
+ -DLL_TESTS:BOOL=OFF \
+ -DNDOF:BOOL=OFF \
+ -DROOT_PROJECT_NAME:STRING=Megapahit \
+ -DVIEWER_CHANNEL:STRING=Megapahit \
+ -DVIEWER_BINARY_NAME:STRING=Megapahit \
+ -DBUILD_SHARED_LIBS:BOOL=OFF \
+ -DINSTALL:BOOL=ON \
+ -DPACKAGE:BOOL=ON \
+ "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \
+ -DVCPKG_TARGET_TRIPLET:STRING=arm64-windows \
+ -DVS_DISABLE_FATAL_WARNINGS:BOOL=ON \
+ ../indra
+
+ - name: Build (arm64)
+ shell: bash
+ run: |
+ cd build-windows-aarch64
+ MSBuild.exe Megapahit.slnx -p:Configuration=Release -m
+
+ - name: Package (arm64)
+ shell: bash
+ run: |
+ cd build-windows-aarch64
+ cpack -G NSIS
+
+ - name: Read version
+ id: version
+ shell: bash
+ run: echo "version=$(cat indra/newview/viewer_version.txt)" >> "$GITHUB_OUTPUT"
+
+ - name: Upload installer artifact (arm64)
+ uses: actions/upload-artifact@v6
+ with:
+ name: megapahit-windows-arm64-${{ steps.version.outputs.version }}
+ path: build-windows-aarch64/Megapahit-*-win64.exe
+ if-no-files-found: error
+
+ - name: Upload to release (arm64)
+ if: startsWith(github.ref, 'refs/tags/')
+ uses: softprops/action-gh-release@v3
+ with:
+ name: ${{ github.ref_name }}
+ files: build-windows-aarch64/Megapahit-*-win64.exe
+ prerelease: ${{ startsWith(github.ref_name, 'test/') || startsWith(github.ref_name, 'build/') }}
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
deleted file mode 100644
index 84c05dacdf..0000000000
--- a/.github/workflows/build.yaml
+++ /dev/null
@@ -1,530 +0,0 @@
-name: Build
-
-on:
- workflow_dispatch:
- inputs:
- installer_type:
- description: 'Windows installer type'
- type: choice
- options:
- - velopack
- - nsis
- default: 'velopack'
- pull_request:
- push:
- branches: ["main", "release/*", "project/*"]
- tags: ["Second_Life*"]
-
-jobs:
- # The whole point of the setup job is that we want to set variables once
- # that will be consumed by multiple subsequent jobs.
- setup:
- runs-on: ubuntu-latest
- outputs:
- release_run: ${{ steps.setvar.outputs.release_run }}
- configurations: ${{ steps.setvar.outputs.configurations }}
- bugsplat_db: ${{ steps.setvar.outputs.bugsplat_db }}
- env:
- # Build with a tag like "Second_Life#abcdef0" to generate a release page
- # (used for builds we are planning to deploy).
- # When you want to use a string variable as a workflow YAML boolean, it's
- # important to ensure it's the empty string when false. If you omit || '',
- # its value when false is "false", which is interpreted as true.
- RELEASE_RUN: ${{ (github.event.inputs.release_run || github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life')) && 'Y' || '' }}
- FROM_FORK: ${{ github.event.pull_request.head.repo.fork }}
- steps:
- - name: Set Variables
- id: setvar
- shell: bash
- run: |
- echo "release_run=$RELEASE_RUN" >> "$GITHUB_OUTPUT"
-
- if [[ "$FROM_FORK" == "true" ]]; then
- # PR from fork; don't build with Bugsplat, proprietary libs
- echo 'configurations=["ReleaseOS"]' >> $GITHUB_OUTPUT
- echo "bugsplat_db=" >> $GITHUB_OUTPUT
- else
- echo 'configurations=["Release"]' >> $GITHUB_OUTPUT
- echo "bugsplat_db=SecondLife_Viewer_2018" >> $GITHUB_OUTPUT
- fi
- build:
- needs: setup
- strategy:
- matrix:
- runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-2022","macos-15-xlarge"]') }}
- configuration: ${{ fromJson(needs.setup.outputs.configurations) }}
- runs-on: ${{ matrix.runner }}
- outputs:
- viewer_channel: ${{ steps.build.outputs.viewer_channel }}
- viewer_version: ${{ steps.build.outputs.viewer_version }}
- viewer_branch: ${{ steps.which-branch.outputs.branch }}
- relnotes: ${{ steps.which-branch.outputs.relnotes }}
- imagename: ${{ steps.build.outputs.imagename }}
- configuration: ${{ matrix.configuration }}
- # Windows Velopack outputs (passed to sign-pkg-windows)
- velopack_pack_id: ${{ steps.build.outputs.velopack_pack_id }}
- velopack_pack_version: ${{ steps.build.outputs.velopack_pack_version }}
- velopack_pack_title: ${{ steps.build.outputs.velopack_pack_title }}
- velopack_main_exe: ${{ steps.build.outputs.velopack_main_exe }}
- velopack_exclude: ${{ steps.build.outputs.velopack_exclude }}
- velopack_icon: ${{ steps.build.outputs.velopack_icon }}
- velopack_installer_base: ${{ steps.build.outputs.velopack_installer_base }}
- # macOS Velopack outputs (passed to sign-pkg-mac)
- velopack_mac_pack_id: ${{ steps.build.outputs.velopack_mac_pack_id }}
- velopack_mac_pack_version: ${{ steps.build.outputs.velopack_mac_pack_version }}
- velopack_mac_pack_title: ${{ steps.build.outputs.velopack_mac_pack_title }}
- velopack_mac_main_exe: ${{ steps.build.outputs.velopack_mac_main_exe }}
- velopack_mac_bundle_id: ${{ steps.build.outputs.velopack_mac_bundle_id }}
- env:
- AUTOBUILD_ADDRSIZE: 64
- AUTOBUILD_BUILD_ID: ${{ github.run_id }}
- AUTOBUILD_CONFIGURATION: ${{ matrix.configuration }}
- # authorizes fetching private constituent packages
- AUTOBUILD_GITHUB_TOKEN: ${{ secrets.SHARED_AUTOBUILD_GITHUB_TOKEN }}
- AUTOBUILD_INSTALLABLE_CACHE: ${{ github.workspace }}/.autobuild-installables
- AUTOBUILD_VARIABLES_FILE: ${{ github.workspace }}/.build-variables/variables
- # Direct autobuild to store vcs_url, vcs_branch and vcs_revision in
- # autobuild-package.xml.
- AUTOBUILD_VCS_INFO: "true"
- AUTOBUILD_VSVER: "170"
- DEVELOPER_DIR: "/Applications/Xcode_16.4.app/Contents/Developer"
- # Ensure that Linden viewer builds engage Bugsplat.
- BUGSPLAT_DB: ${{ needs.setup.outputs.bugsplat_db }}
- build_coverity: false
- build_log_dir: ${{ github.workspace }}/.logs
- build_viewer: true
- BUILDSCRIPTS_SHARED: ${{ github.workspace }}/.shared
- # extracted and committed to viewer repo
- BUILDSCRIPTS_SUPPORT_FUNCTIONS: ${{ github.workspace }}/buildscripts_support_functions
- GIT_REF: ${{ github.head_ref || github.ref }}
- LL_SKIP_REQUIRE_SYSROOT: 1
- # Setting this variable directs Linden's TUT test driver code to capture
- # test-program log output at the specified level, but to display it only if
- # the individual test fails.
- LOGFAIL: DEBUG
- master_message_template_checkout: ${{ github.workspace }}/.master-message-template
- # Only set variants to the one configuration: don't let build.sh loop
- # over variants, let GitHub distribute variants over multiple hosts.
- variants: ${{ matrix.configuration }}
- # Pass USE_VELOPACK to CMake when using Velopack installer (default) - Windows and macOS
- autobuild_configure_parameters: ${{ (contains(matrix.runner, 'windows') || contains(matrix.runner, 'macos')) && (github.event.inputs.installer_type || 'velopack') == 'velopack' && '-- -DUSE_VELOPACK:BOOL=ON' || '' }}
- steps:
- - name: Checkout code
- uses: actions/checkout@v6
- with:
- ref: ${{ github.event.pull_request.head.sha || github.sha }}
-
- - name: Setup python
- uses: actions/setup-python@v6
- with:
- python-version: "3.11"
- - name: Checkout build variables
- uses: actions/checkout@v6
- with:
- repository: secondlife/build-variables
- ref: master
- path: .build-variables
-
- - name: Checkout master-message-template
- uses: actions/checkout@v6
- with:
- repository: secondlife/master-message-template
- path: .master-message-template
-
- - name: Install autobuild and python dependencies
- run: pip3 install autobuild llsd
-
- - name: Cache autobuild packages
- id: cache-installables
- uses: actions/cache@v5
- with:
- path: .autobuild-installables
- key: ${{ runner.os }}-64-${{ matrix.configuration }}-${{ hashFiles('autobuild.xml') }}
- restore-keys: |
- ${{ runner.os }}-64-${{ matrix.configuration }}-
- ${{ runner.os }}-64-
-
- - name: Determine source branch
- id: which-branch
- uses: secondlife/viewer-build-util/which-branch@v2
- with:
- token: ${{ github.token }}
-
- - name: Setup .NET for Velopack
- if: (runner.os == 'Windows' || runner.os == 'macOS') && (github.event.inputs.installer_type || 'velopack') == 'velopack'
- uses: actions/setup-dotnet@v4
- with:
- dotnet-version: '9.0.x'
-
- - name: Install Velopack CLI
- if: (runner.os == 'Windows' || runner.os == 'macOS') && (github.event.inputs.installer_type || 'velopack') == 'velopack'
- shell: bash
- run: dotnet tool install -g vpk
-
- - name: Build
- id: build
- shell: bash
- env:
- AUTOBUILD_VCS_BRANCH: ${{ steps.which-branch.outputs.branch }}
- RUNNER_OS: ${{ runner.os }}
- run: |
- # set up things the viewer's build.sh script expects
- set -x
- mkdir -p "$build_log_dir"
- mkdir -p "$BUILDSCRIPTS_SHARED/packages/lib/python"
- source "$BUILDSCRIPTS_SUPPORT_FUNCTIONS"
- if [[ "$OSTYPE" =~ cygwin|msys ]]
- then
- native_path() { cygpath --windows "$1"; }
- shell_path() { cygpath --unix "$1"; }
- else
- native_path() { echo "$1"; }
- shell_path() { echo "$1"; }
- fi
- finalize()
- {
- case "$1" in
- true|0)
- record_success "Build Succeeded"
- ;;
- *)
- record_failure "Build Failed with $1"
- ;;
- esac
- }
- initialize_build()
- {
- echo "initialize_build"
- }
- initialize_version()
- {
- export revision="$AUTOBUILD_BUILD_ID"
- }
- python_cmd()
- {
- if [[ "x${1:0:1}" == "x-" ]] # -m, -c, etc.
- then # if $1 is a switch, don't try to twiddle paths
- "$(shell_path "$PYTHON_COMMAND")" "$@"
- elif [[ "$(basename "$1")" == "codeticket.py" ]]
- then # ignore any attempt to contact codeticket
- echo "## $@"
- else # running a script at an explicit path: fix path for Python
- local script="$1"
- shift
- "$(shell_path "$PYTHON_COMMAND")" "$(native_path "$script")" "$@"
- fi
- }
- repo_branch()
- {
- echo "$AUTOBUILD_VCS_BRANCH"
- }
- record_dependencies_graph()
- {
- echo "TODO: generate and post dependency graph"
- }
- # Since we're not uploading to codeticket, DO NOT sleep for minutes.
- sleep()
- {
- echo "Not sleeping for $1 seconds"
- }
- export -f native_path shell_path finalize initialize_build initialize_version
- export -f python_cmd repo_branch record_dependencies_graph sleep
- ## Useful for diagnosing Windows LLProcess/LLLeap test failures
- ##export APR_LOG="${RUNNER_TEMP}/apr.log"
- export arch=$(uname | cut -b-6)
- # Surprise! GH Windows runner's MINGW6 is a $arch value we've never
- # seen before, so numerous tests don't know about it.
- [[ "$arch" == "MINGW6" ]] && arch=CYGWIN
- export AUTOBUILD="$(which autobuild)"
-
- # determine the viewer channel from the branch or tag name
- # trigger an EDU build by including "edu" in the tag
- edu=${{ github.ref_type == 'tag' && contains(github.ref_name, 'edu') }}
- echo "ref_type=${{ github.ref_type }}, ref_name=${{ github.ref_name }}, edu='$edu'"
- branch=$AUTOBUILD_VCS_BRANCH
- if [[ "$edu" == "true" ]]
- then
- export viewer_channel="Second Life Release edu"
- elif [[ "$branch" == "develop" ]];
- then
- export viewer_channel="Second Life Develop"
- else
- IFS='/' read -ra ba <<< "$branch"
- prefix=${ba[0]}
- if [ "$prefix" == "project" ]; then
- IFS='_' read -ra prj <<< "${ba[1]}"
- prj_str="${prj[*]}"
- # uppercase first letter of each word
- capitalized=$(echo "$prj_str" | awk '{for (i=1; i<=NF; i++) $i = toupper(substr($i,1,1)) substr($i,2); print}')
- export viewer_channel="Second Life Project $capitalized"
- elif [[ "$prefix" == "release" || "$prefix" == "main" ]];
- then
- export viewer_channel="Second Life Release"
- else
- export viewer_channel="Second Life Test"
- fi
- fi
- echo "viewer_channel=$viewer_channel"
- echo "viewer_channel=$viewer_channel" >> "$GITHUB_OUTPUT"
- # On windows we need to point the build to the correct python
- # as neither CMake's FindPython nor our custom Python.cmake module
- # will resolve the correct interpreter location.
- if [[ "$RUNNER_OS" == "Windows" ]]; then
- export PYTHON="$(native_path "$(which python)")"
- echo "Python location: $PYTHON"
- export PYTHON_COMMAND="$PYTHON"
- else
- export PYTHON_COMMAND="python3"
- fi
- export PYTHON_COMMAND_NATIVE="$(native_path "$PYTHON_COMMAND")"
-
- ./build.sh
-
- # Each artifact is downloaded as a distinct .zip file. Multiple jobs
- # (per the matrix above) writing the same filepath to the same
- # artifact name will *overwrite* that file. Moreover, they can
- # interfere with each other, causing the upload to fail.
- # https://github.com/actions/upload-artifact#uploading-to-the-same-artifact
- # Given the size of our installers, and the fact that we typically
- # only want to download just one instead of a single zip containing
- # several, generate a distinct artifact name for each installer.
- # If the matrix above can run multiple builds on the same
- # platform, we must disambiguate on more than the platform name.
- # e.g. if we were still running Windows 32-bit builds, we'd need to
- # qualify the artifact with bit width.
- if [[ "$AUTOBUILD_CONFIGURATION" == "ReleaseOS" ]]
- then cfg_suffix='OS'
- else cfg_suffix=''
- fi
- echo "artifact=$RUNNER_OS$cfg_suffix" >> $GITHUB_OUTPUT
-
- - name: Upload executable
- if: steps.build.outputs.viewer_app
- uses: actions/upload-artifact@v6
- with:
- name: "${{ steps.build.outputs.artifact }}-app"
- path: |
- ${{ steps.build.outputs.viewer_app }}
-
- # The other upload of nontrivial size is the symbol file. Use a distinct
- # artifact for that too.
- - name: Upload symbol file
- if: steps.build.outputs.symbolfile
- uses: actions/upload-artifact@v6
- with:
- name: "${{ steps.build.outputs.artifact }}-symbols"
- path: ${{ steps.build.outputs.symbolfile }}
-
- - name: Upload metadata
- uses: actions/upload-artifact@v6
- with:
- name: "${{ steps.build.outputs.artifact }}-metadata"
- # emitted by build.sh, possibly multiple lines
- path: |
- ${{ steps.build.outputs.metadata }}
-
- - name: Upload physics package
- uses: actions/upload-artifact@v6
- # should only be set for viewer-private
- if: matrix.configuration == 'Release' && steps.build.outputs.physicstpv
- with:
- name: "${{ steps.build.outputs.artifact }}-physics"
- # emitted by build.sh, zero or one lines
- path: |
- ${{ steps.build.outputs.physicstpv }}
-
- sign-and-package-windows:
- env:
- AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }}
- AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }}
- AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
- AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
- AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
- needs: build
- runs-on: windows-2022
- steps:
- - name: Sign and package Windows viewer
- if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID
- uses: secondlife/viewer-build-util/sign-pkg-windows@v2.1.0
- with:
- vault_uri: "${{ env.AZURE_KEY_VAULT_URI }}"
- cert_name: "${{ env.AZURE_CERT_NAME }}"
- client_id: "${{ env.AZURE_CLIENT_ID }}"
- client_secret: "${{ env.AZURE_CLIENT_SECRET }}"
- tenant_id: "${{ env.AZURE_TENANT_ID }}"
- installer_type: "${{ github.event.inputs.installer_type || 'velopack' }}"
- velopack_pack_id: "${{ needs.build.outputs.velopack_pack_id }}"
- velopack_pack_version: "${{ needs.build.outputs.velopack_pack_version }}"
- velopack_pack_title: "${{ needs.build.outputs.velopack_pack_title }}"
- velopack_main_exe: "${{ needs.build.outputs.velopack_main_exe }}"
- velopack_exclude: "${{ needs.build.outputs.velopack_exclude }}"
- velopack_icon: "${{ needs.build.outputs.velopack_icon }}"
- velopack_installer_base: "${{ needs.build.outputs.velopack_installer_base }}"
-
- sign-and-package-mac:
- env:
- NOTARIZE_CREDS_MACOS: ${{ secrets.NOTARIZE_CREDS_MACOS }}
- SIGNING_CERT_MACOS: ${{ secrets.SIGNING_CERT_MACOS }}
- SIGNING_CERT_MACOS_IDENTITY: ${{ secrets.SIGNING_CERT_MACOS_IDENTITY }}
- SIGNING_CERT_MACOS_PASSWORD: ${{ secrets.SIGNING_CERT_MACOS_PASSWORD }}
- needs: build
- runs-on: macos-latest
- steps:
- - name: Unpack Mac notarization credentials
- if: env.NOTARIZE_CREDS_MACOS
- id: note-creds
- shell: bash
- run: |
- # In NOTARIZE_CREDS_MACOS we expect to find:
- # USERNAME="..."
- # PASSWORD="..."
- # TEAM_ID="..."
- eval "${{ env.NOTARIZE_CREDS_MACOS }}"
- echo "::add-mask::$USERNAME"
- echo "::add-mask::$PASSWORD"
- echo "::add-mask::$TEAM_ID"
- echo "note_user=$USERNAME" >> "$GITHUB_OUTPUT"
- echo "note_pass=$PASSWORD" >> "$GITHUB_OUTPUT"
- echo "note_team=$TEAM_ID" >> "$GITHUB_OUTPUT"
- # If we didn't manage to retrieve all of these credentials, better
- # find out sooner than later.
- [[ -n "$USERNAME" && -n "$PASSWORD" && -n "$TEAM_ID" ]]
-
- - name: Sign and package Mac viewer
- if: env.SIGNING_CERT_MACOS && env.SIGNING_CERT_MACOS_IDENTITY && env.SIGNING_CERT_MACOS_PASSWORD && steps.note-creds.outputs.note_user && steps.note-creds.outputs.note_pass && steps.note-creds.outputs.note_team
- uses: secondlife/viewer-build-util/sign-pkg-mac@v2.1.0
- with:
- channel: ${{ needs.build.outputs.viewer_channel }}
- imagename: ${{ needs.build.outputs.imagename }}
- cert_base64: ${{ env.SIGNING_CERT_MACOS }}
- cert_name: ${{ env.SIGNING_CERT_MACOS_IDENTITY }}
- cert_pass: ${{ env.SIGNING_CERT_MACOS_PASSWORD }}
- note_user: ${{ steps.note-creds.outputs.note_user }}
- note_pass: ${{ steps.note-creds.outputs.note_pass }}
- note_team: ${{ steps.note-creds.outputs.note_team }}
- velopack_pack_id: "${{ needs.build.outputs.velopack_mac_pack_id }}"
- velopack_pack_version: "${{ needs.build.outputs.velopack_mac_pack_version }}"
- velopack_pack_title: "${{ needs.build.outputs.velopack_mac_pack_title }}"
- velopack_main_exe: "${{ needs.build.outputs.velopack_mac_main_exe }}"
- velopack_bundle_id: "${{ needs.build.outputs.velopack_mac_bundle_id }}"
-
- post-windows-symbols:
- env:
- BUGSPLAT_DATABASE: "${{ secrets.BUGSPLAT_DATABASE }}"
- SYMBOL_UPLOAD_CLIENT_ID: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_ID }}"
- SYMBOL_UPLOAD_CLIENT_SECRET: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_SECRET }}"
- needs: build
- if: needs.build.outputs.configuration == 'Release'
- runs-on: ubuntu-latest
- steps:
- - name: Download viewer exe
- uses: actions/download-artifact@v7
- with:
- name: Windows-app
- path: _artifacts
- - name: Download Windows Symbols
- if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID
- uses: actions/download-artifact@v7
- with:
- name: Windows-symbols
- - name: Extract viewer pdb
- if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID
- shell: bash
- run: |
- tar -xJf "${{ needs.build.outputs.viewer_channel }}.sym.tar.xz" -C _artifacts
- - name: Post Windows symbols
- if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID
- uses: BugSplat-Git/symbol-upload@095d163ae9ceb006d286a731dcd35cf6a1b458c8
- with:
- clientId: "${{ env.SYMBOL_UPLOAD_CLIENT_ID }}"
- clientSecret: "${{ env.SYMBOL_UPLOAD_CLIENT_SECRET }}"
- database: "${{ env.BUGSPLAT_DATABASE }}"
- application: ${{ needs.build.outputs.viewer_channel }}
- version: ${{ needs.build.outputs.viewer_version }}
- directory: _artifacts
- files: "**/{SecondLifeViewer.exe,llwebrtc.dll,*.pdb}"
- node-version: "22"
- dumpSyms: false
-
- post-mac-symbols:
- env:
- BUGSPLAT_DATABASE: "${{ secrets.BUGSPLAT_DATABASE }}"
- SYMBOL_UPLOAD_CLIENT_ID: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_ID }}"
- SYMBOL_UPLOAD_CLIENT_SECRET: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_SECRET }}"
- needs: build
- if: needs.build.outputs.configuration == 'Release'
- runs-on: ubuntu-latest
- steps:
- - name: Download Mac Symbols
- if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID
- uses: actions/download-artifact@v7
- with:
- name: macOS-symbols
- - name: Post Mac symbols
- if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID
- uses: BugSplat-Git/symbol-upload@095d163ae9ceb006d286a731dcd35cf6a1b458c8
- with:
- clientId: "${{ env.SYMBOL_UPLOAD_CLIENT_ID }}"
- clientSecret: "${{ env.SYMBOL_UPLOAD_CLIENT_SECRET }}"
- database: "${{ env.BUGSPLAT_DATABASE }}"
- application: ${{ needs.build.outputs.viewer_channel }}
- version: ${{ needs.build.outputs.viewer_version }} (${{ needs.build.outputs.viewer_version }})
- directory: .
- files: "**/*.xcarchive.zip"
- node-version: "22"
- dumpSyms: false
-
- release:
- needs: [setup, build, sign-and-package-windows, sign-and-package-mac]
- runs-on: ubuntu-latest
- if: needs.setup.outputs.release_run
- steps:
- - uses: actions/download-artifact@v7
- with:
- pattern: "*-installer"
-
- - uses: actions/download-artifact@v7
- with:
- pattern: "*-metadata"
-
- - uses: actions/download-artifact@v4
- with:
- pattern: "*-releases"
-
- - name: Rename metadata
- run: |
- cp Windows-metadata/autobuild-package.xml Windows-autobuild-package.xml
- cp Windows-metadata/newview/viewer_version.txt Windows-viewer_version.txt
- cp macOS-metadata/autobuild-package.xml macOS-autobuild-package.xml
- cp macOS-metadata/newview/viewer_version.txt macOS-viewer_version.txt
-
- # forked from softprops/action-gh-release
- - name: Create GitHub release
- id: release
- uses: secondlife-3p/action-gh-release@v1
- with:
- # name the release page for the branch
- name: "${{ needs.build.outputs.viewer_branch }}"
- # SL-20546: want the channel and version to be visible on the
- # release page
- body: |
- Build ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- ${{ needs.build.outputs.viewer_channel }}
- ${{ needs.build.outputs.viewer_version }}
- ${{ needs.build.outputs.relnotes }}
- prerelease: true
- generate_release_notes: true
- target_commitish: ${{ github.sha }}
- append_body: true
- fail_on_unmatched_files: false
- files: |
- macOS-installer/*.dmg
- Windows-installer/*.exe
- *-autobuild-package.xml
- *-viewer_version.txt
- Windows-releases/*
- macOS-releases/*
-
- - name: post release URL
- run: |
- echo "::notice::Release ${{ steps.release.outputs.url }}"
diff --git a/.github/workflows/check-pr.yaml b/.github/workflows/check-pr.yaml
deleted file mode 100644
index 08e907e83f..0000000000
--- a/.github/workflows/check-pr.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-name: Check PR
-
-on:
- pull_request:
- types: [opened, edited, reopened, synchronize]
-
-permissions:
- contents: read
-
-jobs:
- check-description:
- runs-on: ubuntu-latest
- steps:
- - name: Check PR description
- uses: actions/github-script@v8
- with:
- script: |
- const description = context.payload.pull_request.body || '';
- if (description.trim().length < 20) {
- core.setFailed("❌ PR description is too short. Please provide at least 20 characters.");
- }
diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml
deleted file mode 100644
index 800f3c42d1..0000000000
--- a/.github/workflows/cla.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: Check CLA
-
-on:
- issue_comment:
- types: [created]
- pull_request_target:
- types: [opened, closed, synchronize]
-
-jobs:
- cla:
- name: Check CLA
- runs-on: ubuntu-latest
- steps:
- - name: CLA Assistant
- if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
- uses: secondlife-3p/contributor-assistant@v2.6.1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- PERSONAL_ACCESS_TOKEN: ${{ secrets.SHARED_CLA_TOKEN }}
- with:
- branch: main
- path-to-document: https://github.com/secondlife/cla/blob/main/CLA.md
- path-to-signatures: signatures.json
- remote-organization-name: secondlife
- remote-repository-name: cla-signatures
- allowlist: callum@mbp.localdomain,rye@lindenlab.com,rye,signal@lindenlab.com,dependabot*,bot*
diff --git a/.github/workflows/label.yaml b/.github/workflows/label.yaml
deleted file mode 100644
index 218327ef47..0000000000
--- a/.github/workflows/label.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-name: Pull Request Labeler
-on:
- - pull_request_target
-
-jobs:
- triage:
- permissions:
- contents: read
- pull-requests: write
- runs-on: ubuntu-latest
- steps:
- - uses: actions/labeler@v6
- with:
- configuration-path: .github/labeler.yaml
- repo-token: "${{ secrets.GITHUB_TOKEN }}"
diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml
deleted file mode 100644
index 93bcafdea8..0000000000
--- a/.github/workflows/pre-commit.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-name: pre-commit
-
-on:
- pull_request:
- push:
- branches: [main, contribute]
- tags: [v*]
-
-
-jobs:
- pre-commit:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v6
- - uses: actions/setup-python@v6
- with:
- python-version: 3.x
- - uses: pre-commit/action@v3.0.1
diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml
deleted file mode 100644
index b6883d88d4..0000000000
--- a/.github/workflows/qatest.yaml
+++ /dev/null
@@ -1,610 +0,0 @@
-name: Run QA Test # Runs automated tests on self-hosted QA machines
-
-permissions:
- contents: read
-
-on:
- workflow_run:
- workflows: ["Build"]
- types:
- - completed
- workflow_dispatch:
- inputs:
- build_id:
- description: 'Build workflow run ID (e.g. For github.com/secondlife/viewer/actions/runs/1234567890 the ID is 1234567890)'
- required: true
- default: '14806728332'
-
-jobs:
- debug-workflow:
- runs-on: ubuntu-latest
- steps:
- - name: Debug Workflow Variables
- run: |
- echo "Workflow Conclusion: ${{ github.event.workflow_run.conclusion }}"
- echo "Workflow Head Branch: ${{ github.event.workflow_run.head_branch }}"
- echo "Workflow Run ID: ${{ github.event.workflow_run.id }}"
- echo "Head Commit Message: ${{ github.event.workflow_run.head_commit.message }}"
- echo "GitHub Ref: ${{ github.ref }}"
- echo "GitHub Ref Name: ${{ github.ref_name }}"
- echo "GitHub Event Name: ${{ github.event_name }}"
- echo "GitHub Workflow Name: ${{ github.workflow }}"
-
- install-viewer-and-run-tests:
- concurrency:
- group: ${{ github.workflow }}-${{ matrix.runner }}
- cancel-in-progress: false # Prevents cancellation of in-progress jobs
-
- strategy:
- matrix:
- include:
- - os: windows
- runner: qa-windows-atlas
- artifact: Windows-installer
- install-path: 'C:\viewer-automation-main'
- - os: windows
- runner: qa-windows-asus-dan
- artifact: Windows-installer
- install-path: 'C:\viewer-automation-main'
- - os: windows
- runner: qa-windows-kurt
- artifact: Windows-installer
- install-path: 'C:\viewer-automation-main'
- - os: mac
- runner: qa-mac-dan
- artifact: macOS-installer
- install-path: '$HOME/Documents/viewer-automation'
- - os: mac
- runner: qa-mac-atlas
- artifact: macOS-installer
- install-path: '$HOME/Documents/viewer-automation'
- - os: mac
- runner: qa-mac-caleb
- artifact: macOS-installer
- install-path: '$HOME/Documents/viewer-automation'
- fail-fast: false
-
- runs-on: [self-hosted, "${{ matrix.runner }}"]
- # Run test only on successful builds of Second_Life_X branches or on manual dispatch
- if: >
- (github.event_name == 'workflow_run' &&
- github.event.workflow_run.conclusion == 'success' &&
- startsWith(github.event.workflow_run.head_branch, 'Second_Life')) ||
- github.event_name == 'workflow_dispatch'
-
- steps:
- # Windows-specific steps
- - name: Set Build ID
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- if ("${{ github.event_name }}" -eq "workflow_dispatch") {
- echo "BUILD_ID=${{ github.event.inputs.build_id }}" | Out-File -FilePath $env:GITHUB_ENV -Append
- echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.inputs.build_id }}/artifacts" | Out-File -FilePath $env:GITHUB_ENV -Append
- } else {
- echo "BUILD_ID=${{ github.event.workflow_run.id }}" | Out-File -FilePath $env:GITHUB_ENV -Append
- echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.workflow_run.id }}/artifacts" | Out-File -FilePath $env:GITHUB_ENV -Append
- }
-
- - name: Temporarily Allow PowerShell Scripts (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- Set-ExecutionPolicy RemoteSigned -Scope Process -Force
-
- - name: Verify viewer-automation-main Exists (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- if (-Not (Test-Path -Path '${{ matrix.install-path }}')) {
- Write-Host '❌ Error: viewer-automation folder not found on runner!'
- exit 1
- }
- Write-Host '✅ viewer-automation folder is provided.'
-
- - name: Verify viewer-automation-main is Up-To-Date (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- continue-on-error: true
- run: |
- cd ${{ matrix.install-path }}
- Write-Host "Checking for repository updates..."
-
- # Check if .git directory exists
- if (Test-Path -Path ".git") {
- try {
- # Save local changes instead of discarding them
- git stash push -m "Automated stash before update $(Get-Date)"
- Write-Host "Local changes saved (if any)"
-
- # Update the repository
- git pull
- Write-Host "✅ Repository updated successfully"
-
- # Try to restore local changes if any were stashed
- $stashList = git stash list
- if ($stashList -match "Automated stash before update") {
- try {
- git stash pop
- Write-Host "✅ Local changes restored successfully"
- } catch {
- Write-Host "⚠️ Conflict when restoring local changes"
- # Save the conflicted state in a new branch for later review
- $branchName = "conflict-recovery-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
- git checkout -b $branchName
- Write-Host "✅ Created branch '$branchName' with conflicted state"
-
- # For test execution, revert to a clean state
- git reset --hard HEAD
- Write-Host "✅ Reset to clean state for test execution"
- }
- }
- } catch {
- Write-Host "⚠️ Could not update repository: $_"
- Write-Host "Continuing with existing files..."
- }
- } else {
- Write-Host "⚠️ Not a Git repository, using existing files"
- }
-
- - name: Verify Python Installation (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- try {
- $pythonVersion = (python --version)
- Write-Host "✅ Python found: $pythonVersion"
- } catch {
- Write-Host "❌ Error: Python not found in PATH. Please install Python on this runner."
- exit 1
- }
-
- - name: Setup Python Virtual Environment (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
- cd ${{ matrix.install-path }}
-
- if (-Not (Test-Path -Path ".venv")) {
- Write-Host "Creating virtual environment..."
- python -m venv .venv
- } else {
- Write-Host "Using existing virtual environment"
- }
-
- # Direct environment activation to avoid script execution issues
- $env:VIRTUAL_ENV = "$PWD\.venv"
- $env:PATH = "$env:VIRTUAL_ENV\Scripts;$env:PATH"
-
- # Install dependencies
- if (Test-Path -Path "requirements.txt") {
- Write-Host "Installing dependencies from requirements.txt..."
- pip install -r requirements.txt
-
- # Install Playwright browsers - add this line
- Write-Host "Installing Playwright browsers..."
- python -m playwright install
- } else {
- pip install outleap requests behave playwright
- # Install Playwright browsers - add this line
- Write-Host "Installing Playwright browsers..."
- python -m playwright install
- }
-
- - name: Fetch & Download Installer Artifact (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- $BUILD_ID = "${{ env.BUILD_ID }}"
- $ARTIFACTS_URL = "${{ env.ARTIFACTS_URL }}"
-
- # Fetch the correct artifact URL
- $response = Invoke-RestMethod -Headers @{Authorization="token ${{ secrets.GITHUB_TOKEN }}" } -Uri $ARTIFACTS_URL
- $ARTIFACT_NAME = ($response.artifacts | Where-Object { $_.name -eq "${{ matrix.artifact }}" }).archive_download_url
-
- if (-Not $ARTIFACT_NAME) {
- Write-Host "❌ Error: ${{ matrix.artifact }} artifact not found!"
- exit 1
- }
-
- Write-Host "✅ Artifact found: $ARTIFACT_NAME"
-
- # Secure download path
- $DownloadPath = "$env:TEMP\secondlife-build-$BUILD_ID"
- New-Item -ItemType Directory -Path $DownloadPath -Force | Out-Null
- $InstallerPath = "$DownloadPath\installer.zip"
-
- # Download the ZIP
- Invoke-WebRequest -Uri $ARTIFACT_NAME -Headers @{Authorization="token ${{ secrets.GITHUB_TOKEN }}"} -OutFile $InstallerPath
-
- # Ensure download succeeded
- if (-Not (Test-Path $InstallerPath)) {
- Write-Host "❌ Error: Failed to download ${{ matrix.artifact }}.zip"
- exit 1
- }
-
- # Set the path for other steps
- echo "DOWNLOAD_PATH=$DownloadPath" | Out-File -FilePath $env:GITHUB_ENV -Append
-
- - name: Extract Installer & Locate Executable (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- $BUILD_ID = "${{ env.BUILD_ID }}"
- $ExtractPath = "${{ env.DOWNLOAD_PATH }}"
- $InstallerZip = "$ExtractPath\installer.zip"
-
- # Print paths for debugging
- Write-Host "Extract Path: $ExtractPath"
- Write-Host "Installer ZIP Path: $InstallerZip"
-
- # Verify ZIP exists before extracting
- if (-Not (Test-Path $InstallerZip)) {
- Write-Host "❌ Error: ZIP file not found at $InstallerZip!"
- exit 1
- }
-
- Write-Host "✅ ZIP file exists and is valid. Extracting..."
-
- Expand-Archive -Path $InstallerZip -DestinationPath $ExtractPath -Force
-
- # Find installer executable
- $INSTALLER_PATH = (Get-ChildItem -Path $ExtractPath -Filter '*.exe' -Recurse | Select-Object -First 1).FullName
-
- if (-Not $INSTALLER_PATH -or $INSTALLER_PATH -eq "") {
- Write-Host "❌ Error: No installer executable found in the extracted files!"
- Write-Host "📂 Extracted Files:"
- Get-ChildItem -Path $ExtractPath -Recurse | Format-Table -AutoSize
- exit 1
- }
-
- Write-Host "✅ Installer found: $INSTALLER_PATH"
- echo "INSTALLER_PATH=$INSTALLER_PATH" | Out-File -FilePath $env:GITHUB_ENV -Append
-
- - name: Install Second Life (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- # Windows - Use Task Scheduler to bypass UAC
- $action = New-ScheduledTaskAction -Execute "${{ env.INSTALLER_PATH }}" -Argument "/S"
- $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
- $task = New-ScheduledTask -Action $action -Principal $principal
- Register-ScheduledTask -TaskName "SilentSLInstaller" -InputObject $task -Force
- Start-ScheduledTask -TaskName "SilentSLInstaller"
-
- - name: Wait for Installation to Complete (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- Write-Host "Waiting for the Second Life installer to finish..."
- do {
- Start-Sleep -Seconds 5
- $installerProcess = Get-Process | Where-Object { $_.Path -eq "${{ env.INSTALLER_PATH }}" }
- } while ($installerProcess)
-
- Write-Host "✅ Installation completed!"
-
- - name: Cleanup After Installation (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- # Cleanup Task Scheduler Entry
- Unregister-ScheduledTask -TaskName "SilentSLInstaller" -Confirm:$false
- Write-Host "✅ Task Scheduler entry removed."
-
- # Delete Installer ZIP
- $DeletePath = "${{ env.DOWNLOAD_PATH }}\installer.zip"
-
- Write-Host "Checking if installer ZIP exists: $DeletePath"
-
- # Ensure the ZIP file exists before trying to delete it
- if (Test-Path $DeletePath) {
- Remove-Item -Path $DeletePath -Force
- Write-Host "✅ Successfully deleted: $DeletePath"
- } else {
- Write-Host "⚠️ Warning: ZIP file does not exist, skipping deletion."
- }
-
- - name: Run QA Test Script (Windows)
- if: matrix.os == 'windows'
- shell: pwsh
- run: |
- Write-Host "Running QA Test script on Windows runner: ${{ matrix.runner }}..."
- cd ${{ matrix.install-path }}
-
- # Activate virtual environment
- Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
- $env:VIRTUAL_ENV = "$PWD\.venv"
- $env:PATH = "$env:VIRTUAL_ENV\Scripts;$env:PATH"
-
- # Set runner name as environment variable
- $env:RUNNER_NAME = "${{ matrix.runner }}"
-
- # Run the test script
- python runTests.py
-
- # Mac-specific steps
- - name: Set Build ID (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
- echo "BUILD_ID=${{ github.event.inputs.build_id }}" >> $GITHUB_ENV
- echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.inputs.build_id }}/artifacts" >> $GITHUB_ENV
- else
- echo "BUILD_ID=${{ github.event.workflow_run.id }}" >> $GITHUB_ENV
- echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.workflow_run.id }}/artifacts" >> $GITHUB_ENV
- fi
-
- - name: Verify viewer-automation-main Exists (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- if [ ! -d "${{ matrix.install-path }}" ]; then
- echo "❌ Error: viewer-automation folder not found on runner!"
- exit 1
- fi
- echo "✅ viewer-automation is provided."
-
- - name: Verify viewer-automation-main is Up-To-Date (Mac)
- if: matrix.os == 'mac'
- shell: bash
- continue-on-error: true
- run: |
- cd ${{ matrix.install-path }}
- echo "Checking for repository updates..."
-
- # Check if .git directory exists
- if [ -d ".git" ]; then
- # Save local changes instead of discarding them
- git stash push -m "Automated stash before update $(date)"
- echo "Local changes saved (if any)"
-
- # Update the repository
- git pull || echo "⚠️ Could not update repository"
- echo "✅ Repository updated (or attempted update)"
-
- # Try to restore local changes if any were stashed
- if git stash list | grep -q "Automated stash before update"; then
- # Try to pop the stash, but be prepared for conflicts
- if ! git stash pop; then
- echo "⚠️ Conflict when restoring local changes"
- # Save the conflicted state in a new branch for later review
- branch_name="conflict-recovery-$(date +%Y%m%d-%H%M%S)"
- git checkout -b "$branch_name"
- echo "✅ Created branch '$branch_name' with conflicted state"
-
- # For test execution, revert to a clean state
- git reset --hard HEAD
- echo "✅ Reset to clean state for test execution"
- else
- echo "✅ Local changes restored successfully"
- fi
- fi
- else
- echo "⚠️ Not a Git repository, using existing files"
- fi
-
- - name: Verify Python Installation (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- if command -v python3 &> /dev/null; then
- PYTHON_VERSION=$(python3 --version)
- echo "✅ Python found: $PYTHON_VERSION"
- else
- echo "❌ Error: Python3 not found in PATH. Please install Python on this runner."
- exit 1
- fi
-
- - name: Setup Python Virtual Environment (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- cd ${{ matrix.install-path }}
-
- # Create virtual environment if it doesn't exist
- if [ ! -d ".venv" ]; then
- echo "Creating virtual environment..."
- python3 -m venv .venv
- else
- echo "Using existing virtual environment"
- fi
-
- # Activate virtual environment
- source .venv/bin/activate
-
- # Install dependencies
- if [ -f "requirements.txt" ]; then
- pip install -r requirements.txt
- echo "✅ Installed dependencies from requirements.txt"
-
- # Install Playwright browsers - add this line
- echo "Installing Playwright browsers..."
- python -m playwright install
- else
- pip install outleap requests behave playwright
- echo "⚠️ requirements.txt not found, installed basic dependencies"
-
- # Install Playwright browsers - add this line
- echo "Installing Playwright browsers..."
- python -m playwright install
- fi
-
- - name: Fetch & Download Installer Artifact (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- # Mac-specific Bash commands
- response=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s ${{ env.ARTIFACTS_URL }})
- ARTIFACT_NAME=$(echo $response | jq -r '.artifacts[] | select(.name=="${{ matrix.artifact }}") | .archive_download_url')
-
- if [ -z "$ARTIFACT_NAME" ]; then
- echo "❌ Error: ${{ matrix.artifact }} artifact not found!"
- exit 1
- fi
-
- echo "✅ Artifact found: $ARTIFACT_NAME"
-
- # Secure download path
- DOWNLOAD_PATH="/tmp/secondlife-build-${{ env.BUILD_ID }}"
- mkdir -p $DOWNLOAD_PATH
- INSTALLER_PATH="$DOWNLOAD_PATH/installer.zip"
-
- # Download the ZIP
- curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -L $ARTIFACT_NAME -o $INSTALLER_PATH
-
- # Ensure download succeeded
- if [ ! -f "$INSTALLER_PATH" ]; then
- echo "❌ Error: Failed to download ${{ matrix.artifact }}.zip"
- exit 1
- fi
-
- # Set the path for other steps
- echo "DOWNLOAD_PATH=$DOWNLOAD_PATH" >> $GITHUB_ENV
-
- - name: Extract Installer & Locate Executable (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- EXTRACT_PATH="${{ env.DOWNLOAD_PATH }}"
- INSTALLER_ZIP="$EXTRACT_PATH/installer.zip"
-
- # Debug output
- echo "Extract Path: $EXTRACT_PATH"
- echo "Installer ZIP Path: $INSTALLER_ZIP"
-
- # Verify ZIP exists
- if [ ! -f "$INSTALLER_ZIP" ]; then
- echo "❌ Error: ZIP file not found at $INSTALLER_ZIP!"
- exit 1
- fi
-
- echo "✅ ZIP file exists and is valid. Extracting..."
-
- # Extract the ZIP
- unzip -o "$INSTALLER_ZIP" -d "$EXTRACT_PATH"
-
- # Find DMG file
- INSTALLER_PATH=$(find "$EXTRACT_PATH" -name "*.dmg" -type f | head -1)
-
- if [ -z "$INSTALLER_PATH" ]; then
- echo "❌ Error: No installer DMG found in the extracted files!"
- echo "📂 Extracted Files:"
- ls -la "$EXTRACT_PATH"
- exit 1
- fi
-
- echo "✅ Installer found: $INSTALLER_PATH"
- echo "INSTALLER_PATH=$INSTALLER_PATH" >> $GITHUB_ENV
-
- - name: Install Second Life (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- # Mac installation
- echo "Mounting DMG installer..."
- MOUNT_POINT="/tmp/secondlife-dmg"
- mkdir -p "$MOUNT_POINT"
-
- # Mount the DMG
- hdiutil attach "$INSTALLER_PATH" -mountpoint "$MOUNT_POINT" -nobrowse
-
- echo "✅ DMG mounted at $MOUNT_POINT"
-
- echo "Installing application to default location from DMG..."
-
- # Find the .app bundle in the DMG
- APP_PATH=$(find "$MOUNT_POINT" -name "*.app" -type d | head -1)
-
- if [ -z "$APP_PATH" ]; then
- echo "❌ Error: No .app bundle found in the mounted DMG!"
- exit 1
- fi
-
- APP_NAME=$(basename "$APP_PATH")
- DEST_PATH="/Applications/$APP_NAME"
-
- # Handle existing installation
- if [ -d "$DEST_PATH" ]; then
- echo "Found existing installation at: $DEST_PATH"
- echo "Moving existing installation to trash..."
-
- # Move to trash instead of force removing
- TRASH_PATH="$HOME/.Trash/$(date +%Y%m%d_%H%M%S)_$APP_NAME"
- mv "$DEST_PATH" "$TRASH_PATH" || {
- echo "⚠️ Could not move to trash, trying direct removal..."
- rm -rf "$DEST_PATH" || {
- echo "❌ Could not remove existing installation"
- echo "Please manually remove: $DEST_PATH"
- exit 1
- }
- }
-
- echo "✅ Existing installation handled successfully"
- fi
-
- # Copy the .app to /Applications
- echo "Copying app from: $APP_PATH"
- echo "To destination: /Applications/"
- cp -R "$APP_PATH" /Applications/
-
- # Verify the app was copied successfully
- if [ ! -d "$DEST_PATH" ]; then
- echo "❌ Error: Failed to install application to /Applications!"
- exit 1
- fi
-
- echo "✅ Application installed successfully to /Applications"
-
- # Save mount point for cleanup
- echo "MOUNT_POINT=$MOUNT_POINT" >> $GITHUB_ENV
-
- - name: Wait for Installation to Complete (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- echo "Waiting for installation to complete..."
- # Sleep to allow installation to finish (adjust as needed)
- sleep 30
- echo "✅ Installation completed"
-
- - name: Cleanup After Installation (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- # Mac cleanup
- # Unmount the DMG
- echo "Unmounting DMG..."
- hdiutil detach "${{ env.MOUNT_POINT }}" -force
-
- # Clean up temporary files
- echo "Cleaning up temporary files..."
- rm -rf "${{ env.DOWNLOAD_PATH }}"
- rm -rf "${{ env.MOUNT_POINT }}"
-
- echo "✅ Cleanup completed"
-
- - name: Run QA Test Script (Mac)
- if: matrix.os == 'mac'
- shell: bash
- run: |
- echo "Running QA Test script on Mac runner: ${{ matrix.runner }}..."
- cd ${{ matrix.install-path }}
-
- # Activate virtual environment
- source .venv/bin/activate
-
- # Set runner name as environment variable
- export RUNNER_NAME="${{ matrix.runner }}"
-
- # Run the test script
- python runTests.py
-
- # - name: Upload Test Results
- # if: always()
- # uses: actions/upload-artifact@v4
- # with:
- # name: test-results-${{ matrix.runner }}
- # path: ${{ matrix.install-path }}/regressionTest/test_results.html
diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml
deleted file mode 100644
index edfe71b693..0000000000
--- a/.github/workflows/stale.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-name: Stale PRs
-on:
- workflow_dispatch:
- schedule:
- - cron: 0 0 * * *
-
-permissions:
- issues: write
- pull-requests: write
-
-jobs:
- stale:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/stale@v10
- id: stale
- with:
- stale-pr-message: This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or it will be closed in 7 days
- days-before-stale: 30
- days-before-close: 7
- days-before-issue-close: -1
- exempt-pr-labels: blocked,must,should,keep
- stale-pr-label: stale
- - name: Print outputs
- run: echo ${{ join(steps.stale.outputs.*, ',') }}
diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml
deleted file mode 100644
index 0f826222a0..0000000000
--- a/.github/workflows/tag-release.yaml
+++ /dev/null
@@ -1,72 +0,0 @@
-name: Tag a Build
-
-on:
- # schedule event triggers always run on the default branch
- # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule
- schedule:
- # run "nightly" builds on default branch every mon/wed/fri
- - cron: "21 2 * * 2,4,6" # 2:21am UTC tues/thurs/sat == 7:21pm PDT mon/wed/fri -- see https://crontab.guru/#21_01_*_*_2,4,6
- workflow_dispatch:
- inputs:
- channel:
- description: "Channel to configure the build"
- required: true
- type: choice
- default: "Test"
- options:
- - "Test"
- - "Develop"
- - "Project"
- - "Release"
- project:
- description: "Project Name (used for channel name in project builds, and tag name for all builds)"
- default: "hippo"
- tag_override:
- description: "Override the tag name (optional). If the tag already exists, a numeric suffix is appended."
- required: false
-
-jobs:
- tag-release:
- runs-on: ubuntu-latest
- steps:
- - name: Setup Env Vars
- run: |
- CHANNEL="${{ inputs.channel }}"
- echo VIEWER_CHANNEL="Second_Life_${CHANNEL:-Develop}" >> ${GITHUB_ENV}
- NIGHTLY_DATE=$(date --rfc-3339=date)
- echo NIGHTLY_DATE=${NIGHTLY_DATE} >> ${GITHUB_ENV}
- echo TAG_ID="$(echo ${{ github.sha }} | cut -c1-8)-${{ inputs.project || '${NIGHTLY_DATE}' }}" >> ${GITHUB_ENV}
- - name: Create Tag
- uses: actions/github-script@v8
- with:
- # use a real access token instead of GITHUB_TOKEN default.
- # required so that the results of this tag creation can trigger the build workflow
- # https://stackoverflow.com/a/71372524
- # https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow
- # this token will need to be renewed anually in January
- github-token: ${{ secrets.LL_TAG_RELEASE_TOKEN }}
- script: |
- const override = `${{ inputs.tag_override }}`.trim();
- const baseTag = override || `${{ env.VIEWER_CHANNEL }}#${{ env.TAG_ID }}`;
-
- // Try the base tag first, then append -2, -3, etc. if it already exists
- let tag = baseTag;
- for (let attempt = 1; ; attempt++) {
- try {
- await github.rest.git.createRef({
- owner: context.repo.owner,
- repo: context.repo.repo,
- ref: `refs/tags/${tag}`,
- sha: context.sha
- });
- core.info(`Created tag: ${tag}`);
- break;
- } catch (e) {
- if (e.status === 422 && attempt < 10) {
- core.info(`Tag '${tag}' already exists, trying next suffix...`);
- tag = `${baseTag}-${attempt + 1}`;
- } else {
- throw e;
- }
- }
- }