Project Verification

name: Project Verification

on:
  workflow_dispatch:
  schedule:
    - cron: "0 0 * * *"

jobs:

  gradleValidation:
    name: Gradle Validation
    uses: ./.github/workflows/reusable-gradleValidation.yml


Nightly Release (scheduled)

name: Nightly Release (scheduled)

# Automatically run the release-nightly job
#
# The scheduled release will be disabled on forks, preventing unnecessary work.

on:
  schedule:
    - cron: "0 0 * * *"

jobs:

  release-nightly:
    if: contains('JetBrains/gradle-intellij-plugin', github.repository)
    uses: ./.github/workflows/release-nightly.yml
    secrets: inherit


Nightly Release

name: Nightly Release
on:
  workflow_dispatch:
    inputs:
      skipTests:
        description: 'Skip tests'
        required: false
        default: false
        type: boolean
  workflow_call:

jobs:

  gradleValidation:
    name: Gradle Validation
    uses: ./.github/workflows/reusable-gradleValidation.yml

  unitTests:
    if: ${{ !inputs.skipTests }}
    name: Unit Tests
    needs: gradleValidation
    uses: ./.github/workflows/reusable-unitTests.yml

  integrationTests:
    if: ${{ !inputs.skipTests }}
    name: Integration Tests
    needs: [ gradleValidation, unitTests ]
    uses: ./.github/workflows/reusable-integrationTests.yml

  #  integrationTestsEAP:
  #    name: Integration Tests EAP
  #    needs: gradleValidation
  #    uses: ./.github/workflows/reusable-integrationTests.yml
  #    with:
  #      platformVersion: 222-EAP-SNAPSHOT

  codeInspection:
    if: ${{ !inputs.skipTests }}
    name: Code Inspection
    needs: gradleValidation
    uses: ./.github/workflows/reusable-codeInspection.yml

  # Prepare and publish the Gradle Plugins repository
  release:
    name: Release to Gradle Plugins
    needs:
      - unitTests
      - integrationTests
      #      - integrationTestsEAP
      - codeInspection
    if: always()
    runs-on: ubuntu-latest
    steps:

      # Fail if the conditional job failed
      - name: Safety Check
        if: ${{ contains(needs.*.result, 'failure') }}
        run: exit 1

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.release.tag_name }}

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          distribution: zulu
          java-version: 11

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3
        with:
          gradle-home-cache-cleanup: true

      # Publish the plugin to the Gradle Plugins
      - name: Publish Plugin
        env:
          OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
          OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
        run: ./gradlew publish -Psnapshot=true -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD

      # Store already-built plugin as an artifact for downloading
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          path: ./build/libs/*-SNAPSHOT.jar


Release

name: Release

on:
  release:
    types: [prereleased, released]

jobs:

  # Prepare and publish the Gradle Plugins repository
  release:
    name: Release to Gradle Plugins
    runs-on: ubuntu-latest
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.release.tag_name }}

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          distribution: zulu
          java-version: 11

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3
        with:
          gradle-home-cache-cleanup: true

      # Set environment variables
      - name: Export Properties
        id: properties
        shell: bash
        run: |
          CHANGELOG="$(cat << 'EOM' | sed -e 's/^[[:space:]]*$//g' -e '/./,$!d'
          ${{ github.event.release.body }}
          EOM
          )"

          echo "changelog<<EOF" >> $GITHUB_OUTPUT
          echo "$CHANGELOG" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      # Update Unreleased section with the current release note
      - name: Patch Changelog
        if: ${{ steps.properties.outputs.changelog != '' }}
        env:
          CHANGELOG: ${{ steps.properties.outputs.changelog }}
        run: |
          ./gradlew patchChangelog --release-note="$CHANGELOG"

      # Publish the plugin to the Gradle Plugins
      - name: Publish Plugin
        env:
          GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }}
          GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }}
        run: ./gradlew publishPlugins -Pgradle.publish.key=$GRADLE_PUBLISH_KEY -Pgradle.publish.secret=$GRADLE_PUBLISH_SECRET

      # Upload artifact as a release asset
      - name: Upload Release Asset
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: gh release upload ${{ github.event.release.tag_name }} ./build/libs/*

      # Create pull request
      - name: Create Pull Request
        if: ${{ steps.properties.outputs.changelog != '' }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          VERSION="${{ github.event.release.tag_name }}"
          BRANCH="changelog-update-$VERSION"
          LABEL="release changelog"

          git config user.email "action@github.com"
          git config user.name "GitHub Action"

          git checkout -b $BRANCH
          git commit -am "Changelog update - $VERSION"
          git push --set-upstream origin $BRANCH

          gh label create "$LABEL" \
            --description "Pull requests with release changelog update" \
            || true

          gh pr create \
            --title "Changelog update - \`$VERSION\`" \
            --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \
            --label "$LABEL" \
            --head $BRANCH


Reusable Code Inspection

name: Reusable Code Inspection

on: [ workflow_call ]

jobs:
  codeInspection:
    name: Code Inspection
    runs-on: ubuntu-latest
    steps:

      - name: Fetch Sources
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # only report issues that appeared in a PR

      - name: Qodana - Code Inspection
        uses: JetBrains/qodana-action@v2023.3.1
        if: ${{ false }}  # disable for now


Reusable Gradle Wrapper Test

name: Reusable Gradle Wrapper Test

on: [ workflow_call ]

jobs:
  gradleValidation:
    name: Gradle Wrapper
    runs-on: ubuntu-latest
    steps:

      - name: Fetch Sources
        uses: actions/checkout@v4

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          distribution: zulu
          java-version: 11

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3
        with:
          gradle-home-cache-cleanup: true

      - name: Gradle Wrapper Validation
        uses: gradle/wrapper-validation-action@v2.1.1


Reusable Integration Tests

name: Reusable Integration Tests

on:
  workflow_call:
    inputs:
      platformVersion:
        required: false
        default: 2022.1.4
        type: string

jobs:
  integrationTests:
    name: Gradle ${{ matrix.gradleVersion }} @ ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        gradleVersion:
          - "7.6"
          - "8.6"
        os:
          - windows-latest
          - ubuntu-latest
          - macos-latest

    steps:

      - name: Fetch Sources
        uses: actions/checkout@v4

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          distribution: zulu
          java-version: 11

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3
        with:
          gradle-home-cache-cleanup: true

      - name: Run Tests
        env:
          TEST_NAME: ${{ inputs.testName }}
        shell: bash
        run: |
          [ -z "$TEST_NAME" ] && TESTS="" || TESTS="--tests $TEST_NAME"

          ./gradlew integrationTest \
            -PtestGradleVersion="${{ matrix.gradleVersion }}" \
            ${{ runner.os == 'Windows' && '-PtestGradleUserHome="C:\\testGradleHome"' || '' }} \
            --console=plain

      - name: Test Report
        uses: dorny/test-reporter@v1
        if: ${{ always() }}
        with:
          name: "Integration Tests Report: Gradle ${{ matrix.gradleVersion }} @ ${{ matrix.os }}"
          path: "**/build/test-results/*/TEST-*.xml"
          reporter: java-junit

      - name: Collect Test Results
        if: ${{ always() }}
        uses: actions/upload-artifact@v4
        with:
          name: integration-tests-${{ matrix.gradleVersion }}-${{ runner.os }}
          path: |
            ${{ github.workspace }}/build/reports/tests
            ${{ github.workspace }}/build/reports/configuration-cache


Single Unit Test

name: Single Unit Test

on:
  workflow_call:
    inputs:
      gradleVersion:
        type: string
        required: true
        description: 'Gradle version – see: https://github.com/gradle/gradle/releases'
      os:
        type: string
        required: true
        description: 'Operation system'
      testName:
        type: string
        required: false
        description: 'Optional test name to run'

jobs:
  unitTests:
    name: Gradle ${{ inputs.gradleVersion }} @ ${{ inputs.os }}
    runs-on: ${{ inputs.os }}
    permissions:
      checks: write
    steps:

      # Free GitHub Actions Environment Disk Space
      - name: Maximize Build Space
        if: runner.os == 'Linux'
        uses: jlumbroso/free-disk-space@main
        with:
          tool-cache: false
          large-packages: false

      - name: Fetch Sources
        uses: actions/checkout@v4

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          distribution: zulu
          java-version: 11

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3
        with:
          gradle-home-cache-cleanup: true

      - name: Run Tests
        env:
          TEST_NAME: ${{ inputs.testName }}
        shell: bash
        run: |
          [ -z "$TEST_NAME" ] && TESTS="" || TESTS="--tests $TEST_NAME"

          ./gradlew check test \
            -PtestGradleVersion="${{ inputs.gradleVersion }}" \
            ${{ runner.os == 'Windows' && '-PtestGradleUserHome="C:\\testGradleHome"' || '' }} \
            $TESTS \
            --console=plain

      - name: Test Report
        uses: dorny/test-reporter@v1
        if: ${{ always() }}
        with:
          name: "Unit Tests Report: Gradle ${{ inputs.gradleVersion }} @ ${{ inputs.os }}"
          path: "**/build/test-results/*/TEST-*.xml"
          reporter: java-junit

      - name: Collect Test Results
        if: ${{ always() }}
        uses: actions/upload-artifact@v4
        with:
          name: unit-tests-${{ inputs.gradleVersion }}-${{ runner.os }}
          path: |
            ${{ github.workspace }}/build/reports/tests
            ${{ github.workspace }}/build/reports/configuration-cache


Reusable Unit Tests

name: Reusable Unit Tests

on: [ workflow_call ]

jobs:
  baseUnitTest:
    name: Gradle 8.5 @ ubuntu-latest
    uses: ./.github/workflows/reusable-single-unitTest.yml
    with:
      gradleVersion: "8.5"
      os: ubuntu-latest

  unitTests:
    name: Gradle ${{ matrix.gradleVersion }} @ ${{ matrix.os }}
    needs: baseUnitTest
    uses: ./.github/workflows/reusable-single-unitTest.yml
    with:
      gradleVersion: ${{ matrix.gradleVersion }}
      os: ${{ matrix.os }}

    strategy:
      fail-fast: false
      matrix:
        gradleVersion:
          - "7.6"
          - "8.6"
        os:
          - windows-latest
          - ubuntu-latest
          - macos-latest
        exclude:
          - os: ubuntu-latest
            gradleVersion: "8.5"


Manual Unit Tests

name: Manual Unit Tests
on:
  workflow_dispatch:
    inputs:
      testName:
        description: "Test name"
        required: false
        type: string
      gradleVersion:
        description: "Gradle Version"
        required: true
        type: string
        default: "8.5"
      os:
        description: "Operation System"
        required: true
        type: choice
        options:
          - ubuntu-latest
          - windows-latest
          - macos-latest
  workflow_call:

jobs:
  unitTest:
    name: Gradle ${{ inputs.gradleVersion }} @ ${{ inputs.os }}
    uses: ./.github/workflows/reusable-single-unitTest.yml
    with:
      gradleVersion: ${{ inputs.gradleVersion }}
      os: ${{ inputs.os }}
      testName: ${{ inputs.testName }}


Auto-commit generated code

name: Auto-commit generated code

on:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest

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

      - name: Set up JDK 11
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '11'

      - name: Run Gradle task
        run: ./gradlew :core:processKDocsMain

      - name: Commit changes
        run: |
          git config --global user.name 'github-actions[bot]'
          git config --global user.email 'github-actions[bot]@users.noreply.github.com'
          git add ./core/generated-sources
          git diff --staged --quiet || git commit -m "Automated commit of generated code"
          git push
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


Show generated code in PR

name: Show generated code in PR

on:
  pull_request:
    types:
      - edited
      - opened
      - synchronize
      - converted_to_draft
      - ready_for_review

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Cancel Previous Runs
        uses: styfle/cancel-workflow-action@0.9.1
        with:
          access_token: ${{ github.token }}

      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Set up JDK 11
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '11'

      - name: Configure Git User
        run: |
          git config --global user.email "actions@github.com"
          git config --global user.name "GitHub Actions"

      - name: Run Gradle task
        run: ./gradlew :core:processKDocsMain

      - name: Check for changes in generated sources
        id: git-diff
        run: echo "::set-output name=changed::$(if git diff --quiet './core/generated-sources'; then echo 'false'; else echo 'true'; fi)"

      - name: Commit and push if changes
        id: git-commit
        if: steps.git-diff.outputs.changed == 'true'
        run: |
          git checkout -b generated-sources/docs-update-${{ github.run_number }}
          git add './core/generated-sources'
          git commit -m "Update generated sources with recent changes"
          git push origin generated-sources/docs-update-${{ github.run_number }}
          echo "::set-output name=commit::$(git rev-parse HEAD)"

      - name: Remove old comments
        uses: actions/github-script@v5
        if: steps.git-diff.outputs.changed == 'true'
        with:
          # language=js
          script: |
            const issue_number = context.issue.number;
            const {owner, repo} = context.repo;

            const comments = await github.rest.issues.listComments({
                issue_number,
                owner,
                repo,
            });

            const botComments = comments.data.filter(
                (comment) => comment.user.login === 'github-actions[bot]'
            );

            for (const comment of botComments) {
                await github.rest.issues.deleteComment({
                    comment_id: comment.id,
                    owner,
                    repo,
                });
            }

      - name: Add comment to PR
        uses: actions/github-script@v5
        if: steps.git-diff.outputs.changed == 'true'
        with:
          # language=js
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: "Generated sources will be updated after merging this PR.\nPlease inspect the changes in [here](https://github.com/${{ github.repository }}/commit/${{ steps.git-commit.outputs.commit }}).",
            });


Validate Gradle Wrapper

name: "Validate Gradle Wrapper"
on: [push, pull_request]

jobs:
  validation:
    name: "Validation"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: gradle/wrapper-validation-action@v2


Build docs

name: Build docs

on:
  # Specify to run a workflow manually from the Actions tab on GitHub.
  workflow_dispatch:

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

env:
  PRODUCT: StardustDocs/d
  ARTIFACT: webHelpD2-all.zip
  ALGOLIA_ARTIFACT: algolia-indexes-D.zip
  ALGOLIA_APP_NAME: JWPLKSKZVF
  ALGOLIA_INDEX_NAME: prod_DATAFRAME_HELP
  ALGOLIA_KEY: ${{ secrets.ALGOLIA_KEY }}
  CONFIG_JSON_PRODUCT: Dataframe
  CONFIG_JSON_VERSION: '0.13'

jobs:
  build-job:
    runs-on: ubuntu-latest
    container: registry.jetbrains.team/p/writerside/builder/writerside-builder:2.1.1481-p3872-df
    outputs:
      artifact: ${{ steps.generate-artifact.outputs.artifact }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
      - name: Prepare for build
        run: |
          apt-get update
          apt-get install -y zip
          mkdir -p artifacts
      - name: Build docs # and include sitemap.xml TODO: uncomment when sitemap.xml is available
        run: |
          export DISPLAY=:99
          Xvfb :99 &
          /opt/builder/bin/idea.sh helpbuilderinspect -source-dir . -product $PRODUCT --runner github -output-dir artifacts/ || true
          test -e artifacts/$ARTIFACT && echo $ARTIFACT exists
#          cp docs/StardustDocs/sitemap.xml artifacts/sitemap.xml
#          cd artifacts
#          zip -r $ARTIFACT sitemap.xml
        working-directory: ${{ github.workspace }}
      - name: Upload modified documentation artifact
        uses: actions/upload-artifact@v3
        with:
          name: help
          path: artifacts/${{ env.ARTIFACT }}
          retention-days: 7
      - name: Upload algolia-indexes
        uses: actions/upload-artifact@v3
        with:
          name: algolia-indexes
          path: artifacts/${{ env.ALGOLIA_ARTIFACT }}
          retention-days: 7

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    # Requires the build-job results
    needs: build-job
    runs-on: ubuntu-latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v3
        with:
          name: help
      - name: Unzip artifact
        uses: montudor/action-zip@v1
        with:
          args: unzip -qq ${{ env.ARTIFACT }} -d dir
      - name: Setup Pages
        uses: actions/configure-pages@v2
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v1
        with:
          path: dir
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v1

  publish-indexes:
    # Requires the build-job results
    needs: build-job
    runs-on: ubuntu-latest
    container:
        image: registry.jetbrains.team/p/writerside/builder/algolia-publisher:2.0.32-2

    steps:
        - uses: actions/checkout@v3
        - uses: actions/download-artifact@v3
          with:
              name: algolia-indexes
        - uses: montudor/action-zip@v1
          with:
              args: unzip -qq algolia-indexes-D.zip -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


Build

name: Build
on: [pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2.3.1
        with:
          submodules: recursive

      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@v41

      - name: Check changed files
        run: |
          for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
            ./gradlew clean run --args="verbose singleChainCheck $file"
          done

      - name: Build
        run: |
          ./gradlew run


name: Build
on:
  push:
    branches: [ master ]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2.3.1
        with:
          submodules: recursive
      - name: Build
        run: |
          ./gradlew run
      - name: Set Node.js 18.x
        uses: actions/setup-node@v3
        with:
          node-version: 18.x
      - name: Run yarn install
        uses: borales/actions-yarn@v4
        with:
         dir: 'website'
         cmd: install # will run `yarn install` command
      - name: Run yarn build
        uses: borales/actions-yarn@v4
        with:
          dir: 'website'
          cmd: run build # will run `yarn test` command
      - name: Merge
        run: |
          cp -a output/. website/public/
      - name: Deploy
        uses: JamesIves/github-pages-deploy-action@4.1.4
        with:
          branch: gh-pages
          folder: website/public


on:
  pull_request_target:
    types: [closed]
jobs:
  comment_on_merged_pr:
    if: github.event.pull_request.merged
    runs-on: ubuntu-latest
    name: Comment after PR merge
    steps:
      - name: Comment PR
        uses: thollander/actions-comment-pull-request@v2
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          message: |
            PR merged - please consider contributing some funds to lists.eth


Run PR Checks

name: Run PR Checks

on:
  pull_request:

jobs:
  validate_icons:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 0

    - uses: nrwl/nx-set-shas@v3
      id: last_successful_commit_push
      with:
        main-branch-name: master
        workflow-id: 'pr_checks.yml'

    - name: Get changed icons
      id: changed-icons
      uses: tj-actions/changed-files@v41
      with:
        files: _data/icons/*.json
        base_sha: ${{ steps.last_successful_commit_push.outputs.base }}

    - name: Get changed icon blobs
      id: changed-icon-blobs
      uses: tj-actions/changed-files@v41
      with:
        files: _data/iconsDownload/*
        base_sha: ${{ steps.last_successful_commit_push.outputs.base }}

    - run: sudo apt-get -y install jq curl exiftool

    - name: Verify the changed icons
      if: steps.changed-icons.outputs.any_changed == 'true'
      run: |
        set -euo pipefail

        BAD=0

        CHANGED_ICON_BLOBS=(${{ steps.changed-icon-blobs.outputs.all_changed_files }})

        for CHANGED_FILE in ${{ steps.changed-icons.outputs.all_changed_files }}; do
          echo "Checking icon $CHANGED_FILE"
          URL=$(cat "$CHANGED_FILE" | jq '.[0].url' -r)
          if [[ "$URL" =~ ^ipfs://([A-Za-z0-9]+)$ ]]; then
            IPFS_HASH=${BASH_REMATCH[1]}

            if [[ "${CHANGED_ICON_BLOBS[*]} " =~ "_data/iconsDownload/$IPFS_HASH " ]]; then
              TARGET_FILE="_data/iconsDownload/$IPFS_HASH"
            else
              echo "Trying to download the image..."
              TARGET_FILE=icon
              curl -Lo icon "https://cloudflare-ipfs.com/ipfs/$IPFS_HASH" 2>/dev/null
            fi

            METADATA=$(exiftool $TARGET_FILE -json)

            SCHEMA_WIDTH=$(cat "$CHANGED_FILE" | jq '.[0].width' -r)
            SCHEMA_HEIGHT=$(cat "$CHANGED_FILE" | jq '.[0].height' -r)
            SCHEMA_TYPE=$(cat "$CHANGED_FILE" | jq '.[0].format' -r)
            META_WIDTH=$(echo "$METADATA" | jq '.[0].ImageWidth' -r)
            META_HEIGHT=$(echo "$METADATA" | jq '.[0].ImageHeight' -r)
            META_TYPE=$(echo "$METADATA" | jq '.[0].FileTypeExtension' -r)

            if [ "$SCHEMA_WIDTH" != "$META_WIDTH" ]; then
              echo "Expected width $SCHEMA_WIDTH, got $META_WIDTH"
              BAD=1
            fi

            if [ "$SCHEMA_HEIGHT" != "$META_HEIGHT" ]; then
              echo "Expected height $SCHEMA_HEIGHT, got $META_HEIGHT"
              BAD=1
            fi

            case "$SCHEMA_TYPE" in
              png)
                if [ "$META_TYPE" != "png" ]; then
                  echo "Expected type png, got $META_TYPE"
                  BAD=1
                fi
                ;;
              jpg)
                if [ "$META_TYPE" != "jpg" ]; then
                  echo "Expected type jpg, got $META_TYPE"
                  BAD=1
                fi
                ;;
              svg)
                if [ "$META_TYPE" != "svg" ]; then
                  echo "Expected type svg, got $META_TYPE"
                  BAD=1
                fi
                ;;
              *)
                echo "Expected type png, jpg, or svg, got $SCHEMA_TYPE"
                BAD=1
                ;;
            esac
          else
            echo "Expected an IPFS URL, got $URL"
            BAD=1
          fi
        done
        exit $BAD

  validate_formatting:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 0

    - uses: nrwl/nx-set-shas@v3
      id: last_successful_commit_push
      with:
        main-branch-name: master
        workflow-id: 'pr_checks.yml'

    - name: Get changed files
      id: changed-files
      uses: tj-actions/changed-files@v41
      with:
        files: _data/*/*.json
        base_sha: ${{ steps.last_successful_commit_push.outputs.base }}

    - run: sudo npm i -g prettier

    - name: Verify the changed icons
      if: steps.changed-files.outputs.any_changed == 'true'
      run: |
        set -euo pipefail

        BAD=0

        for CHANGED_FILE in ${{ steps.changed-files.outputs.all_changed_files }}; do
          echo "Checking $CHANGED_FILE"
          diff -u "$CHANGED_FILE" <(prettier "$CHANGED_FILE")
        done


