name: Build & publish embedded packages for releases

on:
  release:
    types: [published]
  pull_request:
    types:
      - synchronize
      - opened
      - labeled
  push:
    branches: [livekit]

jobs:
  versioning:
    name: Versioning
    runs-on: ubuntu-latest
    outputs:
      DRY_RUN: ${{ steps.dry_run.outputs.DRY_RUN }}
      PREFIXED_VERSION: ${{ steps.prefixed_version.outputs.PREFIXED_VERSION }}
      UNPREFIXED_VERSION: ${{ steps.unprefixed_version.outputs.UNPREFIXED_VERSION }}
      TAG: ${{ steps.tag.outputs.TAG }}
    steps:
      - name: Calculate VERSION
        # Safely store dynamic values in environment variables
        # to prevent shell injection (template-injection)
        run: |
          # The logic is executed within the shell using the env variables
          if [ "$EVENT_NAME" = "release" ]; then
            echo "VERSION=$RELEASE_TAG" >> "$GITHUB_ENV"
          else
            echo "VERSION=v0.0.0-pre.0" >> "$GITHUB_ENV"
          fi
        env:
          RELEASE_TAG: ${{ github.event.release.tag_name }}
          EVENT_NAME: ${{ github.event_name }}
      - id: dry_run
        name: Set DRY_RUN
        # We perform a dry run for all events except releases.
        # This is to help make sure that we notice if the packaging process has become
        # broken ahead of a release.
        run: echo "DRY_RUN=${{ github.event_name != 'release' }}" >> "$GITHUB_OUTPUT"
      - id: prefixed_version
        name: Set PREFIXED_VERSION
        run: echo "PREFIXED_VERSION=${VERSION}" >> "$GITHUB_OUTPUT"
      - id: unprefixed_version
        name: Set UNPREFIXED_VERSION
        # This just strips the leading character
        run: echo "UNPREFIXED_VERSION=${VERSION:1}" >> "$GITHUB_OUTPUT"
      - id: tag
        # latest = a proper release
        # other = anything else
        name: Set tag
        run: |
          if [[ "${VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "TAG=latest" >> "$GITHUB_OUTPUT"
          elif [[ "${VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+\-rc\.[0-9]+$ ]]; then
            echo "TAG=rc" >> "$GITHUB_OUTPUT"
          else
            echo "TAG=other" >> "$GITHUB_OUTPUT"
          fi

  build_element_call:
    needs: versioning
    uses: ./.github/workflows/build-element-call.yaml
    with:
      vite_app_version: embedded-${{ needs.versioning.outputs.PREFIXED_VERSION }}
      package: embedded
    secrets:
      SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
      SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
      SENTRY_URL: ${{ secrets.SENTRY_URL }}
      SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

  publish_tarball:
    needs: [build_element_call, versioning]
    if: always()
    name: Publish tarball
    runs-on: ubuntu-latest
    permissions:
      contents: write # required to upload release asset
    steps:
      - name: Determine filename
        run: echo "FILENAME_PREFIX=element-call-embedded-${NEEDS_VERSIONING_OUTPUTS_UNPREFIXED_VERSION}" >> "$GITHUB_ENV"
        env:
          NEEDS_VERSIONING_OUTPUTS_UNPREFIXED_VERSION: ${{ needs.versioning.outputs.UNPREFIXED_VERSION }}
      - name: 📥 Download built element-call artifact
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          run-id: ${{ github.event.workflow_run.id || github.run_id }}
          name: build-output-embedded
          path: ${{ env.FILENAME_PREFIX}}
      - name: Create Tarball
        run: tar --numeric-owner -cvzf ${FILENAME_PREFIX}.tar.gz ${FILENAME_PREFIX}
      - name: Create Checksum
        run: find ${FILENAME_PREFIX} -type f -print0 | sort -z | xargs -0 sha256sum | tee ${FILENAME_PREFIX}.sha256
      - name: Upload
        if: ${{ needs.versioning.outputs.DRY_RUN == 'false' }}
        uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
        with:
          files: |
            ${{ env.FILENAME_PREFIX }}.tar.gz
            ${{ env.FILENAME_PREFIX }}.sha256

  publish_npm:
    needs: [build_element_call, versioning]
    if: always()
    name: Publish NPM
    runs-on: ubuntu-latest
    outputs:
      ARTIFACT_VERSION: ${{ steps.artifact_version.outputs.ARTIFACT_VERSION }}
    permissions:
      contents: read
      id-token: write # Allow npm to authenticate as a trusted publisher
    steps:
      - name: Checkout
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          persist-credentials: false

      - name: 📥 Download built element-call artifact
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          run-id: ${{ github.event.workflow_run.id || github.run_id }}
          name: build-output-embedded
          path: embedded/web/dist

      # n.b. We don't enable corepack here because we are using plain npm
      - name: Setup node
        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
        with:
          node-version-file: .node-version
          registry-url: "https://registry.npmjs.org"

      - name: Publish npm
        working-directory: embedded/web
        run: |
          npm version ${NEEDS_VERSIONING_OUTPUTS_PREFIXED_VERSION} --no-git-tag-version
          echo "ARTIFACT_VERSION=$(jq '.version' --raw-output package.json)" >> "$GITHUB_ENV"
          npm publish --provenance --access public --tag ${NEEDS_VERSIONING_OUTPUTS_TAG} ${{ needs.versioning.outputs.DRY_RUN == 'true' && '--dry-run' || '' }}
        env:
          NEEDS_VERSIONING_OUTPUTS_PREFIXED_VERSION: ${{ needs.versioning.outputs.PREFIXED_VERSION }}
          NEEDS_VERSIONING_OUTPUTS_TAG: ${{ needs.versioning.outputs.TAG }}

      - id: artifact_version
        name: Output artifact version
        run: echo "ARTIFACT_VERSION=${ARTIFACT_VERSION}" >> "$GITHUB_OUTPUT"

  publish_android:
    needs: [build_element_call, versioning]
    if: always()
    name: Publish Android AAR
    runs-on: ubuntu-latest
    outputs:
      ARTIFACT_VERSION: ${{ steps.artifact_version.outputs.ARTIFACT_VERSION }}
    permissions:
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          persist-credentials: false

      - name: 📥 Download built element-call artifact
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          run-id: ${{ github.event.workflow_run.id || github.run_id }}
          name: build-output-embedded
          path: embedded/android/lib/src/main/assets/element-call

      - name: ☕️ Setup Java
        uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
        with:
          distribution: "temurin"
          java-version: "17"

      - name: Get artifact version
        # Anything that is not a final release will be tagged as a snapshot
        run: |
          if [[ "${NEEDS_VERSIONING_OUTPUTS_TAG}" == "latest" ]]; then
            echo "ARTIFACT_VERSION=${NEEDS_VERSIONING_OUTPUTS_UNPREFIXED_VERSION}" >> "$GITHUB_ENV"
          elif [[ "${NEEDS_VERSIONING_OUTPUTS_TAG}" == "rc" ]]; then
            echo "ARTIFACT_VERSION=${NEEDS_VERSIONING_OUTPUTS_UNPREFIXED_VERSION}" >> "$GITHUB_ENV"
          else
            echo "ARTIFACT_VERSION=${NEEDS_VERSIONING_OUTPUTS_UNPREFIXED_VERSION}-SNAPSHOT" >> "$GITHUB_ENV"
          fi
        env:
          NEEDS_VERSIONING_OUTPUTS_TAG: ${{ needs.versioning.outputs.TAG }}
          NEEDS_VERSIONING_OUTPUTS_UNPREFIXED_VERSION: ${{ needs.versioning.outputs.UNPREFIXED_VERSION }}

      - name: Set version string
        run: sed -i "s/0.0.0/${ARTIFACT_VERSION}/g" embedded/android/lib/src/main/kotlin/io/element/android/call/embedded/Version.kt

      - name: Publish AAR
        working-directory: embedded/android
        env:
          EC_VERSION: ${{ env.ARTIFACT_VERSION }}
          ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_RELEASE_USERNAME }}
          ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_RELEASE_PASSWORD }}
          ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SIGNING_KEY }}
          ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SIGNING_KEY_PASSWORD }}
        run: ./gradlew publishToMavenCentral --no-daemon ${{ needs.versioning.outputs.DRY_RUN == 'true' && '--dry-run' || '' }}

      - id: artifact_version
        name: Output artifact version
        run: echo "ARTIFACT_VERSION=${ARTIFACT_VERSION}" >> "$GITHUB_OUTPUT"

  publish_ios:
    needs: [build_element_call, versioning]
    if: always()
    name: Publish SwiftPM Library
    runs-on: ubuntu-latest
    outputs:
      ARTIFACT_VERSION: ${{ steps.artifact_version.outputs.ARTIFACT_VERSION }}
    permissions:
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          path: element-call
          persist-credentials: false

      - name: 📥 Download built element-call artifact
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          run-id: ${{ github.event.workflow_run.id || github.run_id }}
          name: build-output-embedded
          path: element-call/embedded/ios/Sources/dist

      - name: Checkout element-call-swift
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          repository: element-hq/element-call-swift
          path: element-call-swift
          persist-credentials: false

      - name: Copy files
        run: rsync -a --delete --exclude .git element-call/embedded/ios/ element-call-swift

      - name: Get artifact version
        run: echo "ARTIFACT_VERSION=${NEEDS_VERSIONING_OUTPUTS_UNPREFIXED_VERSION}" >> "$GITHUB_ENV"
        env:
          NEEDS_VERSIONING_OUTPUTS_UNPREFIXED_VERSION: ${{ needs.versioning.outputs.UNPREFIXED_VERSION }}

      - name: Set version string
        run: sed -i "s/0.0.0/${ARTIFACT_VERSION}/g" element-call-swift/Sources/EmbeddedElementCall/EmbeddedElementCall.swift

      - name: Test build
        working-directory: element-call-swift
        run: swift build

      - name: Commit and tag
        working-directory: element-call-swift
        run: |
          git config --global user.email "ci@element.io"
          git config --global user.name "Element CI"
          git add -A
          git commit -am "Release ${NEEDS_VERSIONING_OUTPUTS_PREFIXED_VERSION}"
          git tag -a ${ARTIFACT_VERSION} -m "${GITHUB_EVENT_RELEASE_HTML_URL}"
        env:
          NEEDS_VERSIONING_OUTPUTS_PREFIXED_VERSION: ${{ needs.versioning.outputs.PREFIXED_VERSION }}
          GITHUB_EVENT_RELEASE_HTML_URL: ${{ github.event.release.html_url }}

      - name: Push
        if: ${{ needs.versioning.outputs.DRY_RUN == 'false' }}
        working-directory: element-call-swift
        run: |
          git push "https://x-access-token:${SWIFT_RELEASE_TOKEN}@github.com/element-hq/element-call-swift.git" --tags
        env:
          SWIFT_RELEASE_TOKEN: ${{ secrets.SWIFT_RELEASE_TOKEN }}

      - id: artifact_version
        name: Output artifact version
        run: echo "ARTIFACT_VERSION=${ARTIFACT_VERSION}" >> "$GITHUB_OUTPUT"

  release_notes:
    needs: [versioning, publish_npm, publish_android, publish_ios]
    if: always()
    name: Update release notes
    runs-on: ubuntu-latest
    permissions:
      contents: write # to update release notes
    steps:
      - name: Log versions
        run: |
          echo "NPM: ${NEEDS_PUBLISH_NPM_OUTPUTS_ARTIFACT_VERSION}"
          echo "Android: ${NEEDS_PUBLISH_ANDROID_OUTPUTS_ARTIFACT_VERSION}"
          echo "iOS: ${NEEDS_PUBLISH_IOS_OUTPUTS_ARTIFACT_VERSION}"
        env:
          NEEDS_PUBLISH_NPM_OUTPUTS_ARTIFACT_VERSION: ${{ needs.publish_npm.outputs.ARTIFACT_VERSION }}
          NEEDS_PUBLISH_ANDROID_OUTPUTS_ARTIFACT_VERSION: ${{ needs.publish_android.outputs.ARTIFACT_VERSION }}
          NEEDS_PUBLISH_IOS_OUTPUTS_ARTIFACT_VERSION: ${{ needs.publish_ios.outputs.ARTIFACT_VERSION }}
      - name: Add release notes
        if: ${{ needs.versioning.outputs.DRY_RUN == 'false' }}
        uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
        with:
          append_body: true
          body: |

            ## Embedded packages

            This release includes the following embedded packages that allow Element Call to be used as an embedded widget
            within another application.

            ### NPM

            ```
            npm install @element-hq/element-call-embedded@${{ needs.publish_npm.outputs.ARTIFACT_VERSION }}
            ```

            ### Android AAR

            ```
            dependencies {
              implementation 'io.element.android:element-call-embedded:${{ needs.publish_android.outputs.ARTIFACT_VERSION }}'
            }
            ```

            ### SwiftPM

            ```
            .package(url: "https://github.com/element-hq/element-call-swift.git", from: "${{ needs.publish_ios.outputs.ARTIFACT_VERSION }}")
            ```
