🚀 ci(publish): Updating builds and creating release/publish workflow #573
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: Main Pipeline | |
| permissions: | |
| contents: read | |
| on: | |
| pull_request: | |
| jobs: | |
| setup: | |
| name: pnpm install 🛠️ | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set up pnpm cache (Namespace) | |
| uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: pnpm | |
| - run: pnpm install --prefer-offline --frozen-lockfile | |
| license-check: | |
| name: License Check 📄 | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| needs: setup | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| filters: | | |
| lock: | |
| - 'pnpm-lock.yaml' | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set up pnpm cache (Namespace) | |
| if: steps.filter.outputs.lock == 'true' | |
| uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: pnpm | |
| - if: steps.filter.outputs.lock == 'true' | |
| run: pnpm install --prefer-offline --frozen-lockfile | |
| - if: steps.filter.outputs.lock == 'true' | |
| run: > | |
| echo "In case of error, please see ./CONTRIBUTING.md" pnpx license-checker \ --summary \ | |
| --production \ --relativeLicensePath \ --onlyAllow | |
| 'MIT;Apache-2.0;ISC;BSD-3-Clause;BSD-2-Clause;MIT*;Apache | |
| 2.0;Unlicense;Unlicensed;:CC0-1.0;CC-BY-4.0;WTFPL;0BSD;UNLICENSED;Python-2.0;MPL-2.0;CC-BY-3.0;CC0-1.0' | |
| format: | |
| name: Format Check 🎨 | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| needs: setup | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: pnpm | |
| - run: pnpm install --prefer-offline --frozen-lockfile | |
| - run: pnpm format:check | |
| build: | |
| name: Build 📦 | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| timeout-minutes: 15 | |
| needs: setup | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: pnpm | |
| - run: pnpm install --prefer-offline --frozen-lockfile | |
| - run: pnpm build | |
| type-check: | |
| name: Type Check 🔷 | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| needs: setup | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: pnpm | |
| - run: pnpm install --prefer-offline --frozen-lockfile | |
| - run: pnpm typecheck | |
| lint: | |
| name: Lint 🎨 | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| needs: setup | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: pnpm | |
| - run: pnpm install --prefer-offline --frozen-lockfile | |
| - run: pnpm lint:check | |
| test: | |
| name: Test 🧪 | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| timeout-minutes: 15 | |
| needs: setup | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: pnpm | |
| - run: pnpm install --prefer-offline --frozen-lockfile | |
| - run: pnpm test:unit | |
| e2e-node-ssr-only: | |
| name: E2E Node SSR Only 🖥️ | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| timeout-minutes: 15 | |
| needs: setup | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - run: | | |
| echo "DOTENV_CONFIG_QUIET=true" >>implementations/node-ssr-only/.env | |
| echo "VITE_NINETAILED_CLIENT_ID=${{secrets.NINETAILED_CLIENT_ID}}" >>implementations/node-ssr-only/.env | |
| echo "VITE_NINETAILED_ENVIRONMENT=${{secrets.NINETAILED_ENVIRONMENT}}" >>implementations/node-ssr-only/.env | |
| echo "VITE_EXPERIENCE_API_BASE_URL=http://localhost:8000/experience/" >>implementations/node-ssr-only/.env | |
| echo "VITE_INSIGHTS_API_BASE_URL=http://localhost:8000/insights/" >>implementations/node-ssr-only/.env | |
| echo "VITE_CONTENTFUL_TOKEN=${{secrets.CONTENTFUL_TOKEN}}" >>implementations/node-ssr-only/.env | |
| echo "VITE_CONTENTFUL_PREVIEW_TOKEN=${{secrets.CONTENTFUL_PREVIEW_TOKEN}}" >>implementations/node-ssr-only/.env | |
| echo "VITE_CONTENTFUL_ENVIRONMENT=${{secrets.CONTENTFUL_ENVIRONMENT}}" >>implementations/node-ssr-only/.env | |
| echo "VITE_CONTENTFUL_SPACE_ID=${{secrets.CONTENTFUL_SPACE_ID}}" >>implementations/node-ssr-only/.env | |
| echo "VITE_CONTENTFUL_CDA_HOST=localhost:8000" >>implementations/node-ssr-only/.env | |
| echo "VITE_CONTENTFUL_BASE_PATH=contentful" >>implementations/node-ssr-only/.env | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set up caches (Namespace) | |
| uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: | | |
| pnpm | |
| playwright | |
| apt | |
| - run: pnpm install --prefer-offline --frozen-lockfile | |
| - run: pnpm --filter @implementation/node-ssr-only exec playwright install --with-deps | |
| - run: pnpm --filter @implementation/node-ssr-only test:e2e | |
| - uses: actions/upload-artifact@v6 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: ci-results-node-ssr-only | |
| path: | | |
| ./implementations/node-ssr-only/playwright-report/ | |
| ./implementations/node-ssr-only/test-results/ | |
| retention-days: 1 | |
| e2e-node-ssr-web-vanilla: | |
| name: E2E Node SSR + Web Vanilla 🖥️ | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| timeout-minutes: 15 | |
| needs: setup | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - run: | | |
| echo "DOTENV_CONFIG_QUIET=true" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_NINETAILED_CLIENT_ID=${{secrets.NINETAILED_CLIENT_ID}}" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_NINETAILED_ENVIRONMENT=${{secrets.NINETAILED_ENVIRONMENT}}" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_EXPERIENCE_API_BASE_URL=http://localhost:8000/experience/" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_INSIGHTS_API_BASE_URL=http://localhost:8000/insights/" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_CONTENTFUL_TOKEN=${{secrets.CONTENTFUL_TOKEN}}" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_CONTENTFUL_PREVIEW_TOKEN=${{secrets.CONTENTFUL_PREVIEW_TOKEN}}" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_CONTENTFUL_ENVIRONMENT=${{secrets.CONTENTFUL_ENVIRONMENT}}" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_CONTENTFUL_SPACE_ID=${{secrets.CONTENTFUL_SPACE_ID}}" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_CONTENTFUL_CDA_HOST=localhost:8000" >>implementations/node-ssr-web-vanilla/.env | |
| echo "VITE_CONTENTFUL_BASE_PATH=contentful" >>implementations/node-ssr-web-vanilla/.env | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set up caches (Namespace) | |
| uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: | | |
| pnpm | |
| playwright | |
| apt | |
| - run: pnpm install --prefer-offline --frozen-lockfile | |
| - run: pnpm --filter @implementation/node-ssr-web-vanilla exec playwright install --with-deps | |
| - run: pnpm --filter @implementation/node-ssr-web-vanilla test:e2e | |
| - uses: actions/upload-artifact@v6 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: ci-results-node-ssr-web-vanilla | |
| path: | | |
| ./implementations/node-ssr-web-vanilla/playwright-report/ | |
| ./implementations/node-ssr-web-vanilla/test-results/ | |
| retention-days: 1 | |
| e2e-web: | |
| name: E2E Web Vanilla 🖥️ | |
| runs-on: namespace-profile-linux-8-vcpu-16-gb-ram-optimal | |
| timeout-minutes: 15 | |
| needs: setup | |
| steps: | |
| - uses: docker/setup-compose-action@v1 | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - name: Create .env and copy to implementations | |
| run: | | |
| cat > .env << 'EOF' | |
| DOTENV_CONFIG_QUIET=true | |
| VITE_NINETAILED_CLIENT_ID=${{secrets.NINETAILED_CLIENT_ID}} | |
| VITE_NINETAILED_ENVIRONMENT=${{secrets.NINETAILED_ENVIRONMENT}} | |
| VITE_EXPERIENCE_API_BASE_URL=http://localhost:8000/experience/ | |
| VITE_INSIGHTS_API_BASE_URL=http://localhost:8000/insights/ | |
| VITE_CONTENTFUL_TOKEN=${{secrets.CONTENTFUL_TOKEN}} | |
| VITE_CONTENTFUL_PREVIEW_TOKEN=${{secrets.CONTENTFUL_PREVIEW_TOKEN}} | |
| VITE_CONTENTFUL_ENVIRONMENT=${{secrets.CONTENTFUL_ENVIRONMENT}} | |
| VITE_CONTENTFUL_SPACE_ID=${{secrets.CONTENTFUL_SPACE_ID}} | |
| VITE_CONTENTFUL_CDA_HOST=localhost:8000 | |
| VITE_CONTENTFUL_BASE_PATH=contentful | |
| EOF | |
| cp .env implementations/node-ssr-only/ | |
| cp .env implementations/web-vanilla/ | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set up caches (Namespace) | |
| uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: | | |
| pnpm | |
| playwright | |
| apt | |
| - run: pnpm install --prefer-offline --frozen-lockfile | |
| - run: pnpm --filter @implementation/web-vanilla exec playwright install --with-deps | |
| - run: pnpm --filter @implementation/web-vanilla test:e2e | |
| - uses: actions/upload-artifact@v6 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: ci-results-web-vanilla | |
| path: | | |
| ./implementations/web-vanilla/playwright-report/ | |
| ./implementations/web-vanilla/test-results/ | |
| retention-days: 1 | |
| e2e-react-native-android: | |
| name: E2E React Native Android 📱 | |
| runs-on: namespace-profile-linux-16-vcpu-32-gb-ram-optimal | |
| timeout-minutes: 60 | |
| needs: setup | |
| env: | |
| DETOX_AVD_NAME: test | |
| CI: 'true' | |
| # Conservative defaults; adjust if you want more parallelism | |
| GRADLE_OPTS: >- | |
| -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.jvmargs=-Xmx4g | |
| -Dkotlin.daemon.jvm.options=-Xmx2g | |
| steps: | |
| - uses: namespacelabs/nscloud-checkout-action@v8 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| package-manager-cache: false | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set Android SDK environment variables | |
| run: | | |
| echo "ANDROID_SDK_ROOT=$HOME/.android/sdk" >> "$GITHUB_ENV" | |
| echo "ANDROID_HOME=$HOME/.android/sdk" >> "$GITHUB_ENV" | |
| - name: Prepare cache directories | |
| run: | | |
| mkdir -p "$HOME/.android/sdk" "$HOME/.android/avd" "$HOME/.android/cache" | |
| - name: Set up caches (Namespace) | |
| uses: namespacelabs/nscloud-cache-action@v1 | |
| with: | |
| cache: | | |
| apt | |
| pnpm | |
| gradle | |
| path: | | |
| ~/.android/sdk | |
| ~/.android/avd | |
| ~/.android/cache | |
| - name: Install system dependencies (Android emulator + React Native) | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends \ | |
| ca-certificates curl unzip zip git \ | |
| python3 python3-pip build-essential \ | |
| netcat-openbsd watchman \ | |
| cpu-checker \ | |
| libgl1 libnss3 libx11-6 libx11-xcb1 libxcomposite1 libxdamage1 libxrandr2 libxtst6 \ | |
| libxi6 libxrender1 libxkbcommon0 libgbm1 libdbus-1-3 libdrm2 libpulse0 | |
| sudo apt-get install -y --no-install-recommends libasound2 || sudo apt-get install -y --no-install-recommends libasound2t64 | |
| - name: Verify KVM is available | |
| run: | | |
| if [ ! -e /dev/kvm ]; then | |
| echo "/dev/kvm not found; Android hardware acceleration will not work." >&2 | |
| exit 1 | |
| fi | |
| ls -l /dev/kvm | |
| # Optional diagnostic; may return non-zero if permissions are restrictive. | |
| sudo kvm-ok || true | |
| - name: Setup Java | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Setup Android SDK | |
| uses: android-actions/setup-android@v3 | |
| - name: Install JS dependencies | |
| run: pnpm install --prefer-offline --frozen-lockfile | |
| - name: Create .env file for React Native | |
| run: | | |
| cat > implementations/react-native/.env << 'EOF' | |
| VITE_NINETAILED_CLIENT_ID=${{ secrets.NINETAILED_CLIENT_ID }} | |
| VITE_NINETAILED_ENVIRONMENT=${{ secrets.NINETAILED_ENVIRONMENT }} | |
| VITE_EXPERIENCE_API_BASE_URL=http://localhost:8000/experience/ | |
| VITE_INSIGHTS_API_BASE_URL=http://localhost:8000/insights/ | |
| VITE_CONTENTFUL_TOKEN=${{ secrets.CONTENTFUL_TOKEN }} | |
| VITE_CONTENTFUL_ENVIRONMENT=${{ secrets.CONTENTFUL_ENVIRONMENT }} | |
| VITE_CONTENTFUL_SPACE_ID=${{ secrets.CONTENTFUL_SPACE_ID }} | |
| VITE_CONTENTFUL_CDA_HOST=localhost:8000 | |
| VITE_CONTENTFUL_BASE_PATH=contentful | |
| EOF | |
| - name: Build Android app (Detox) | |
| run: | | |
| pnpm --filter @implementation/react-native test:e2e:android:build | |
| - name: Start Mock Server | |
| run: | | |
| pnpm --filter mocks serve > /tmp/mock-server.log 2>&1 & | |
| echo $! > /tmp/mock-server.pid | |
| for i in {1..60}; do | |
| if nc -z localhost 8000 2>/dev/null; then | |
| echo "Mock server is ready" | |
| break | |
| fi | |
| echo "Waiting for mock server... ($i/60)" | |
| sleep 1 | |
| done | |
| if ! nc -z localhost 8000 2>/dev/null; then | |
| echo "Mock server failed to start:" | |
| cat /tmp/mock-server.log | |
| exit 1 | |
| fi | |
| - name: Start Metro Bundler | |
| run: | | |
| cd implementations/react-native | |
| npx react-native start --port 8081 > /tmp/metro.log 2>&1 & | |
| echo $! > /tmp/metro.pid | |
| for i in {1..60}; do | |
| if nc -z localhost 8081 2>/dev/null; then | |
| echo "Metro is ready" | |
| break | |
| fi | |
| echo "Waiting for Metro... ($i/60)" | |
| sleep 1 | |
| done | |
| if ! nc -z localhost 8081 2>/dev/null; then | |
| echo "Metro failed to start:" | |
| cat /tmp/metro.log | |
| exit 1 | |
| fi | |
| - name: Run Android E2E Tests (emulator) | |
| uses: reactivecircus/android-emulator-runner@v2 | |
| with: | |
| api-level: 33 | |
| arch: x86_64 | |
| target: google_apis | |
| profile: pixel_tablet | |
| avd-name: test | |
| force-avd-creation: true | |
| emulator-boot-timeout: 600 | |
| cores: 6 | |
| ram-size: 4096M | |
| disk-size: 8G | |
| disable-animations: true | |
| emulator-options: | |
| -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect -no-snapshot | |
| -no-snapshot-save | |
| script: | | |
| echo "Verifying JAVA_HOME: $JAVA_HOME" | |
| java -version | |
| echo "Setting up adb reverse port forwarding..." | |
| adb reverse tcp:8000 tcp:8000 | |
| adb reverse tcp:8081 tcp:8081 | |
| echo "Running E2E tests..." | |
| pnpm --filter @implementation/react-native test:e2e:android:run --retries 2 | |
| - name: Upload Metro logs on failure | |
| if: failure() | |
| run: | | |
| echo "=== Metro Bundler Logs ===" | |
| cat /tmp/metro.log || echo "No metro logs found" | |
| echo "=== Mock Server Logs ===" | |
| cat /tmp/mock-server.log || echo "No mock server logs found" | |
| - name: Stop Metro and Mock Server | |
| if: always() | |
| run: | | |
| kill $(cat /tmp/metro.pid) 2>/dev/null || true | |
| kill $(cat /tmp/mock-server.pid) 2>/dev/null || true | |
| - uses: actions/upload-artifact@v6 | |
| if: always() | |
| with: | |
| name: ci-results-react-native-android | |
| path: | | |
| implementations/react-native/android/app/build/outputs/ | |
| implementations/react-native/.detox/ | |
| implementations/react-native/android/app/build/reports/ | |
| /tmp/metro.log | |
| /tmp/mock-server.log | |
| retention-days: 7 |