diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 000000000..c61f6729e --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,10 @@ +# Actionlint configuration to register custom runner labels +# This prevents actionlint warnings about unrecognized runner labels + +# Custom runner labels used in this repository +labels: + # Namespace-managed Apple Silicon runners + - namespace-profile-apple-silicon-6cpu + + # High-memory runners for circuit compilation + - "128ram" diff --git a/.github/workflows/mobile-bundle-analysis.yml b/.github/workflows/mobile-bundle-analysis.yml index d53fcfc1e..9e653f9cb 100644 --- a/.github/workflows/mobile-bundle-analysis.yml +++ b/.github/workflows/mobile-bundle-analysis.yml @@ -8,7 +8,21 @@ env: NODE_ENV: "production" on: + push: + branches: + - dev + - staging + - main + paths: + - "app/**" + - "packages/mobile-sdk-alpha/**" + - ".github/workflows/mobile-bundle-analysis.yml" + - ".github/actions/**" pull_request: + branches: + - dev + - staging + - main paths: - "app/**" - "packages/mobile-sdk-alpha/**" @@ -18,7 +32,7 @@ on: jobs: analyze-android: - runs-on: macos-latest-large + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Read and sanitize Node.js version @@ -83,7 +97,9 @@ jobs: working-directory: ./app analyze-ios: - runs-on: macos-latest-large + if: github.event_name == 'workflow_dispatch' || github.event_name == 'push' + # runs-on: macos-latest-large + runs-on: namespace-profile-apple-silicon-6cpu steps: - uses: actions/checkout@v4 - name: Read and sanitize Node.js version @@ -122,6 +138,21 @@ jobs: with: path: app/ios/Pods lockfile: app/ios/Podfile.lock + - name: Check Java installation + run: | + echo "INSTALL_JAVA=false" >> "$GITHUB_ENV" + if command -v java &> /dev/null && java -version &> /dev/null; then + echo "Java already installed: $(java -version 2>&1 | head -n 1)" + else + echo "Java not found or not working, will install..." + echo "INSTALL_JAVA=true" >> "$GITHUB_ENV" + fi + - name: Setup Java environment + if: env.INSTALL_JAVA == 'true' + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: ${{ env.JAVA_VERSION }} - name: Generate token for self repositories if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }} uses: ./.github/actions/generate-github-token diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 924542201..f6ea2ea06 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -203,7 +203,10 @@ jobs: yarn test:ci working-directory: ./app build-ios: - runs-on: macos-latest-large + # This is mostly covered in mobile-e2e.yml so we don't need to run it here frequently + if: github.event_name == 'workflow_dispatch' + # runs-on: macos-latest-large + runs-on: namespace-profile-apple-silicon-6cpu needs: build-deps timeout-minutes: 60 env: @@ -251,6 +254,21 @@ jobs: echo "Xcode path:" xcode-select -p + - name: Check Java installation + run: | + echo "INSTALL_JAVA=false" >> "$GITHUB_ENV" + if command -v java &> /dev/null && java -version &> /dev/null; then + echo "Java already installed: $(java -version 2>&1 | head -n 1)" + else + echo "Java not found or not working, will install..." + echo "INSTALL_JAVA=true" >> "$GITHUB_ENV" + fi + - name: Setup Java environment + if: env.INSTALL_JAVA == 'true' + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: ${{ env.JAVA_VERSION }} - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -267,8 +285,7 @@ jobs: - name: Cache Ruby gems uses: ./.github/actions/cache-bundler with: - # TODO(jcortejoso): Confirm the path of the bundle cache - path: app/ios/vendor/bundle + path: app/vendor/bundle lock-file: app/Gemfile.lock cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.GH_GEMS_CACHE_VERSION }}-ruby${{ env.RUBY_VERSION }} - name: Cache Pods @@ -297,6 +314,14 @@ jobs: key: ${{ runner.os }}-xcode-index-${{ env.XCODE_VERSION }}-${{ hashFiles('app/ios/Podfile.lock') }} restore-keys: | ${{ runner.os }}-xcode-index-${{ env.XCODE_VERSION }}- + - name: Generate token for self repositories + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }} + uses: ./.github/actions/generate-github-token + id: github-token + with: + app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }} + private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }} + configure-netrc: "true" - name: Install Mobile Dependencies uses: ./.github/actions/yarn-install - name: Cache Built Dependencies @@ -306,6 +331,8 @@ jobs: cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }} - name: Build dependencies (cache miss) # if: steps.built-deps.outputs.cache-hit != 'true' + env: + SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token || '' }} run: | echo "Cache miss for built dependencies. Building now..." yarn workspace @selfxyz/mobile-app run build:deps @@ -315,14 +342,6 @@ jobs: bundle config set --local path 'vendor/bundle' bundle install --jobs 4 --retry 3 working-directory: ./app - - name: Generate token for self repositories - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }} - uses: ./.github/actions/generate-github-token - id: github-token - with: - app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }} - private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }} - configure-netrc: "true" - name: Install iOS Dependencies uses: nick-fields/retry@v3 with: @@ -405,6 +424,8 @@ jobs: build-android: runs-on: ubuntu-latest needs: build-deps + # This is mostly covered in mobile-e2e.yml so we don't need to run it here frequently + if: github.event_name == 'workflow_dispatch' timeout-minutes: 60 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/mobile-deploy.yml b/.github/workflows/mobile-deploy.yml index 65609a404..1084325b6 100644 --- a/.github/workflows/mobile-deploy.yml +++ b/.github/workflows/mobile-deploy.yml @@ -265,7 +265,8 @@ jobs: build-ios: needs: [bump-version] - runs-on: macos-latest-large + # runs-on: macos-latest-large + runs-on: namespace-profile-apple-silicon-6cpu permissions: contents: read actions: write @@ -430,6 +431,21 @@ jobs: fi echo "✅ Lock files exist" + - name: Check Java installation + run: | + echo "INSTALL_JAVA=false" >> "$GITHUB_ENV" + if command -v java &> /dev/null && java -version &> /dev/null; then + echo "Java already installed: $(java -version 2>&1 | head -n 1)" + else + echo "Java not found or not working, will install..." + echo "INSTALL_JAVA=true" >> "$GITHUB_ENV" + fi + - name: Setup Java environment + if: env.INSTALL_JAVA == 'true' + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: ${{ env.JAVA_VERSION }} - name: Generate token for self repositories if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }} uses: ./.github/actions/generate-github-token diff --git a/.github/workflows/mobile-e2e.yml b/.github/workflows/mobile-e2e.yml index 3ecb7b2b3..ad4ea7083 100644 --- a/.github/workflows/mobile-e2e.yml +++ b/.github/workflows/mobile-e2e.yml @@ -17,6 +17,15 @@ env: MAESTRO_VERSION: 1.41.0 on: + push: + branches: + - dev + - staging + - main + paths: + - "app/**" + - "packages/mobile-sdk-alpha/**" + - ".github/workflows/mobile-e2e.yml" pull_request: branches: - dev @@ -26,6 +35,7 @@ on: - "app/**" - "packages/mobile-sdk-alpha/**" - ".github/workflows/mobile-e2e.yml" + workflow_dispatch: jobs: android-build-test: @@ -229,7 +239,8 @@ jobs: e2e-ios: timeout-minutes: 120 - runs-on: macos-latest-large + # runs-on: macos-latest-large + runs-on: namespace-profile-apple-silicon-6cpu concurrency: group: ${{ github.workflow }}-ios-${{ github.ref }} cancel-in-progress: true @@ -273,6 +284,21 @@ jobs: - name: Toggle Yarn hardened mode for trusted PRs if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false }} run: echo "YARN_ENABLE_HARDENED_MODE=0" >> $GITHUB_ENV + - name: Check Java installation + run: | + echo "INSTALL_JAVA=false" >> "$GITHUB_ENV" + if command -v java &> /dev/null && java -version &> /dev/null; then + echo "Java already installed: $(java -version 2>&1 | head -n 1)" + else + echo "Java not found or not working, will install..." + echo "INSTALL_JAVA=true" >> "$GITHUB_ENV" + fi + - name: Setup Java environment + if: env.INSTALL_JAVA == 'true' + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: ${{ env.JAVA_VERSION }} - name: Generate token for self repositories if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }} uses: ./.github/actions/generate-github-token diff --git a/.github/workflows/mobile-sdk-demo-e2e.yml b/.github/workflows/mobile-sdk-demo-e2e.yml index be554e3df..684a61963 100644 --- a/.github/workflows/mobile-sdk-demo-e2e.yml +++ b/.github/workflows/mobile-sdk-demo-e2e.yml @@ -19,6 +19,15 @@ env: E2E_TESTING: 1 on: + push: + branches: + - dev + - staging + - main + paths: + - "packages/mobile-sdk-demo/**" + - "packages/mobile-sdk-alpha/**" + - ".github/workflows/mobile-sdk-demo-e2e.yml" pull_request: branches: - dev @@ -28,6 +37,7 @@ on: - "packages/mobile-sdk-demo/**" - "packages/mobile-sdk-alpha/**" - ".github/workflows/mobile-sdk-demo-e2e.yml" + workflow_dispatch: jobs: android-e2e: @@ -202,7 +212,11 @@ jobs: ios-e2e: timeout-minutes: 60 - runs-on: macos-latest-large + # runs-on: macos-latest-large + runs-on: namespace-profile-apple-silicon-6cpu + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' name: iOS E2E Tests Demo App concurrency: group: ${{ github.workflow }}-ios-${{ github.ref }} @@ -244,6 +258,21 @@ jobs: - name: Toggle Yarn hardened mode for trusted PRs if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false }} run: echo "YARN_ENABLE_HARDENED_MODE=0" >> $GITHUB_ENV + - name: Check Java installation + run: | + echo "INSTALL_JAVA=false" >> "$GITHUB_ENV" + if command -v java &> /dev/null && java -version &> /dev/null; then + echo "Java already installed: $(java -version 2>&1 | head -n 1)" + else + echo "Java not found or not working, will install..." + echo "INSTALL_JAVA=true" >> "$GITHUB_ENV" + fi + - name: Setup Java environment + if: env.INSTALL_JAVA == 'true' + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: ${{ env.JAVA_VERSION }} - name: Generate token for self repositories if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }} uses: ./.github/actions/generate-github-token diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 4c2a8d32c..bd61914f8 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -161,7 +161,6 @@ jobs: with: node-version-file: .nvmrc registry-url: "https://registry.npmjs.org" - - uses: actions/checkout@v4 - name: Install Dependencies uses: ./.github/actions/yarn-install - name: Build package diff --git a/app/fastlane/DEV.md b/app/fastlane/DEV.md index 61b9d205f..06d7eb297 100644 --- a/app/fastlane/DEV.md +++ b/app/fastlane/DEV.md @@ -396,7 +396,7 @@ The workflow consists of parallel jobs for each platform: #### `build-ios` Job -Runs on `macos-latest-large` and performs the following steps: +Runs on `namespace-profile-apple-silicon-6cpu` and performs the following steps: 1. Sets up the environment (Node.js, Ruby, CocoaPods) 2. Processes iOS secrets and certificates 3. Runs appropriate Fastlane lane based on branch diff --git a/packages/mobile-sdk-alpha/scripts/build-android.sh b/packages/mobile-sdk-alpha/scripts/build-android.sh index bb8732b50..8a74b2cdc 100755 --- a/packages/mobile-sdk-alpha/scripts/build-android.sh +++ b/packages/mobile-sdk-alpha/scripts/build-android.sh @@ -52,9 +52,9 @@ if [ -d "$MOBILE_SDK_NATIVE" ]; then rm -f "dist/android/mobile-sdk-alpha-release.aar" fi - # Update submodule to latest - echo "🔄 Updating submodule to latest..." - git submodule update --init --recursive mobile-sdk-native + # Setup and update submodule using the setup script + echo "🔄 Setting up and updating submodule..." + node scripts/setup-native-source.cjs # Navigate to android directory cd android diff --git a/packages/mobile-sdk-alpha/scripts/setup-native-source.cjs b/packages/mobile-sdk-alpha/scripts/setup-native-source.cjs index e465601aa..564998f51 100644 --- a/packages/mobile-sdk-alpha/scripts/setup-native-source.cjs +++ b/packages/mobile-sdk-alpha/scripts/setup-native-source.cjs @@ -9,6 +9,7 @@ const path = require('path'); // Constants const SCRIPT_DIR = __dirname; const SDK_DIR = path.dirname(SCRIPT_DIR); +const REPO_ROOT = path.resolve(SDK_DIR, '../../'); const PRIVATE_MODULE_PATH = path.join(SDK_DIR, 'mobile-sdk-native'); const GITHUB_ORG = 'selfxyz'; @@ -34,10 +35,10 @@ function log(message, type = 'info') { console.log(`${prefix} ${message}`); } -function runCommand(command, options = {}) { +function runCommand(command, options = {}, cwd = SDK_DIR) { const defaultOptions = { stdio: isDryRun ? 'pipe' : 'inherit', - cwd: SDK_DIR, + cwd: cwd, encoding: 'utf8', ...options, }; @@ -112,18 +113,98 @@ function setupSubmodule() { } try { - // Check if submodule already exists - if (fs.existsSync(PRIVATE_MODULE_PATH)) { - log('Submodule already exists, updating...', 'info'); - runCommand(`git submodule update --init --recursive mobile-sdk-native`); + // Check if submodule is registered in .gitmodules (at repo root) + const gitmodulesPath = path.join(REPO_ROOT, '.gitmodules'); + const gitmodulesExists = fs.existsSync(gitmodulesPath); + const gitmodulesContent = gitmodulesExists ? fs.readFileSync(gitmodulesPath, 'utf8') : ''; + const isSubmoduleRegistered = + gitmodulesExists && gitmodulesContent.includes('[submodule "packages/mobile-sdk-alpha/mobile-sdk-native"]'); + + if (process.env.DEBUG_SETUP === 'true') { + log(`Environment: CI=${isCI}, hasAppToken=${!!appToken}, hasRepoToken=${!!repoToken}`, 'info'); + log(`Submodule registered: ${isSubmoduleRegistered}`, 'info'); + } + + // Check if submodule directory exists and has content + const submoduleExists = fs.existsSync(PRIVATE_MODULE_PATH); + let submoduleHasContent = false; + try { + submoduleHasContent = submoduleExists && fs.readdirSync(PRIVATE_MODULE_PATH).length > 0; + } catch { + // Directory might not be readable, treat as empty + submoduleHasContent = false; + } + + log(`Submodule directory exists: ${submoduleExists}, has content: ${submoduleHasContent}`, 'info'); + + // If submodule is registered, update its URL first (important for CI where we switch from SSH to HTTPS) + if (isSubmoduleRegistered) { + log(`Submodule is registered, updating URL from SSH to HTTPS...`, 'info'); + log(`Target URL: ${submoduleUrl}`, 'info'); + + // Update submodule URL using git submodule set-url (Git 2.25+) + try { + const setUrlResult = runCommand( + `git submodule set-url packages/mobile-sdk-alpha/mobile-sdk-native "${submoduleUrl}"`, + { stdio: 'pipe' }, + REPO_ROOT, + ); + log('Updated submodule URL using git submodule set-url', 'success'); + log(`Command result: ${setUrlResult}`, 'info'); + } catch (error) { + log(`git submodule set-url failed: ${error.message}`, 'warning'); + // Fallback: Update .gitmodules file directly + try { + let gitmodulesContent = fs.readFileSync(gitmodulesPath, 'utf8'); + log(`Current .gitmodules content:\n${gitmodulesContent}`, 'info'); + // Replace the URL for mobile-sdk-native submodule + const oldContent = gitmodulesContent; + gitmodulesContent = gitmodulesContent.replace( + /(\[submodule\s+"packages\/mobile-sdk-alpha\/mobile-sdk-native"\]\s+path\s*=\s*packages\/mobile-sdk-alpha\/mobile-sdk-native\s+url\s*=\s*)[^\s]+/, + `$1${submoduleUrl}`, + ); + if (oldContent !== gitmodulesContent) { + fs.writeFileSync(gitmodulesPath, gitmodulesContent, 'utf8'); + log('Updated .gitmodules with new submodule URL', 'success'); + log(`New .gitmodules content:\n${gitmodulesContent}`, 'info'); + } else { + log('No changes made to .gitmodules - regex may not match', 'warning'); + } + } catch (fallbackError) { + log(`Could not update .gitmodules: ${fallbackError.message}`, 'error'); + } + } + } + + // If directory exists but is empty, remove it so we can re-initialize + if (submoduleExists && !submoduleHasContent) { + log('Submodule directory exists but is empty, removing...', 'info'); + runCommand(`rm -rf "${path.relative(REPO_ROOT, PRIVATE_MODULE_PATH)}"`, { stdio: 'pipe' }, REPO_ROOT); + } + + if (isSubmoduleRegistered) { + // Submodule is registered, update/init it + log('Updating and initializing submodule...', 'info'); + try { + const updateResult = runCommand( + `git submodule update --init --recursive packages/mobile-sdk-alpha/mobile-sdk-native`, + {}, + REPO_ROOT, + ); + log(`Submodule update completed: ${updateResult}`, 'success'); + } catch (error) { + log(`Submodule update failed: ${error.message}`, 'error'); + throw error; + } } else { - // Add submodule - const addCommand = `git submodule add -b ${BRANCH} "${submoduleUrl}" mobile-sdk-native`; + // Submodule not registered, add it + log('Adding submodule...', 'info'); + const addCommand = `git submodule add -b ${BRANCH} "${submoduleUrl}" packages/mobile-sdk-alpha/mobile-sdk-native`; if (isCI && (appToken || repoToken)) { // Security: Run command silently to avoid token exposure in logs - runCommand(addCommand, { stdio: 'pipe' }); + runCommand(addCommand, { stdio: 'pipe' }, REPO_ROOT); } else { - runCommand(addCommand); + runCommand(addCommand, {}, REPO_ROOT); } }