Repository navigation
fix(): release prep #63
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| workflow_call: | |
| inputs: | |
| run_cross_platform: | |
| description: Build every supported host and mobile target family | |
| required: false | |
| default: true | |
| type: boolean | |
| push: | |
| branches: | |
| - master | |
| - dev | |
| - 'jwerle/**' | |
| - 'feature/**' | |
| - 'fix/**' | |
| pull_request: | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| env: | |
| CI: true | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| PUPPETEER_SKIP_DOWNLOAD: 'true' | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| changes: | |
| name: Determine required coverage | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| outputs: | |
| run_ci: ${{ steps.scope.outputs.run_ci }} | |
| runtime_changed: ${{ steps.scope.outputs.runtime_changed }} | |
| steps: | |
| - name: Classify changed files | |
| id: scope | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| BEFORE_SHA: ${{ github.event.before }} | |
| CURRENT_SHA: ${{ github.sha }} | |
| REF_NAME: ${{ github.ref_name }} | |
| PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} | |
| run: | | |
| run_ci=true | |
| if [[ "$EVENT_NAME" == 'push' && "$REF_NAME" != 'master' && "$REF_NAME" != 'dev' ]]; then | |
| if pull_count="$(gh api "/repos/$GITHUB_REPOSITORY/commits/$CURRENT_SHA/pulls" --jq '[.[] | select(.state == "open")] | length')" && (( pull_count > 0 )); then | |
| run_ci=false | |
| fi | |
| fi | |
| echo "run_ci=$run_ci" >> "$GITHUB_OUTPUT" | |
| if [[ "$run_ci" != 'true' ]]; then | |
| echo 'An open pull-request run already covers this branch commit; skipping the duplicate push run.' >> "$GITHUB_STEP_SUMMARY" | |
| echo 'runtime_changed=false' >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| changed_files="$RUNNER_TEMP/changed-files.txt" | |
| case "$EVENT_NAME" in | |
| pull_request) | |
| if ! gh api --paginate \ | |
| "/repos/$GITHUB_REPOSITORY/pulls/$PULL_REQUEST_NUMBER/files?per_page=100" \ | |
| --jq '.[].filename' > "$changed_files"; then | |
| printf '*\n' > "$changed_files" | |
| fi | |
| ;; | |
| push) | |
| if [[ -z "$BEFORE_SHA" || "$BEFORE_SHA" =~ ^0+$ ]]; then | |
| printf '*\n' > "$changed_files" | |
| else | |
| if comparison="$(gh api "/repos/$GITHUB_REPOSITORY/compare/$BEFORE_SHA...$CURRENT_SHA")"; then | |
| jq -r '.files[].filename' <<< "$comparison" > "$changed_files" | |
| else | |
| printf '*\n' >> "$changed_files" | |
| fi | |
| if (( $(wc -l < "$changed_files") >= 300 )); then | |
| printf '*\n' >> "$changed_files" | |
| fi | |
| fi | |
| ;; | |
| *) | |
| printf '*\n' > "$changed_files" | |
| ;; | |
| esac | |
| runtime_changed=false | |
| while IFS= read -r file; do | |
| case "$file" in | |
| '') ;; | |
| *.md|LICENSE*|share/man/*) ;; | |
| *) runtime_changed=true ;; | |
| esac | |
| done < "$changed_files" | |
| echo "runtime_changed=$runtime_changed" >> "$GITHUB_OUTPUT" | |
| if [[ "$runtime_changed" == "true" ]]; then | |
| echo 'Runtime, tooling, or workflow changes require build coverage.' >> "$GITHUB_STEP_SUMMARY" | |
| else | |
| echo 'Documentation-only changes skip native builds and integration tests.' >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| lint: | |
| name: Lint | |
| needs: changes | |
| if: needs.changes.outputs.run_ci == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 | |
| - name: Setup pnpm and Node.js | |
| uses: pnpm/setup@84cb39b217b10273981911c288cd62326dc7c6d2 # v2.0.2 | |
| with: | |
| runtime: node@24 | |
| cache: true | |
| cache-dependency-path: pnpm-lock.yaml | |
| install: false | |
| - name: Setup Python | |
| uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 | |
| with: | |
| python-version: '3.x' | |
| cache: pip | |
| cache-dependency-path: .github/requirements-lint.txt | |
| - name: Install actionlint | |
| shell: bash | |
| env: | |
| ACTIONLINT_VERSION: 1.7.11 | |
| ACTIONLINT_SHA256: 900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a | |
| run: | | |
| archive="$RUNNER_TEMP/actionlint.tar.gz" | |
| bin_dir="$RUNNER_TEMP/actionlint-bin" | |
| curl --fail --location --retry 3 --silent --show-error \ | |
| --output "$archive" \ | |
| "https://github.com/rhysd/actionlint/releases/download/v$ACTIONLINT_VERSION/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" | |
| echo "$ACTIONLINT_SHA256 $archive" | sha256sum --check --status | |
| mkdir -p "$bin_dir" | |
| tar -xzf "$archive" -C "$bin_dir" actionlint | |
| echo "$bin_dir" >> "$GITHUB_PATH" | |
| - name: Install cpplint | |
| run: python -m pip install --requirement .github/requirements-lint.txt | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile --prefer-offline | |
| - name: Lint GitHub Actions workflows | |
| run: actionlint .github/workflows/*.yml | |
| - name: Run tooling unit tests | |
| run: npm run test:unit | |
| - name: Lint | |
| run: npm run test:lint:ci | |
| - name: Validate generated documentation and declarations are committed | |
| run: | | |
| npm run gen:docs | |
| git diff --exit-code | |
| node-compatibility: | |
| name: Tooling unit tests / Node 22 | |
| needs: [changes, lint] | |
| if: needs.changes.outputs.runtime_changed == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 | |
| with: | |
| node-version: 22.x | |
| - name: Run tooling unit tests | |
| run: npm run test:unit | |
| linux-integration: | |
| name: Linux x64 integration / Node 24 | |
| needs: [changes, lint] | |
| if: needs.changes.outputs.runtime_changed == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 90 | |
| env: | |
| CCACHE_BASEDIR: ${{ github.workspace }} | |
| CCACHE_COMPILERCHECK: content | |
| CCACHE_DIR: ${{ github.workspace }}/.cache/ccache | |
| CCACHE_TEMPDIR: ${{ github.workspace }}/.cache/ccache-tmp | |
| DEBUG: '1' | |
| GDK_BACKEND: x11 | |
| GSK_RENDERER: cairo | |
| LIBGL_ALWAYS_SOFTWARE: '1' | |
| NO_ANDROID: '1' | |
| NO_IOS: '1' | |
| ORO_CI_FAST_COMPILE: '1' | |
| ORO_CI_ID: linux-x64-node24 | |
| ORO_SKIP_PATH_PROMPT: '1' | |
| ORO_TEST_HEADLESS: '1' | |
| ORO_TEST_SKIP_DESKTOP_EXTENSION: '1' | |
| ORO_TEST_SKIP_TEST_EXTENSIONS: '1' | |
| WEBKIT_DISABLE_COMPOSITING_MODE: '1' | |
| XDG_RUNTIME_DIR: /tmp/oro-xdg-runtime | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 | |
| with: | |
| node-version: 24.x | |
| - name: Setup Go for libipfs | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7 | |
| with: | |
| go-version: '1.23.2' | |
| cache: false | |
| - name: Setup Unix Rust compiler cache | |
| uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 | |
| with: | |
| version: v0.17.0 | |
| - name: Configure Unix Rust compiler cache | |
| shell: bash | |
| run: | | |
| { | |
| echo 'SCCACHE_GHA_ENABLED=true' | |
| echo 'RUSTC_WRAPPER=sccache' | |
| } >> "$GITHUB_ENV" | |
| - name: Restore native compiler cache | |
| id: native-cache | |
| uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: ${{ env.CCACHE_DIR }} | |
| key: ccache-v1-${{ runner.os }}-${{ runner.arch }}-linux-x64-${{ github.sha }}-${{ github.run_attempt }} | |
| restore-keys: | | |
| ccache-v1-${{ runner.os }}-${{ runner.arch }}-linux-x64-${{ github.sha }}- | |
| ccache-v1-${{ runner.os }}-${{ runner.arch }}-linux-x64- | |
| ccache-v1-${{ runner.os }}-${{ runner.arch }}- | |
| - name: Restore Rust dependency cache | |
| uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: | | |
| ~/.cargo/git | |
| ~/.cargo/registry | |
| ~/.rustup/toolchains/nightly-2023-10-05-* | |
| ~/.rustup/update-hashes/nightly-2023-10-05-* | |
| key: cargo-v2-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('rust/**/Cargo.lock', 'rust/**/Cargo.toml') }} | |
| restore-keys: | | |
| cargo-v2-${{ runner.os }}-${{ runner.arch }}- | |
| cargo-v1-${{ runner.os }}-${{ runner.arch }}- | |
| - name: Restore Go build cache | |
| uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: | | |
| .cache/go-build | |
| .cache/go-mod | |
| key: go-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('bin/install.sh') }} | |
| restore-keys: | | |
| go-v1-${{ runner.os }}-${{ runner.arch }}- | |
| - name: Restore test dependency cache | |
| uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: ~/.npm | |
| key: npm-test-v1-${{ runner.os }}-${{ runner.arch }}-node24-${{ hashFiles('test/package-lock.json') }} | |
| restore-keys: | | |
| npm-test-v1-${{ runner.os }}-${{ runner.arch }}-node24- | |
| - name: Install Linux system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| autoconf \ | |
| automake \ | |
| build-essential \ | |
| ccache \ | |
| clang-18 \ | |
| curl \ | |
| dbus-daemon \ | |
| git \ | |
| libdbus-1-dev \ | |
| libgtk-3-dev \ | |
| libsoup-3.0-dev \ | |
| libsystemd-dev \ | |
| libtool \ | |
| libwebkit2gtk-4.1-dev \ | |
| pkg-config | |
| - name: Configure native compiler cache and headless runtime | |
| shell: bash | |
| run: | | |
| echo /usr/lib/ccache >> "$GITHUB_PATH" | |
| { | |
| echo "ORO_HOME=$RUNNER_TEMP/oro-ci-linux-x64-node24" | |
| echo "PREFIX=$RUNNER_TEMP/oro-ci-linux-x64-node24" | |
| echo 'CMAKE_C_COMPILER_LAUNCHER=ccache' | |
| echo 'CMAKE_CXX_COMPILER_LAUNCHER=ccache' | |
| } >> "$GITHUB_ENV" | |
| mkdir -p "$CCACHE_TEMPDIR" | |
| ccache --max-size 1536M | |
| ccache --zero-stats | |
| mkdir -p "$XDG_RUNTIME_DIR" | |
| chmod 700 "$XDG_RUNTIME_DIR" | |
| - name: Install test harness dependencies | |
| run: npm ci --prefix test --no-audit --prefer-offline | |
| - name: Build Oro Runtime CLI | |
| id: build-runtime | |
| timeout-minutes: 20 | |
| shell: bash | |
| run: ./bin/install.sh --yes-deps | |
| - name: Save native compiler cache | |
| if: ${{ always() && steps.native-cache.outcome == 'success' && steps.native-cache.outputs.cache-hit != 'true' }} | |
| uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: ${{ env.CCACHE_DIR }} | |
| key: ${{ steps.native-cache.outputs.cache-primary-key }} | |
| - name: Validate desktop-only target families | |
| id: validate-targets | |
| if: ${{ always() && steps.build-runtime.outcome == 'success' }} | |
| shell: bash | |
| run: | | |
| shopt -s nullglob | |
| mobile_targets=( | |
| "$ORO_HOME"/lib/*-android | |
| "$ORO_HOME"/lib/*-iPhoneOS | |
| "$ORO_HOME"/lib/*-iPhoneSimulator | |
| "$ORO_HOME"/lib/*-ios | |
| "$ORO_HOME"/lib/*-ios-simulator | |
| ) | |
| if (( ${#mobile_targets[@]} != 0 )); then | |
| echo >&2 'Linux desktop CI unexpectedly contains a mobile target directory' | |
| exit 1 | |
| fi | |
| - name: Smoke test staged CLI | |
| id: smoke-test | |
| if: ${{ always() && steps.validate-targets.outcome == 'success' }} | |
| run: | | |
| node -e "const { spawnSync } = require('node:child_process'); const path = require('node:path'); const cli = path.join(process.env.ORO_HOME, 'bin', 'oroc'); const result = spawnSync(cli, ['--version'], { stdio: 'inherit' }); process.exit(result.status ?? 1)" | |
| node -e "const { spawnSync } = require('node:child_process'); const path = require('node:path'); const cli = path.join(process.env.ORO_HOME, 'bin', 'oroc'); const result = spawnSync(cli, ['help'], { stdio: 'inherit' }); process.exit(result.status ?? 1)" | |
| - name: Run desktop tests | |
| if: ${{ always() && steps.smoke-test.outcome == 'success' }} | |
| timeout-minutes: 20 | |
| run: dbus-run-session -- npm test | |
| - name: Run child process integration tests | |
| if: ${{ always() && steps.smoke-test.outcome == 'success' }} | |
| timeout-minutes: 15 | |
| run: dbus-run-session -- npm run test:child-process | |
| - name: Run MCP integration tests | |
| if: ${{ always() && steps.smoke-test.outcome == 'success' }} | |
| timeout-minutes: 15 | |
| run: dbus-run-session -- npm run test:mcp | |
| - name: Run runtime-core tests | |
| if: ${{ always() && steps.smoke-test.outcome == 'success' }} | |
| timeout-minutes: 15 | |
| run: dbus-run-session -- npm run test:runtime-core | |
| - name: Report native compiler cache | |
| if: always() | |
| run: ccache --show-stats || true | |
| test-platform: | |
| name: Build and test ${{ matrix.name }} | |
| needs: [changes, lint] | |
| if: >- | |
| needs.changes.outputs.runtime_changed == 'true' && | |
| (github.event_name != 'workflow_call' || inputs.run_cross_platform) | |
| runs-on: ${{ matrix.runs_on }} | |
| timeout-minutes: 120 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - name: Linux arm64 | |
| id: linux-arm64 | |
| runs_on: ubuntu-24.04-arm | |
| release_support: desktop | |
| build_android: false | |
| exclude_android: true | |
| exclude_ios: true | |
| install_tests: false | |
| test_desktop: false | |
| test_child_process: false | |
| test_android: false | |
| test_ios: false | |
| windows: false | |
| - name: Android x86_64 | |
| id: android-x86_64 | |
| runs_on: ubuntu-24.04 | |
| release_support: android | |
| android_supported_abis: x86_64 | |
| build_android: true | |
| exclude_android: false | |
| exclude_ios: true | |
| install_tests: true | |
| test_desktop: false | |
| test_child_process: false | |
| test_android: true | |
| test_ios: false | |
| windows: false | |
| - name: Android arm64-v8a | |
| id: android-arm64-v8a | |
| runs_on: ubuntu-24.04 | |
| release_support: android | |
| android_supported_abis: arm64-v8a | |
| build_android: true | |
| exclude_android: false | |
| exclude_ios: true | |
| install_tests: false | |
| test_desktop: false | |
| test_child_process: false | |
| test_android: false | |
| test_ios: false | |
| windows: false | |
| - name: macOS x64 | |
| id: macos-x64 | |
| runs_on: macos-15-intel | |
| compile_only: true | |
| release_support: desktop | |
| build_android: false | |
| exclude_android: true | |
| exclude_ios: true | |
| install_tests: false | |
| test_desktop: false | |
| test_child_process: false | |
| test_android: false | |
| test_ios: false | |
| windows: false | |
| - name: macOS + iOS arm64 | |
| id: macos-ios-arm64 | |
| runs_on: macos-14 | |
| release_support: ios | |
| apple_mobile_targets: arm64-iPhoneSimulator | |
| build_android: false | |
| exclude_android: true | |
| exclude_ios: false | |
| install_tests: true | |
| test_desktop: true | |
| test_child_process: false | |
| test_android: false | |
| test_ios: true | |
| windows: false | |
| - name: Windows x64 | |
| id: windows-x64 | |
| runs_on: windows-2022 | |
| release_support: desktop | |
| build_android: false | |
| exclude_android: true | |
| exclude_ios: true | |
| install_tests: true | |
| test_desktop: true | |
| test_child_process: true | |
| test_android: false | |
| test_ios: false | |
| windows: true | |
| env: | |
| ANDROID_SUPPORTED_ABIS: ${{ matrix.android_supported_abis }} | |
| BUILD_ANDROID: ${{ matrix.build_android }} | |
| CCACHE_BASEDIR: ${{ github.workspace }} | |
| CCACHE_COMPILERCHECK: content | |
| CCACHE_DIR: ${{ github.workspace }}/.cache/ccache | |
| CCACHE_TEMPDIR: ${{ github.workspace }}/.cache/ccache-tmp | |
| DEBUG: '1' | |
| EXCLUDE_ANDROID: ${{ matrix.exclude_android }} | |
| EXCLUDE_IOS: ${{ matrix.exclude_ios }} | |
| GDK_BACKEND: x11 | |
| GSK_RENDERER: cairo | |
| LIBGL_ALWAYS_SOFTWARE: '1' | |
| ORO_CI_APPLE_MOBILE_TARGETS: ${{ matrix.apple_mobile_targets }} | |
| ORO_CI_FAST_COMPILE: '1' | |
| ORO_CI_ID: ${{ matrix.id }} | |
| ORO_RUNTIME_COMPILE_ONLY: ${{ matrix.compile_only }} | |
| ORO_PRUNE_BUILD_OUTPUTS_AFTER_INSTALL: ${{ matrix.test_android }} | |
| ORO_PRUNE_IROH_BUILD_OUTPUTS: ${{ matrix.build_android }} | |
| ORO_PRUNE_TRANSIENT_BUILD_OUTPUTS: ${{ matrix.build_android }} | |
| ORO_SKIP_PATH_PROMPT: '1' | |
| ORO_TEST_HEADLESS: '1' | |
| ORO_TEST_SKIP_DESKTOP_EXTENSION: '1' | |
| ORO_TEST_SKIP_TEST_EXTENSIONS: '1' | |
| RELEASE_SUPPORT: ${{ matrix.release_support }} | |
| WEBKIT_DISABLE_COMPOSITING_MODE: '1' | |
| XDG_RUNTIME_DIR: /tmp/oro-xdg-runtime | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 | |
| with: | |
| node-version: 24.x | |
| - name: Setup Go for libipfs | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7 | |
| with: | |
| go-version: '1.23.2' | |
| cache: false | |
| - name: Setup Windows native compiler cache | |
| if: matrix.windows | |
| uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 | |
| with: | |
| version: v0.17.0 | |
| - name: Setup Unix Rust compiler cache | |
| if: runner.os != 'Windows' | |
| uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 | |
| with: | |
| version: v0.17.0 | |
| - name: Configure Windows native compiler cache | |
| if: matrix.windows | |
| shell: bash | |
| run: | | |
| { | |
| echo 'SCCACHE_GHA_ENABLED=true' | |
| echo 'RUSTC_WRAPPER=sccache' | |
| echo 'CMAKE_C_COMPILER_LAUNCHER=sccache' | |
| echo 'CMAKE_CXX_COMPILER_LAUNCHER=sccache' | |
| } >> "$GITHUB_ENV" | |
| - name: Configure Unix Rust compiler cache | |
| if: runner.os != 'Windows' | |
| shell: bash | |
| run: | | |
| { | |
| echo 'SCCACHE_GHA_ENABLED=true' | |
| echo 'RUSTC_WRAPPER=sccache' | |
| } >> "$GITHUB_ENV" | |
| - name: Setup Java for Android | |
| if: matrix.build_android | |
| uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| cache: gradle | |
| cache-dependency-path: | | |
| bin/android-functions.sh | |
| bin/generate-gradle-files.sh | |
| - name: Resolve Android SDK cache root | |
| if: matrix.build_android | |
| id: android-sdk | |
| shell: bash | |
| run: echo "root=$ANDROID_HOME" >> "$GITHUB_OUTPUT" | |
| - name: Reclaim Android build disk | |
| if: matrix.build_android && runner.os == 'Linux' | |
| shell: bash | |
| run: | | |
| for directory in \ | |
| /usr/share/dotnet \ | |
| /opt/ghc \ | |
| /usr/local/.ghcup \ | |
| /opt/hostedtoolcache/CodeQL \ | |
| "$ANDROID_HOME/system-images" | |
| do | |
| if [[ -e "$directory" ]]; then | |
| sudo rm -rf -- "$directory" | |
| fi | |
| done | |
| android_group="$(id -gn)" | |
| for directory in \ | |
| "$ANDROID_HOME" \ | |
| "$ANDROID_HOME/build-tools" \ | |
| "$ANDROID_HOME/cmdline-tools" \ | |
| "$ANDROID_HOME/ndk" \ | |
| "$ANDROID_HOME/platforms" | |
| do | |
| if [[ -e "$directory" ]]; then | |
| sudo chown "$USER":"$android_group" "$directory" | |
| else | |
| sudo install -d -o "$USER" -g "$android_group" "$directory" | |
| fi | |
| done | |
| shopt -s nullglob | |
| cache_directories=( | |
| "$ANDROID_HOME/build-tools/36.0.0" | |
| "$ANDROID_HOME/cmdline-tools/23.0" | |
| "$ANDROID_HOME/ndk/29.0.14206865" | |
| "$ANDROID_HOME/platform-tools" | |
| "$ANDROID_HOME"/platforms/android-37* | |
| ) | |
| for directory in "${cache_directories[@]}"; do | |
| if [[ -e "$directory" ]]; then | |
| sudo chown -R "$USER":"$android_group" "$directory" | |
| fi | |
| done | |
| sudo apt-get clean | |
| df -h . | |
| - name: Restore Android build SDK cache | |
| if: matrix.build_android | |
| uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: | | |
| ${{ steps.android-sdk.outputs.root }}/build-tools/36.0.0 | |
| ${{ steps.android-sdk.outputs.root }}/cmdline-tools/23.0 | |
| ${{ steps.android-sdk.outputs.root }}/ndk/29.0.14206865 | |
| ${{ steps.android-sdk.outputs.root }}/platform-tools | |
| ${{ steps.android-sdk.outputs.root }}/platforms/android-37* | |
| key: android-build-sdk-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('bin/android-functions.sh') }} | |
| - name: Restore native compiler cache | |
| if: runner.os != 'Windows' | |
| id: native-cache | |
| uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: ${{ env.CCACHE_DIR }} | |
| key: ccache-v1-${{ runner.os }}-${{ runner.arch }}-${{ matrix.id }}-${{ github.sha }}-${{ github.run_attempt }} | |
| restore-keys: | | |
| ccache-v1-${{ runner.os }}-${{ runner.arch }}-${{ matrix.id }}-${{ github.sha }}- | |
| ccache-v1-${{ runner.os }}-${{ runner.arch }}-${{ matrix.id }}- | |
| ccache-v1-${{ runner.os }}-${{ runner.arch }}- | |
| - name: Restore Rust dependency cache | |
| uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: | | |
| ~/.cargo/git | |
| ~/.cargo/registry | |
| ~/.rustup/toolchains/nightly-2023-10-05-* | |
| ~/.rustup/update-hashes/nightly-2023-10-05-* | |
| key: cargo-v2-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('rust/**/Cargo.lock', 'rust/**/Cargo.toml') }} | |
| restore-keys: | | |
| cargo-v2-${{ runner.os }}-${{ runner.arch }}- | |
| cargo-v1-${{ runner.os }}-${{ runner.arch }}- | |
| - name: Restore Go build cache | |
| uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: | | |
| .cache/go-build | |
| .cache/go-mod | |
| key: go-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('bin/install.sh') }} | |
| restore-keys: | | |
| go-v1-${{ runner.os }}-${{ runner.arch }}- | |
| - name: Restore test dependency cache | |
| if: matrix.install_tests | |
| uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: ~/.npm | |
| key: npm-test-v1-${{ runner.os }}-${{ runner.arch }}-node24-${{ hashFiles('test/package-lock.json') }} | |
| restore-keys: | | |
| npm-test-v1-${{ runner.os }}-${{ runner.arch }}-node24- | |
| - name: Install Linux system dependencies | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| autoconf \ | |
| automake \ | |
| build-essential \ | |
| ccache \ | |
| clang-18 \ | |
| curl \ | |
| git \ | |
| libdbus-1-dev \ | |
| libgtk-3-dev \ | |
| libsoup-3.0-dev \ | |
| libsystemd-dev \ | |
| libtool \ | |
| libwebkit2gtk-4.1-dev \ | |
| pkg-config | |
| - name: Install macOS system dependencies | |
| if: runner.os == 'macOS' | |
| shell: bash | |
| env: | |
| HOMEBREW_NO_AUTO_UPDATE: '1' | |
| run: brew install automake ccache libomp libtool pkg-config | |
| - name: Configure native compiler cache | |
| if: runner.os != 'Windows' | |
| shell: bash | |
| run: | | |
| if [[ "$RUNNER_OS" == 'Linux' ]]; then | |
| echo /usr/lib/ccache >> "$GITHUB_PATH" | |
| else | |
| echo "$(brew --prefix ccache)/libexec" >> "$GITHUB_PATH" | |
| fi | |
| echo 'CMAKE_C_COMPILER_LAUNCHER=ccache' >> "$GITHUB_ENV" | |
| echo 'CMAKE_CXX_COMPILER_LAUNCHER=ccache' >> "$GITHUB_ENV" | |
| mkdir -p "$CCACHE_TEMPDIR" | |
| if [[ "$RUNNER_OS" == 'macOS' ]]; then | |
| ccache --max-size 3G | |
| else | |
| ccache --max-size 1536M | |
| fi | |
| ccache --zero-stats | |
| - name: Prepare Linux headless runtime directory | |
| if: runner.os == 'Linux' | |
| shell: bash | |
| run: | | |
| mkdir -p "$XDG_RUNTIME_DIR" | |
| chmod 700 "$XDG_RUNTIME_DIR" | |
| - name: Configure source-build target families | |
| shell: bash | |
| run: | | |
| { | |
| echo "ORO_HOME=$RUNNER_TEMP/oro-ci-$ORO_CI_ID" | |
| echo "PREFIX=$RUNNER_TEMP/oro-ci-$ORO_CI_ID" | |
| if [[ "$ORO_RUNTIME_COMPILE_ONLY" == "true" ]]; then | |
| # The Intel macOS lane validates every host translation unit. | |
| # Apple Silicon performs the complete archive, link, and tests. | |
| echo "ORO_RUNTIME_SOURCE_PREFLIGHT=1" | |
| else | |
| # Archive builds compile the complete source surface. Do not | |
| # syntax-compile every translation unit a second time first. | |
| echo "ORO_RUNTIME_SOURCE_PREFLIGHT=0" | |
| fi | |
| if [[ "$EXCLUDE_ANDROID" == "true" ]]; then | |
| echo "NO_ANDROID=1" | |
| else | |
| echo "NO_ANDROID=" | |
| fi | |
| if [[ "$EXCLUDE_IOS" == "true" ]]; then | |
| echo "NO_IOS=1" | |
| else | |
| echo "NO_IOS=" | |
| fi | |
| # The Linux integration lane exercises the desktop networking FFI. | |
| # Cross-platform lanes focus on their platform runtime and tests. | |
| echo "ORO_SKIP_IROH=1" | |
| echo "ORO_SKIP_LIBIPFS=1" | |
| if [[ "$RELEASE_SUPPORT" != "desktop" ]]; then | |
| echo "ORO_RUNTIME_SEQUENTIAL_TARGET_BUILDS=1" | |
| fi | |
| if [[ "$BUILD_ANDROID" == "true" ]]; then | |
| echo "ORO_ANDROID_CI=1" | |
| echo "ORO_RUNTIME_DESKTOP_CLI_ONLY=1" | |
| echo "ANDROID_SDK_MANAGER_ACCEPT_LICENSES=yes" | |
| fi | |
| } >> "$GITHUB_ENV" | |
| - name: Report host toolchain and disk | |
| shell: bash | |
| run: | | |
| uname -a || true | |
| node --version | |
| df -h . || true | |
| if [[ "$RUNNER_OS" == "macOS" ]]; then | |
| xcodebuild -version | |
| xcrun --sdk iphoneos --show-sdk-path | |
| xcrun --sdk iphonesimulator --show-sdk-path | |
| fi | |
| if [[ "$RUNNER_OS" == "Windows" ]]; then | |
| cmd.exe /c ver | |
| fi | |
| - name: Install test harness dependencies | |
| if: matrix.install_tests | |
| run: npm ci --prefix test --no-audit --prefer-offline | |
| - name: Build Oro Runtime CLI (Unix) | |
| id: build-runtime-unix | |
| if: runner.os != 'Windows' | |
| timeout-minutes: 45 | |
| shell: bash | |
| run: ./bin/install.sh --yes-deps | |
| - name: Quiesce native compiler cache | |
| if: ${{ always() && runner.os != 'Windows' && steps.native-cache.outcome == 'success' && steps.native-cache.outputs.cache-hit != 'true' }} | |
| shell: bash | |
| run: | | |
| native_compiler_pids() { | |
| ps -Ao pid=,command= | awk -v workspace="$GITHUB_WORKSPACE" ' | |
| index($0, workspace) && | |
| $0 ~ /(^|[\/ ])(ccache|clang|clang\+\+)( |$)/ { print $1 } | |
| ' | |
| } | |
| for native_signal in TERM KILL; do | |
| native_pids="$(native_compiler_pids)" | |
| if [[ -z "$native_pids" ]]; then | |
| break | |
| fi | |
| while IFS= read -r native_pid; do | |
| if [[ -n "$native_pid" ]]; then | |
| kill -"$native_signal" "$native_pid" 2>/dev/null || true | |
| fi | |
| done <<< "$native_pids" | |
| if [[ "$native_signal" == "TERM" ]]; then | |
| sleep 2 | |
| fi | |
| done | |
| ccache --cleanup | |
| - name: Save native compiler cache | |
| if: ${{ always() && runner.os != 'Windows' && steps.native-cache.outcome == 'success' && steps.native-cache.outputs.cache-hit != 'true' }} | |
| uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: ${{ env.CCACHE_DIR }} | |
| key: ${{ steps.native-cache.outputs.cache-primary-key }} | |
| - name: Build Oro Runtime CLI (Windows) | |
| id: build-runtime-windows | |
| if: matrix.windows | |
| timeout-minutes: 20 | |
| shell: pwsh | |
| run: .\bin\install.ps1 -yesdeps -debug | |
| - name: Ensure WebView2 Runtime is installed | |
| id: setup-webview2 | |
| if: ${{ matrix.windows && steps.build-runtime-windows.outcome == 'success' }} | |
| timeout-minutes: 5 | |
| shell: pwsh | |
| run: .\test\scripts\bootstrap-webview2.ps1 | |
| - name: Validate staged target families | |
| id: validate-targets-unix | |
| if: ${{ always() && runner.os != 'Windows' && matrix.compile_only != true && steps.build-runtime-unix.outcome == 'success' }} | |
| shell: bash | |
| run: | | |
| shopt -s nullglob | |
| android_targets=("$ORO_HOME"/lib/*-android) | |
| ios_targets=("$ORO_HOME"/lib/*-iPhoneOS "$ORO_HOME"/lib/*-iPhoneSimulator "$ORO_HOME"/lib/*-ios "$ORO_HOME"/lib/*-ios-simulator) | |
| case "$RELEASE_SUPPORT" in | |
| desktop) | |
| (( ${#android_targets[@]} == 0 && ${#ios_targets[@]} == 0 )) | |
| ;; | |
| android) | |
| if (( ${#ios_targets[@]} != 0 )); then | |
| echo >&2 'Android CI unexpectedly contains an Apple-mobile target directory' | |
| exit 1 | |
| fi | |
| read -r -a required_android_abis <<< "$ANDROID_SUPPORTED_ABIS" | |
| if (( ${#required_android_abis[@]} == 0 )); then | |
| echo >&2 'Android CI has no assigned ABI target' | |
| exit 1 | |
| fi | |
| for abi in "${required_android_abis[@]}"; do | |
| target="$abi-android" | |
| if [[ ! -d "$ORO_HOME/lib/$target" ]]; then | |
| echo >&2 "Android CI is missing required ABI target: $target" | |
| exit 1 | |
| fi | |
| done | |
| for path in "${android_targets[@]}"; do | |
| target="$(basename "$path")" | |
| expected=false | |
| for abi in "${required_android_abis[@]}"; do | |
| if [[ "$target" == "$abi-android" ]]; then | |
| expected=true | |
| break | |
| fi | |
| done | |
| if [[ "$expected" != "true" ]]; then | |
| echo >&2 "Android CI built an unassigned ABI target: $target" | |
| exit 1 | |
| fi | |
| done | |
| ;; | |
| ios) | |
| if (( ${#android_targets[@]} != 0 )); then | |
| echo >&2 'Apple CI unexpectedly contains an Android target directory' | |
| exit 1 | |
| fi | |
| read -r -a required_ios_targets <<< "$ORO_CI_APPLE_MOBILE_TARGETS" | |
| if (( ${#required_ios_targets[@]} == 0 )); then | |
| echo >&2 'Apple CI has no assigned iOS targets' | |
| exit 1 | |
| fi | |
| for target in "${required_ios_targets[@]}"; do | |
| if [[ ! -d "$ORO_HOME/lib/$target" ]]; then | |
| echo >&2 "Apple CI is missing required iOS target: $target" | |
| exit 1 | |
| fi | |
| done | |
| for path in "${ios_targets[@]}"; do | |
| target="$(basename "$path")" | |
| expected=false | |
| for required_target in "${required_ios_targets[@]}"; do | |
| if [[ "$target" == "$required_target" ]]; then | |
| expected=true | |
| break | |
| fi | |
| done | |
| if [[ "$expected" != "true" ]]; then | |
| echo >&2 "Apple CI built an unassigned iOS target: $target" | |
| exit 1 | |
| fi | |
| done | |
| ;; | |
| *) | |
| echo >&2 "Unknown platform family: $RELEASE_SUPPORT" | |
| exit 1 | |
| ;; | |
| esac | |
| - name: Validate staged target families (Windows) | |
| id: validate-targets-windows | |
| if: ${{ always() && matrix.windows && steps.build-runtime-windows.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| if ($env:RELEASE_SUPPORT -ne 'desktop') { | |
| throw "Windows CI has unsupported target family: $env:RELEASE_SUPPORT" | |
| } | |
| $libRoot = Join-Path $env:ORO_HOME 'lib' | |
| $targets = if (Test-Path $libRoot) { @(Get-ChildItem -Path $libRoot -Directory) } else { @() } | |
| $mobileTargets = @($targets | Where-Object { | |
| $_.Name -like '*-android' -or $_.Name -match '-(iPhoneOS|iPhoneSimulator|ios|ios-simulator)$' | |
| }) | |
| if ($mobileTargets.Count -ne 0) { | |
| throw 'Windows desktop build unexpectedly contains a mobile target directory' | |
| } | |
| - name: Smoke test staged CLI | |
| id: smoke-test | |
| if: >- | |
| ${{ always() && | |
| ((runner.os != 'Windows' && steps.validate-targets-unix.outcome == 'success') || | |
| (runner.os == 'Windows' && steps.validate-targets-windows.outcome == 'success' && | |
| steps.setup-webview2.outcome == 'success')) }} | |
| run: | | |
| node -e "const { spawnSync } = require('node:child_process'); const path = require('node:path'); const cli = path.join(process.env.ORO_HOME, 'bin', process.platform === 'win32' ? 'oroc.exe' : 'oroc'); const result = spawnSync(cli, ['--version'], { stdio: 'inherit' }); process.exit(result.status ?? 1)" | |
| node -e "const { spawnSync } = require('node:child_process'); const path = require('node:path'); const cli = path.join(process.env.ORO_HOME, 'bin', process.platform === 'win32' ? 'oroc.exe' : 'oroc'); const result = spawnSync(cli, ['help'], { stdio: 'inherit' }); process.exit(result.status ?? 1)" | |
| - name: Run desktop tests | |
| if: ${{ always() && matrix.test_desktop && steps.smoke-test.outcome == 'success' }} | |
| timeout-minutes: 20 | |
| run: npm test | |
| - name: Run child process integration tests | |
| if: ${{ always() && matrix.test_child_process && steps.smoke-test.outcome == 'success' }} | |
| timeout-minutes: 15 | |
| run: npm run test:child-process | |
| - name: Boot iOS Simulator and run tests | |
| if: ${{ always() && matrix.test_ios && steps.smoke-test.outcome == 'success' }} | |
| timeout-minutes: 20 | |
| shell: bash | |
| run: | | |
| simulator_udid="$(python3 - <<'PY' | |
| import json | |
| import subprocess | |
| devices = json.loads(subprocess.check_output([ | |
| 'xcrun', 'simctl', 'list', 'devices', 'available', '--json' | |
| ]))['devices'] | |
| for runtime_devices in devices.values(): | |
| for device in runtime_devices: | |
| if device.get('isAvailable') and device.get('name', '').startswith('iPhone'): | |
| print(device['udid']) | |
| raise SystemExit(0) | |
| raise SystemExit('No available iPhone simulator was found') | |
| PY | |
| )" | |
| trap 'xcrun simctl shutdown "$simulator_udid" || true' EXIT | |
| xcrun simctl boot "$simulator_udid" || true | |
| xcrun simctl bootstatus "$simulator_udid" -b | |
| export ORO_IOS_SIMULATOR_UDID="$simulator_udid" | |
| export ORO_RC="$RUNNER_TEMP/oro-ios-tests.ororc" | |
| printf '[settings.ios]\nsimulator_uuid = "%s"\n' "$simulator_udid" > "$ORO_RC" | |
| npm run test:ios-simulator | |
| - name: Upload macOS crash reports | |
| if: ${{ failure() && runner.os == 'macOS' }} | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | |
| with: | |
| name: macos-crash-reports-${{ runner.arch }} | |
| path: | | |
| ~/Library/Logs/DiagnosticReports/**/oro-runtime-javascript-tests* | |
| /Library/Logs/DiagnosticReports/**/oro-runtime-javascript-tests* | |
| if-no-files-found: ignore | |
| retention-days: 7 | |
| # Restore the multi-gigabyte emulator only after native outputs have been | |
| # staged and pruned so both trees do not consume runner disk together. | |
| - name: Restore Android emulator cache | |
| id: android-emulator-cache | |
| if: ${{ always() && matrix.test_android && steps.smoke-test.outcome == 'success' }} | |
| uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 | |
| with: | |
| path: | | |
| ${{ steps.android-sdk.outputs.root }}/emulator | |
| ${{ steps.android-sdk.outputs.root }}/system-images/android-37.0/google_apis/x86_64 | |
| ~/.android/avd | |
| key: android-emulator-v37.1.11-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('test/scripts/bootstrap-android-emulator.sh') }} | |
| - name: Grant Android emulator KVM access | |
| id: android-kvm | |
| if: ${{ always() && matrix.test_android && runner.os == 'Linux' && steps.android-emulator-cache.outcome == 'success' }} | |
| shell: bash | |
| run: | | |
| if [[ ! -e /dev/kvm ]]; then | |
| echo >&2 'Android emulator acceleration is unavailable: /dev/kvm does not exist' | |
| exit 1 | |
| fi | |
| sudo chmod a+rw /dev/kvm | |
| - name: Run Android emulator tests | |
| if: ${{ always() && matrix.test_android && steps.android-emulator-cache.outcome == 'success' && steps.android-kvm.outcome == 'success' }} | |
| timeout-minutes: 20 | |
| shell: bash | |
| run: npm run test:android-emulator | |
| - name: Capture Android failure logs | |
| if: ${{ failure() && matrix.test_android }} | |
| shell: bash | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/android-failure-logs" | |
| if [[ ! -s "$RUNNER_TEMP/android-failure-logs/logcat.txt" ]]; then | |
| "$ANDROID_HOME/platform-tools/adb" logcat -d -b all > "$RUNNER_TEMP/android-failure-logs/logcat.txt" 2>&1 || true | |
| fi | |
| if [[ ! -s "$RUNNER_TEMP/android-failure-logs/activities.txt" ]]; then | |
| "$ANDROID_HOME/platform-tools/adb" shell dumpsys activity activities > "$RUNNER_TEMP/android-failure-logs/activities.txt" 2>&1 || true | |
| fi | |
| - name: Upload Android failure logs | |
| if: ${{ failure() && matrix.test_android }} | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | |
| with: | |
| name: android-failure-logs-${{ runner.arch }} | |
| path: ${{ runner.temp }}/android-failure-logs | |
| if-no-files-found: ignore | |
| retention-days: 7 | |
| - name: Report native compiler cache | |
| if: always() && runner.os != 'Windows' | |
| shell: bash | |
| run: ccache --show-stats || true | |
| - name: Report final disk usage | |
| if: always() | |
| shell: bash | |
| run: df -h . || true |