Run prettier check

name: Run prettier check

on:
  push:

jobs:
  prettier:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repo
        uses: actions/checkout@v2
      - uses: actions/cache@v2
        name: Configure npm caching
        with:
          path: ~/.npm
          key: ${{ runner.os }}-npm-${{ hashFiles('**/workflows/prettier.yml') }}
          restore-keys: |
            ${{ runner.os }}-npm-
      - name: Run prettier
        run: |-
          npx prettier --check '_data/*/*.json'


Run prettier write

name: Run prettier write

on:
  pull_request:

jobs:
  prettier:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repo
        uses: actions/checkout@v2
        env:
          PAT: ${{ secrets.PAT }}
        with:
          token: ${{ PAT }}
          repository: ${{ github.event.pull_request.head.repo.full_name }}
          ref: ${{ github.event.pull_request.head.ref }}
      - uses: actions/cache@v2
        name: Configure npm caching
        with:
          path: ~/.npm
          key: ${{ runner.os }}-npm-${{ hashFiles('**/workflows/prettier.yml') }}
          restore-keys: |
            ${{ runner.os }}-npm-
      - name: Run prettier
        run: |-
          npx prettier --write '_data/*/*.json'
      - name: Commit changes
        uses: EndBug/add-and-commit@v9
        with:
          message: 'Fix formatting'


