cicd tag #131
Workflow file for this run
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: | |
| tags: | |
| - 'v*' | |
| permissions: | |
| contents: write | |
| jobs: | |
| # ============================================ | |
| # CI Jobs - Run on tag push | |
| # ============================================ | |
| 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 | |
| env: | |
| GIT_TAG: ${{ github.ref_name }} | |
| - name: Build packages | |
| run: pnpm build:packages | |
| - name: Typecheck | |
| run: pnpm typecheck | |
| build-apk: | |
| runs-on: ubuntu-latest | |
| needs: [lint-and-typecheck] | |
| if: needs.lint-and-typecheck.result == 'success' | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.ref }} | |
| - 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 }} | |
| GIT_TAG: ${{ github.ref_name }} | |
| - 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: 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 - Run on tag push | |
| # ============================================ | |
| deploy-landing: | |
| runs-on: ubuntu-latest | |
| needs: [lint-and-typecheck] | |
| if: needs.lint-and-typecheck.result == 'success' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.ref }} | |
| - name: Extract version from STATE.md | |
| id: version | |
| run: | | |
| VERSION=$(node scripts/extract-version.cjs) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| env: | |
| GIT_TAG: ${{ github.ref_name }} | |
| - 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/[email protected] | |
| 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/[email protected] | |
| with: | |
| host: ${{ secrets.DO_HOST }} | |
| username: ${{ secrets.DO_USERNAME }} | |
| key: ${{ secrets.DO_SSH_KEY }} | |
| script: sudo systemctl reload nginx | |
| deploy-deck-builder: | |
| runs-on: ubuntu-latest | |
| needs: [lint-and-typecheck] | |
| if: needs.lint-and-typecheck.result == 'success' | |
| 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 | |
| id: version | |
| run: | | |
| VERSION=$(node scripts/extract-version.cjs) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| env: | |
| GIT_TAG: ${{ github.ref_name }} | |
| - name: Build packages | |
| run: pnpm build:packages | |
| - name: Run deck-builder tests | |
| run: pnpm --filter @lumio/deck-builder test | |
| - name: Build deck-builder | |
| run: pnpm --filter @lumio/deck-builder build | |
| env: | |
| VITE_SUPABASE_URL: ${{ secrets.SUPABASE_URL }} | |
| VITE_SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }} | |
| - name: Inject version into index.html | |
| 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/deck-builder/dist/index.html | |
| - name: Deploy to DigitalOcean | |
| uses: appleboy/[email protected] | |
| with: | |
| host: ${{ secrets.DO_HOST }} | |
| username: ${{ secrets.DO_USERNAME }} | |
| key: ${{ secrets.DO_SSH_KEY }} | |
| source: 'apps/deck-builder/dist/*' | |
| target: '/var/www/deck-lumio' | |
| strip_components: 3 | |
| - name: Reload Nginx | |
| uses: appleboy/[email protected] | |
| 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: needs.lint-and-typecheck.result == 'success' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.ref }} | |
| - 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: [lint-and-typecheck] | |
| if: needs.lint-and-typecheck.result == 'success' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.ref }} | |
| - 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}" | |
| env: | |
| GIT_TAG: ${{ github.ref_name }} | |
| - 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 }} | |
| supabase functions deploy deck-commit --no-verify-jwt --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 }} |