name: Autofill Feature Critical Path End-to-End tests

on:
  schedule:
    - cron: '30 6 * * *' # run at 6.30 AM UTC
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  instrumentation_tests:
    runs-on: ubuntu-latest
    name: Autofill Critical Path End-to-End Tests

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Create folder
        if: always()
        run: mkdir apk

      - name: Decode keys
        uses: davidSchuppa/base64Secret-toFile-action@v2
        with:
          secret: ${{ secrets.FAKE_RELEASE_PROPERTIES }}
          fileName: ddg_android_build.properties
          destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/

      - name: Decode key file
        uses: davidSchuppa/base64Secret-toFile-action@v2
        with:
          secret: ${{ secrets.FAKE_RELEASE_KEY }}
          fileName: android
          destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/

      - name: Assemble APK which does not require auth to use Autofill
        uses: gradle/gradle-build-action@v2
        with:
          arguments: assemblePlayRelease -Pautofill-disable-auth-requirement -Pforce-default-variant -x lint

      - name: Move APK to new folder
        if: always()
        run: find . -name "*.apk"  -exec mv '{}' apk/release.apk \;

      - name: Autofill Critical Path E2E Flows
        uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
        with:
          api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
          name: ${{ github.sha }}
          app-file: apk/release.apk
          android-api-level: 30
          workspace: .maestro
          include-tags: autofillNoAuthTests

      - name: Create Asana task when workflow failed
        if: ${{ failure() }}
        id: create-failure-task
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          asana-pat: ${{ secrets.GH_ASANA_SECRET }}
          asana-project: ${{ vars.GH_ANDROID_APP_PROJECT_ID }}
          asana-section: ${{ vars.GH_ANDROID_APP_INCOMING_SECTION_ID }}
          asana-task-name: GH Workflow Failure - Autofill Critical Path E2E Flows
          asana-task-description: Autofill critical path tests have failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}
          action: 'create-asana-task'


End-to-End tests

name: End-to-End tests

on:
  schedule:
    - cron: '0 4 * * *' # run at 4 AM UTC
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  instrumentation_tests:
    runs-on: ubuntu-latest
    name: End-to-End tests

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Create folder
        if: always()
        run: mkdir apk

      - name: Decode keys
        uses: davidSchuppa/base64Secret-toFile-action@v2
        with:
          secret: ${{ secrets.FAKE_RELEASE_PROPERTIES }}
          fileName: ddg_android_build.properties
          destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/

      - name: Decode key file
        uses: davidSchuppa/base64Secret-toFile-action@v2
        with:
          secret: ${{ secrets.FAKE_RELEASE_KEY }}
          fileName: android
          destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/

      - name: Assemble release APK
        uses: gradle/gradle-build-action@v2
        with:
          arguments: assemblePlayRelease -Pforce-default-variant

      - name: Move APK to new folder
        if: always()
        run: find . -name "*.apk"  -exec mv '{}' apk/release.apk \;

      - name: Ad click detection flows
        uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
        with:
          api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
          name: ${{ github.sha }}
          app-file: apk/release.apk
          android-api-level: 30
          workspace: .maestro
          include-tags: adClickTest

      - name: Privacy Tests
        if: always()
        uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
        with:
          api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
          name: ${{ github.sha }}
          app-file: apk/release.apk
          android-api-level: 30
          workspace: .maestro
          include-tags: privacyTest

      - name: Security Tests
        if: always()
        uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
        with:
          api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
          name: ${{ github.sha }}
          app-file: apk/release.apk
          android-api-level: 30
          workspace: .maestro
          include-tags: securityTest

      - name: Release Tests
        if: always()
        uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
        with:
          api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
          name: ${{ github.sha }}
          app-file: apk/release.apk
          android-api-level: 30
          workspace: .maestro
          include-tags: releaseTest

      - name: Notifications permissions Android 13+
        if: always()
        uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
        with:
          api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
          name: ${{ github.sha }}
          app-file: apk/release.apk
          android-api-level: 33
          workspace: .maestro/notifications_permissions_android13_plus

      - name: Create Asana task when workflow failed
        if: ${{ failure() }}
        uses: honeycombio/gha-create-asana-task@main
        with:
          asana-secret: ${{ secrets.GH_ASANA_SECRET }}
          asana-workspace-id: ${{ secrets.GH_ASANA_WORKSPACE_ID }}
          asana-project-id: ${{ secrets.GH_ASANA_AOR_PROJECT_ID }}
          asana-section-id: ${{ secrets.GH_ASANA_INCOMING_ID }}
          asana-task-name: GH Workflow Failure - End to end tests
          asana-task-description: The end to end workflow has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}


External Content Scope Scripts Tests

name: External Content Scope Scripts Tests