Automatic Rebase

name: Automatic Rebase
on:
  issue_comment:
    types: [created]
jobs:
  rebase:
    name: Rebase
    runs-on: ubuntu-latest
    if: >-
      github.event.issue.pull_request != '' &&
      (
        contains(github.event.comment.body, '/rebase') ||
        contains(github.event.comment.body, '/autosquash')
      )
    steps:
      - name: Checkout the latest code
        uses: actions/checkout@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
      - name: Automatic Rebase
        uses: cirrus-actions/rebase@1.7
        with:
          autosquash: ${{ contains(github.event.comment.body, '/autosquash') || contains(github.event.comment.body, '/rebase-autosquash') }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


Close stale issues and PRs

name: 'Close stale issues and PRs'
on:
  schedule:
    - cron: '30 1 * * *'

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@v4
        with:
          stale-issue-message: 'This issue has no activity in a while - it will be closed soon.'
          exempt-issue-labels: enhancement
          stale-pr-message: 'This PR has no activity in a while - it will be closed soon.'
          days-before-stale: 42
          days-before-close: 7


Check JSON Schema

name: Check JSON Schema

on:
  push:
  pull_request:

jobs:
  validate_json:
    runs-on: ubuntu-latest
    steps:
    - name: Check out repo
      uses: actions/checkout@v2
    - uses: actions/cache@v2
      name: Configure npm caching
      with:
        path: ~/.npm
        key: ${{ runner.os }}-npm-${{ hashFiles('**/workflows/validate_json.yml') }}
        restore-keys: |
          ${{ runner.os }}-npm-
    - name: Run JSON Validation
      working-directory: ./tools
      run: |-
        npm install
        node schemaCheck.js


Java CI

name: Java CI

on: [ push, pull_request, workflow_dispatch ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout latest code
        uses: actions/checkout@v2

      - name: Set outputs
        id: vars
        run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"

      - name: Set up JDK 21
        uses: actions/setup-java@v2
        with:
          distribution: 'temurin'
          java-version: 21

      - name: Setup build cache
        uses: actions/cache@v2.1.6
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - run: ./gradlew build --full-stacktrace

      - uses: actions/upload-artifact@v2
        with:
          name: eco-dev-${{ steps.vars.outputs.sha_short }}
          path: build/libs


PR Alert for Master Branch

name: PR Alert for Master Branch
on:
  pull_request:
    branches:
      - master

jobs:
  alert:
    runs-on: ubuntu-latest
    steps:
      - name: Comment PR
        uses: actions/github-script@v5
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          script: |
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '⚠ PRs should not be opened against the `master` branch directly. Please use the `develop` branch as the base for your PRs. ⚠'
            })


Publish release

name: Publish release

on:
  release:
    types: [published]

jobs:
  publish-release:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout latest code
        uses: actions/checkout@v2

      - name: Set up JDK 21
        uses: actions/setup-java@v2
        with:
          distribution: 'temurin'
          java-version: 21

      - name: Setup build cache
        uses: actions/cache@v2.1.6
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Publish artifact
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
          MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}

        # The GITHUB_REF tag comes in the format 'refs/tags/xxx'.
        # So if we split on '/' and take the 3rd value, we can get the release name.
        run: |
          NEW_VERSION=$(echo "${GITHUB_REF}" | cut -d "/" -f3)
          echo "New version: ${NEW_VERSION}"
          echo "Github username: ${GITHUB_ACTOR}"
          ./gradlew -Pversion=${NEW_VERSION} publish


Publish API (Dev)

name: Publish API (Dev)

on: [ push, pull_request ]

jobs:
  publish-release:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout latest code
        uses: actions/checkout@v2

      - name: Set outputs
        id: vars
        run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"

      - name: Set up JDK 21
        uses: actions/setup-java@v2
        with:
          distribution: 'temurin'
          java-version: 21

      - name: Setup build cache
        uses: actions/cache@v2.1.6
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - name: Publish artifact
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

        # The GITHUB_REF tag comes in the format 'refs/tags/xxx'.
        # So if we split on '/' and take the 3rd value, we can get the release name.
        run: |
          NEW_VERSION=$(echo "${GITHUB_REF}" | cut -d "/" -f3)
          echo "New version: ${{ steps.vars.outputs.sha_short }}"
          echo "Github username: ${GITHUB_ACTOR}"
          ./gradlew -Pversion=dev-${{ steps.vars.outputs.sha_short }} publish


Dependency Submission

name: Dependency Submission

on:
  push:
    branches:
      - 'develop'

permissions:
  contents: write

jobs:
  dependency-submission:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: 17
      - name: Generate and submit dependency graph
        uses: gradle/actions/dependency-submission@v3


ReadMe Production GitHub Action 🦉

# This GitHub Actions workflow syncs Markdown files to the Bloomreach production documentation site.
name: ReadMe Production GitHub Action 🦉

on:
  push:
    branches:
      # This workflow will run every time you push code to the following branch: `main`
      # Check out GitHub's docs for more info on configuring this:
      # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows
      - main

jobs:
  rdme-docs:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repo 📚
        uses: actions/checkout@v4

      - name: Run `docs` command 🚀
        uses: readmeio/rdme@v8
        with:
          rdme: docs Documentation --key=${{ secrets.README_PRODUCTION_API_KEY }} --version=2


ReadMe Sandbox GitHub Action 🦉

# This GitHub Actions workflow syncs Markdown files to the Bloomreach sandbox documentation site.
name: ReadMe Sandbox GitHub Action 🦉

on:
  push:
    branches:
      # This workflow will run every time you push code to the following branch: `develop`
      # Check out GitHub's docs for more info on configuring this:
      # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows
      - develop

jobs:
  rdme-docs:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repo 📚
        uses: actions/checkout@v4

      - name: Run `docs` command 🚀
        uses: readmeio/rdme@v8
        with:
          rdme: docs Documentation --key=${{ secrets.README_SANDBOX_API_KEY }} --version=2


API compatibility verification

name: API compatibility verification

on:
  pull_request:
    types: [ opened, synchronize, reopened, labeled, unlabeled ]
    branches: [ main ]

jobs:
  api-compat-verification:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Check for API compatibility
        if: ${{ !contains(github.event.pull_request.labels.*.name, 'acknowledge-api-break') }}
        run: |
          git fetch origin ${{ github.base_ref }} --depth 1 && \
          git diff remotes/origin/${{ github.base_ref }} --numstat "*.api" | awk '
            BEGIN { s = 0 }

            # git diff numstat shows lines deleted in field 2, hence sum up field 2 across all items
            { s += $2 }

            # exit with the number of lines deleted as the result code so that `if failure()` works below
            END { exit s }
          '
      - name: Error message
        if: ${{ failure() }}
        run: |
          echo "::error ::This change modifies the public API in a way that may be backwards-incompatible. Carefully review this pull request and either:"
          echo "::error ::* Revert the changes which caused the API incompatibility –or–"
          echo "::error ::* Add the 'acknowledge-api-break' label to this PR (in rare cases warranting an API breakage)"
          exit 1


Changelog verification

name: Changelog verification

on:
  pull_request:
    types: [ opened, synchronize, reopened, labeled, unlabeled ]
    branches: [ main ]

jobs:
  changelog-verification:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Check for changelog entry
        if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-changelog') }}
        run: |
          git fetch origin ${{ github.base_ref }} --depth 1 && \
          git diff remotes/origin/${{ github.base_ref }} --name-only | grep -P "\.changes/[0-9a-f-]+\.json"
      - name: Error message
        if: ${{ failure() }}
        run: |
          echo "::error ::No new/updated changelog entry found in /.changes directory. Please either:"
          echo "::error ::* Add a changelog entry (see CONTRIBUTING.md for instructions) –or–"
          echo "::error ::* Add the 'no-changelog' label to this PR (in rare cases not warranting a changelog entry)"
          exit 1


Closed Issue Message

name: Closed Issue Message
on:
    issues:
       types: [closed]
jobs:
    auto_comment:
        runs-on: ubuntu-latest
        steps:
        - uses: aws-actions/closed-issue-message@v1
          with:
            # These inputs are both required
            repo-token: "${{ secrets.GITHUB_TOKEN }}"
            message: |
                     ### ⚠COMMENT VISIBILITY WARNING⚠
                     Comments on closed issues are hard for our team to see.
                     If you need more assistance, please either tag a team member or open a new issue that references this one.
                     If you wish to keep having a conversation with other community members under this issue feel free to do so.


