Update README.md #112
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/CD | |
| on: | |
| push: | |
| branches: [main, develop] | |
| pull_request: | |
| branches: [main, develop] | |
| permissions: | |
| contents: write | |
| jobs: | |
| # ============================================ | |
| # CI Jobs - Run on all pushes and PRs | |
| # ============================================ | |
| lint-and-typecheck: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.ref }} | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Extract version from STATE.md | |
| run: node scripts/extract-version.cjs | |
| - name: Build packages | |
| run: pnpm build:packages | |
| - name: Typecheck | |
| run: pnpm typecheck | |
| build-apk: | |
| runs-on: ubuntu-latest | |
| needs: [lint-and-typecheck] | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint-and-typecheck.result == 'success' | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| - name: Cache Gradle | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| key: gradle-${{ hashFiles('apps/android/android/gradle/wrapper/gradle-wrapper.properties') }} | |
| restore-keys: gradle- | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Extract version from STATE.md | |
| id: version | |
| run: | | |
| VERSION=$(node scripts/extract-version.cjs) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "build_number=${{ github.run_number }}" >> $GITHUB_OUTPUT | |
| echo "git_sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT | |
| env: | |
| BUILD_NUMBER: ${{ github.run_number }} | |
| GIT_SHA: ${{ github.sha }} | |
| - name: Build packages | |
| run: pnpm build:packages | |
| - name: Expo prebuild | |
| working-directory: apps/android | |
| run: npx expo prebuild --platform android --clean | |
| env: | |
| EXPO_PUBLIC_SUPABASE_URL: ${{ secrets.SUPABASE_URL }} | |
| EXPO_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }} | |
| EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID: ${{ secrets.GOOGLE_WEB_CLIENT_ID }} | |
| - name: Decode keystore | |
| run: echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > apps/android/android/app/release.keystore | |
| - name: Build release APK | |
| working-directory: apps/android/android | |
| run: ./gradlew app:assembleRelease -PversionCode=${{ github.run_number }} -PversionName=${{ steps.version.outputs.version }} | |
| env: | |
| ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| EXPO_PUBLIC_SUPABASE_URL: ${{ secrets.SUPABASE_URL }} | |
| EXPO_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }} | |
| EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID: ${{ secrets.GOOGLE_WEB_CLIENT_ID }} | |
| - name: Rename APK | |
| run: cp apps/android/android/app/build/outputs/apk/release/app-release.apk lumio.apk | |
| - name: Rename APK with version | |
| run: mv lumio.apk "lumio-v${{ steps.version.outputs.version }}+${{ github.run_number }}.${GITHUB_SHA::7}.apk" | |
| - name: Upload APK artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: lumio-apk-v${{ steps.version.outputs.version }}-build${{ github.run_number }} | |
| path: lumio-v*.apk | |
| retention-days: 30 | |
| create-release: | |
| runs-on: ubuntu-latest | |
| needs: [build-apk] | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.build-apk.result == 'success' | |
| steps: | |
| - name: Download APK artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: lumio-apk-v${{ needs.build-apk.outputs.version }}-build${{ github.run_number }} | |
| - name: Prepare short SHA | |
| id: sha | |
| run: echo "short=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT | |
| - name: Rename APK to lumio.apk | |
| run: mv lumio-v*.apk lumio.apk | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ needs.build-apk.outputs.version }} | |
| name: v${{ needs.build-apk.outputs.version }} | |
| body: "Lumio v${{ needs.build-apk.outputs.version }} - Build #${{ github.run_number }} (${{ steps.sha.outputs.short }})" | |
| files: lumio.apk | |
| make_latest: true | |
| draft: false | |
| prerelease: false | |
| # ============================================ | |
| # Deploy Jobs - Only on push to main | |
| # ============================================ | |
| deploy-landing: | |
| runs-on: ubuntu-latest | |
| needs: [lint-and-typecheck] | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint-and-typecheck.result == 'success' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| - name: Extract version from STATE.md | |
| id: version | |
| run: | | |
| VERSION=$(node scripts/extract-version.cjs) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Inject version into landing page | |
| run: | | |
| SHORT_SHA=${GITHUB_SHA::7} | |
| DISPLAY_VERSION="${{ steps.version.outputs.version }}+${{ github.run_number }}.${SHORT_SHA}" | |
| sed -i "s/__LUMIO_VERSION__/${DISPLAY_VERSION}/g" apps/landing/index.html | |
| - name: Deploy to DigitalOcean | |
| uses: appleboy/scp-action@v0.1.7 | |
| with: | |
| host: ${{ secrets.DO_HOST }} | |
| username: ${{ secrets.DO_USERNAME }} | |
| key: ${{ secrets.DO_SSH_KEY }} | |
| source: 'apps/landing/*' | |
| target: '/var/www/lumio' | |
| strip_components: 2 | |
| - name: Reload Nginx | |
| uses: appleboy/ssh-action@v1.0.3 | |
| with: | |
| host: ${{ secrets.DO_HOST }} | |
| username: ${{ secrets.DO_USERNAME }} | |
| key: ${{ secrets.DO_SSH_KEY }} | |
| script: sudo systemctl reload nginx | |
| deploy-migrations: | |
| runs-on: ubuntu-latest | |
| needs: [lint-and-typecheck] | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint-and-typecheck.result == 'success' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| - uses: supabase/setup-cli@v1 | |
| with: | |
| version: latest | |
| - name: Link Supabase project | |
| run: supabase link --project-ref ${{ secrets.SUPABASE_PROJECT_REF }} | |
| env: | |
| SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} | |
| - name: Backup database | |
| if: ${{ vars.ENABLE_DB_BACKUP == 'true' }} | |
| run: | | |
| TIMESTAMP=$(date +%Y%m%d_%H%M%S) | |
| supabase db dump --data-only -f "db_backup_${TIMESTAMP}.sql" | |
| echo "Backup created: db_backup_${TIMESTAMP}.sql" | |
| env: | |
| SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} | |
| SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }} | |
| - name: Upload backup artifact | |
| if: ${{ vars.ENABLE_DB_BACKUP == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: db-backup-${{ github.run_number }} | |
| path: db_backup_*.sql | |
| retention-days: 30 | |
| - name: Run database migrations | |
| run: supabase db push | |
| env: | |
| SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} | |
| deploy-functions: | |
| runs-on: ubuntu-latest | |
| needs: [deploy-migrations] | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.deploy-migrations.result == 'success' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| - name: Extract version from STATE.md | |
| id: version | |
| run: | | |
| VERSION=$(node scripts/extract-version.cjs) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "build_number=${{ github.run_number }}" >> $GITHUB_OUTPUT | |
| echo "git_sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT | |
| echo "build_date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_OUTPUT | |
| echo "Deploying Edge Functions - Version: $VERSION, Build: ${{ github.run_number }}, SHA: ${GITHUB_SHA::7}" | |
| - uses: supabase/setup-cli@v1 | |
| with: | |
| version: latest | |
| - name: Deploy Edge Functions | |
| run: | | |
| supabase functions deploy git-sync --no-verify-jwt --project-ref ${{ secrets.SUPABASE_PROJECT_REF }} | |
| supabase functions deploy docora-webhook --no-verify-jwt --project-ref ${{ secrets.SUPABASE_PROJECT_REF }} | |
| supabase functions deploy llm-proxy --no-verify-jwt --project-ref ${{ secrets.SUPABASE_PROJECT_REF }} | |
| supabase functions deploy question-generator --no-verify-jwt --project-ref ${{ secrets.SUPABASE_PROJECT_REF }} | |
| supabase functions deploy study-planner --project-ref ${{ secrets.SUPABASE_PROJECT_REF }} | |
| supabase functions deploy version --project-ref ${{ secrets.SUPABASE_PROJECT_REF }} | |
| env: | |
| SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} | |
| LUMIO_VERSION: ${{ steps.version.outputs.version }} | |
| BUILD_NUMBER: ${{ steps.version.outputs.build_number }} | |
| GIT_SHA: ${{ steps.version.outputs.git_sha }} | |
| BUILD_DATE: ${{ steps.version.outputs.build_date }} |