on:
  workflow_dispatch:
    inputs:
      branchName:
        description: 'Branch to pull from content scope scripts repo'
        type: string
        required: true
        default: 'main'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  unit_tests:
    name: External content scope script tests
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Setup jq
        uses: dcarbone/install-jq-action@v1.0.1
        with:
          force: true

      - name: Install from branch
        run: npm install "https://github.com/duckduckgo/content-scope-scripts#${{ inputs.branchName }}" --save

      - name: Npm install
        working-directory: node_modules/@duckduckgo/content-scope-scripts
        run: npm install

      - name: Npm build
        working-directory: node_modules/@duckduckgo/content-scope-scripts
        run: npm run build

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Decode secret
        env:
          FLANK: ${{ secrets.FLANK }}
        run: echo $FLANK > flank.json

      - name: Build
        uses: gradle/gradle-build-action@v2
        with:
          arguments: androidTestsBuild

      - name: Run Android Tests
        uses: gradle/gradle-build-action@v2
        with:
          arguments: runFlankPrivacyTests

      - name: Bundle the Android CI tests report
        if: always()
        run: find . -type d -name 'fladleResults' | zip -@ -r android-tests-report.zip

      - name: Generate json file with failures
        if: ${{ failure() }}
        run: cat build/fladle/fladleResults/HtmlErrorReport.html | cut -d\`  -f2 >> results.json

      - name: Print failure report
        if: ${{ failure() }}
        run: |
          jq -r '.[] | .label as $id | .items[] | "Test:", $id, "Failure:", .label, "URL:", .url, "\n"' results.json

      - name: Upload the Android CI tests report
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: android-tests-report
          path: android-tests-report.zip


External Reference Tests

name: External Reference Tests

on:
  workflow_dispatch:
    inputs:
      branchName:
        description: 'Branch to pull reference tests from the reference tests repo'
        type: string
        required: true
        default: 'main'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  unit_tests:
    name: External reference tests unit tests
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Install copy-files-from-to
        run: npm install -g copy-files-from-to

      - name: Install package
        run: npm install "https://github.com/duckduckgo/privacy-reference-tests#${{ inputs.branchName }}" --save

      - name: Copy files
        run: copy-files-from-to

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: JVM tests
        uses: gradle/gradle-build-action@v2
        with:
          arguments: jvm_tests

      - name: Bundle the JVM checks report
        if: always()
        run: find . -type d -name 'reports' | zip -@ -r unit-tests-report.zip

      - name: Upload the JVM checks report
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: unit-tests-report
          path: unit-tests-report.zip

  android_tests:
    runs-on: ubuntu-latest
    name: External reference tests android tests

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Setup jq
        uses: dcarbone/install-jq-action@v1.0.1
        with:
          force: true

      - name: Install copy-files-from-to
        run: npm install -g copy-files-from-to

      - name: Install package
        run: npm install "https://github.com/duckduckgo/privacy-reference-tests#${{ inputs.branchName }}" --save

      - name: Copy files
        run: copy-files-from-to

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Decode secret
        env:
          FLANK: ${{ secrets.FLANK }}
        run: echo $FLANK > flank.json

      - name: Build
        uses: gradle/gradle-build-action@v2
        with:
          arguments: androidTestsBuild

      - name: Run Android Tests
        uses: gradle/gradle-build-action@v2
        with:
          arguments: runFlankAndroidTests

      - name: Bundle the Android CI tests report
        if: always()
        run: find . -type d -name 'fladleResults' | zip -@ -r android-tests-report.zip

      - name: Generate json file with failures
        if: ${{ failure() }}
        run: cat build/fladle/fladleResults/HtmlErrorReport.html | cut -d\`  -f2 >> results.json

      - name: Print failure report
        if: ${{ failure() }}
        run: |
          jq -r '.[] | .label as $id | .items[] | "Test:", $id, "Failure:", .label, "URL:", .url, "\n"' results.json

      - name: Upload the Android CI tests report
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: android-tests-report
          path: android-tests-report.zip


Nightly

name: Nightly

on:
  schedule:
    - cron: '0 2 * * *' # run at 2 AM UTC
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  code_formatting:
    name: Code Formatting
    runs-on: ubuntu-20.04 #https://github.com/actions/runner-images/issues/6709

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Run Code Formatting Checks
        uses: gradle/gradle-build-action@v2
        with:
          arguments: code_format_checks

  unit_tests:
    name: Unit tests
    runs-on: ubuntu-20.04 #https://github.com/actions/runner-images/issues/6709

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: JVM tests
        uses: gradle/gradle-build-action@v2
        with:
          arguments: jvm_tests

      - name: Bundle the JVM checks report
        if: always()
        run: find . -type d -name 'reports' | zip -@ -r unit-tests-report.zip

      - name: Upload the JVM checks report
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: unit-tests-report
          path: unit-tests-report.zip

  lint:
    name: Lint
    runs-on: ubuntu-20.04 #https://github.com/actions/runner-images/issues/6709

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Set up Go
        uses: actions/setup-go@v2
        with:
          go-version: '1.18.3'

      - name: Lint
        uses: gradle/gradle-build-action@v2
        with:
          arguments: lint

      - name: Bundle the lint report
        if: always()
        run: find . -name lint-results\* | zip -@ -r lint-report.zip

      - name: Upload the JVM lint report
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: lint-report
          path: lint-report.zip

  android_tests:
    runs-on: ubuntu-20.04 #https://github.com/actions/runner-images/issues/6709
    name: Android CI checks

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Setup jq
        uses: dcarbone/install-jq-action@v1.0.1
        with:
          force: true

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Set up Go
        uses: actions/setup-go@v2
        with:
          go-version: '1.18.3'

      - name: Decode secret
        env:
          FLANK: ${{ secrets.FLANK }}
        run: echo $FLANK > flank.json

      - name: Build
        uses: gradle/gradle-build-action@v2
        with:
          arguments: androidTestsBuild

      - name: Run Android Tests
        uses: gradle/gradle-build-action@v2
        with:
          arguments: runFlankAndroidTests

      - name: Bundle the Android CI tests report
        if: always()
        run: find . -type d -name 'fladleResults' | zip -@ -r android-tests-report.zip

      - name: Generate json file with failures
        if: ${{ failure() }}
        run: cat build/fladle/fladleResults/HtmlErrorReport.html | cut -d\`  -f2 >> results.json

      - name: Print failure report
        if: ${{ failure() }}
        run: |
          jq -r '.[] | .label as $id | .items[] | "Test:", $id, "Failure:", .label, "URL:", .url, "\n"' results.json

      - name: Upload the Android CI tests report
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: android-tests-report
          path: android-tests-report.zip

  create_task_when_failed:
    name: Create Asana task when workflow failed
    runs-on: ubuntu-20.04 #https://github.com/actions/runner-images/issues/6709
    needs: [code_formatting, unit_tests, lint, android_tests]
    if: ${{ failure() }}
    steps:
      - name: Create Asana task when workflow failed
        uses: honeycombio/gha-create-asana-task@main
        with:
          asana-secret: ${{ secrets.GH_ASANA_SECRET }}
          asana-workspace-id: ${{ secrets.GH_ASANA_WORKSPACE_ID }}
          asana-project-id: ${{ secrets.GH_ASANA_AOR_PROJECT_ID }}
          asana-section-id: ${{ secrets.GH_ASANA_INCOMING_ID }}
          asana-task-name: GH Workflow Failure - Nightly
          asana-task-description: The nightly workflow has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}


Privacy Dashboard End-to-End tests

name: Privacy Dashboard End-to-End tests

on:
  pull_request:
    paths:
      - 'node_modules/@duckduckgo/privacy-dashboard/**'
      - 'privacy-dashboard/privacy-dashboard-api/**'
      - 'privacy-dashboard/privacy-dashboard-impl/**'
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  instrumentation_tests:
    runs-on: ubuntu-latest
    name: End-to-End tests

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Create folder
        if: always()
        run: mkdir apk

      - name: Decode keys
        uses: davidSchuppa/base64Secret-toFile-action@v2
        with:
          secret: ${{ secrets.FAKE_RELEASE_PROPERTIES }}
          fileName: ddg_android_build.properties
          destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/

      - name: Decode key file
        uses: davidSchuppa/base64Secret-toFile-action@v2
        with:
          secret: ${{ secrets.FAKE_RELEASE_KEY }}
          fileName: android
          destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/

      - name: Assemble release APK
        uses: gradle/gradle-build-action@v2
        with:
          arguments: assemblePlayRelease -Pforce-default-variant

      - name: Move APK to new folder
        if: always()
        run: find . -name "*.apk"  -exec mv '{}' apk/release.apk \;

      - name: Ad click detection flows
        uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
        with:
          api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
          name: ${{ github.sha }}
          app-file: apk/release.apk
          workspace: .maestro
          include-tags: adClickTest

      - name: Privacy Tests
        if: always()
        uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
        with:
          api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
          name: ${{ github.sha }}
          app-file: apk/release.apk
          workspace: .maestro
          include-tags: privacyTest


Privacy Tests

name: Privacy Tests

on:
  pull_request:
    types: [ labeled ]
  schedule:
    - cron: '0 3 * * *' # run at 3 AM UTC
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  privacy_tests:
    if: ${{ contains(github.event.pull_request.labels.*.name, 'content scope scripts') || github.event.schedule == '0 3 * * *' || github.event_name == 'workflow_dispatch' }}
    name: Privacy Tests
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Setup jq
        uses: dcarbone/install-jq-action@v1.0.1
        with:
          force: true

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Set up Go
        uses: actions/setup-go@v2
        with:
          go-version: '1.18.3'

      - name: Decode secret
        env:
          FLANK: ${{ secrets.FLANK }}
        run: echo $FLANK > flank.json

      - name: Build
        uses: gradle/gradle-build-action@v2
        with:
          arguments: androidTestsBuild

      - name: Run Android Tests
        uses: gradle/gradle-build-action@v2
        with:
          arguments: runFlankPrivacyTests

      - name: Bundle the Android CI tests report
        if: always()
        run: find . -type d -name 'fladleResults' | zip -@ -r android-tests-report.zip

      - name: Generate json file with failures
        if: ${{ failure() }}
        run: cat build/fladle/fladleResults/HtmlErrorReport.html | cut -d\`  -f2 >> results.json

      - name: Print failure report
        if: ${{ failure() }}
        run: |
          jq -r '.[] | .label as $id | .items[] | "Test:", $id, "Failure:", .label, "URL:", .url, "\n"' results.json

      - name: Upload the Android CI tests report
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: android-tests-report
          path: android-tests-report.zip

      - name: Create Asana task when workflow failed
        if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
        uses: honeycombio/gha-create-asana-task@main
        with:
          asana-secret: ${{ secrets.GH_ASANA_SECRET }}
          asana-workspace-id: ${{ secrets.GH_ASANA_WORKSPACE_ID }}
          asana-project-id: ${{ secrets.GH_ASANA_AOR_PROJECT_ID }}
          asana-section-id: ${{ secrets.GH_ASANA_INCOMING_ID }}
          asana-task-name: GH Workflow Failure - Privacy tests
          asana-task-description: The privacy workflow has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}


name: Sync Feature Critical Path End-to-End tests

on:
  schedule:
    - cron: '0 5 * * *' # run at 5 AM UTC
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  instrumentation_tests:
    runs-on: ubuntu-latest
    name: Sync Feature Critical Path End-to-End tests

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'adopt'

      - name: Create test account for Sync and return the recovery code
        uses: duckduckgo/sync_crypto/action@main
        id: sync-recovery-code
        with:
          debug: true
          no-teardown: false # Turn this to true so the account is not deleted after the test

      - name: Create folder
        if: always()
        run: mkdir apk

      - name: Decode keys
        uses: davidSchuppa/base64Secret-toFile-action@v2
        with:
          secret: ${{ secrets.FAKE_RELEASE_PROPERTIES }}
          fileName: ddg_android_build.properties
          destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/

      - name: Decode key file
        uses: davidSchuppa/base64Secret-toFile-action@v2
        with:
          secret: ${{ secrets.FAKE_RELEASE_KEY }}
          fileName: android
          destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/

      - name: Assemble internal release APK
        uses: gradle/gradle-build-action@v2
        with:
          arguments: assembleInternalRelease -Pforce-default-variant -Psync-disable-auth-requirement -x lint

      - name: Move APK to new folder
        if: always()
        run: find . -name "*.apk"  -exec mv '{}' apk/release.apk \;

      - name: Sync Flows
        uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
        with:
          api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
          name: ${{ github.sha }}
          app-file: apk/release.apk
          android-api-level: 30
          workspace: .maestro
          include-tags: syncCriticalPathTest
          env: |
            CODE=${{ steps.sync-recovery-code.outputs.recovery-code }}

      - name: Create Asana task when workflow failed
        if: ${{ failure() }}
        id: create-failure-task
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          asana-pat: ${{ secrets.GH_ASANA_SECRET }}
          asana-project: ${{ vars.GH_ANDROID_APP_PROJECT_ID }}
          asana-section: ${{ vars.GH_ANDROID_APP_INCOMING_SECTION_ID }}
          asana-task-name: GH Workflow Failure - Android Sync Critical Path E2E Flows
          asana-task-description: The Android Sync Critical Path Flows E2E workflow has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}
          action: 'create-asana-task'

      - name: Add Asana task to Browser Sync & Backup project
        if: ${{ failure() }}
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          asana-pat: ${{ secrets.GH_ASANA_SECRET }}
          asana-project: ${{ vars.GH_BROWSER_SYNC_BACKUP_PROJECT_ID }}
          asana-section: ${{ vars.GGH_BROWSER_SYNC_BACKUP_PROJECT_TRIAGE_SECTION_ID }}
          asana-task-id: ${{ steps.create-failure-task.outputs.taskId }}
          action: 'add-task-asana-project'


Update Content Scope Scripts

name: Update Content Scope Scripts

on:
  schedule:
    - cron: '30 1 * * *' # run at 1 AM UTC
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  update-content-scope-scripts:
    name: Update Content Scope scripts
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Install npm-check-updates
        run: npm install -g npm-check-updates

      - name: Check for updates
        id: update-check
        continue-on-error: true
        run: ncu @duckduckgo/content-scope-scripts --errorLevel 2

      - name: Update content scope scripts
        if: ${{ steps.update-check.outcome == 'failure' }}
        run: ncu @duckduckgo/content-scope-scripts -u

      - name: Install package
        if: ${{ steps.update-check.outcome == 'failure' }}
        run: npm update

      - name: Find latest release version of Content Scope scripts in package.json
        if: ${{ steps.update-check.outcome == 'failure' }}
        id: find-latest-release
        uses: notiz-dev/github-action-json-property@release
        with:
          path: 'package.json'
          prop_path: 'dependencies.@duckduckgo/content-scope-scripts'

      - name: Extract release version
        if: ${{ steps.update-check.outcome == 'failure' }}
        uses: rishabhgupta/split-by@v1
        id: extract-release-version
        with:
          string: ${{steps.find-latest-release.outputs.prop}}
          split-by: '#'

      - name: Create Pull Request in Android repo
        if: ${{ steps.update-check.outcome == 'failure' }}
        env:
          RELEASE_VERSION: ${{ steps.extract-release-version.outputs._1}}
        id: create-pr
        uses: peter-evans/create-pull-request@v5.0.2
        with:
          base: "develop"
          title: Update content scope scripts to version ${{ steps.extract-release-version.outputs._1}}
          author: daxmobile <daxmobile@users.noreply.github.com>
          token: ${{ secrets.GT_DAXMOBILE }}
          commit-message: Update content scope scripts to version ${{ steps.extract-release-version.outputs._1}}
          labels: content scope scripts, automated pr
          branch: automated/update-content-scope-scripts-dependencies-${{ steps.extract-release-version.outputs._1}}
          body: |
            - Automated content scope scripts dependency update

            This PR updates the content scope scripts dependency to the latest available version and copies the necessary files.
            If tests have failed, see https://app.asana.com/0/1202561462274611/1203986899650836/f for further information on what to do next.

            - [ ] All tests must pass

      - name: Create Asana task in Android App project
        if: ${{ steps.update-check.outcome == 'failure' }}
        id: create-task
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          asana-pat: ${{ secrets.GH_ASANA_SECRET }}
          asana-project: ${{ vars.GH_ANDROID_APP_PROJECT_ID }}
          asana-section: ${{ vars.GH_ANDROID_APP_INCOMING_SECTION_ID }}
          asana-task-name: Update content scope scripts to version ${{ steps.extract-release-version.outputs._1}}
          asana-task-description: |
            Content scope scripts have been updated and a PR created.

            If tests failed check out https://app.asana.com/0/1202561462274611/1203986899650836/f for further information on what to do next.

            See ${{ steps.create-pr.outputs.pull-request-url }}
          action: 'create-asana-task'

      - name: Add Asana task to Release Board project
        if: ${{ steps.create-task.outputs.duplicate == 'false' }}
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          asana-pat: ${{ secrets.GH_ASANA_SECRET }}
          asana-project: ${{ vars.GH_ANDROID_RELEASE_BOARD_PROJECT_ID }}
          asana-section: ${{ vars.GH_ANDROID_RELEASE_BOARD_PR_SECTION_ID }}
          asana-task-id: ${{ steps.create-task.outputs.taskId }}
          action: 'add-task-asana-project'

      - name: Update PR description with Asana task
        if: ${{ steps.create-task.outputs.duplicate == 'false' }}
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          github-pat: ${{ secrets.GT_DAXMOBILE }}
          github-pr: ${{ steps.create-pr.outputs.pull-request-number }}
          github-repository: 'android'
          github-org: 'duckduckgo'
          asana-project: ${{ vars.GH_ANDROID_RELEASE_BOARD_PROJECT_ID }}
          asana-task-id: ${{ steps.create-task.outputs.taskId }}
          action: 'add-task-pr-description'

      - name: Create Asana task when workflow failed
        if: ${{ failure() }}
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          asana-pat: ${{ secrets.GH_ASANA_SECRET }}
          asana-project: ${{ vars.GH_ANDROID_APP_PROJECT_ID }}
          asana-section: ${{ vars.GH_ANDROID_APP_INCOMING_SECTION_ID }}
          asana-task-name: GH Workflow Failure - Update content scope scripts
          asana-task-description: The update content scope scripts tests workflow has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}
          action: 'create-asana-task'


Update Privacy Reference Tests

name: Update Privacy Reference Tests

on:
  schedule:
    - cron: '0 1 * * *' # run at 1 AM UTC
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  update-ref-tests:
    name: Update reference tests
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Install npm-check-updates
        run: npm install -g npm-check-updates

      - name: Install copy-files-from-to
        run: npm install -g copy-files-from-to

      - name: Check for updates
        id: update-check
        continue-on-error: true
        run: ncu @duckduckgo/privacy-reference-tests --errorLevel 2

      - name: Update reference steps
        if: ${{ steps.update-check.outcome == 'failure' }}
        run: ncu @duckduckgo/privacy-reference-tests -u

      - name: Install package
        if: ${{ steps.update-check.outcome == 'failure' }}
        run: npm update

      - name: Copy files
        if: ${{ steps.update-check.outcome == 'failure' }}
        run: copy-files-from-to

      - name: Find latest release version of Content Scope scripts in package.json
        if: ${{ steps.update-check.outcome == 'failure' }}
        id: find-latest-release
        uses: notiz-dev/github-action-json-property@release
        with:
          path: 'package.json'
          prop_path: 'dependencies.@duckduckgo/privacy-reference-tests'

      - name: Extract release version
        if: ${{ steps.update-check.outcome == 'failure' }}
        uses: rishabhgupta/split-by@v1
        id: extract-release-version
        with:
          string: ${{steps.find-latest-release.outputs.prop}}
          split-by: '#'

      - name: Create Pull Request in Android repo
        if: ${{ steps.update-check.outcome == 'failure' }}
        env:
          RELEASE_VERSION: ${{ steps.extract-release-version.outputs._1}}
        id: create-pr
        uses: peter-evans/create-pull-request@v5
        with:
          base: "develop"
          title: Update reference tests to version ${{ steps.extract-release-version.outputs._1}}
          author: daxmobile <daxmobile@users.noreply.github.com>
          token: ${{ secrets.GT_DAXMOBILE }}
          commit-message: Update content scope scripts to version ${{ steps.extract-release-version.outputs._1}}
          labels: reference tests, automated pr
          branch: automated/update-ref-tests-dependencies-${{ steps.extract-release-version.outputs._1}}
          body: |
            - Automated reference tests dependency update

            This PR updates the reference tests dependency to the latest available version and copies the necessary files.
            If tests have failed, see https://app.asana.com/0/0/1203766026095653/f for further information on what to do next.

            - [ ] All tests must pass

      - name: Create Asana task in Android App project
        if: ${{ steps.update-check.outcome == 'failure' }}
        id: create-task
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          asana-pat: ${{ secrets.GH_ASANA_SECRET }}
          asana-project: ${{ vars.GH_ANDROID_APP_PROJECT_ID }}
          asana-section: ${{ vars.GH_ANDROID_APP_INCOMING_SECTION_ID }}
          asana-task-name: Update reference tests to version ${{ steps.extract-release-version.outputs._1}}
          asana-task-description: |
            Reference tests have been updated and a PR created.

            If tests failed check out https://app.asana.com/0/0/1203766026095653/f for further information on what to do next.

            See ${{ steps.create-pr.outputs.pull-request-url }}
          action: 'create-asana-task'

      - name: Add Asana task to Release Board project
        if: ${{ steps.create-task.outputs.duplicate == 'false' }}
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          asana-pat: ${{ secrets.GH_ASANA_SECRET }}
          asana-project: ${{ vars.GH_ANDROID_RELEASE_BOARD_PROJECT_ID }}
          asana-section: ${{ vars.GH_ANDROID_RELEASE_BOARD_PR_SECTION_ID }}
          asana-task-id: ${{ steps.create-task.outputs.taskId }}
          action: 'add-task-asana-project'

      - name: Update PR description with Asana task
        if: ${{ steps.create-task.outputs.duplicate == 'false' }}
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          github-pat: ${{ secrets.GT_DAXMOBILE }}
          github-pr: ${{ steps.create-pr.outputs.pull-request-number }}
          github-repository: 'android'
          github-org: 'duckduckgo'
          asana-project: ${{ vars.GH_ANDROID_RELEASE_BOARD_PROJECT_ID }}
          asana-task-id: ${{ steps.create-task.outputs.taskId }}
          action: 'add-task-pr-description'

      - name: Create Asana task when workflow failed
        if: ${{ failure() }}
        uses: duckduckgo/native-github-asana-sync@v1.1
        with:
          asana-pat: ${{ secrets.GH_ASANA_SECRET }}
          asana-project: ${{ vars.GH_ANDROID_APP_PROJECT_ID }}
          asana-section: ${{ vars.GH_ANDROID_APP_INCOMING_SECTION_ID }}
          asana-task-name: GH Workflow Failure - Update reference tests
          asana-task-description: The update reference tests workflow has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}
          action: 'create-asana-task'


Update Website

name: Update Website
on:
  push:
    branches:
      - master
permissions:
  contents: read

jobs:
  release-site:
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v4.1.1
      - uses: actions/setup-python@v5.0.0
        with:
          python-version: '3.10.2'
          architecture: 'x64'
      - run: pip install -r requirements.txt
      - run: ./tools/embed_code.py
      - uses: actions/checkout@v4.1.1
        with:
          repository: http4k/http4k.github.io
          path: tmp
          token: ${{ secrets.TOOLBOX_REPO_TOKEN }}
      - run: cp -R build/docs-website/docs tmp/
      - run: cp -R src/mkdocs.yml tmp/
      - run: pushd tmp && mkdocs gh-deploy && popd


Build

name: Build
on:
  push:
    branches:
      - 'master'
    paths-ignore:
      - '**/*.md'
  pull_request:
    branches:
      - '*'
    paths-ignore:
      - '**/*.md'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4.1.1
        with:
          # required by release-tag.sh to correctly identify files changed in the last commit
          fetch-depth: 2
          # required by release-tag.sh to allow pushing with another credentials so other workflows are triggered
          persist-credentials: false
      - uses: actions/setup-java@v4.0.0
        with:
          distribution: temurin
          java-version: 21
          cache: gradle
      - name: Cache Gradle packages
        uses: actions/cache@v4.0.0
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Build
        timeout-minutes: 15
        run: ./build-ci.sh
      - name: Cleanup Gradle Cache
          # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
        # Restoring these files from a GitHub Actions cache might cause problems for future builds.
        run: |
          rm -f ~/.gradle/caches/modules-2/modules-2.lock
          rm -f ~/.gradle/caches/modules-2/gc.properties
      - name: Publish Test Report
        uses: mikepenz/action-junit-report@v4.1.0
        if: always()
        with:
          report_paths: '**/build/test-results/test/TEST-*.xml'
          github_token: ${{ secrets.GITHUB_TOKEN }}
      - name: Release (if required)
        run: |
          git config user.name github-actions
          git config user.email github-actions@github.com
          git remote set-url origin https://x-access-token:${{ secrets.ORG_PUBLIC_REPO_RELEASE_TRIGGERING }}@github.com/${GITHUB_REPOSITORY}.git
          ./release-tag.sh
        if: github.ref == 'refs/heads/master'
        env:
          GH_TOKEN: ${{ secrets.ORG_PUBLIC_REPO_RELEASE_TRIGGERING }}


New Release - GitHub

name: New Release - GitHub
on:
  repository_dispatch:
    types: [http4k-release]
permissions:
  contents: read

jobs:
  release:
    permissions:
      contents: write  # for actions/create-release to create a release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4.1.1
      - run: ./build-release-note.sh ${{ github.event.client_payload.version }} > NOTE.md
      - uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.event.client_payload.version }}
          release_name: ${{ github.event.client_payload.version }}
          body_path: NOTE.md
          draft: false
          prerelease: false


New Release - Slack

name: New Release - Slack
on:
  repository_dispatch:
    types: [http4k-release]
permissions:
  contents: read

jobs:
  slackify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4.1.1
      - run: ./notify-slack.sh ${{ github.event.client_payload.version }}
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}


New Release - Update other projects

name: New Release - Update other projects
on:
  repository_dispatch:
    types: [http4k-release]
jobs:
  create-upgrade-branches:
    strategy:
      matrix:
        repo:
          - 'http4k/toolbox'
          - 'http4k/examples'
          - 'http4k/http4k-by-example'
          - 'http4k/http4k-connect'
          - 'http4k/http4k-connect-examples'
          - 'http4k/http4k-contract-todo-backend'
          - 'http4k/http4k-bin'
          - 'http4k/http4k-todo-backend'

    runs-on: ubuntu-latest
    steps:
      - name: Trigger ${{ matrix.repo }}
        uses: peter-evans/repository-dispatch@v3.0.0
        with:
          token: ${{ secrets.TOOLBOX_REPO_TOKEN }}
          repository: ${{ matrix.repo }}
          event-type: http4k-release
          client-payload: '{"version": "${{ github.event.client_payload.version }}"}'


Publish Artifacts

name: Publish Artifacts
on:
  push:
    tags:
      - '*'
env:
  ACTIONS_ALLOW_UNSECURE_COMMANDS: true
jobs:
  ReleaseMC:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4.1.1
      - name: Grab tag name
        uses: olegtarasov/get-tag@v2.1.3
        id: tagName
      - name: Setup Java
        uses: actions/setup-java@v4.0.0
        with:
          distribution: temurin
          java-version: 21
          cache: gradle
      - name: Upload to Sonatype
        run: |
          ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository \
          -Psign=true \
          -PreleaseVersion="${{ steps.tagName.outputs.tag }}" \
          -PsigningKey="${{ secrets.SIGNING_KEY }}" \
          -PsigningPassword="${{ secrets.SIGNING_PASSWORD }}" \
          -PnexusUsername="${{ secrets.NEXUS_USERNAME }}" \
          -PnexusPassword="${{ secrets.NEXUS_PASSWORD }}"


Broadcast Release

name: Broadcast Release
on:
  schedule:
    - cron: '0 * * * *' # every hour
  push:
    branches:
      - master
    paths-ignore:
      - '**/*.md'
jobs:
  check-new-version:
    runs-on: ubuntu-latest
    outputs:
      requires-broadcast: ${{ steps.check-version.outputs.requires-broadcast }}
      version: ${{ steps.check-version.outputs.version }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4.1.1
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4.0.2
        with:
          aws-access-key-id: ${{ secrets.S3_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.S3_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - name: Check new version
        id: check-version
        shell: bash
        run: |
          LOCAL_VERSION=$(jq -r .http4k.version ./version.json)
          S3_VERSION=$(aws s3 cp s3://http4k/latest-broadcasted-version.txt -)

          if [[ $S3_VERSION == $LOCAL_VERSION ]]; then
            echo "Version $LOCAL_VERSION has been broadcasted already."
            echo "requires-broadcast=false" >> $GITHUB_OUTPUT
            exit 0
          fi;

          echo "Latest broadcasted version was ${S3_VERSION}. Checking for ${LOCAL_VERSION} in maven central..."

          MC_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
            "https://repo1.maven.org/maven2/org/http4k/http4k-core/${LOCAL_VERSION}/http4k-core-${LOCAL_VERSION}.pom"
          )

          if [[ $MC_STATUS == "200" ]]; then
            echo "Version $LOCAL_VERSION available in MC. Preparing for broadcast..."
            echo "${LOCAL_VERSION}" | aws s3 cp - s3://http4k/latest-broadcasted-version.txt
            echo "requires-broadcast=true" >> $GITHUB_OUTPUT
            echo "version=${LOCAL_VERSION}" >> $GITHUB_OUTPUT
          fi;
  broadcast-release:
    runs-on: ubuntu-latest
    needs: [check-new-version]
    if: ${{ needs.check-new-version.outputs.requires-broadcast == 'true' }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4.1.1
      - name: Grab tag name
        uses: olegtarasov/get-tag@v2.1.3
        id: tagName
      - name: Dispatch Release Event
        uses: peter-evans/repository-dispatch@v3.0.0
        with:
          token: ${{ secrets.ORG_PUBLIC_REPO_WORKFLOW_TRIGGERING }}
          repository: http4k/http4k
          event-type: http4k-release
          client-payload: '{"version": "${{ needs.check-new-version.outputs.version }}"}'


Refresh Dependencies

# Worfklow for https://jmfayard.github.io/refreshVersions/

name: Refresh Dependencies

on:
  workflow_dispatch:
  schedule:
    - cron: '0 7 * * 1'

jobs:
  refresh-versions:
    name: Check New Versions
    runs-on: "ubuntu-latest"
    steps:
      - id: step-0
        name: check-out
        uses: actions/checkout@v4.1.1
        with:
          ref: master
      - id: step-1
        name: setup-java
        uses: actions/setup-java@v4.0.0
        with:
          distribution: temurin
          java-version: 21
          cache: gradle
      - id: step-2
        name: create-branch
        uses: peterjgrainger/action-create-branch@v2.2.0
        with:
          branch: dependency-update
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - id: step-3
        name: gradle refreshVersions
        uses: gradle/gradle-build-action@v2.4.2
        with:
          arguments: refreshVersions
      - id: step-4
        name: Commit
        uses: EndBug/add-and-commit@v9
        with:
          author_name: GitHub Actions
          author_email: noreply@github.com
          message: Refresh versions.properties
          new_branch: dependency-update
          push: --force --set-upstream origin dependency-update
      - id: step-5
        name: Pull Request
        uses: repo-sync/pull-request@v2
        with:
          source_branch: dependency-update
          destination_branch: master
          pr_title: Upgrade gradle dependencies
          pr_body: '[refreshVersions](https://github.com/jmfayard/refreshVersions) has found those library updates!'
          pr_draft: false
          github_token: ${{ secrets.GITHUB_TOKEN }}


# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "Security - Vulnerability Scanning (CodeQL)"

on:
  push:
    branches: [ "master" ]
    paths-ignore:
      - '**/*.md'
  pull_request:
    # The branches below must be a subset of the branches above
    branches: [ "master" ]
    paths-ignore:
      - '**/*.md'
  schedule:
    - cron: '30 23 * * 3'

jobs:
  analyze:
    name: Analyze
    runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
    timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: [ 'java' ]
        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ]
        # Use only 'java' to analyze code written in Java, Kotlin or both
        # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
        # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4.1.1

    - uses: actions/setup-java@v4.0.0
      with:
        distribution: temurin
        java-version: 21
        cache: gradle

    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v3
      with:
        languages: ${{ matrix.language }}
        # If you wish to specify custom queries, you can do so here or in a config file.
        # By default, queries listed here will override any specified in a config file.
        # Prefix the list here with "+" to use these queries and those in the config file.

        # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
        # queries: security-extended,security-and-quality

    # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v3

    # ℹ Command-line programs to run using the OS shell.
    # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun

    #   If the Autobuild fails above, remove it and uncomment the following three lines.
    #   modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.

    # - run: |
    #     echo "Run, Build Application using script"
    #     ./location_of_script_within_repo/buildscript.sh

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v3
      with:
        category: "/language:${{matrix.language}}"


name: "Security - Dependency Analysis (dependabot)"
on:
  push:
    branches:
      - 'master'
    paths-ignore:
      - '**/*.md'

jobs:
  build:
    name: Dependencies
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: 'Checkout Repository'
        uses: actions/checkout@v4.1.1

      - uses: actions/setup-java@v4.0.0
        with:
          distribution: temurin
          java-version: 21
          cache: gradle

      - name: Run snapshot action
        uses: mikepenz/gradle-dependency-submission@v0.8.6
        with:
          sub-module-mode: COMBINED


Android CI

name: Android CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  lint:
    name: Spotless check
    runs-on: ubuntu-latest
    steps:
      - name: Check out code
        uses: actions/checkout@v4.1.7
      - name: Set up JDK
        uses: actions/setup-java@v4.2.1
        with:
          distribution: zulu
          java-version: 17
      - uses: gradle/gradle-build-action@v3.4.2
      - name: spotless
        run: ./gradlew spotlessCheck

  api_check:
    name: API check
    runs-on: ubuntu-latest
    steps:
      - name: Check out code
        uses: actions/checkout@v4.1.7
      - name: Set up JDK
        uses: actions/setup-java@v4.2.1
        with:
          distribution: zulu
          java-version: 17
      - uses: gradle/gradle-build-action@v3.4.2
      - name: API check
        run: ./gradlew apiCheck

  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4.1.7
      - name: set up JDK
        uses: actions/setup-java@v4.2.1
        with:
          distribution: zulu
          java-version: 17

      - uses: gradle/gradle-build-action@v3.4.2
      - name: Make Gradle executable
        run: chmod +x ./gradlew

      - name: Build with Gradle
        run: |
          ./gradlew --scan --stacktrace \
              assemble -x :benchmark:pixel6api31Setup -x :benchmark:pixel6api31NonMinifiedReleaseAndroidTest -x :benchmark:collectNonMinifiedReleaseBaselineProfile


baseline-profiles

# Workflow name
name: baseline-profiles

# Workflow title
run-name: ${{ github.actor }} requested a workflow

# This should be a manual trigger so this actions gets executed every time make a new pull request.
# Change this event to what suits your project best.
# Read more at https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
on:
  workflow_dispatch:

# Environment variables (Optional)
# Small projects might have signingConfigs locally. This could lead to failures on GitHub Actions.
# If that's the case, upload your properties defined locally to GitHub Secrets.

# On your signingConfigs, you can recover GitHub Secrets using: variable = System.getenv("VARIABLE")

# Then uncomment this block properly defining your uploaded variables
# env:
#  VARIABLE: ${{ secrets.VARIABLE }}

# Read more at https://docs.github.com/en/actions/security-guides/encrypted-secrets

# Jobs to executed on GitHub machines
jobs:

  # Job name
  generate-baseline-profiles:

    # Operating system where the job gets to be executed
    runs-on: macos-latest

    # Job steps
    steps:

      # Checks your code out on the machine
      - uses: actions/checkout@v4

      # Sets java up
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: 17

      # Sets gradle up
      - name: Setup Gradle
        uses: gradle/gradle-build-action@v3.4.2

      # Grants execute permission to gradle (safety step)
      - name: Grant Permissions to gradlew
        run: chmod +x gradlew

      # This allows us to build most of what we need without the emulator running
      # and using resources
      - name: Build app and benchmark
        run: ./gradlew :benchmark-app:assembleBenchmark

      # Cleans managed device if previously settle and space currently is not available
      - name: Clean Managed Devices
        run: ./gradlew cleanManagedDevices --unused-only

      # Generates Baseline Profile
      - name: Generate Baseline Profile
        run: ./gradlew generateBaselineProfile -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile -Pandroid.experimental.testOptions.managedDevices.setupTimeoutMinutes=20 -Dorg.gradle.workers.max=4

      # Create Pull Request
      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v6
        with:
          commit-message: "Generate baseline profiles"
          title: "Generate baseline profiles"
          delete-branch: true
          reviewers: skydoves
          branch: actions/baseline-profiles


Publish

name: Publish

on:
  release:
    types: [ released ]
  workflow_dispatch:

jobs:
  publish:
    name: Snapshot build and publish
    runs-on: ubuntu-latest
    steps:
      - name: Check out code
        uses: actions/checkout@v4.1.7

      - name: Set up JDK 17
        uses: actions/setup-java@v4.2.1
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Grant Permission to Execute Gradle
        run: chmod +x gradlew

      - name: Release build
        run: ./gradlew assemble --scan -x :benchmark:pixel6api31Setup -x :benchmark:pixel6api31NonMinifiedReleaseAndroidTest -x :benchmark:collectNonMinifiedReleaseBaselineProfile

      - name: Publish to MavenCentral
        run: |
          ./gradlew publishAllPublicationsToMavenCentral --no-configuration-cache
        env:
          ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.OSSRH_USERNAME }}
          ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.OSSRH_PASSWORD }}
          ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }}
          ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }}
          ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_KEY }}


CI

name: CI
on:
  push:
    branches:
      - master
  pull_request:

env:
  STRIPE_END_TO_END_TESTS_BACKEND_URL: ${{ secrets.STRIPE_END_TO_END_TESTS_BACKEND_URL }}
  STRIPE_END_TO_END_TESTS_PUBLISHABLE_KEY: ${{ secrets.STRIPE_END_TO_END_TESTS_PUBLISHABLE_KEY }}
  GRADLE_OPTS: -Dkotlin.incremental=false

jobs:
  end-to-end-tests:
    name: End-to-end tests
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: End-to-end tests
        run: ./gradlew :stripe-test-e2e:testDebugUnitTest
      - uses: actions/upload-artifact@v3
        if: failure()
        with:
          name: unit-test-report
          path: stripe-test-e2e/build/reports/tests/testDebugUnitTest/

  build-paymentsheet-example-project:
    name: Build paymentsheet example project
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Build example projects
        run: ./gradlew :paymentsheet-example:assembleAndroidTest
      - uses: actions/upload-artifact@v3
        if: failure()
        with:
          name: test-failures
          path: |
            **/build/reports/tests/
            **/out/failures/

  payment-sheet-apk-size-analysis:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Generate Android release bundle
        run: ./gradlew :paymentsheet-example:bundleRelease
      - name: Upload artifact to Emerge
        uses: EmergeTools/emerge-upload-action@3477b597fc62054136eb6f499e0ba78144f8a999
        with:
          artifact_path: paymentsheet-example/build/outputs/bundle/release/paymentsheet-example-release.aab
          emerge_api_key: ${{ secrets.EMERGE_API_KEY }}
          build_type: pull_request

  check-for-untranslated-strings:
    name: Check for untranslated strings
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v4
      - name: Check for untranslated strings
        run: cd scripts && ruby lokalise/check_untranslated_strings.rb
        env:
          LOKALISE_API_TOKEN: ${{ secrets.LOKALISE_API_TOKEN }}


Generate Dokka

name: Generate Dokka
on:
  workflow_dispatch:
  pull_request:
    paths:
      - '**/*.gradle'
      - '*.gradle'
  push:
    branches:
      - master

jobs:
  generate-dokka:
    name: Generate Dokka
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Generate Dokka Documentation
        run: ./gradlew dokkaHtmlMultiModule


End-to-end tests

name: End-to-end tests
on:
  schedule:
    # every day at 8am
    - cron: '0 8 * * *'
jobs:
  end-to-end-tests:
    name: End-to-end tests
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: End-to-end tests
        env:
          STRIPE_END_TO_END_TESTS_BACKEND_URL: ${{ secrets.STRIPE_END_TO_END_TESTS_BACKEND_URL }}
          STRIPE_END_TO_END_TESTS_PUBLISHABLE_KEY: ${{ secrets.STRIPE_END_TO_END_TESTS_PUBLISHABLE_KEY }}
        run: ./gradlew :stripe-test-e2e:testDebugUnitTest
      - uses: actions/upload-artifact@v3
        if: failure()
        with:
          name: unit-test-report
          path: stripe-test-e2e/build/reports/tests/testDebugUnitTest/
      - name: Notify failure endpoint
        id: notifyFailureEndpoint
        if: failure()
        run: |
          ./scripts/notify_failure_endpoint.rb \
          ${{ secrets.SDK_FAILURE_NOTIFICATION_ENDPOINT }} \
          ${{ secrets.SDK_FAILURE_NOTIFICATION_ENDPOINT_HMAC_KEY }} \
          "https://github.com/stripe/stripe-android/actions/runs/${{ github.run_id }}" \
          RUN_MOBILESDK


Fetch Lokalize translations

name: Fetch Lokalize translations
on:
  workflow_dispatch:
  schedule:
    # Every Monday at 10 AM East Coast time / 7 AM West Coast time / 2 PM UTC
    - cron: "0 14 * * 1"
jobs:
  fetch-lokalize-translations:
    runs-on: macos-latest
    steps:
      - name: Check out the current state
        uses: actions/checkout@v4
      - name: Fetch translations
        run: cd scripts && ./localize.sh
        shell: bash
        env:
          LOKALISE_API_TOKEN: ${{ secrets.LOKALISE_API_TOKEN }}
      - name: Compute timestamp
        id: timestamp
        run: echo "TIMESTAMP=$(date +'%Y%m%d-%H%M%S')" >> $GITHUB_OUTPUT
      - name: Generate translations app token
        id: generate-translations-app-token
        uses: actions/create-github-app-token@eaddb9eb7e4226c68cf4b39f167c83e5bd132b3e
        with:
          app-id: ${{ secrets.ANDROID_TRANSLATIONS_APP_ID }}
          private-key: ${{ secrets.ANDROID_TRANSLATIONS_APP_PRIVATE_KEY }}
      - name: Create Pull Request
        uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38
        id: create-pull-request
        with:
          token: ${{ steps.generate-translations-app-token.outputs.token }}
          commit-message: Fetch latest Lokalize translations
          author: ${{ secrets.ANDROID_TRANSLATIONS_APP_AUTHOR }}
          committer: ${{ secrets.ANDROID_TRANSLATIONS_APP_AUTHOR }}
          title: Update translations
          body: This pull request contains the latest translations from Lokalize.
          branch: update-translations-${{ steps.timestamp.outputs.TIMESTAMP }}
          base: master
      - name: Enable Auto-Merge
        if: ${{ steps.create-pull-request.outputs.pull-request-url }}
        run: gh pr merge --squash --auto ${{ steps.create-pull-request.outputs.pull-request-url }}
        env:
          GH_TOKEN: ${{ github.token }}


financial-connections-pr

name: financial-connections-pr
on:
  pull_request:
jobs:
  # Use emerge tools to analyze the example app size
  apk-size-analysis:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Generate Android release bundle
        run: ./gradlew :financial-connections-example:bundleRelease
      - name: Upload artifact to Emerge
        uses: EmergeTools/emerge-upload-action@3477b597fc62054136eb6f499e0ba78144f8a999
        with:
          artifact_path: financial-connections-example/build/outputs/bundle/release/financial-connections-example-release.aab
          emerge_api_key: ${{ secrets.EMERGE_API_KEY }}
          build_type: release


identity-example size diff

name: identity-example size diff
on:
  pull_request:
jobs:
  # Checkout base branch and build the APK
  build-base:
    name: Build base
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ github.base_ref }}
      - uses: ./.github/actions/stripe_setup
      - name: Build base branch
        run: ./gradlew :identity-example:assembleRelease && mv identity-example/build/outputs/apk/theme1/release/identity-example-theme1-release.apk identity-example/build/outputs/apk/theme1/release/identity-example-release-base.apk
      - name: Upload APK
        uses: actions/upload-artifact@v3
        with:
          name: apk
          path: identity-example/build/outputs/apk/theme1/release/identity-example-release-base.apk

  # Checkout PR branch and build the APK
  build-pr:
    name: Build PR
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Build PR branch
        run: ./gradlew :identity-example:assembleRelease && mv identity-example/build/outputs/apk/theme1/release/identity-example-theme1-release.apk identity-example/build/outputs/apk/theme1/release/identity-example-release-pr.apk
      - name: Upload APK
        uses: actions/upload-artifact@v3
        with:
          name: apk
          path: identity-example/build/outputs/apk/theme1/release/identity-example-release-pr.apk

  # Execute Diffuse only when the two APKs are built successfully
  diffuse:
    needs: [ build-base, build-pr ]
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - name: Download APKs
        uses: actions/download-artifact@v1
        with:
          name: apk
      - name: diffuse
        id: diffuse
        uses: usefulness/diffuse-action@d816fd102c1f5f69519ee4bb8e0e12a42d005788
        with:
          old-file-path: apk/identity-example-release-base.apk
          new-file-path: apk/identity-example-release-pr.apk

      # Post comment with output

      - uses: peter-evans/find-comment@d2dae40ed151c634e4189471272b57e76ec19ba8
        id: find_comment
        with:
          issue-number: ${{ github.event.pull_request.number }}
          body-includes: Diffuse output

      - uses: peter-evans/create-or-update-comment@a35cf36e5301d70b76f316e867e7788a55a31dae
        if: ${{ steps.diffuse.outputs.diff-raw != null || steps.find_comment.outputs.comment-id != null }}
        with:
          body: |
            Diffuse output:

            ${{ steps.diffuse.outputs.diff-gh-comment }}
          edit-mode: replace
          comment-id: ${{ steps.find_comment.outputs.comment-id }}
          issue-number: ${{ github.event.pull_request.number }}
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Upload diffuse output
        uses: actions/upload-artifact@v3
        with:
          name: diffuse-output
          path: ${{ steps.diffuse.outputs.diff-file }}

  # Use emerge tools to analyze the example app size
  apk-size-analysis:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Generate Android release bundle
        run: ./gradlew :identity-example:bundleRelease
      - name: Upload artifact to Emerge
        uses: EmergeTools/emerge-upload-action@3477b597fc62054136eb6f499e0ba78144f8a999
        with:
          artifact_path: identity-example/build/outputs/bundle/theme1Release/identity-example-theme1-release.aab
          emerge_api_key: ${{ secrets.EMERGE_API_KEY }}
          build_type: pull_request


Instrumentation tests

name: Instrumentation tests
on:
  workflow_dispatch:
  schedule:
    # every 12 hours
    - cron: '0 */12 * * *'
jobs:
  # This should be updated to use the browserstack github actions when supported
  browserstack-instrumentation-tests:
    name: Browserstack Instrumentation tests
    runs-on: ubuntu-latest
    timeout-minutes: 240
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: 'Build'
        run: ./gradlew :paymentsheet-example:assembleDebugAndroidTest :paymentsheet-example:assembleDebug -PIS_NIGHTLY_BUILD=true -PIS_BROWSERSTACK_BUILD=true

      - name: 'Install pip modules'
        run: pip install requests_toolbelt requests

      - name: 'Run BrowserStack tests'
        timeout-minutes: 180
        env:
          BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
          BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
        run: python scripts/browserstack.py --test --apk paymentsheet-example/build/outputs/apk/debug/paymentsheet-example-debug.apk --espresso paymentsheet-example/build/outputs/apk/androidTest/debug/paymentsheet-example-debug-androidTest.apk --is-nightly --num-retries 5

      - name: Notify failure endpoint
        id: notifyFailureEndpoint
        if: failure()
        run: |
          ./scripts/notify_failure_endpoint.rb \
          ${{ secrets.SDK_FAILURE_NOTIFICATION_ENDPOINT }} \
          ${{ secrets.SDK_FAILURE_NOTIFICATION_ENDPOINT_HMAC_KEY }} \
          "https://github.com/stripe/stripe-android/actions/runs/${{ github.run_id }}" \
          RUN_MOBILESDK


Notify Risky Change

name: Notify Risky Change
on:
  pull_request:
    types: [opened, labeled, unlabeled, synchronize]
    paths:
      - 'example/build.gradle'
      - '**-example/build.gradle'

jobs:
  validate-risky-change:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: peter-evans/find-comment@a54c31d7fa095754bfef525c0c8e5e5674c4b4b1
        id: find_comment
        with:
          issue-number: ${{ github.event.pull_request.number }}
          body-includes: Risky Change
      - uses: peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d
        with:
          body: |
            Risky Change

            This is considered a risky change because it adjusts the sample app build.gradle, please review carefully.
            We've seen issues in the past which resulted in failed builds for merchants. Please make sure the build.gradle change is intended.

            By adding the label `accept-risky-change` to this PR, I acknowledge that I'm changing an example app and have verified that the SDK remains in a shippable state.
          edit-mode: replace
          comment-id: ${{ steps.find_comment.outputs.comment-id }}
          issue-number: ${{ github.event.pull_request.number }}
          token: ${{ secrets.GITHUB_TOKEN }}
      - name: Fail if not accepted
        if: "!contains(github.event.pull_request.labels.*.name, 'accept-risky-change')"
        run: exit 1


paymentsheet-example size diff

name: paymentsheet-example size diff
on:
  pull_request:
    paths:
      - 'payments/**'
      - 'payments-core/**'
      - 'payments-model/**'
      - 'stripe-core/**'
      - 'payments-model/**'
      - 'payments-ui-core/**'
      - 'link/**'
      - 'dependencies.gradle'
jobs:
  # Checkout master branch and build the APK
  build-master:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: master
      - uses: ./.github/actions/stripe_setup
      - name: Build in master
        run: ./gradlew :paymentsheet-example:assembleRelease && mv paymentsheet-example/build/outputs/apk/release/paymentsheet-example-release.apk paymentsheet-example/build/outputs/apk/release/paymentsheet-example-release-master.apk
      - name: Upload APK
        uses: actions/upload-artifact@v3
        with:
          name: apk
          path: paymentsheet-example/build/outputs/apk/release/paymentsheet-example-release-master.apk

  # Checkout PR branch and build the APK
  build-pr:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Build from PR
        run: ./gradlew :paymentsheet-example:assembleRelease && mv paymentsheet-example/build/outputs/apk/release/paymentsheet-example-release.apk paymentsheet-example/build/outputs/apk/release/paymentsheet-example-release-pr.apk
      - name: Upload APK
        uses: actions/upload-artifact@v3
        with:
          name: apk
          path: paymentsheet-example/build/outputs/apk/release/paymentsheet-example-release-pr.apk

  # Execute Diffuse only when the two APKs are built successfully
  diffuse:
    needs: [build-master, build-pr]
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - name: Download APKs
        uses: actions/download-artifact@v1
        with:
          name: apk
      - name: diffuse
        id: diffuse
        uses: usefulness/diffuse-action@d816fd102c1f5f69519ee4bb8e0e12a42d005788
        with:
          old-file-path: apk/paymentsheet-example-release-master.apk
          new-file-path: apk/paymentsheet-example-release-pr.apk

      # Post comment with output

      - uses: peter-evans/find-comment@d2dae40ed151c634e4189471272b57e76ec19ba8
        id: find_comment
        with:
          issue-number: ${{ github.event.pull_request.number }}
          body-includes: Diffuse output

      - uses: peter-evans/create-or-update-comment@a35cf36e5301d70b76f316e867e7788a55a31dae
        if: ${{ steps.diffuse.outputs.diff-raw != null || steps.find_comment.outputs.comment-id != null }}
        with:
          body: |
            Diffuse output:

            ${{ steps.diffuse.outputs.diff-gh-comment }}
          edit-mode: replace
          comment-id: ${{ steps.find_comment.outputs.comment-id }}
          issue-number: ${{ github.event.pull_request.number }}
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Upload diffuse output
        uses: actions/upload-artifact@v3
        with:
          name: diffuse-output
          path: ${{ steps.diffuse.outputs.diff-file }}


Upload aabs on push

name: Upload aabs on push
# Upload aabs of example apps when changes are merged to master branch.
# The aab is used as a base reference to compare with aab built from pull requests.

on:
  push:
    branches:
      - master

jobs:
  upload-identity:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Generate Android release bundle for Identity example app
        run: ./gradlew :identity-example:bundleRelease
      - name: Upload artifact to Emerge
        uses: EmergeTools/emerge-upload-action@3477b597fc62054136eb6f499e0ba78144f8a999
        with:
          artifact_path: identity-example/build/outputs/bundle/theme1Release/identity-example-theme1-release.aab
          emerge_api_key: ${{ secrets.EMERGE_API_KEY }}
          build_type: push
  upload-financial-connections:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Generate Android release bundle for Financial Connections example app
        run: ./gradlew :financial-connections-example:bundleRelease
      - name: Upload artifact to Emerge
        uses: EmergeTools/emerge-upload-action@3477b597fc62054136eb6f499e0ba78144f8a999
        with:
          artifact_path: financial-connections-example/build/outputs/bundle/release/financial-connections-example-release.aab
          emerge_api_key: ${{ secrets.EMERGE_API_KEY }}
          build_type: push
  upload-payment-sheet:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/stripe_setup
      - name: Generate Android release bundle for Payment Sheet example app
        run: ./gradlew :paymentsheet-example:bundleRelease
      - name: Upload artifact to Emerge
        uses: EmergeTools/emerge-upload-action@3477b597fc62054136eb6f499e0ba78144f8a999
        with:
          artifact_path: paymentsheet-example/build/outputs/bundle/release/paymentsheet-example-release.aab
          emerge_api_key: ${{ secrets.EMERGE_API_KEY }}
          build_type: push


CI

name: CI

on:
  push:
    branches:
      - master
  pull_request:

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: '21'
      - name: Build
        run: |
          ./gradlew build -Ptest=false

  test:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - uses: gradle/actions/wrapper-validation@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: '17'
      - name: Tests and benchmarks
        run: |
          ./gradlew allTests -Ptest=true


Unit Test

# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle

name: Unit Test

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main, feature/* ]

jobs:
  build:
    name: Mac

    runs-on: macos-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK 17
      uses: actions/setup-java@v1
      with:
        java-version: 17
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
    - name: Build with Gradle
      run: ./gradlew check coverageReport --info --full-stacktrace --console plain


Qodana

name: Qodana

on:
  workflow_dispatch:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main, feature/* ]

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  qodana:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: 'Qodana Scan'
        uses: JetBrains/qodana-action@v2023.1.0
        with:
          cache-default-branch-only: true
      - uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json


SSM Integration Test

# This workflow tests the SSM plugin resolution and installation

name: SSM Integration Test

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main, feature/* ]
    # PRs only need to run this if the SSM plugin logic has changed
    paths:
      - 'jetbrains-core/src/software/aws/toolkits/jetbrains/services/ssm/SsmPlugin.kt'
      - 'jetbrains-core/it/software/aws/toolkits/jetbrains/services/ssm/SsmPluginTest.kt'

jobs:
  build:
    name: ${{ matrix.os }}

    runs-on: ${{ matrix.os }}

    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]

    steps:
      - name: Support longpaths
        run: git config --system core.longpaths true
        if: ${{ matrix.os == 'windows-latest' }}
      - uses: actions/checkout@v2
      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17
      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
      - name: Build with Gradle
        run: ./gradlew :plugin-toolkit:jetbrains-core:integrationTest --info --full-stacktrace --console plain --tests "software.aws.toolkits.jetbrains.services.ssm.SsmPluginTest"


Close stale issues

name: "Close stale issues"

# Controls when the action will run.
on:
  # allows doing a manual trigger of the action and running it on a schedule at 10am PT everyday(converted since expression is anchored to UTC)
  workflow_dispatch:
  schedule:
    - cron: "0 17 * * *"

permissions: {}
jobs:
  cleanup:
    permissions:
      issues: write # to label, comment and close issues (aws-actions/stale-issue-cleanup)

    runs-on: ubuntu-latest
    name: Stale issues
    steps:
      - uses: aws-actions/stale-issue-cleanup@v6
        with:
          # Types of issues that will be processed
          issue-types: issues
          # Setting messages to an empty string will cause the automation to skip
          # that category
          stale-issue-message: This issue is missing required information and will be closed in 7 days. To keep the issue open, leave a comment.
          # this has been added as a placeholder but will likely not be used because the timeline is set as 100 years
          ancient-issue-message: This issue will automatically close because it has stalled for 1 year. To keep the issue open, leave a comment.

          # These labels are required
          stale-issue-label: closing-soon
          exempt-issue-labels: no-autoclose
          response-requested-label: needs-response
          closed-for-staleness-label: closed-for-staleness

          # Issue timing
          days-before-stale: 30
          days-before-close: 7
          # setting this to 100 years to avoid closing valid old issues that are yet to be triaged
          days-before-ancient: 36500

          # If you don't want to mark an issue as being ancient based on a
          # threshold of "upvotes", you can set this here. An "upvote" is
          # the total number of +1, heart, hooray, and rocket reactions
          # on an issue.
          minimum-upvotes-to-exempt: 5

          # Leave this alone, or set to a PAT for the action to use
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          # Testing/debugging options
          loglevel: DEBUG
          # Set dry-run to true to not perform label or close actions.
          dry-run: false


Prerelease

name: Prerelease
on:
  workflow_dispatch:
    inputs:
      tag_name:
        description: 'Tag name for release'
        required: false
        default: prerelease
  push:
    branches: [ main, feature/* ]

jobs:
  generate_artifact_toolkit_standalone:
    strategy:
      matrix:
        supported_versions: [ '2023.3', '2023.2', '2024.1' ]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: remove unwanted dependencies
        run: |
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf /opt/ghc
          sudo rm -rf "/usr/local/share/boost"
          sudo rm -rf "$AGENT_TOOLSDIRECTORY"
      - uses: actions/setup-java@v4
        with:
          distribution: 'corretto'
          java-version: '17'
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '6.x'
      - name: Generate artifact
        run: |
          ./gradlew -PideProfileName=${{ matrix.supported_versions }} :plugin-toolkit:intellij-standalone:buildPlugin
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: plugin-standalone-${{ matrix.supported_versions }}
          path: ./plugins/toolkit/intellij-standalone/build/distributions/*.zip
          retention-days: 1

  generate_artifact_q:
    strategy:
      matrix:
        supported_versions: [ '2023.3', '2023.2', '2024.1' ]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: remove unwanted dependencies
        run: |
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf /opt/ghc
          sudo rm -rf "/usr/local/share/boost"
          sudo rm -rf "$AGENT_TOOLSDIRECTORY"
      - uses: actions/setup-java@v4
        with:
          distribution: 'corretto'
          java-version: '17'
      - name: Generate artifact
        run: |
          ./gradlew -PideProfileName=${{ matrix.supported_versions }} :plugin-amazonq:buildPlugin
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: plugin-amazonq-${{ matrix.supported_versions }}
          path: ./plugins/amazonq/build/distributions/*.zip
          retention-days: 1

  generate_artifact_core:
    strategy:
      matrix:
        supported_versions: [ '2023.3', '2023.2', '2024.1' ]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: remove unwanted dependencies
        run: |
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf /opt/ghc
          sudo rm -rf "/usr/local/share/boost"
          sudo rm -rf "$AGENT_TOOLSDIRECTORY"
      - uses: actions/setup-java@v4
        with:
          distribution: 'corretto'
          java-version: '17'

      - name: Generate artifact
        run: |
          ./gradlew -PideProfileName=${{ matrix.supported_versions }} :plugin-core:buildPlugin
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: plugin-core-${{ matrix.supported_versions }}
          path: ./plugins/core/build/distributions/*.zip
          retention-days: 1

  generate_changelog:
    runs-on: ubuntu-latest
    outputs:
      feature: ${{ steps.assign_output.outputs.feature }}
      tagname: ${{ steps.assign_output.outputs.tagname }}
      version: ${{ steps.assign_output.outputs.version }}
      changes: ${{ steps.assign_output.outputs.changes }}
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-java@v4
        with:
          distribution: 'corretto'
          java-version: '17'

      - if: github.event_name == 'workflow_dispatch'
        run: |
          echo "TAG_NAME=${{ github.event.inputs.tag_name }}" >> $GITHUB_ENV
      - if: github.ref_name != 'main'
        run: |
          TAG_NAME=${{ github.ref_name }}
          FEAT_NAME=$(echo $TAG_NAME | sed 's/feature\///')
          echo "FEAT_NAME=$FEAT_NAME" >> $GITHUB_ENV
          echo "TAG_NAME=pre-$FEAT_NAME" >> $GITHUB_ENV
      - if: github.ref_name == 'main'
        run: |
          echo "FEAT_NAME=" >> $GITHUB_ENV
          echo "TAG_NAME=prerelease" >> $GITHUB_ENV
      - name: Generate changelog
        id: changelog
        run: |
          ./gradlew :createRelease :generateChangelog
      - name: Provide the metadata to output
        id: assign_output
        run: |
          echo "feature=$FEAT_NAME" >> $GITHUB_OUTPUT
          echo "tagname=$TAG_NAME" >> $GITHUB_OUTPUT
          echo "version=$(cat gradle.properties | grep toolkitVersion | cut -d'=' -f2)" >> $GITHUB_OUTPUT
          echo 'changes<<EOF' >> $GITHUB_OUTPUT
          cat CHANGELOG.md | perl -ne 'BEGIN{$/="\n\n"} print; exit if $. == 1' >> $GITHUB_OUTPUT
          echo 'EOF' >> $GITHUB_OUTPUT

  publish:
    needs: [  generate_artifact_toolkit_standalone, generate_artifact_core, generate_artifact_q, generate_changelog ]
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      GH_REPO: ${{ github.repository }}
      FEAT_NAME: ${{ needs.generate_changelog.outputs.feature }}
      TAG_NAME: ${{ needs.generate_changelog.outputs.tagname }}
      AWS_TOOLKIT_VERSION: ${{ needs.generate_changelog.outputs.version }}
      BRANCH: ${{ github.ref_name }}
      AWS_TOOLKIT_CHANGES: ${{ needs.generate_changelog.outputs.changes }}
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
      - name: Delete existing prerelease
        # "prerelease" (main branch) or "pre-<feature>"
        if: "env.TAG_NAME == 'prerelease' || startsWith(env.TAG_NAME, 'pre-')"
        run: |
          echo "SUBJECT=AWS Toolkit ${AWS_TOOLKIT_VERSION}: ${FEAT_NAME:-${TAG_NAME}}" >> $GITHUB_ENV
          gh release delete "$TAG_NAME" --cleanup-tag --yes || true
      - name: Publish to GitHub Releases
        run: |
          envsubst < "$GITHUB_WORKSPACE/.github/workflows/prerelease_notes.md" > "$RUNNER_TEMP/prerelease_notes.md"
          gh release create "$TAG_NAME" --prerelease --notes-file "$RUNNER_TEMP/prerelease_notes.md" --title "$SUBJECT" --target $GITHUB_SHA plugin-standalone-*/*.zip
      - name: Publish core
        run: |
          gh release upload "$TAG_NAME" plugin-core-*/*.zip
      - name: Publish Q
        run: |
          gh release upload "$TAG_NAME" plugin-amazonq-*/*.zip
      - name: Publish XML manifest
        run: |
          gh release view "$TAG_NAME" --repo "$GITHUB_REPOSITORY" --json assets | python3 "$GITHUB_WORKSPACE/.github/workflows/generateUpdatesXml.py" - > updatePlugins.xml
          gh release upload "$TAG_NAME" updatePlugins.xml


Build docs

name: Build docs

# See main.yml
on:
  workflow_dispatch:
  push:
    branches: [ master ]
  pull_request:
    types: [opened, synchronize]
  merge_group:
# Cancel builds if a new commit is pushed, except on master
concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

# Gives the workflow permissions to clone the repo and create a page deployment
permissions:
  id-token: write
  pages: write

env:
  PRODUCT: Writerside/texify-docs
  DOC_ARTIFACT: webHelpTEXIFY-DOCS2-all.zip
  ALGOLIA_ARTIFACT: algolia-indexes-TEXIFY-DOCS.zip
  ALGOLIA_APP_NAME: D5M21MXSWC
  ALGOLIA_INDEX_NAME: TeXiFy-IDEA
  ALGOLIA_KEY: ${{ secrets.ALGOLIA_KEY }}
  CONFIG_JSON_PRODUCT: texify-docs
  CONFIG_JSON_VERSION: master

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
      - name: Build Writerside docs using Docker
        uses: JetBrains/writerside-github-action@v3
      - name: Upload documentation
        uses: actions/upload-artifact@v4
        with:
          name: docs
          path: |
            artifacts/${{ env.DOC_ARTIFACT }}
            artifacts/report.json
          retention-days: 7
      - name: Upload algolia-indexes
        uses: actions/upload-artifact@v4
        with:
          name: algolia-indexes
          path: artifacts/${{ env.ALGOLIA_ARTIFACT }}
          retention-days: 7
  test:
    needs: build
    runs-on: ubuntu-latest

    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          name: docs
          path: artifacts

      - name: Test documentation
        uses: JetBrains/writerside-checker-action@v1
        with:
          instance: ${{ env.INSTANCE }}

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    # Requires the build results
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/master'
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: docs
      - name: Unzip artifact
        uses: montudor/action-zip@v1
        with:
          args: unzip -qq ${{ env.DOC_ARTIFACT }} -d dir
      - name: Setup Pages
        uses: actions/configure-pages@v5
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: dir
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

  publish-indexes:
    needs: build
    runs-on: ubuntu-latest
    container:
      image: registry.jetbrains.team/p/writerside/builder/algolia-publisher:2.0.32-3

    steps:
      - uses: actions/checkout@v3
      - uses: actions/download-artifact@v4
        with:
          name: algolia-indexes
      - uses: montudor/action-zip@v1
        with:
          args: unzip -qq ${{ env.ALGOLIA_ARTIFACT }} -d algolia-indexes
      - run: |
          env "algolia-key=${{env.ALGOLIA_KEY}}" java -jar /opt/builder/help-publication-agent.jar \
          update-index \
          --application-name ${{env.ALGOLIA_APP_NAME}} \
          --index-name ${{env.ALGOLIA_INDEX_NAME}} \
          --product ${{env.CONFIG_JSON_PRODUCT}} \
          --version ${{env.CONFIG_JSON_VERSION}} \
          --index-directory algolia-indexes/ \
          2>&1 | tee algolia-update-index-log.txt


CI

name: CI

on:
  workflow_dispatch:
  push:
    branches: [ master ]
  pull_request:
    types: [opened, synchronize]
  merge_group:
# Cancel builds if a new commit is pushed, except on master
concurrency:
  group: ${{ github.ref }}
  cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
  qodana:
    name: Qodana
    # Note: updating to ubuntu-latest may slow the build and produce a "The runner has received a shutdown signal."
    runs-on: ubuntu-20.04
    if: github.event.pull_request.draft == false
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'zulu'
      - name: Generate lexer/parser
        run: ./gradlew setupDependencies
      - uses: JetBrains/qodana-action@main
        name: Qodana
        with:
          post-pr-comment: false
          pr-mode: false
          args: >
            --baseline,qodana.sarif.json,
            --source-directory,src
          cache-default-branch-only: true
        env:
          QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
      # https://www.jetbrains.com/help/qodana/github.html#GitHub+code+scanning
      - name: Upload SARIF report to GitHub
        # Also upload report if quality gate fails
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json
  test:
    runs-on: ${{ matrix.os }}
    if: github.event.pull_request.draft == false
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
    steps:
    - name: configure Pagefile
      if: matrix.os == 'windows-latest'
      uses: al-cheb/configure-pagefile-action@v1.4
      with:
        minimum-size: 8GB
    - uses: actions/checkout@v4
      with:
        fetch-depth: 2
    - uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'zulu'
    - name: Run linting
      run: |
        chmod +x gradlew
        ./gradlew ktlintCheck
    - name: Run tests
      run: ./gradlew check koverXmlReport
    - name: Upload coverage report
      if: success() && matrix.os == 'ubuntu-latest'
      run: |
        curl -Os https://uploader.codecov.io/latest/linux/codecov
        chmod +x codecov
        ./codecov -t ${CODECOV_TOKEN}


Youtrack Issue Linker

name: "Youtrack Issue Linker"
on:
  issues:
    types:
      - opened
      - edited
  issue_comment:
    types:
      - created
      - edited
  pull_request:
    types:
      - opened
      - edited
  pull_request_review:
    types:
      - submitted
      - edited
  pull_request_review_comment:
    types:
      - created
      - edited

jobs:
  add-youtrack-issue-links:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install dependencies
        run: |
          cd ./.github/actions/insert-youtrack-link
          npm install
      - id: replace
        uses: ./.github/actions/insert-youtrack-link
        with:
          issue-prefix: 'TEX'
          youtrack-base-url: 'https://texify-idea.myjetbrains.com/youtrack'
          repo-token: ${{ secrets.GITHUB_TOKEN }}


Static Analysis

name: Static Analysis

on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main

env:
  GRADLE_OPTS: -Dorg.gradle.daemon=false

jobs:
  commit-lint:
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: wagoid/commitlint-github-action@v6
        with:
          configFile: .commitlintrc.yml
  code-base-checks:
    runs-on: ubuntu-22.04
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4
    - name: Setup Gradle
      uses: gradle/actions/setup-gradle@v3
      with:
        gradle-home-cache-cleanup: true
    - name: Check copyrights, license headers, and .gitattributes
      run: ./gradlew checkCopyrightsInNoticeFile checkLicenseHeaders checkGitAttributes
  detekt-issues:
    runs-on: ubuntu-22.04
    permissions:
      security-events: write
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4
    - name: Setup Gradle
      uses: gradle/actions/setup-gradle@v3
      with:
        gradle-home-cache-cleanup: true
    - name: Check for Detekt Issues
      run: ./gradlew detekt
    - name: Check for Detekt Issues with type resolution
      run: ./gradlew detektMain detektTestFixtures detektTest detektFunTest
    - name: Upload SARIF File
      uses: github/codeql-action/upload-sarif@v3
      if: always() # Upload even if the previous step failed.
      with:
        sarif_file: build/reports/detekt/merged.sarif
  markdown-links:
    runs-on: ubuntu-22.04
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4
    - name: Check Links
      uses: gaurav-nelson/github-action-markdown-link-check@v1
      with:
        base-branch: main
        check-modified-files-only: yes
        max-depth: 2
        use-quiet-mode: yes
  markdownlint:
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup Node
        uses: actions/setup-node@v4
      - name: Check for Markdown issues
        run: |
          npm install -g markdownlint-rule-max-one-sentence-per-line@0.0.2
          npx markdownlint-cli2
  qodana-scan:
    if: ${{ github.event_name == 'pull_request' }}
    runs-on: ubuntu-22.04
    permissions:
      security-events: write
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4
      with:
        fetch-depth: 0
    - name: Qodana Scan
      uses: JetBrains/qodana-action@v2024.1.5
      with:
        post-pr-comment: false
        use-caches: false
    - uses: github/codeql-action/upload-sarif@v3
      with:
        sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json
  reuse-tool:
    runs-on: ubuntu-22.04
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4
    - name: Setup Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.10"
        cache: pip
    - name: Check REUSE Compliance
      run: |
        pip install --user reuse
        ~/.local/bin/reuse lint