AWS CodeBuild CI

name: AWS CodeBuild CI

on:
  release:
    types: [ published ]
  pull_request:
    types: [ opened, synchronize, reopened, labeled, unlabeled ]
    branches: [ main ]
  workflow_dispatch:
    inputs:
      aws-sdk-kotlin-pr:
        description: aws-sdk-kotlin PR number (optional)
        type: number
        required: false
      smithy-kotlin-pr:
        description: smithy-kotlin PR number (optional)
        type: number
        required: false
      check-pr:
        description: I verified that the PRs are not running any malicious code (If running for an external contributor)
        required: true
        type: boolean
        default: false

env:
  SDK_PR: ${{ inputs.aws-sdk-kotlin-pr }}
  SMITHY_PR: ${{ inputs.smithy-kotlin-pr }}

permissions:
  id-token: write
  contents: read
  pull-requests: write

# Allow one instance of this workflow per pull request, and cancel older runs when new changes are pushed
concurrency:
  group: ci-codebuild-${{ github.ref }}
  cancel-in-progress: true

jobs:
  e2e-tests:
    if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
    runs-on: ubuntu-latest
    steps:
      - name: Verify PRs are not running malicious code
        if: ${{ (inputs.aws-sdk-kotlin-pr != '' || inputs.smithy-kotlin-pr != '') && inputs.check-pr == false }}
        run: |
          echo Please verify the PRs are not running any malicious code and mark the checkbox true when running the workflow
          exit 1
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.CI_AWS_ROLE_ARN }}
          aws-region: us-west-2
      - name: Run E2E Tests
        id: e2e-tests
        uses: aws-actions/aws-codebuild-run-build@v1
        with:
          project-name: gh-aws-sdk-kotlin-e2e-tests
          env-vars-for-codebuild: SDK_PR, SMITHY_PR
      - name: Cancel build
        if: ${{ cancelled() }}
        env:
          BUILD_ID: ${{ steps.e2e-tests.outputs.aws-build-id }}
        run: |
          if [ ! -z "$BUILD_ID"]; then
            echo "cancelling in-progress build: id=$BUILD_ID"
            aws codebuild stop-build --id $BUILD_ID
          fi

  service-check-batch-and-artifact-size-metrics:
    if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
    runs-on: ubuntu-latest
    steps:
      - name: Verify PRs are not running malicious code
        if: ${{ (inputs.aws-sdk-kotlin-pr != '' || inputs.smithy-kotlin-pr != '') && inputs.check-pr == false }}
        run: |
          echo Please verify the PRs are not running any malicious code and mark the checkbox true when running the workflow
          exit 1
      - name: Checkout sources
        uses: actions/checkout@v2
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.CI_AWS_ROLE_ARN }}
          aws-region: us-west-2
      - name: Run Service Check Batch and Calculate Artifact Size Metrics
        id: svc-check-batch
        run: |
          REPOSITORY=$(echo ${{ github.repository }} | cut -d '/' -f 2)
          PULL_REQUEST=""
          INTERNAL=${{ github.event.number }}
          EXTERNAL=${{ inputs.aws-sdk-kotlin-pr }}

          if [ ! -z "$INTERNAL" ]; then
            PULL_REQUEST=${{ github.event.number }}
            echo "Identified this an internal pull request build: $PULL_REQUEST"
          elif [ ! -z "$EXTERNAL" ]; then
            PULL_REQUEST=${{ inputs.aws-sdk-kotlin-pr }}
            echo "Identified this as an external pull request build: $PULL_REQUEST"
          else
            echo "Couldn't identify this as an internal or external pull request"
            exit 1
          fi

          .github/scripts/run-codebuild-batch-job.sh \
            --project gh-aws-sdk-kotlin-svc-check-batch \
            --source ${{ github.event.pull_request.head.sha }} \
            --pr-number $PULL_REQUEST \
            --repository $REPOSITORY \
            --external-contributor-sdk-pr-number ${{ inputs.aws-sdk-kotlin-pr }} \
            --external-contributor-smithy-pr-number ${{ inputs.smithy-kotlin-pr }}
      - name: Cancel build
        if: ${{ cancelled() }}
        env:
          BUILD_ID: ${{ steps.svc-check-batch.outputs.aws-build-id }}
        run: |
          if [ ! -z "$BUILD_ID" ]; then
            echo "cancelling in-progress batch build: id=$BUILD_ID"
            aws codebuild stop-build --id $BUILD_ID
          fi
      - name: Collect Artifact Size Metrics
        run: |
          PULL_REQUEST=""
          INTERNAL=${{ github.event.number }}
          EXTERNAL=${{ inputs.aws-sdk-kotlin-pr }}

          if [ ! -z "$INTERNAL" ]; then
            PULL_REQUEST=${{ github.event.number }}
            echo "Identified this an internal pull request build: $PULL_REQUEST"
          elif [ ! -z "$EXTERNAL" ]; then
            PULL_REQUEST=${{ inputs.aws-sdk-kotlin-pr }}
            echo "Identified this as an external pull request build: $PULL_REQUEST"
          else
            echo "Couldn't identify this as an internal or external pull request"
            exit 1
          fi

          ./gradlew collectDelegatedArtifactSizeMetrics -PpullRequest=$PULL_REQUEST
      - name: Analyze Artifact Size Metrics
        run: ./gradlew analyzeArtifactSizeMetrics
      - name: Show Results
        uses: actions/github-script@v7
        with:
          script: |
            const getComments =
              `query {
                repository(owner:"${context.repo.owner}", name:"${context.repo.repo}"){
                  pullRequest(number: ${context.issue.number ?? process.env.SDK_PR}) {
                    id
                    comments(last:100) {
                      nodes {
                        id
                        body
                        author {
                          login
                        }
                        isMinimized
                      }
                    }
                  }
                }
              }`

            const response = await github.graphql(getComments)
            const comments = response.repository.pullRequest.comments.nodes

            const mutations = comments
              .filter(comment => comment.author.login == 'github-actions' && !comment.isMinimized && comment.body.startsWith('Affected Artifacts'))
              .map(comment =>
                github.graphql(
                  `mutation {
                    minimizeComment(input:{subjectId:"${comment.id}", classifier:OUTDATED}){
                      clientMutationId
                    }
                  }`
                )
              )
            await Promise.all(mutations)

            const fs = require('node:fs')
            const comment = fs.readFileSync('build/reports/metrics/artifact-analysis.md', 'utf8')

            const writeComment =
              `mutation {
                addComment(input:{body:"""${comment}""", subjectId:"${response.repository.pullRequest.id}"}){
                  clientMutationId
                }
              }`

            await github.graphql(writeComment)

      - name: Evaluate Result
        if: ${{ !contains(github.event.pull_request.labels.*.name, 'acknowledge-artifact-size-increase') }}
        run: |
          cd build/reports/metrics
          cat has-significant-change.txt | grep false || {
            echo An artifact increased in size by more than allowed or a new artifact was created.
            echo If this is expected please add the 'acknowledge-artifact-size-increase' label to this pull request.
            exit 1
          }

  release-artifact-size-metrics:
    if: github.event_name == 'release'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout sources
        uses: actions/checkout@v2
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.CI_AWS_ROLE_ARN }}
          aws-region: us-west-2
      - name: Calculate Artifact Size Metrics
        id: svc-check-batch
        run: |
          REPOSITORY=$(echo ${{ github.repository }} | cut -d '/' -f 2)

          .github/scripts/run-codebuild-batch-job.sh \
            --project gh-aws-sdk-kotlin-svc-check-batch \
            --source ${{ github.event.pull_request.head.sha }} \
            --repository $REPOSITORY \
            --release ${{ github.event.release.tag_name }}
      - name: Cancel build
        if: ${{ cancelled() }}
        env:
          BUILD_ID: ${{ steps.svc-check-batch.outputs.aws-build-id }}
        run: |
          if [ ! -z "$BUILD_ID" ]; then
            echo "cancelling in-progress batch build: id=$BUILD_ID"
            aws codebuild stop-build --id $BUILD_ID
          fi
      - name: Collect Artifact Size Metrics
        run: ./gradlew collectDelegatedArtifactSizeMetrics -Prelease=${{ github.event.release.tag_name }}
      - name: Save Artifact Size Metrics
        run: ./gradlew saveArtifactSizeMetrics -Prelease=${{ github.event.release.tag_name }}
      - name: Put Artifact Size Metrics in CloudWatch
        run: ./gradlew putArtifactSizeMetricsInCloudWatch -Prelease=${{ github.event.release.tag_name }}


codegen diff preview

name: codegen diff preview
# This job will generate a codegen output diff comparing the target base ref with current HEAD ref and push it to S3
# and comment on GitHub PR with a link to the HTML output.
on:
  pull_request:
    types:
      - opened
      - reopened
      - synchronize

permissions:
  id-token: write
  contents: read
  pull-requests: write

# Allow one instance of this workflow per pull request, and cancel older runs when new changes are pushed
concurrency:
  group: ci-codegen-diff-${{ github.ref }}
  cancel-in-progress: true

env:
  JAVA_VERSION: 17
  RUN: ${{ github.run_id }}-${{ github.run_number }}
  DIFF2HTML_VERSION: 5.2.5
  # Below is the set of services that are generated for codegen preview
  # These are carefully selected to exercise every Smithy protocol.
  #  - @awsJson1_0: dynamodb
  #  - @awsJson1_1: codebuild
  #  - @awsQuery: sts
  #  - @ec2Query: ec2
  #  - @restJson1: polly
  #  - @restXml: s3
  PREVIEW_SERVICES: +dynamodb,+codebuild,+sts,+ec2,+polly,+s3
  HEAD_BRANCH_NAME: __tmp-localonly-head
  BASE_BRANCH_NAME: __tmp-localonly-base

