diff --git a/.github/CICD.md b/.github/CICD.md index 2ca4c8b4f..00ea8f61d 100644 --- a/.github/CICD.md +++ b/.github/CICD.md @@ -59,96 +59,42 @@ The workflow requires these permissions: - `GITHUB_TOKEN` - Automatically provided by GitHub Actions -### Update Formplayer Assets - -**Workflow File**: `.github/workflows/update-formplayer-assets.yml` - -#### Purpose - -Automates the build and synchronization of formplayer assets between `formulus-formplayer` (React web app) and `formulus` (React Native app). This eliminates the need for manual asset synchronization PRs and ensures formulus always has the latest built assets. - -#### Triggers - -- **Push to `main`/`dev`**: Builds assets and commits them to the repository -- **Pull Requests**: Builds assets for validation (does not commit) - -#### Path Filters - -The workflow only runs when files in these paths change: -- `formulus-formplayer/**` - Any file in the formulus-formplayer project -- `.github/workflows/update-formplayer-assets.yml` - The workflow itself - -#### Workflow Behavior - -**On Pull Requests:** -1. Builds formplayer assets using `npm run build:rn` -2. Validates that assets were built successfully -3. Uploads assets as GitHub Actions artifact -4. Does NOT commit assets (validation only) - -**On Merge (Push to main/dev):** -1. Builds formplayer assets using `npm run build:rn` -2. Checks if assets have changed -3. Commits updated assets to repository with `[skip ci]` message -4. Uploads assets as GitHub Actions artifact -5. Prevents infinite loops by ignoring asset-only commits - -#### Asset Location - -Assets are copied to: -``` -formulus/android/app/src/main/assets/formplayer_dist/ -``` - -#### Permissions Required - -- `contents: write` - To commit assets to the repository - -#### Benefits - -- **Automated**: No manual PRs needed for asset synchronization -- **Consistent**: All developers get latest assets automatically on `git pull` -- **Efficient**: Android builds use committed assets (no build step needed) -- **Safe**: Prevents workflow loops with `[skip ci]` and path filters - ### Formulus Android Build **Workflow File**: `.github/workflows/formulus-android.yml` #### Purpose -Builds Android APK for the Formulus React Native application, automatically handling formplayer asset dependencies. +Builds Android APK for the Formulus React Native application, and builds/consumes Formplayer assets in a single, two‑job workflow. #### Triggers -- **Push to `main`/`dev`** (formulus changes only): Builds release APK using committed assets -- **Pull Requests** (formulus changes only): Builds debug APK for validation -- **Workflow Run** (after formplayer assets update): Builds APK using downloaded artifacts +- **Push to `main`/`dev`** (formulus or formulus-formplayer changes): Builds Formplayer assets and then a release APK using those assets +- **Pull Requests** (formulus or formulus-formplayer changes): Builds Formplayer assets and then a debug APK for validation - **Release**: Publishes APK to GitHub Release #### Path Filters The workflow runs when files in these paths change: - `formulus/**` - Any file in the formulus project +- `formulus-formplayer/**` - Any file in the formulus-formplayer project +- `packages/tokens/**` - Shared design tokens and build inputs - `.github/workflows/formulus-android.yml` - The workflow itself -**Note**: The workflow does NOT directly trigger on `formulus-formplayer/**` changes. Instead, it runs via `workflow_run` after the Update Formplayer Assets workflow completes. - #### Asset Handling -The workflow intelligently handles formplayer assets: +The workflow intelligently handles formplayer assets using two jobs: -1. **Via workflow_run** (formplayer changed): - - Downloads assets artifact from Update Formplayer Assets workflow - - Uses downloaded assets for Android build +1. **`build-formplayer-assets` job**: + - Builds `@ode/tokens` + - Builds Formplayer assets using `npm run build:rn` in `formulus-formplayer` + - Uploads the built assets from `formulus/android/app/src/main/assets/formplayer_dist/` as a GitHub Actions artifact -2. **Direct trigger** (formulus-only changes): - - Uses committed assets from repository - - No formplayer build needed +2. **`build-android` job** (depends on assets job): + - Downloads the Formplayer assets artifact into `formulus/android/app/src/main/assets/formplayer_dist/` + - Builds the Android APK (debug for PRs, release for main/dev/release events) -3. **Fallback**: - - If assets don't exist, builds them automatically - - Ensures builds always succeed +Formplayer assets are **not committed to git** and are ignored via `.gitignore`. CI builds always use the assets artifact produced in the same workflow run, ensuring a single, consistent source of truth for each build. #### Build Types @@ -165,18 +111,17 @@ The workflow intelligently handles formplayer assets: #### Workflow Integration -The Formulus Android Build workflow integrates with Update Formplayer Assets: +Formplayer asset building and Android APK building are now handled within the same workflow: ``` -Formplayer Changes → Update Assets Workflow → Android Build (via workflow_run) -Formulus Changes → Android Build (direct, uses committed assets) +Formplayer or Formulus Changes → build-formplayer-assets job → build-android job (consumes artifact) → APK artifact / Release upload ``` This ensures: -- No duplicate builds -- Single source of truth for assets -- Efficient parallel execution -- Automatic asset synchronization +- No duplicate cross-workflow wiring +- A single workflow owns both asset and APK builds +- Each APK is built against the exact assets produced in the same run +- Formplayer build outputs do not pollute git history ## Using Published Images @@ -290,25 +235,19 @@ echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin ### How It Works -The automated asset synchronization process ensures formulus always has the latest formplayer assets: +The automated asset build process ensures Formulus Android builds always have matching Formplayer assets: 1. **Developer makes changes** to `formulus-formplayer` -2. **Opens/updates PR** → Update Formplayer Assets workflow validates build -3. **PR merged to main/dev** → Update Formplayer Assets workflow: - - Builds assets - - Commits them to repository - - Uploads artifact -4. **Android build triggered** → Formulus Android Build workflow: - - Downloads artifact (if formplayer changed) - - Or uses committed assets (if formulus-only change) - - Builds Android APK +2. **Opens/updates PR** (or pushes to `main`/`dev`) → the Formulus Android workflow: + - Runs the `build-formplayer-assets` job to build Formplayer assets and upload them as an artifact + - Runs the `build-android` job, which downloads the artifact and builds the APK ### Benefits -- **No manual work**: Assets are automatically built and committed -- **No conflicts**: Single automated process commits assets -- **Always up-to-date**: Formulus always has latest assets -- **Faster builds**: Android builds use committed assets (no build step) +- **No manual work**: Assets are automatically built and passed between jobs via artifacts +- **No conflicts**: Assets are not committed to git, avoiding noisy diffs and merge issues +- **Always consistent**: Each Android build uses the assets built in that same workflow run +- **Clean repository**: Built assets live only in CI artifacts and local workspaces, not in version control ### Local Development diff --git a/.github/workflows/formulus-android.yml b/.github/workflows/formulus-android.yml index d36c3ca2c..447a59c10 100644 --- a/.github/workflows/formulus-android.yml +++ b/.github/workflows/formulus-android.yml @@ -1,4 +1,4 @@ -name: Formulus Android Build +name: Formulus Android & Formplayer Assets on: push: @@ -7,61 +7,82 @@ on: - dev paths: - 'formulus/**' + - 'formulus-formplayer/**' + - 'packages/tokens/**' - '.github/workflows/formulus-android.yml' - #paths-ignore: - # - 'formulus/android/app/src/main/assets/formplayer_dist/**' pull_request: paths: - 'formulus/**' + - 'formulus-formplayer/**' + - 'packages/tokens/**' - '.github/workflows/formulus-android.yml' - workflow_run: - workflows: ["Update Formplayer Assets"] - types: - - completed - branches: - - main - - dev release: types: [published] +env: + NODE_VERSION_ASSETS: '20' + NODE_VERSION_ANDROID: '18.x' + jobs: + build-formplayer-assets: + name: Build Formplayer Assets + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js for assets + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION_ASSETS }} + cache: 'npm' + cache-dependency-path: | + formulus-formplayer/package-lock.json + packages/tokens/package-lock.json + + - name: Install and build @ode/tokens + working-directory: packages/tokens + run: | + npm install + npm run build + + - name: Install formplayer dependencies + working-directory: formulus-formplayer + run: npm ci + + - name: Build and bundle formplayer + working-directory: formulus-formplayer + run: npm run build:rn + + - name: Upload formplayer assets artifact + uses: actions/upload-artifact@v4 + with: + name: formplayer-assets + path: formulus/android/app/src/main/assets/formplayer_dist + retention-days: 7 + build-android: name: Build Formulus Android APK runs-on: ubuntu-latest + needs: build-formplayer-assets permissions: contents: write env: - NODE_VERSION: '18.x' + NODE_VERSION: ${{ env.NODE_VERSION_ANDROID }} steps: - name: Checkout repository uses: actions/checkout@v4 - with: - ref: ${{ github.event.workflow_run.head_branch || github.ref }} - - name: Download formplayer assets artifact (from update workflow) - id: download-assets - if: github.event_name == 'workflow_run' - uses: dawidd6/action-download-artifact@v3 + - name: Download formplayer assets artifact + uses: actions/download-artifact@v4 with: name: formplayer-assets path: formulus/android/app/src/main/assets/formplayer_dist - github_token: ${{ secrets.GITHUB_TOKEN }} - workflow: update-formplayer-assets.yml - run_id: ${{ github.event.workflow_run.id }} - allow_no_artifact: true - - - name: Check if assets exist - id: check-assets - run: | - if [ -d "formulus/android/app/src/main/assets/formplayer_dist" ] && [ -n "$(ls -A formulus/android/app/src/main/assets/formplayer_dist 2>/dev/null)" ]; then - echo "exists=true" >> $GITHUB_OUTPUT - echo "✅ Formplayer assets found (from artifact or repo)" - else - echo "exists=false" >> $GITHUB_OUTPUT - echo "⚠️ Formplayer assets not found, will build them" - fi - name: Set up Node.js uses: actions/setup-node@v4 @@ -86,16 +107,6 @@ jobs: npm install npm run build - - name: Install npm dependencies (formplayer) - if: steps.check-assets.outputs.exists != 'true' - working-directory: formulus-formplayer - run: npm ci - - - name: Build and bundle formplayer - if: steps.check-assets.outputs.exists != 'true' - working-directory: formulus-formplayer - run: npm run build:rn - - name: Set up Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/update-formplayer-assets.yml b/.github/workflows/update-formplayer-assets.yml deleted file mode 100644 index f57c19a7a..000000000 --- a/.github/workflows/update-formplayer-assets.yml +++ /dev/null @@ -1,135 +0,0 @@ -name: Build and Commit Formplayer Assets - -on: - push: - branches: - - main - - dev - paths: - - 'formulus-formplayer/**' - - '.github/workflows/update-formplayer-assets.yml' - pull_request: - paths: - - 'formulus-formplayer/**' - - '.github/workflows/update-formplayer-assets.yml' - -env: - NODE_VERSION: '20' - -jobs: - build-and-commit-assets: - name: Build and Auto-Commit Formplayer Assets - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - fetch-depth: 0 - # For PRs, checkout the PR branch (head) so we can commit to it - # PR branches are not protected, so we can push directly - # For pushes, checkout the branch that was pushed to - ref: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref }} - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - cache-dependency-path: | - formulus-formplayer/package-lock.json - packages/tokens/package-lock.json - - - name: Install and build @ode/tokens - working-directory: packages/tokens - run: | - npm install - npm run build - - - name: Install formplayer dependencies - working-directory: formulus-formplayer - run: npm ci - - - name: Build and bundle formplayer - working-directory: formulus-formplayer - run: npm run build:rn - - - name: Upload formplayer assets artifact - uses: actions/upload-artifact@v4 - with: - name: formplayer-assets - path: formulus/android/app/src/main/assets/formplayer_dist - retention-days: 1 - - - name: Check for asset changes (PR) - if: github.event_name == 'pull_request' - id: check-changes-pr - run: | - git add formulus/android/app/src/main/assets/formplayer_dist - if git diff --cached --quiet; then - echo "changed=false" >> $GITHUB_OUTPUT - echo "No changes to formplayer assets" - else - echo "changed=true" >> $GITHUB_OUTPUT - echo "Formplayer assets have changed" - fi - - - name: Commit assets to PR branch - if: steps.check-changes-pr.outputs.changed == 'true' && github.event_name == 'pull_request' - run: | - echo "✅ Committing assets to PR branch: ${{ github.head_ref }}" - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add formulus/android/app/src/main/assets/formplayer_dist - git commit -m "chore: update formplayer assets from formulus-formplayer [skip ci]" - git push - echo "✅ Assets committed to PR branch - will be included when PR is merged" - - - name: Validate assets built successfully (PR - no changes) - if: github.event_name == 'pull_request' && steps.check-changes-pr.outputs.changed == 'false' - run: | - if [ ! -d "formulus/android/app/src/main/assets/formplayer_dist" ] || [ -z "$(ls -A formulus/android/app/src/main/assets/formplayer_dist)" ]; then - echo "❌ Formplayer assets were not built successfully" - exit 1 - else - echo "✅ Formplayer assets built successfully (no changes needed)" - fi - - - name: Check for asset changes (Push) - if: github.event_name == 'push' - id: check-changes-push - run: | - git add formulus/android/app/src/main/assets/formplayer_dist - if git diff --cached --quiet; then - echo "changed=false" >> $GITHUB_OUTPUT - echo "No changes to formplayer assets" - else - echo "changed=true" >> $GITHUB_OUTPUT - echo "Formplayer assets have changed" - fi - - - name: Commit and push assets (non-protected branches only) - if: steps.check-changes-push.outputs.changed == 'true' && github.event_name == 'push' - run: | - CURRENT_BRANCH="${{ github.ref_name }}" - - # Skip committing to protected branches (main/dev) - they require PRs - if [[ "$CURRENT_BRANCH" == "main" ]] || [[ "$CURRENT_BRANCH" == "dev" ]]; then - echo "⚠️ Branch $CURRENT_BRANCH is protected and requires PRs" - echo "Assets have been built and uploaded as artifact" - echo "Note: For protected branches, assets should be committed via PR workflow" - echo "Artifact name: formplayer-assets" - exit 0 - fi - - # For non-protected branches, commit and push directly - echo "Committing assets to non-protected branch: $CURRENT_BRANCH" - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add formulus/android/app/src/main/assets/formplayer_dist - git commit -m "chore: update formplayer assets from formulus-formplayer [skip ci]" - git push diff --git a/.gitignore b/.gitignore index 87e1df89d..4b5119949 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ formulus/android/keystores/ *.jks *.keystore local.properties + +# Formplayer built assets +formulus/android/app/src/main/assets/formplayer_dist/ \ No newline at end of file