name: Continuous Delivery

on:
  push:
    branches:
      - main
  pull_request:
  release:
    types:
      - published

jobs:
  # The "Docker" job builds the Docker image and pushes it to the GitHub Container Registry. The job only runs when a
  # commit is pushed to the main branch or a new tag is created.
  docker:
    name: Docker
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' || (github.event_name == 'release' && github.event.action == 'published')
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set Docker Tag
        id: tag
        run: |
          if [[ $GITHUB_REF == refs/tags/* ]]; then
            echo TAG=${GITHUB_REF:10} >> $GITHUB_ENV
          else
            echo TAG=main >> $GITHUB_ENV
          fi

      - name: Setup QEMU
        uses: docker/setup-qemu-action@v3

      - name: Setup Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}
          registry: ghcr.io

      - name: Build and Push Docker Image
        id: docker_build
        uses: docker/build-push-action@v5
        with:
          push: true
          context: ./supabase/functions
          file: ./supabase/functions/_cmd/Dockerfile
          platforms: linux/amd64,linux/arm64/v8
          tags: ghcr.io/${{ github.repository_owner }}/feeddeck:${{ env.TAG }}

  # The "Supabase" job runs the database migrations and deploys all Supabase functions. The job only runs when a commit
  # is pushed to the main branch or a new tag is created.
  supabase:
    name: Supabase
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' || (github.event_name == 'release' && github.event.action == 'published')
    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Supabase
        uses: supabase/setup-cli@v1

      - name: Push Database Migration and Deploy Functions
        if: github.ref == 'refs/heads/main'
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
          SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_STAGE_DB_PASSWORD }}
          PROJECT_ID: ${{ secrets.SUPABASE_STAGE_PROJECT_ID }}
        run: |
          supabase link --project-ref $PROJECT_ID

          supabase db push

          supabase functions deploy add-source-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy delete-user-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy generate-magic-link-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy image-proxy-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy profile-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy profile-v2 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy revenuecat-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy stripe-create-billing-portal-link-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy stripe-create-checkout-session-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy stripe-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json

      - name: Push Database Migration and Deploy Functions
        if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
          SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_PROD_DB_PASSWORD }}
          PROJECT_ID: ${{ secrets.SUPABASE_PROD_PROJECT_ID }}
        run: |
          supabase link --project-ref $PROJECT_ID

          supabase db push

          supabase functions deploy add-source-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy delete-user-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy generate-magic-link-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy image-proxy-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy profile-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy profile-v2 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy revenuecat-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy stripe-create-billing-portal-link-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy stripe-create-checkout-session-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
          supabase functions deploy stripe-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json

  # The "Web" job builds the Flutter web app and publishes it to Cloudflare Pages. The job only runs when a commit is
  # pushed to the main branch or a new tag is created.
  web:
    name: Web
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' || (github.event_name == 'release' && github.event.action == 'published')
    permissions:
      contents: read
    defaults:
      run:
        working-directory: "app"

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Packages
        run: |
          # Required for Flutter
          sudo apt-get update -y
          sudo apt-get install -y ninja-build libgtk-3-dev

      - name: Set Environment Variables
        id: tag
        run: |
          if [[ $GITHUB_REF == refs/tags/* ]]; then
            echo CLOUDFLARE_PROJECT_NAME=${{ secrets.CLOUDFLARE_PROJECT_NAME_PROD }} >> $GITHUB_ENV

            echo SUPABASE_URL=${{ secrets.SUPABASE_PROD_URL }} >> $GITHUB_ENV
            echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_PROD_ANON_KEY }} >> $GITHUB_ENV
            echo SUPABASE_SITE_URL=${{ secrets.SUPABASE_PROD_SITE_URL }} >> $GITHUB_ENV
            echo GOOGLE_CLIENT_ID=${{ secrets.SUPABASE_PROD_GOOGLE_CLIENT_ID }} >> $GITHUB_ENV
          else
            echo CLOUDFLARE_PROJECT_NAME=${{ secrets.CLOUDFLARE_PROJECT_NAME_STAGE }} >> $GITHUB_ENV

            echo SUPABASE_URL=${{ secrets.SUPABASE_STAGE_URL }} >> $GITHUB_ENV
            echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_STAGE_ANON_KEY }} >> $GITHUB_ENV
            echo SUPABASE_SITE_URL=${{ secrets.SUPABASE_STAGE_SITE_URL }} >> $GITHUB_ENV
            echo GOOGLE_CLIENT_ID=${{ secrets.SUPABASE_STAGE_GOOGLE_CLIENT_ID }} >> $GITHUB_ENV
          fi

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.13.7'
          channel: 'stable'
          cache: true
          cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
          cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'

      - name: Install Dependencies
        run: |
          flutter pub get

      - name: Build
        run: |
          flutter config --enable-web
          flutter build web --release --dart-define SUPABASE_URL=${{ env.SUPABASE_URL }} --dart-define SUPABASE_ANON_KEY=${{ env.SUPABASE_ANON_KEY }} --dart-define SUPABASE_SITE_URL=${{ env.SUPABASE_SITE_URL }} --dart-define GOOGLE_CLIENT_ID=${{ env.GOOGLE_CLIENT_ID }}

      - name: Publish to Cloudflare Pages
        uses: cloudflare/pages-action@v1
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          projectName: ${{ env.CLOUDFLARE_PROJECT_NAME }}
          directory: ./app/build/web
          branch: main

  # The "macOS" job builds the Flutter macOS app and uploads it to the GitHub release or the pull request. The job only
  # runs for pull requests and when a new release is published.
  macos:
    name: macOS
    runs-on: macos-latest
    if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')
    permissions:
      contents: write
    defaults:
      run:
        working-directory: "app"

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.13.7'
          channel: 'stable'
          cache: true
          cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
          cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'

      - name: Install Dependencies
        run: |
          flutter pub get

      - name: Build
        run: |
          flutter config --enable-macos-desktop
          FLUTTER_XCODE_CODE_SIGN_IDENTITY="" FLUTTER_XCODE_CODE_SIGNING_REQUIRED=NO flutter build macos --release --dart-define SUPABASE_URL=${{ secrets.SUPABASE_PROD_URL }} --dart-define SUPABASE_ANON_KEY=${{ secrets.SUPABASE_PROD_ANON_KEY }} --dart-define SUPABASE_SITE_URL=${{ secrets.SUPABASE_PROD_SITE_URL }} --dart-define GOOGLE_CLIENT_ID=${{ secrets.SUPABASE_PROD_GOOGLE_CLIENT_ID }}

      - name: Package
        run: |
          ditto -c -k --keepParent "build/macos/Build/Products/Release/FeedDeck.app" "build/macos/Build/Products/Release/feeddeck-macos-universal.zip"

      - name: Upload Artifacts (PR)
        if: ${{ github.event_name == 'pull_request' }}
        uses: actions/upload-artifact@v3
        with:
          name: feeddeck-macos-universal.zip
          path: app/build/macos/Build/Products/Release/feeddeck-macos-universal.zip
          if-no-files-found: error

      - name: Upload Artifacts (Release)
        uses: shogo82148/actions-upload-release-asset@v1
        if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
        with:
          upload_url: ${{ github.event.release.upload_url }}
          asset_path: app/build/macos/Build/Products/Release/feeddeck-macos-universal.zip

  # The "Linux" job builds the Flutter Linux app and uploads it to the GitHub release or the pull request. The job only
  # runs for pull requests and when a new release is published.
  linux:
    name: Linux
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')
    permissions:
      contents: write
    defaults:
      run:
        working-directory: "app"

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install Packages
        run: |
          # Required for Flutter
          sudo apt-get update -y
          sudo apt-get install -y ninja-build libgtk-3-dev

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.13.7'
          channel: 'stable'
          cache: true
          cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
          cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'

      - name: Install Dependencies
        run: |
          flutter pub get

      - name: Build
        run: |
          flutter config --enable-linux-desktop
          flutter build linux --release --dart-define SUPABASE_URL=${{ secrets.SUPABASE_PROD_URL }} --dart-define SUPABASE_ANON_KEY=${{ secrets.SUPABASE_PROD_ANON_KEY }} --dart-define SUPABASE_SITE_URL=${{ secrets.SUPABASE_PROD_SITE_URL }} --dart-define GOOGLE_CLIENT_ID=${{ secrets.SUPABASE_PROD_GOOGLE_CLIENT_ID }}

      - name: Package
        run: |
          cp linux/flatpak/app.feeddeck.feeddeck.desktop build/linux/x64/release/bundle/
          cp linux/flatpak/app.feeddeck.feeddeck.metainfo.xml build/linux/x64/release/bundle/
          cp linux/flatpak/app.feeddeck.feeddeck.svg build/linux/x64/release/bundle/
          cd build
          cp -r linux/x64/release/bundle/ feeddeck-linux-x86_64
          tar -czf feeddeck-linux-x86_64.tar.gz feeddeck-linux-x86_64

      - name: Upload Artifacts (PR)
        if: ${{ github.event_name == 'pull_request' }}
        uses: actions/upload-artifact@v3
        with:
          name: feeddeck-linux-x86_64.tar.gz
          path: app/build/feeddeck-linux-x86_64.tar.gz
          if-no-files-found: error

      - name: Upload Artifacts (Release)
        uses: shogo82148/actions-upload-release-asset@v1
        if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
        with:
          upload_url: ${{ github.event.release.upload_url }}
          asset_path: app/build/feeddeck-linux-x86_64.tar.gz

  # The "Windows" job builds the Flutter Windows app and uploads it to the GitHub release or the pull request. The job
  # only runs for pull requests and when a new release is published.
  windows:
    name: Windows
    runs-on: windows-latest
    if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')
    permissions:
      contents: write
    defaults:
      run:
        working-directory: "app"

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.13.7'
          channel: 'stable'
          cache: true
          cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
          cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'

      - name: Install Dependencies
        run: |
          flutter pub get

      - name: Build
        run: |
          flutter config --enable-windows-desktop
          flutter build windows --release --dart-define SUPABASE_URL=${{ secrets.SUPABASE_PROD_URL }} --dart-define SUPABASE_ANON_KEY=${{ secrets.SUPABASE_PROD_ANON_KEY }} --dart-define SUPABASE_SITE_URL=${{ secrets.SUPABASE_PROD_SITE_URL }} --dart-define GOOGLE_CLIENT_ID=${{ secrets.SUPABASE_PROD_GOOGLE_CLIENT_ID }}

      - name: Package
        run: |
          flutter pub run msix:create --output-path build --output-name feeddeck
          cd build
          7z a -tzip feeddeck-windows-x86_64.zip feeddeck.msix

      - name: Upload Artifacts (PR)
        if: ${{ github.event_name == 'pull_request' }}
        uses: actions/upload-artifact@v3
        with:
          name: feeddeck-windows-x86_64.zip
          path: app/build/feeddeck-windows-x86_64.zip
          if-no-files-found: error

      - name: Upload Artifacts (Release)
        uses: shogo82148/actions-upload-release-asset@v1
        if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
        with:
          upload_url: ${{ github.event.release.upload_url }}
          asset_path: app/build/feeddeck-windows-x86_64.zip