jobs:

  generate-codegen-diff:
    runs-on: ubuntu-latest
    name: Generate diff and upload to S3
    outputs:
      bot-message: ${{ steps.generate-diff.outputs.codegen-diff-msg }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          path: 'aws-sdk-kotlin'
      - uses: actions/checkout@v4
        with:
          repository: 'awslabs/aws-kotlin-repo-tools'
          path: 'aws-kotlin-repo-tools'
      - uses: actions/checkout@v4
        with:
          repository: 'smithy-lang/smithy-kotlin'
          fetch-depth: 0
          path: 'smithy-kotlin'
      - uses: actions/checkout@v4
        with:
          repository: 'smithy-lang/smithy-rs'
          path: 'smithy-rs'
          sparse-checkout: |
            tools/ci-build/difftags
      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: ${{ env.JAVA_VERSION }}
          distribution: 'corretto'
          cache: 'gradle'
      - name: Install deps and setup environment
        run: |
          # store off a copy of head ref of ci.py, otherwise base ref generation will use a different version of this script
          CODEGEN_DIFF_REVISIONS=${{ runner.temp }}/codegen-diff-revisions.py
          cp $GITHUB_WORKSPACE/aws-sdk-kotlin/.github/scripts/codegen-diff-revisions.py $CODEGEN_DIFF_REVISIONS
          echo "CODEGEN_DIFF_REVISIONS=$CODEGEN_DIFF_REVISIONS" >> "$GITHUB_ENV"
          echo "REPO_TOOLS=$GITHUB_WORKSPACE/aws-kotlin-repo-tools" >> "$GITHUB_ENV"
          echo "SMITHY_KOTLIN_DIR=$GITHUB_WORKSPACE/smithy-kotlin" >> "$GITHUB_ENV"
          echo "SDK_DIR=$GITHUB_WORKSPACE/aws-sdk-kotlin" >> "$GITHUB_ENV"
          echo "installing smithy-rs diff tooling"
          pushd $GITHUB_WORKSPACE/smithy-rs/tools/ci-build/difftags
          cargo install --path .
          difftags --version
          popd

      - name: Generate code for head ref
        run: |
          branch=$(python3 $REPO_TOOLS/scripts/ci.py get-branch $SDK_DIR)
          pushd $SMITHY_KOTLIN_DIR
          if git ls-remote --quiet --exit-code --heads origin refs/heads/$branch
          then
            echo "using smithy-kotlin branch $branch for head ref codegen"
          else
            # in the case of feature branches with tentacles we may or may not have a corresponding base ref in smithy-kotlin
            # if we do let's use that, otherwise fallback to main
            echo "$branch does not exist in smithy-kotlin, will attempt base ref $GITHUB_BASE_REF"
            branch=$GITHUB_BASE_REF
          fi
          python3 $REPO_TOOLS/scripts/ci.py -v set-branch --branch $branch
          popd
          pushd $SDK_DIR
          git checkout -b $HEAD_BRANCH_NAME
          $CODEGEN_DIFF_REVISIONS codegen --bootstrap ${{ env.PREVIEW_SERVICES }}
          popd

      - name: Generate code for base ref
        run: |
          branch=$GITHUB_BASE_REF
          echo "checkout smithy-kotlin at base ref: $branch"
          pushd $SMITHY_KOTLIN_DIR
          git switch -f main
          python3 $REPO_TOOLS/scripts/ci.py -v set-branch --branch $branch
          popd
          echo "resetting aws-sdk-kotlin"
          pushd $SDK_DIR
          git switch -f main
          python3 $REPO_TOOLS/scripts/ci.py -v set-branch --branch $branch
          git checkout -b $BASE_BRANCH_NAME
          $CODEGEN_DIFF_REVISIONS codegen --bootstrap ${{ env.PREVIEW_SERVICES }}
          popd

      - name: Generate diffs
        id: generate-diff
        run: |
          pushd $SDK_DIR
          $CODEGEN_DIFF_REVISIONS \
            --head-sha ${{ github.event.pull_request.head.sha }} \
            generate-diffs \
            --base-sha ${{ github.event.pull_request.base.sha }} \
            $BASE_BRANCH_NAME $HEAD_BRANCH_NAME
          cat ./tmp-codegen-diff/bot-message
          {
            echo 'codegen-diff-msg<<DIFF_MSG_EOF'
            echo "$(cat ./tmp-codegen-diff/bot-message)"
            echo 'DIFF_MSG_EOF'
          } >> "$GITHUB_OUTPUT"
          echo $GITHUB_OUTPUT

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          role-to-assume: ${{ secrets.CI_AWS_ROLE_ARN }}
          aws-region: us-west-2

      - name: Upload diff to S3
        run: |
          SDK_DIR=$GITHUB_WORKSPACE/aws-sdk-kotlin
          pushd $SDK_DIR
          if [[ -d ./tmp-codegen-diff/${{ github.event.pull_request.base.sha }} ]]; then
            aws s3 cp ./tmp-codegen-diff/${{ github.event.pull_request.base.sha }} \
                "s3://${{ secrets.CDN_S3_BUCKET_NAME }}/codegen-diff/${{ github.event.pull_request.base.sha }}" --recursive
          fi

  # TODO - generate doc preview for N services and upload and link as well
  post-bot-comment:
    name: Post bot comment
    runs-on: ubuntu-latest
    needs:
      - generate-codegen-diff
    steps:
      - name: Post bot comment
        uses: actions/github-script@v5
        with:
          script: |
            await github.rest.issues.createComment({
              issue_number: ${{ github.event.number }},
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '${{ needs.generate-codegen-diff.outputs.bot-message }}\n\n'
            })


CI

name: CI

on:
  pull_request:
  workflow_dispatch:

# Allow one instance of this workflow per pull request, and cancel older runs when new changes are pushed
concurrency:
  group: ci-pr-${{ github.ref }}
  cancel-in-progress: true

env:
  RUN: ${{ github.run_id }}-${{ github.run_number }}
  GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dkotlin.incremental=false"

jobs:
  jvm:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        # we build with a specific JDK version but source/target compatibility should ensure the jar is usable by
        # the target versions we want to support
        java-version:
          - 8
          - 11
          - 17
          - 21
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
        with:
          path: 'aws-sdk-kotlin'
      - name: Setup Build
        uses: ./aws-sdk-kotlin/.github/actions/setup-build
      - name: Test
        working-directory: ./aws-sdk-kotlin
        shell: bash
        run: |
          pwd
          ls -lsa
          ./gradlew -Ptest.java.version=${{ matrix.java-version }} jvmTest --stacktrace

  all-platforms:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest, macos-latest, windows-latest ]
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
        with:
          path: 'aws-sdk-kotlin'
      - name: Setup Build
        uses: ./aws-sdk-kotlin/.github/actions/setup-build
      - name: Build smithy-kotlin
        working-directory: ./smithy-kotlin
        shell: bash
        run: |
          # protocol tests require everything is published
          pwd
          ./gradlew --parallel assemble
          ./gradlew publishToMavenLocal
      - name: Test
        working-directory: ./aws-sdk-kotlin
        shell: bash
        run: |
          pwd
          ./gradlew :build-support:test
          ./gradlew publishToMavenLocal
          ./gradlew apiCheck
          ./gradlew test jvmTest
          ./gradlew testAllProtocols
      - name: Save Test Reports
        if: failure()
        uses: actions/upload-artifact@v3
        with:
          name: test-reports
          path: '**/build/reports'


Dependabot Dependency Submission

name: Dependabot Dependency Submission

on:
  push:
    branches: [ main ]

permissions:
  contents: write

jobs:
  dependency-submission:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
      - name: Generate and submit dependency graph
        uses: gradle/actions/dependency-submission@v3


Lint

name: Lint

on:
  push:
    branches:
      - '*'
      - '!main'
  pull_request:
    branches: [ main ]
  workflow_dispatch:

env:
  PACKAGE_NAME: aws-sdk-kotlin

jobs:
  ktlint:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout sources
      uses: actions/checkout@v4
    - name: Lint ${{ env.PACKAGE_NAME }}
      run: |
        ./gradlew ktlint


Close stale issues

name: "Close stale issues"

# Controls when the action will run.
on:
  schedule:
  - cron: "0 0/3 * * *"

jobs:
  cleanup:
    name: Stale issue job
    runs-on: ubuntu-latest
    steps:
    - uses: aws-actions/stale-issue-cleanup@v4
      with:
        # Setting messages to an empty string will cause the automation to skip
        # that category
        ancient-issue-message: This is a very old issue that is probably not getting as much
          attention as it deserves. We encourage you to check if this is still an issue in
          the latest release and if you find that this is still a problem, please feel free
          to provide a comment or open a new issue.
        stale-issue-message: It looks like this issue has not been active for more than 5 days.
          In the absence of more information, we will be closing this issue soon. If you find
          that this is still a problem, please add a comment to prevent automatic closure, or
          if the issue is already closed please feel free to reopen it.
        stale-pr-message: It looks like this PR has not been active for more than five days. In
          the absence of more information, we will be closing this PR soon. Please add a
          comment to prevent automatic closure, or if the PR is already closed please feel
          free to open a new one.

        # These labels are required
        stale-issue-label: closing-soon
        exempt-issue-labels: no-auto-closure,feature-request
        stale-pr-label: closing-soon
        exempt-pr-labels: pr/needs-review
        response-requested-label: response-requested

        # Don't set closed-for-staleness label to skip closing very old issues
        # regardless of label
        closed-for-staleness-label: closed-for-staleness

        # Issue timing
        days-before-stale: 10
        days-before-close: 4
        days-before-ancient: 365

        # If you don't want to mark a 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: 1

        repo-token: ${{ secrets.GITHUB_TOKEN }}
        loglevel: DEBUG
        # Set dry-run to true to not perform label or close actions.
        #dry-run: true


Update release branch

name: Update release branch

on:
  workflow_dispatch:
    inputs:
      commit_message:
        description: |
          The merge commit message to use for non fast-forward merges.
        required: false
        type: string
      dry_run:
        description: Dry runs will only attempt to merge but the result will not be pushed to the release branch
        required: true
        type: boolean
        default: true

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

jobs:
  update-release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: 'main'
          fetch-depth: 0
          token: ${{ secrets.CI_USER_PAT }}
      - name: Configure Git
        shell: bash
        run: |
          git config user.name aws-sdk-kotlin-ci
          git config user.email "aws-kotlin-sdk-automation@amazon.com"
      - name: Configure JDK
        uses: actions/setup-java@v3
        with:
          distribution: 'corretto'
          java-version: 17
          cache: 'gradle'
      - name: Check merge base
        shell: bash
        run: |
          git status
          git branch -vv
          git fetch
          main_sha=$(git rev-parse main)
          release_sha=$(git rev-parse origin/release)
          echo "main_sha=$main_sha" >> $GITHUB_ENV
          echo "release_sha=$release_sha" >> $GITHUB_ENV
          if git merge-base --is-ancestor $main_sha $release_sha; then
              echo "main@$main_sha already exists in origin/release, nothing to update";
              echo "MERGE_NEEDED=false" >> $GITHUB_ENV;
          else
              echo "MERGE_NEEDED=true" >> $GITHUB_ENV
          fi
      - name: Release Check - snapshot versions
        if: env.MERGE_NEEDED == 'true'
        run: |
          # We aren't releasable if we (1) directly depend on a snapshot version of a dependency OR (2) can't build the project without unreleased changes
          if grep -q -i snapshot ./gradle/libs.versions.toml; then
            echo "::error ::found snapshot version in libs.versions.toml"
            exit 1
          fi
      - name: Release Check - build
        if: env.MERGE_NEEDED == 'true'
        run: |
          # Our CI is implemented as a "live at HEAD" model where we build against the latest of all our 1P deps (either
          # main branch or matching branch name). Double check that without this "live at HEAD" mode we still build
          # successfully (which is how it is built during release).
          # This should help prevent the cases where we forgot to bump smithy-kotlin versions and don't catch it
          # because CI is masking it
          ./gradlew -Paws.kotlin.native=false test jvmTest
      - name: Release Check - build an SDK client
        if: env.MERGED_NEEDED == 'true'
        shell: bash
        run: |
          # Additionally generate and build a service client to confirm that codegen and build works
          # without "live at HEAD" mode.
          ./gradlew -Paws.services=s3 -Paws.kotlin.native=false bootstrap;
          ./gradlew -Paws.kotlin.native=false build;
      - name: Merge
        if: env.MERGE_NEEDED == 'true'
        shell: bash
        run: |
          echo "merging main @ $main_sha into release @ $release_sha";
          git switch release;
          input_message=${{ inputs.commit_message }}
          message=${input_message:-"Merging main into release"}
          echo "message=$message"
          git merge -m "$message" main;
          if [ "${{ inputs.dry_run }}" == "true" ]; then
            echo "dry run, skipping push to remote";
            git log -n 10 --oneline;
          else
            echo "pushing changes to release branch";
            git push origin release;
          fi


build

name: build  # used as the badge name

on:
  push:
    branches: ['*']
    tags: ['*']
  pull_request:
    types: [opened, synchronize]

env:
  KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
  KEYSTORE_ALIAS: upload
  KEYSTORE_ALIAS_PASSWORD: ${{ secrets.KEYSTORE_ALIAS_PASSWORD }}
  AndroidAutoIdrive_SpotifyApiKey: ${{ secrets.ANDROIDAUTOIDRIVE_SPOTIFYAPIKEY }}
  AndroidAutoIdrive_SentryDsn: ${{ secrets.ANDROIDAUTOIDRIVE_SENTRYDSN }}
  AndroidAutoIdrive_GmapsApiKey: ${{ secrets.ANDROIDAUTOIDRIVE_GMAPSAPIKEY }}
  AndroidAutoIdrive_MapboxAccessToken: ${{ secrets.ANDROIDAUTOIDRIVE_MAPBOXACCESSTOKEN }}
  AndroidAutoIdrive_MapboxDownloadToken: ${{ secrets.ANDROIDAUTOIDRIVE_MAPBOXDOWNLOADTOKEN }}

jobs:
  unitTest:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        map: [Nomap, Gmap, Mapbox]
        analytics: [Nonalytics, Sentry]
        hasSecret:
          - ${{ github.repository == 'BimmerGestalt/AAIdrive' && github.event_name == 'push' }}
        exclude:  # don't run Mapbox tests if we are in a context that doesn't have the Mapbox secret
          - hasSecret: false
            map: Mapbox   # Mapbox requires secrets to build
    steps:
      - name: Checkout the project
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: true
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Prepare cached external dependencies
        uses: actions/cache@v4
        with:
          key: aaidrive_external_${{ hashFiles('.github/actions/download-externals-action/download.sh') }}
          path: |
            external
      - name: Download build dependencies
        uses: ./.github/actions/download-externals-action

      # disabled for being flaky
      #- name: Validate Gradle Wrapper
      #  uses: gradle/wrapper-validation-action@v1
      - name: Build the project
        run: ./gradlew compile${{ matrix.map }}${{ matrix.analytics }}FullDebugKotlin --stacktrace
      - name: Run unit tests
        run: ./gradlew test${{ matrix.map }}${{ matrix.analytics }}FullDebugUnitTestCoverage
      - name: Upload CodeCov report
        if: github.event.pull_request.title != 'New Crowdin updates' && github.event.ref != 'refs/heads/l10n_main'   # don't upload coverage for Crowdin pushes
        uses: codecov/codecov-action@v4
        env:
          CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
        with:
          files: app/build/reports/jacoco/jacoco.xml
          flags: unittests

  instrumentedTest:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        map: [Nomap, Gmap, Mapbox]
        hasSecret:
          - ${{ github.repository == 'BimmerGestalt/AAIdrive' && github.event_name == 'push' }}
        exclude:  # don't run Gmap tests if we are in a context that doesn't have the gmap secret
          - hasSecret: false
            map: Gmap
          - hasSecret: false
            map: Mapbox   # Mapbox requires secrets to build
    steps:
      - name: Enable KVM group perms
        run: |
          echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
          sudo udevadm control --reload-rules
          sudo udevadm trigger --name-match=kvm
      - name: Checkout the project
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: true
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17
      - name: Prepare cached external dependencies
        uses: actions/cache@v4
        with:
          key: aaidrive_external_${{ hashFiles('.github/actions/download-externals-action/download.sh') }}
          path: |
            external
      - name: Download build dependencies
        uses: ./.github/actions/download-externals-action
      - name: Build the project
        run: ./gradlew compile${{ matrix.map }}NonalyticsFullDebugKotlin --stacktrace
      - name: Prepare emulator
        uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: 28
          emulator-build: 6110076
          target: google_apis
          script: adb install external/BMW_Connected_v3.1.1.3078_apkpure.com.apk
      - name: Run instrumented tests
        uses: reactivecircus/android-emulator-runner@v2
        with:
          force-avd-creation: false
          api-level: 28
          emulator-build: 6110076
          target: google_apis
          script: ./gradlew connected${{ matrix.map }}NonalyticsFullDebugAndroidTestCoverage --stacktrace
      - name: Upload CodeCov report
        if: matrix.map == 'Nomap' && github.event.pull_request.title != 'New Crowdin updates' && github.event.ref != 'refs/heads/l10n_main'   # don't upload Gmap test results, which don't run during PRs
        uses: codecov/codecov-action@v4
        env:
          CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
        with:
          files: app/build/reports/jacoco/jacoco.xml
#          flags: instrumentedtests

# android connectedTests don't leave the app or files installed after the test
# so we have to invoke it manually
      - name: Generate screenshots
        uses: reactivecircus/android-emulator-runner@v2
        with:
          force-avd-creation: false
          api-level: 28
          emulator-build: 6110076
          target: google_apis
          script: adb logcat -c && ./gradlew install${{ matrix.map }}NonalyticsFullDebug --stacktrace && ./gradlew install${{ matrix.map }}NonalyticsFullDebugAndroidTest --stacktrace && ( adb shell am instrument -w me.hufman.androidautoidrive.test/me.hufman.androidautoidrive.DexOpenerAndroidJUnitRunner || adb shell am instrument -w me.hufman.androidautoidrive.test/me.hufman.androidautoidrive.DexOpenerAndroidJUnitRunner ) && ./gradlew fetchScreenshots --stacktrace || adb logcat -d
      - name: Package screenshots
        uses: actions/upload-artifact@v3
        if: matrix.map == 'Nomap'
        with:
          retention-days: 7
          name: screenshots
          path: |
            app/build/reports/androidTests/connected/screenshots/*

  package:
    # Only build on the main repo, which has the secrets configured
    if: github.repository == 'BimmerGestalt/AAIdrive' && github.event_name == 'push'
    needs: [unitTest]  # wait for the tests to succeed
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the project
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: true
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Prepare cached external dependencies
        uses: actions/cache@v4
        with:
          key: aaidrive_external_${{ hashFiles('.github/actions/download-externals-action/download.sh') }}
          path: |
            external
      - name: Download build dependencies
        uses: ./.github/actions/download-externals-action
      - name: Extract signing key
        run: "echo ${{ secrets.KEYSTORE_BASE64 }} | base64 -d > keystore.jks"
      - name: Build nomap artifacts
        run: ./gradlew assembleNomap --stacktrace
      - name: Build mapbox artifacts
        run: ./gradlew assembleMapbox --stacktrace

      - name: Calculate APK hashes
        run: "find app/build/outputs/apk -name '*.apk' -execdir sha1sum {} \\;"
      - name: Confirm APK hashes
        run: "find app/build/outputs/apk -name '*.sha1' -exec cat {} \\; -execdir sha1sum -c {} \\;"
      - name: Upload APKs
        uses: actions/upload-artifact@v3
        with:
          retention-days: 7
          name: apk
          path: |
            app/build/outputs/apk/nomapNonalyticsFull/release/*apk
            app/build/outputs/apk/nomapNonalyticsFull/release/*apk.sha1
            app/build/outputs/apk/nomapSentryFull/release/*apk
            app/build/outputs/apk/nomapSentryFull/release/*apk.sha1
            app/build/outputs/apk/mapboxNonalyticsFull/release/*apk
            app/build/outputs/apk/mapboxNonalyticsFull/release/*apk.sha1
            app/build/outputs/apk/mapboxSentryFull/release/*apk
            app/build/outputs/apk/mapboxSentryFull/release/*apk.sha1

  upload_s3:
    if: github.event_name == 'push'
    needs: package
    runs-on: ubuntu-latest
    steps:
      - name: Download project artifacts
        uses: actions/download-artifact@v3
        with:
          name: apk
      - name: Determine branch name
        run: echo "BRANCH_NAME=$(echo $GITHUB_REF | cut -d'/' -f 3)" >> $GITHUB_ENV
      - name: Stage upload directory
        run: |
          mkdir dist
          cp nomapNonalyticsFull/release/*apk dist/androidautoidrive-latest-${BRANCH_NAME}-nomap-nonalytics-release.apk
          cp nomapSentryFull/release/*apk dist/androidautoidrive-latest-${BRANCH_NAME}-nomap-sentry-release.apk
          cp mapboxNonalyticsFull/release/*apk dist/androidautoidrive-latest-${BRANCH_NAME}-mapbox-nonalytics-release.apk
          cp mapboxSentryFull/release/*apk dist/androidautoidrive-latest-${BRANCH_NAME}-mapbox-sentry-release.apk
      - name: Upload to S3
        uses: shallwefootball/s3-upload-action@v1.3.0
        with:
          source_dir: dist
          destination_dir: aaidrive/builds
          aws_bucket: bimmergestalt
          aws_key_id: ${{ secrets.AWS_KEY_ID }}
          aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

  upload_release:
    if: startsWith(github.ref, 'refs/tags/')
    needs: package
    runs-on: ubuntu-latest
    steps:
      - name: Download project artifacts
        uses: actions/download-artifact@v2
        with:
          name: apk
      - name: Stage upload directory
        run: |
          mkdir dist
          cp */release/*apk* dist/
      - name: Upload to Github release
        uses: svenstaro/upload-release-action@v2
        with:
          tag: ${{ github.ref }}
          repo_token: ${{ secrets.GITHUB_TOKEN }}
          file_glob: true
          file: dist/*
          overwrite: true


usage

name: usage

on:
  schedule:
    - cron: '15 15 * * *'
  push:
    branches: ['usage']

jobs:
  updateUsage:
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout the project
        uses: actions/checkout@v4

      - name: Generate usage information
        run: cd usage && python3 generate.py
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          SENTRY_ISSUE_ID: ${{ secrets.SENTRY_ISSUE_ID }}

      - name: Copy to output dir
        run: cd usage && mkdir dist && cp *.json *.html dist

      - name: Upload to S3
        uses: shallwefootball/s3-upload-action@v1.3.0
        with:
          source_dir: usage/dist
          destination_dir: aaidrive/usage
          aws_bucket: bimmergestalt
          aws_key_id: ${{ secrets.AWS_KEY_ID }}
          aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}


publish

name: publish

on:
  workflow_dispatch:
    inputs:
      whats_new:
        description: "What's new:"
        required: true
        default: "Improvements to stability and performance"

env:
  KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
  KEYSTORE_ALIAS: upload
  KEYSTORE_ALIAS_PASSWORD: ${{ secrets.KEYSTORE_ALIAS_PASSWORD }}
  AndroidAutoIdrive_SpotifyApiKey: ${{ secrets.ANDROIDAUTOIDRIVE_SPOTIFYAPIKEY }}
  AndroidAutoIdrive_MapboxAccessToken: ${{ secrets.ANDROIDAUTOIDRIVE_MAPBOXACCESSTOKEN }}
  AndroidAutoIdrive_MapboxDownloadToken: ${{ secrets.ANDROIDAUTOIDRIVE_MAPBOXDOWNLOADTOKEN }}

jobs:
  unitTest:
    runs-on: ubuntu-22.04

    steps:
      - name: Checkout the project
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: true
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Prepare cached external dependencies
        uses: actions/cache@v4
        with:
          key: aaidrive_external_${{ hashFiles('.github/actions/download-externals-action/download.sh') }}
          path: |
            external
      - name: Download build dependencies
        uses: ./.github/actions/download-externals-action

      - name: Build the project
        run: ./gradlew compileMapboxNonalyticsPlayDebugSources

      - name: Run unit tests
        run: ./gradlew testMapboxNonalyticsPlayDebugUnitTest

  package:
    needs: [ unitTest ]  # wait for the tests to succeed
    runs-on: ubuntu-22.04

    steps:

      - name: Checkout the project
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: true
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Prepare cached external dependencies
        uses: actions/cache@v4
        with:
          key: aaidrive_external_${{ hashFiles('.github/actions/download-externals-action/download.sh') }}
          path: |
            external
      - name: Download build dependencies
        uses: ./.github/actions/download-externals-action

      - name: Extract signing key
        run: "echo ${{ secrets.KEYSTORE_BASE64 }} | base64 -d > keystore.jks"

      - name: Build app bundle
        run: ./gradlew bundleMapboxNonalyticsPlayRelease

      - name: Upload bundle
        uses: actions/upload-artifact@v3
        with:
          retention-days: 7
          name: bundle
          path: |
            app/build/outputs/bundle/*/*aab

  upload:
    needs: package
    runs-on: ubuntu-22.04
    steps:
      - name: Download project artifacts
        uses: actions/download-artifact@v3
        with:
          name: bundle
          path: bundle
      - name: Prepare Changelog
        run: mkdir whats_new && echo -e "${{ github.event.inputs.whats_new }}" >> whats_new/whatsnew-en-US
      - uses: r0adkll/upload-google-play@v1.0.15
        with:
          serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SECRET }}
          packageName: me.hufman.androidautoidrive
          releaseFiles: "bundle/*/*.aab"
          track: beta
          whatsNewDirectory: whats_new


GitHub Pages

name: GitHub Pages

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  github-pages-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 0 # Required for version number generation

      - name: Validate Gradle artifacts
        uses: gradle/wrapper-validation-action@v1

      - name: Set up JDK
        uses: actions/setup-java@v1
        with:
          distribution: temurin
          java-version: 11

      - name: Generate Page
        uses: gradle/gradle-build-action@v2
        with:
          arguments: :bgw-docs:jekyllBuild

      - name: Deploy to GitHub Pages
        uses: JamesIves/github-pages-deploy-action@4.1.0
        with:
          branch: gh-pages
          folder: bgw-docs/build/jekyll
          single-commit: true


Analyze, Build and Deploy

name: Analyze, Build and Deploy

on:
  pull_request:
  push:
  workflow_dispatch:

env:
  JDK_VERSION: 11

jobs:
  safety-check:
    name: Check for modified Gradle
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v3

    - name: Validate Gradle artifacts
      uses: gradle/wrapper-validation-action@v1

  detekt:
    name: Generate Detekt report
    needs: safety-check
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        fetch-depth: 0 # Required for version number generation

    - name: Set up JDK
      uses: actions/setup-java@v3
      with:
        distribution: temurin
        java-version: ${{ env.JDK_VERSION }}

    - name: Run Detekt
      uses: gradle/gradle-build-action@v2
      with:
        arguments: detekt

    - name: Collect results
      shell: sh
      run: >
        mkdir sarif &&
        find * -name detekt.sarif -print0 |
        xargs -n1 -0 bash -c 'cp "$1" "sarif/${1//\//-}"' '{}'

    - name: Upload analysis results
      uses: github/codeql-action/upload-sarif@v1
      with:
        sarif_file: sarif
        wait-for-processing: true

  kover:
    name: Generate Kover report
    needs: safety-check
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        fetch-depth: 0 # Required for version number generation

    - name: Set up JDK
      uses: actions/setup-java@v3
      with:
        distribution: temurin
        java-version: ${{ env.JDK_VERSION }}

    - name: Run Kover
      uses: gradle/gradle-build-action@v2
      with:
        arguments: koverReport koverMergedReport

    - name: Upload analysis results
      uses: codecov/codecov-action@v2
      with:
        directory: 'build/reports/kover'
        fail_ci_if_error: true
        verbose: true

  junit-test:
    name: Run JUnit tests
    needs: safety-check
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        fetch-depth: 0 # Required for version number generation

    - name: Set up JDK
      uses: actions/setup-java@v3
      with:
        distribution: temurin
        java-version: ${{ env.JDK_VERSION }}

    - name: Run tests
      uses: gradle/gradle-build-action@v2
      with:
        arguments: test

    - name: Upload test results
      uses: mikepenz/action-junit-report@v2
      if: always() # Must execute after failed tests
      with:
        report_paths: '**/build/test-results/test/TEST-*.xml'

  platform-test:
    name: Run JUnit tests on ${{ matrix.os }}
    needs: junit-test
    strategy:
      matrix:
        os: [ macos-latest, windows-latest ] # Ubuntu is tested in "test" job
      fail-fast: false # Ensure we get all failures on other platforms
    runs-on: ${{ matrix.os }}
    steps:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        fetch-depth: 0 # Required for version number generation

    - name: Set up JDK
      uses: actions/setup-java@v3
      with:
        distribution: temurin
        java-version: ${{ env.JDK_VERSION }}

    - name: Run tests
      uses: gradle/gradle-build-action@v2
      with:
        arguments: test

  spotless:
    name: Run Spotless
    needs: safety-check
    runs-on: ubuntu-latest
    steps:
      - name: Initial Setup
        uses: actions/checkout@v3
        with:
          fetch-depth: 0 # Required for version number generation & diff generation

      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          distribution: temurin
          java-version: ${{ env.JDK_VERSION }}

      - name: Run Spotless checks
        id: spotlessCheck
        uses: gradle/gradle-build-action@v2
        with:
          arguments: spotlessCheck

      - name: Apply Spotless fixes
        if: failure()
        uses: gradle/gradle-build-action@v2
        with:
          arguments: spotlessApply

      - name: Generate diff
        if: failure()
        shell: sh
        run: |
          echo "# Spotless violations" >> $GITHUB_STEP_SUMMARY
          echo "```diff" >> $GITHUB_STEP_SUMMARY
          git diff >> $GITHUB_STEP_SUMMARY
          echo "```" >> $GITHUB_STEP_SUMMARY

  publish-maven:
    name: Publish to Maven Central
    if: ${{ github.event_name != 'pull_request' && github.ref_name == 'main' }}
    needs: [ spotless, platform-test ]
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        fetch-depth: 0 # Required for version number generation

    - name: Set up JDK
      uses: actions/setup-java@v3
      with:
        distribution: temurin
        java-version: ${{ env.JDK_VERSION }}

    - name: Import GPG key
      id: importGPG
      uses: crazy-max/ghaction-import-gpg@v5
      with:
        gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}

    - name: Publish artifacts on Maven Central
      uses: gradle/gradle-build-action@v2
      with:
        arguments: |
          -Psigning.keyId=${{ steps.importGPG.outputs.keyid }}
          -PsonatypeUsername=${{ secrets.SONATYPE_USERNAME }}
          -PsonatypePassword=${{ secrets.SONATYPE_PASSWORD }}
          publishToSonatype
          closeSonatypeStagingRepository

    - name: Get the build version
      shell: sh
      run: |
        echo "GRADLE_PROJECT_VERSION=$(./gradlew --quiet --console=plain :version)" >> $GITHUB_ENV

    - name: Create issue for finalizing release
      if: ${{ !endsWith(env.GRADLE_PROJECT_VERSION, '-SNAPSHOT') }}
      uses: JasonEtco/create-an-issue@v2
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        filename: contrib/release-staging.md

  publish-docker:
    name: Publish to Docker Hub
    if: ${{ github.event_name != 'pull_request' && github.ref_name == 'main' }}
    needs: [ spotless, platform-test ]
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0 # Required for version number generation

      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          distribution: temurin
          java-version: ${{ env.JDK_VERSION }}

      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Publish artifacts on Docker Hub
        uses: gradle/gradle-build-action@v2
        with:
          arguments: buildBootImage


CI

# 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: CI

on:
  pull_request:
    branches: [ main ]
  merge_group:
    branches: [ main ]

env:
 FHIRCORE_USERNAME: ${{ secrets.FHIRCORE_USERNAME }}
 FHIRCORE_ACCESS_TOKEN: ${{ secrets.FHIRCORE_ACCESS_TOKEN }}
 CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
 MAPBOX_SDK_TOKEN: ${{ secrets.MAPBOX_SDK_TOKEN }}

jobs:
  engine-tests:
    runs-on: macos-13
    strategy:
      matrix:
        api-level: [30]
    steps:
      - name: Cancel Previous workflow runs
        uses: styfle/cancel-workflow-action@0.9.1
        with:
          access_token: ${{ github.token }}

      - name: Checkout 🛎
        uses: actions/checkout@v2
        with:
          fetch-depth: 2

      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17

      - name: Add empty local.properties
        run: touch local.properties
        working-directory: android

      - name: Add empty keystore.properties
        run: touch keystore.properties
        working-directory: android

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
        working-directory: android

      - name: Copy CI gradle.properties
        run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties && cat ~/.gradle/gradle.properties

      - name: Setup Gradle cache
        uses: gradle/gradle-build-action@v2

      - name: Spotless check engine module
        run: ./gradlew -PlocalPropertiesFile=local.properties :engine:spotlessCheck :engine:ktlintCheck --stacktrace
        working-directory: android

      - name: Load AVD cache
        uses: actions/cache@v2
        id: avd-cache
        with:
          path: |
            ~/.android/avd/*
            ~/.android/adb*
          key: avd-${{ matrix.api-level }}

      - name: Create AVD and generate snapshot for caching
        if: steps.avd-cache.outputs.cache-hit != 'true'
        uses: reactivecircus/android-emulator-runner@v2
        with:
          working-directory: android
          api-level: ${{ matrix.api-level }}
          arch: x86_64
          force-avd-creation: false
          emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: false
          script: echo "Generated AVD snapshot for caching."

      - name: Run Engine module unit and instrumentation tests and generate coverage report
        uses: reactivecircus/android-emulator-runner@v2
        with:
          working-directory: android
          api-level: ${{ matrix.api-level }}
          arch: x86_64
          force-avd-creation: true
          emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: true
          script: ./gradlew -PlocalPropertiesFile=local.properties :engine:clean :engine:fhircoreJacocoReport --stacktrace

      - name: Upload Engine module test coverage report to Codecov
        if: matrix.api-level == 30 # Only upload coverage on API level 30
        working-directory: android
        run:  bash <(curl -s https://codecov.io/bash) -F engine -f "engine/build/reports/jacoco/fhircoreJacocoReport/fhircoreJacocoReport.xml"

  geowidget-tests:
    runs-on: macos-13
    strategy:
      matrix:
        api-level: [30]
    steps:
      - name: Cancel Previous workflow runs
        uses: styfle/cancel-workflow-action@0.9.1
        with:
          access_token: ${{ github.token }}

      - name: Checkout 🛎
        uses: actions/checkout@v2
        with:
          fetch-depth: 2

      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17

      - name: Add empty local.properties
        run: touch local.properties
        working-directory: android

      - name: Add empty keystore.properties
        run: touch keystore.properties
        working-directory: android

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
        working-directory: android

      - name: Copy CI gradle.properties
        run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties && cat ~/.gradle/gradle.properties

      - name: Setup Gradle cache
        uses: gradle/gradle-build-action@v2

      - name: Spotless check geowidget module
        run: ./gradlew -PlocalPropertiesFile=local.properties :geowidget:spotlessCheck --stacktrace
        working-directory: android

      - name: Load AVD cache
        uses: actions/cache@v2
        id: avd-cache
        with:
          path: |
            ~/.android/avd/*
            ~/.android/adb*
          key: avd-${{ matrix.api-level }}

      - name: Create AVD and generate snapshot for caching
        if: steps.avd-cache.outputs.cache-hit != 'true'
        uses: reactivecircus/android-emulator-runner@v2
        with:
          working-directory: android
          api-level: ${{ matrix.api-level }}
          arch: x86_64
          force-avd-creation: false
          emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: false
          script: echo "Generated AVD snapshot for caching."

      - name: Run Geowidget module unit and instrumentation tests and generate coverage report
        uses: reactivecircus/android-emulator-runner@v2
        with:
          working-directory: android
          api-level: ${{ matrix.api-level }}
          arch: x86_64
          force-avd-creation: true
          emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: true
          script: ./gradlew -PlocalPropertiesFile=local.properties :geowidget:clean :geowidget:fhircoreJacocoReport --stacktrace

      - name: Upload Geowidget module test coverage report to Codecov
        if: matrix.api-level == 30 # Only upload coverage on API level 30
        working-directory: android
        run:  bash <(curl -s https://codecov.io/bash) -F geowidget -f "geowidget/build/reports/jacoco/fhircoreJacocoReport/fhircoreJacocoReport.xml"

  quest-tests:
    runs-on: macos-13
    strategy:
      matrix:
        api-level: [30]
    steps:
      - name: Cancel Previous workflow runs
        uses: styfle/cancel-workflow-action@0.9.1
        with:
          access_token: ${{ github.token }}
      - name: Checkout 🛎
        uses: actions/checkout@v2
        with:
          fetch-depth: 2

      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17

      - name: Add empty local.properties
        run: touch local.properties
        working-directory: android

      - name: Add empty keystore.properties
        run: touch keystore.properties
        working-directory: android

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
        working-directory: android

      - name: Copy CI gradle.properties
        run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties && cat ~/.gradle/gradle.properties

      - name: Setup Gradle cache
        uses: gradle/gradle-build-action@v2

      - name: Spotless check quest application
        run: ./gradlew -PlocalPropertiesFile=local.properties :quest:spotlessCheck --stacktrace :quest:ktlintCheck --stacktrace
        working-directory: android

      - name: Load AVD cache
        uses: actions/cache@v2
        id: avd-cache
        with:
          path: |
            ~/.android/avd/*
            ~/.android/adb*
          key: avd-${{ matrix.api-level }}

      - name: Create AVD and generate snapshot for caching
        if: steps.avd-cache.outputs.cache-hit != 'true'
        uses: reactivecircus/android-emulator-runner@v2
        with:
          working-directory: android
          api-level: ${{ matrix.api-level }}
          arch: x86_64
          force-avd-creation: false
          emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: false
          script: echo "Generated AVD snapshot for caching."

      - name: Run Quest module unit and instrumentation tests and generate coverage report
        uses: reactivecircus/android-emulator-runner@v2
        with:
          working-directory: android
          api-level: ${{ matrix.api-level }}
          arch: x86_64
          force-avd-creation: true
          emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: true
          script: ./gradlew clean  -PlocalPropertiesFile=local.properties :quest:fhircoreJacocoReport --stacktrace -Pandroid.testInstrumentationRunnerArguments.notPackage=org.smartregister.fhircore.quest.performance
          # ./gradlew -PlocalPropertiesFile=local.properties :quest:clean && ./gradlew -PlocalPropertiesFile=local.properties :quest:assembleOpensrpDebugAndroidTest --stacktrace && /Users/runner/Library/Android/sdk/platform-tools/adb install quest/build/outputs/apk/androidTest/opensrp/debug/quest-opensrp-debug-androidTest.apk && ./gradlew -PlocalPropertiesFile=local.properties :quest:assembleOpensrpDebug --stacktrace && /Users/runner/Library/Android/sdk/platform-tools/adb install quest/build/outputs/apk/opensrp/debug/quest-opensrp-debug.apk && /Users/runner/Library/Android/sdk/platform-tools/adb shell am instrument -w -e package org.smartregister.fhircore.quest.ui.profile -e coverage "true" org.smartregister.opensrp.test/org.smartregister.fhircore.quest.QuestTestRunner && /Users/runner/Library/Android/sdk/platform-tools/adb shell run-as org.smartregister.opensrp cat "/data/user/0/org.smartregister.opensrp/files/coverage.ec" > quest/coverage.ec && ./gradlew -PlocalPropertiesFile=local.properties :quest:fhircoreJacocoReport --stacktrace

      - name: Upload Quest module test coverage report to Codecov
        if: matrix.api-level == 30 # Only upload coverage on API level 30
        working-directory: android
        run:  bash <(curl -s https://codecov.io/bash) -F quest -f "quest/build/reports/jacoco/fhircoreJacocoReport/fhircoreJacocoReport.xml"


Docs

name: Docs

on:
  push:
    branches: [ main ]
env:
  MAPBOX_SDK_TOKEN: ${{ secrets.MAPBOX_SDK_TOKEN }}

jobs:
  build-and-deploy-docusaurus:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2.3.1
      - uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: yarn

      - name: Install dependencies
        run: yarn install

      - name: Build website
        run: yarn build
      - name: copy docs into build working-directory
        run: |
          cp -r docs ./build
          cp -r CNAME ./build

      - name: Deploy to gh-pages
        if: ${{ github.event_name == 'push' }}
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_branch: gh-pages
          publish_dir: ./build
          user_name: github-actions[bot]
          user_email: 41898282+github-actions[bot]@users.noreply.github.com

  build-and-deploy-dokka:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout 🛎
        uses: actions/checkout@v2.3.1

      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17

      - name: Add empty local.properties
        run: touch local.properties
        working-directory: android

      - name: Add empty keystore.properties
        run: touch keystore.properties
        working-directory: android

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
        working-directory: android

      - name: Document modules with dokka
        run: ./gradlew dokkaHtmlMultiModule
        working-directory: android
        env:
         FHIRCORE_USERNAME: ${{ secrets.FHIRCORE_USERNAME }}
         FHIRCORE_ACCESS_TOKEN: ${{ secrets.FHIRCORE_ACCESS_TOKEN }}

      - name: Deploy 🚀
        if: ${{ github.event_name == 'push' }}
        uses: JamesIves/github-pages-deploy-action@v4.4.1
        with:
          branch: gh-pages # The branch the action should deploy to.
          folder: android/build/dokka # The folder the action should deploy.
          target-folder: dokka


SonarQube Analysis

name: SonarQube Analysis

on:
  push:
    branches:
      - main
env:
  MAPBOX_SDK_TOKEN: ${{ secrets.MAPBOX_SDK_TOKEN }}

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Cancel previous workflow runs
        uses: styfle/cancel-workflow-action@0.9.1
        with:
          access_token: ${{ github.token }}

      - name: Check out codebase
        uses: actions/checkout@v2
        with:
          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis

      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17

      - name: Cache SonarQube packages
        uses: actions/cache@v1
        with:
          path: ~/.sonar/cache
          key: ${{ runner.os }}-sonar
          restore-keys: ${{ runner.os }}-sonar

      - name: Cache Gradle packages
        uses: actions/cache@v1
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
          restore-keys: ${{ runner.os }}-gradle

      - name: Decode & Generate Keystore file
        run: echo $ENCODED_KEYSTORE | base64 -di > "${HOME}"/fhircore.keystore.jks
        env:
          ENCODED_KEYSTORE: ${{ secrets.KEYSTORE_FILE }}

      - name: Decode & Generate local.properties file
        run: echo $LOCAL_PROPERTIES | base64 -di > local.properties
        working-directory: android
        env:
          LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}

      - name: Decode & Generate keystore.properties file
        run: echo $KEYSTORE_PROPERTIES | base64 -di > keystore.properties
        working-directory: android
        env:
          KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_PROPERTIES }}

      - name: Build and analyze
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
        run: ./gradlew sonar --stacktrace
        working-directory: android