Sync SAS strings

name: Sync SAS strings
on:
  workflow_dispatch:
  schedule:
    # At 00:00 on every Monday UTC
    - cron: '0 0 * * 1'

jobs:
  sync-sas-strings:
    runs-on: ubuntu-latest
    # Skip in forks
    if: github.repository == 'element-hq/element-x-android'
    # No concurrency required, runs every time on a schedule.
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python 3.12
        uses: actions/setup-python@v5
        with:
          python-version: 3.12
      - name: Install Prerequisite dependencies
        run: |
          pip install requests
      - name: Run SAS String script
        run: ./tools/sas/import_sas_strings.py
      - name: Create Pull Request for SAS Strings
        uses: peter-evans/create-pull-request@v6
        with:
          commit-message: Sync SAS Strings
          title: Sync SAS Strings
          body: |
            - Update SAS Strings from matrix-doc.
          branch: sync-sas-strings
          base: develop


Test

name: Test

on:
  workflow_dispatch:
  pull_request:
  merge_group:
  push:
    branches: [ main, develop ]

# Enrich gradle.properties for CI/CD
env:
  GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx7g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.incremental=false -XX:+UseG1GC
  CI_GRADLE_ARG_PROPERTIES: --stacktrace -Dsonar.gradle.skipCompile=true

jobs:
  tests:
    name: Runs unit tests
    runs-on: ubuntu-latest

    # Allow all jobs on main and develop. Just one per PR.
    concurrency:
      group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('unit-tests-{0}', github.ref) }}
      cancel-in-progress: true
    steps:
      # Increase swapfile size to prevent screenshot tests getting terminated
      # https://github.com/actions/runner-images/discussions/7188#discussioncomment-6750749
      - name: 💽 Increase swapfile size
        run: |
          sudo swapoff -a
          sudo fallocate -l 8G /mnt/swapfile
          sudo chmod 600 /mnt/swapfile
          sudo mkswap /mnt/swapfile
          sudo swapon /mnt/swapfile
          sudo swapon --show
      - name: ⏬ Checkout with LFS
        uses: nschloe/action-cached-lfs-checkout@v1.2.2
        with:
          # Ensure we are building the branch and not the branch after being merged on develop
          # https://github.com/actions/checkout/issues/881
          ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
      - name: ☕ Use JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin' # See 'Supported distributions' for available options
          java-version: '17'
      - name: Configure gradle
        uses: gradle/actions/setup-gradle@v3
        with:
          cache-read-only: ${{ github.ref != 'refs/heads/develop' }}

      - name: ⚙ Run unit tests for debug variant
        run: ./gradlew testDebugUnitTest $CI_GRADLE_ARG_PROPERTIES

      - name: 📸 Run screenshot tests
        run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES

      - name: 📈Generate kover report and verify coverage
        run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyAll $CI_GRADLE_ARG_PROPERTIES

      - name: 🚫 Upload kover failed coverage reports
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: kover-error-report
          path: |
            app/build/reports/kover/verifyGplayDebug.err

      - name: ✅ Upload kover report (disabled)
        if: always()
        run: echo "This is now done only once a day, see nightlyReports.yml"

      - name: 🚫 Upload test results on error
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: tests-and-screenshot-tests-results
          path: |
            **/build/paparazzi/failures/
            **/build/reports/tests/*UnitTest/

      # https://github.com/codecov/codecov-action
      - name: ☂ Upload coverage reports to codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}
          files: app/build/reports/kover/reportGplayDebug.xml
          verbose: true


name: Move new issues onto issue triage board v2

on:
  issues:
    types: [ opened ]

jobs:
  triage-new-issues:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/add-to-project@main
        with:
          project-url: https://github.com/orgs/element-hq/projects/91
          github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}


name: Move labelled issues to correct boards and columns

on:
  issues:
    types: [labeled]

jobs:
  move_element_x_issues:
    name: ElementX issues to ElementX project board
    runs-on: ubuntu-latest
    # Skip in forks
    if: >
      github.repository == 'element-hq/element-x-android'
    steps:
      - uses: actions/add-to-project@main
        with:
          project-url: https://github.com/orgs/element-hq/projects/43
          github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}

  move_needs_info:
    name: Move triaged needs info issues on board
    runs-on: ubuntu-latest
    steps:
      - uses: actions/add-to-project@main
        id: addItem
        with:
          project-url: https://github.com/orgs/element-hq/projects/91
          github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
          labeled: X-Needs-Info
      - name: Print itemId
        run: echo ${{ steps.addItem.outputs.itemId }}
      - uses: kalgurn/update-project-item-status@main
        if: ${{ steps.addItem.outputs.itemId }}
        with:
          project-url: https://github.com/orgs/element-hq/projects/91
          github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
          item-id: ${{ steps.addItem.outputs.itemId }}
          status: "Needs info"

  ex_plorers:
    name: Add labelled issues to X-Plorer project
    runs-on: ubuntu-latest
    if: >
      contains(github.event.issue.labels.*.name, 'Team: Element X Feature')
    steps:
      - uses: actions/add-to-project@main
        with:
          project-url: https://github.com/orgs/element-hq/projects/73
          github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}

  verticals_feature:
    name: Add labelled issues to Verticals Feature project
    runs-on: ubuntu-latest
    if: >
      contains(github.event.issue.labels.*.name, 'Team: Verticals Feature')
    steps:
      - uses: actions/add-to-project@main
        with:
          project-url: https://github.com/orgs/element-hq/projects/57
          github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}

  qa:
    name: Add labelled issues to QA project
    runs-on: ubuntu-latest
    if: >
      contains(github.event.issue.labels.*.name, 'Team: QA') ||
      contains(github.event.issue.labels.*.name, 'X-Needs-Signoff')
    steps:
      - uses: actions/add-to-project@main
        with:
          project-url: https://github.com/orgs/element-hq/projects/69
          github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}

  signoff:
    name: Add labelled issues to signoff project
    runs-on: ubuntu-latest
    if: >
      contains(github.event.issue.labels.*.name, 'X-Needs-Signoff')
    steps:
      - uses: actions/add-to-project@main
        with:
          project-url: https://github.com/orgs/element-hq/projects/89
          github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}


Validate Git LFS

name: Validate Git LFS

on: [pull_request, merge_group]

jobs:
  build:
    runs-on: ubuntu-latest
    name: Validate
    steps:
      - uses: nschloe/action-cached-lfs-checkout@v1.2.2

      - run: |
          ./tools/git/validate_lfs.sh


name: Build docker on every push except main branch

on:
  push:
    branches-ignore:
      - main

jobs:
  build:
    name: "Build"
    runs-on: "ubuntu-latest"
    steps:
      - uses: actions/checkout@v3
      - name: Setup cache
        uses: actions/cache@v2
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Build and push Docker images (issuer)
        uses: docker/build-push-action@v4.0.0
        with:
          push: false
          file: waltid-services/waltid-issuer-api/Dockerfile
          #tags: waltid/issuer-api:latest, waltid/issuer-api:${{ env.release_version }}
      - name: Build and push Docker images (verifier)
        uses: docker/build-push-action@v4.0.0
        with:
          push: false
          file: waltid-services/waltid-verifier-api/Dockerfile
          #tags: waltid/verifier-api:latest, waltid/verifier-api:${{ env.release_version }}
      - name: Build and push Docker images (wallet-api)
        uses: docker/build-push-action@v4.0.0
        with:
          push: false
          file: waltid-services/waltid-wallet-api/Dockerfile
          #tags: waltid/wallet-api:latest, waltid/wallet-api:${{ env.release_version }}
      - name: Build and push Docker images (waltid-web-wallet)
        uses: docker/build-push-action@v4.0.0
        with:
          push: false
          file: waltid-applications/waltid-web-wallet/Dockerfile
          #tags: waltid/waltid-web-wallet:latest, waltid/waltid-web-wallet:${{ env.release_version }}
      - name: Build and push Docker images (wallet-portal)
        uses: docker/build-push-action@v4
        with:
          push: false
          file: waltid-applications/waltid-web-portal/Dockerfile
          #tags: waltid/portal:latest, waltid/portal:${{ env.release_version }}


Build on every push except main branch

name: Build on every push except main branch

on:
  push:
    branches-ignore:
      - main

jobs:
  build:
    name: "Build"
    runs-on: "ubuntu-latest"
    steps:
      - uses: actions/checkout@v3
      - name: Setup java
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '21'
      - name: Setup cache
        uses: actions/cache@v2
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Gradle wrapper validation
        uses: gradle/wrapper-validation-action@v3

      - name: Get changed files in the frontend
        id: frontend-changed-files
        uses: tj-actions/changed-files@v44
        with:
          files: |
            waltid-applications/waltid-web-portal/**
            waltid-applications/waltid-web-wallet/web/**

      - name: Running gradle build
        uses: eskatos/gradle-command-action@v3.4.1
        env:
          MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
          MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
        with:
          arguments: build --no-daemon
        if: ${{ steps.frontend-changed-files.outputs.any_changed == 'false' }}


Docker Compose test pipeline

name: Docker Compose test pipeline

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

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Deploy Fedora Pod
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.HETZNER_KUBE_CONFIG }}
        with:
          args: apply -f docker-compose/podman.yaml

      - name: Wait for pod to be ready
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.HETZNER_KUBE_CONFIG }}
        with:
          args: wait --for=condition=ready pod -l app=podman-priv --timeout=120s

      - uses: tale/kubectl-action@v1

        with:
          base64-kube-config: ${{ secrets.HETZNER_KUBE_CONFIG }}

      - name: Get Pod Name
        id: get-pod
        run: echo "POD_NAME=$(kubectl get pods -l app=podman-priv -o jsonpath='{.items[0].metadata.name}')" >> "$GITHUB_OUTPUT"

      - name: Wait for project directory to be cloned
        run: |
          POD_NAME=$(kubectl get pods -l app=podman-priv -o jsonpath="{.items[0].metadata.name}")
          TIMEOUT=60  # 1 minute timeout
          INTERVAL=5  # Check every 5 seconds
          ELAPSED=0
          until kubectl exec -it "$POD_NAME" -- test -d /waltid-identity || [ $ELAPSED -ge $TIMEOUT ]; do
            echo "Waiting for project directory..."
            sleep $INTERVAL
            ELAPSED=$((ELAPSED + INTERVAL))
          done
          if [ $ELAPSED -ge $TIMEOUT ]; then
            echo "Error: Project directory not found within 1 minute"
            exit 1
          fi
          echo "Project directory found."
      - name: Wait for Docker Compose containers to be ready
        run: |
          POD_NAME=$(kubectl get pods -l app=podman-priv -o jsonpath="{.items[0].metadata.name}")
          TIMEOUT=300  # 5 minutes timeout
          INTERVAL=10  # Check every 10 seconds
          ELAPSED=0
          until kubectl exec -it "$POD_NAME" -- bash -c "cd /waltid-identity/docker-compose && podman-compose ps | grep -q 'Up'" || [ $ELAPSED -ge $TIMEOUT ]; do
            echo "Waiting for Docker Compose containers to be up..."
            sleep $INTERVAL
            ELAPSED=$((ELAPSED + INTERVAL))
          done
          if [ $ELAPSED -ge $TIMEOUT ]; then
            echo "Error: Docker Compose containers not up within 5 minutes"
            exit 1
          fi
          echo "Docker Compose containers are up."

      - name: Print Pod Name
        env:
          POD_NAME: ${{ steps.get-pod.outputs.POD_NAME }}
        run: echo "$POD_NAME"

      - name: Run Tests
        run: kubectl exec --stdin --tty ${{ steps.get-pod.outputs.POD_NAME }}  -- bash -c "cd waltid-identity/docker-compose && pip3 install requests && python3 api-test.py"


Pre-release on push to main

name: Pre-release on push to main

on:
  push:
    branches:
      - main

jobs:
  release:
    name: "Pre-release"
    runs-on: ubuntu-latest
    steps:
      - name: Free Disk Space (Ubuntu)
        uses: jlumbroso/free-disk-space@v1.3.1
        with:
          tool-cache: false
          docker-images: false
      - uses: actions/checkout@v3
      - name: Calculate release version
        run: |
          echo "release_version=1.0.$(date +'%g%m%d%H%M')-SNAPSHOT" >> $GITHUB_ENV
      - name: Set version
        run: |
          sed -i "s/1.0.0-SNAPSHOT/${{ env.release_version }}/g" build.gradle.kts
      - run: |
          git tag v${{ env.release_version }}
          git push --tags
      - name: Setup cache
        uses: actions/cache@v2
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Gradle wrapper validation
        uses: gradle/wrapper-validation-action@v3
      - name: Running gradle build
        uses: eskatos/gradle-command-action@v3.4.1
        env:
          MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
          MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
        with:
          arguments: build publish --no-daemon
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push Docker images (issuer)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-services/waltid-issuer-api/Dockerfile
          tags: waltid/issuer-api:latest, waltid/issuer-api:${{ env.release_version }}
      - name: Build and push Docker images (verifier)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-services/waltid-verifier-api/Dockerfile
          tags: waltid/verifier-api:latest, waltid/verifier-api:${{ env.release_version }}
      - name: Build and push Docker images (wallet-api)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-services/waltid-wallet-api/Dockerfile
          tags: waltid/wallet-api:latest, waltid/wallet-api:${{ env.release_version }}
      - name: Build and push Docker images (waltid-web-wallet)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-applications/waltid-web-wallet/Dockerfile
          tags: waltid/waltid-web-wallet:latest, waltid/waltid-web-wallet:${{ env.release_version }}
      - name: Build and push Docker images (wallet-portal)
        uses: docker/build-push-action@v4
        with:
          push: true
          file: waltid-applications/waltid-web-portal/Dockerfile
          tags: waltid/portal:latest, waltid/portal:${{ env.release_version }}

      - name: Changelog
        uses: ardalanamini/auto-changelog@v3
        id: changelog
        with:
          github-token: ${{ github.token }}
          commit-types: |
            breaking: Breaking Changes
            feat: New Features
            fix: Bug Fixes
            revert: Reverts
            perf: Performance Improvements
            refactor: Refactors
            deps: Dependencies
            docs: Documentation Changes
            style: Code Style Changes
            build: Build System
            ci: Continuous Integration
            test: Tests
            chore: Chores
            other: Other Changes
          default-commit-type: Other Changes
          release-name: v${{ env.release_version }}
          mention-authors: true
          mention-new-contributors: true
          include-compare: true
          semver: true
      - name: Create Release
        uses: softprops/action-gh-release@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: v${{ env.release_version }}
          body: |
            ${{ steps.changelog.outputs.changelog }}
          prerelease: ${{ steps.changelog.outputs.prerelease }}


Release on manual push

name: Release on manual push

on:
  workflow_dispatch:
    inputs:
      release_version:
        description: 'Release version'
        required: true

jobs:
  release:
    name: "Release"
    runs-on: ubuntu-latest
    env:
      IMAGE_TAG: ${{ inputs.release_version }}
    steps:
      - name: Free Disk Space (Ubuntu)
        uses: jlumbroso/free-disk-space@v1.3.1
        with:
          tool-cache: false
          docker-images: false
      - uses: actions/checkout@v3
      - name: Set version
        run: |
          sed -i "s/1.0.0-SNAPSHOT/${{ inputs.release_version }}/g" build.gradle.kts
      - run: |
          git tag v${{ inputs.release_version }}
          git push --tags
      - name: Setup cache
        uses: actions/cache@v2
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Gradle wrapper validation
        uses: gradle/wrapper-validation-action@v3
      - name: Running gradle build
        uses: eskatos/gradle-command-action@v3.4.1
        env:
          MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
          MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
        with:
          arguments: build publish --no-daemon
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push Docker images (issuer)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-services/waltid-issuer-api/Dockerfile
          tags: waltid/issuer-api:latest, waltid/issuer-api:${{ inputs.release_version }}
      - name: Build and push Docker images (verifier)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-services/waltid-verifier-api/Dockerfile
          tags: waltid/verifier-api:latest, waltid/verifier-api:${{ inputs.release_version }}
      - name: Build and push Docker images (wallet-api)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-services/waltid-wallet-api/Dockerfile
          tags: waltid/wallet-api:latest, waltid/wallet-api:${{ inputs.release_version }}
      - name: Build and push Docker images (waltid-web-wallet)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-applications/waltid-web-wallet/Dockerfile
          tags: waltid/waltid-web-wallet:latest, waltid/waltid-web-wallet:${{ inputs.release_version }}
      - name: Build and push Docker images (wallet-portal)
        uses: docker/build-push-action@v4
        with:
          push: true
          file: waltid-applications/waltid-web-portal/Dockerfile
          tags: waltid/portal:latest, waltid/portal:${{ inputs.release_version }}

      - name: Changelog
        uses: ardalanamini/auto-changelog@v3
        id: changelog
        with:
          github-token: ${{ github.token }}
          commit-types: |
            breaking: Breaking Changes
            feat: New Features
            fix: Bug Fixes
            revert: Reverts
            perf: Performance Improvements
            refactor: Refactors
            deps: Dependencies
            docs: Documentation Changes
            style: Code Style Changes
            build: Build System
            ci: Continuous Integration
            test: Tests
            chore: Chores
            other: Other Changes
          default-commit-type: Other Changes
          release-name: v${{ inputs.release_version }}
          mention-authors: true
          mention-new-contributors: true
          include-compare: true
          semver: true
      - name: Create Release
        uses: softprops/action-gh-release@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: v${{ inputs.release_version }}
          body: |
            ${{ steps.changelog.outputs.changelog }}
          prerelease: ${{ steps.changelog.outputs.prerelease }}
      #      issuer-api
      - name: Prepare CD - issuer
        run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" waltid-services/waltid-issuer-api/k8s/deployment-prod.yaml |
          sed "s/__DEFAULT_IMAGE_TAG__/$IMAGE_TAG/g" > waltid-services/waltid-issuer-api/k8s/deployment_mod.yaml
      - name: Continuous deployment - issuer
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
        with:
          args: apply -n portals -f waltid-services/waltid-issuer-api/k8s/deployment_mod.yaml
      #      verifier-api
      - name: Prepare CD - verifier
        run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" waltid-services/waltid-verifier-api/k8s/deployment-prod.yaml |
          sed "s/__DEFAULT_IMAGE_TAG__/$IMAGE_TAG/g" > waltid-services/waltid-verifier-api/k8s/deployment_mod.yaml
      - name: Continuous deployment - verifier
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
        with:
          args: apply -n portals -f waltid-services/waltid-verifier-api/k8s/deployment_mod.yaml
      #      wallet-api
      - name: Prepare CD - wallet.walt.id
        env:
          PROD_KEYCLOAK_CLIENT_SECRET: ${{ secrets.PROD_KEYCLOAK_CLIENT_SECRET }}
        run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" waltid-services/waltid-wallet-api/k8s/deployment-prod.yaml |
          sed "s/__DEFAULT_KEYCLOAK_CLIENT_SECRET__/$PROD_KEYCLOAK_CLIENT_SECRET/g" |
          sed "s/__DEFAULT_IMAGE_TAG__/$IMAGE_TAG/g" > waltid-services/waltid-wallet-api/k8s/deployment_mod.yaml
      - name: Continuous deployment - wallet.walt.id
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
        with:
          args: apply -n default -f waltid-services/waltid-wallet-api/k8s/deployment_mod.yaml
      #     portal
      - name: Prepare CD - portal.walt.id
        run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" waltid-applications/waltid-web-portal/k8s/deployment-prod.yaml |
          sed "s/__DEFAULT_IMAGE_TAG__/$IMAGE_TAG/g" > waltid-applications/waltid-web-portal/k8s/deployment_mod.yaml
      - name: Continuous deployment - portal.walt.id
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
        with:
          args: apply -n portals -f waltid-applications/waltid-web-portal/k8s/deployment_mod.yaml


Close stale issues and PRs

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

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@v3
        with:
          stale-issue-message: 'This issue has been marked as stale.'
          stale-pr-message: 'This pull request has been marked as stale.'


Deploy manually to test environment

name: Deploy manually to test environment

on:
  workflow_dispatch:

jobs:
  build:
    name: "Deploy to test environment"
    runs-on: "ubuntu-latest"
    steps:
      - name: Free Disk Space (Ubuntu)
        uses: jlumbroso/free-disk-space@v1.3.1
        with:
          tool-cache: false
          docker-images: false
      - uses: actions/checkout@v3
      - name: Calculate release version
        run: |
          BRANCH=$(echo ${{ github.ref }} | sed -e 's/refs\/heads\///' -e 's/\//-/g')
          echo "BRANCH=${BRANCH}" >> $GITHUB_ENV
          echo "release_version=1.0.$(date +'%g%m%d%H%M')-${BRANCH}" >> $GITHUB_ENV
      - name: Set version
        run: |
          sed -i "s/1.0.0-SNAPSHOT/${{ env.release_version }}/g" build.gradle.kts
      - run: |
          git tag v${{ env.release_version }}
          git push --tags
      - name: Setup java
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '21'
      - name: Setup cache
        uses: actions/cache@v2
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - name: Gradle wrapper validation
        uses: gradle/wrapper-validation-action@v3
      - name: Running gradle build
        uses: eskatos/gradle-command-action@v3.4.1
        with:
          arguments: build --no-daemon

      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - name: Build and push Docker images (issuer)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-services/waltid-issuer-api/Dockerfile
          tags: waltid/issuer-api:dev, waltid/issuer-api:${{ env.release_version }}
      - name: Build and push Docker images (verifier)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-services/waltid-verifier-api/Dockerfile
          tags: waltid/verifier-api:dev, waltid/verifier-api:${{ env.release_version }}
      - name: Build and push Docker images (wallet-api)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-services/waltid-wallet-api/Dockerfile
          tags: waltid/wallet-api:dev, waltid/wallet-api:${{ env.release_version }}
      - name: Build and push Docker images (waltid-web-wallet)
        uses: docker/build-push-action@v4.0.0
        with:
          push: true
          file: waltid-applications/waltid-web-wallet/Dockerfile
          tags: waltid/waltid-web-wallet:dev, waltid/waltid-web-wallet:${{ env.release_version }}
      - name: Build and push Docker images (wallet-portal)
        uses: docker/build-push-action@v4
        with:
          push: true
          file: waltid-applications/waltid-web-portal/Dockerfile
          tags: waltid/portal:dev, waltid/portal:${{ env.release_version }}

      - name: Prepare CD - issuer
        run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" waltid-services/waltid-issuer-api/k8s/deployment-dev.yaml > waltid-services/waltid-issuer-api/k8s/deployment_mod.yaml
      - name: Continuous deployment - issuer
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
        with:
          args: apply -n dev -f waltid-services/waltid-issuer-api/k8s/deployment_mod.yaml
      - name: Prepare CD - verifier
        run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" waltid-services/waltid-verifier-api/k8s/deployment-dev.yaml > waltid-services/waltid-verifier-api/k8s/deployment_mod.yaml
      - name: Continuous deployment - verifier
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
        with:
          args: apply -n dev -f waltid-services/waltid-verifier-api/k8s/deployment_mod.yaml
      - name: Prepare CD - wallet.walt-test.cloud
        env:
          DEV_KEYCLOAK_CLIENT_SECRET: ${{ secrets.DEV_KEYCLOAK_CLIENT_SECRET }}

        run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" waltid-services/waltid-wallet-api/k8s/deployment-dev.yaml |
          sed "s/__DEFAULT_KEYCLOAK_CLIENT_SECRET__/$DEV_KEYCLOAK_CLIENT_SECRET/g" > waltid-services/waltid-wallet-api/k8s/deployment_mod.yaml

      - name: Continuous deployment - wallet.walt-test.cloud
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
        with:
          args: apply -n dev -f waltid-services/waltid-wallet-api/k8s/deployment_mod.yaml
      - name: Prepare CD - portal.walt.id
        run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" waltid-applications/waltid-web-portal/k8s/deployment-dev.yaml > waltid-applications/waltid-web-portal/k8s/deployment_mod.yaml
      - name: Continuous deployment - portal.walt.id
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
        with:
          args: apply -n dev -f waltid-applications/waltid-web-portal/k8s/deployment_mod.yaml


Trigger HL7 CI/CD Workflow

name: Trigger HL7 CI/CD Workflow
on:
  workflow_dispatch:
    inputs:
      data-exchange-hl7-workflow:
        description: '(Required) Specify CI/CD workflow associated with one HL7 function app to trigger autodeploy from CDCEnt/data-exchange-hl7-devops repo'
        required: true
        type: choice
        default: 'deploy-receiver-debatcher.yml'
        options:
#        - deploy-mmg-based-transformer.yml
#        - deploy-mmg-sql-transformer.yml
        - deploy-receiver-debatcher.yml
        - deploy-redactor.yml
        - deploy-lake-segs-transformer.yml
#        - deploy-mmg-validator.yml
        - deploy-json-lake.yml
        - deploy-structure-validator.yml
#        - deploy-cache-loader.yml
        - deploy-svc-cloud-transport.yml
        - publish-nist-validator-lib.yml
        - publish-dex-commons-lib.yml
        - publish-cloud-proxy-lib.yml
        - publish-bumblebee-lib.yml
      commitID:
        description: '(Optional) Enter Full Commit Hash to trigger redeploy of prior version'
        required: false
        type: string
      data-exchange-hl7-branch:
        description: '(Optional) Enter Source Branch to trigger deployment of tip revision to the development or test environment. Defaults to develop branch'
        required: false
        type: string
        default: 'develop'
      targetEnv:
        description: 'Environment to deploy'
        required: true
        type: string
        default: 'dev'

  pull_request:
    types:
       - synchronize
       - opened
    branches:
      - 'develop'
      # - 'main'
    paths:
    - fns-hl7-pipeline/**
#    - fn-cache-loader/**
    - svc-cloud-transport/**
    - local_libs/**
  push:
    branches:
      - 'develop'
      # - 'main'
    paths:
    - fns-hl7-pipeline/**
#    - fn-cache-loader/**
    - svc-cloud-transport/**
    - local_libs/*.*

jobs:
  invoke-manual-cicd-trigger:
    if: github.event_name == 'workflow_dispatch'
    runs-on: ubuntu-latest
    name: Invoke ${{ inputs.data-exchange-hl7-workflow }}
    environment: dev
    env:
      GH_TOKEN: ${{ github.token }}
    steps:
        - name: Gen GitHub App Access Token For Manual Trigger
          id: github-app-token
          run: |
            echo ${{ github.workspace }}
            if [ ! -d data-exchange-hl7 ]; then git clone https://github.com/kave/github-app-token.git; fi;
            sudo tree -df
            cd github-app-token
            sudo gem install jwt
            echo "${{ secrets.CDC_COE_BOTFREY_PEM }}" > app-private-key.pem
            chmod +x ./get-github-app-access-token.sh;
            . ./get-github-app-access-token.sh;
            echo "access_token=${TOKEN}" >> "$GITHUB_ENV"
        - name: Git Commit SHA
          id: getsha
          run: |
            echo "sha=${{ inputs.commitID }}" >> "$GITHUB_ENV"
        - name: Manually Dispatch Remote CICD Trigger Event
          id: manual-devops-wkflow-dispatch
          uses: aurelien-baudet/workflow-dispatch@v2.1.1
          with:
              workflow: '${{ github.event.inputs.data-exchange-hl7-workflow }}'
              repo: cdcent/data-exchange-hl7-devops
              token: ${{ env.access_token }}
              inputs: '{ "targetEnv": "${{ github.event.inputs.targetEnv }}", "commitID": "${{ env.sha }}", "data-exchange-hl7-branch": "${{ github.event.inputs.data-exchange-hl7-branch  }}" }'
              ref: 'main'
              wait-for-completion: true
              wait-for-completion-timeout: 120m
              wait-for-completion-interval: 300s
              display-workflow-run-url: true
           #  workflow-logs: print --- This nice-to-have feature is documented in readme but apparantly not implemented in current version - follow up required
          # uses: actions/github-script@v6.4.1
          # with:
          #   debug: ${{ secrets.ACTIONS_RUNNER_DEBUG }}
          #   github-token: '${{ env.access_token }}'
          #   script: |
          #     try {
          #       const result = await github.rest.actions.createWorkflowDispatch({
          #         owner: 'cdcent',
          #         repo: 'data-exchange-hl7-devops',
          #         workflow_id: '${{ github.event.inputs.data-exchange-hl7-workflow }}',
          #         ref: 'main',
          #         inputs: {
          #           commitID: '${{ steps.getsha.outputs.commitID }}',
          #           'data-exchange-hl7-branch': '${{ github.event.inputs.data-exchange-hl7-branch  }}'
          #         }
          #       })
          #       console.log(result);
          #     } catch(error) {
          #       console.error(error);
          #       core.setFailed(error);
          #     }
  prepare-remote-cicd:
    permissions: write-all
    if: github.event_name != 'workflow_dispatch'
    runs-on: ubuntu-latest
    environment: dev
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
      merge_branch: ${{ steps.gettargetbranch.outputs.target_branch }}
    env:
      GH_TOKEN: ${{ github.token }}
    steps:
        - name: Get PR Commits
          if:  ${{ github.event_name }} == 'pull_request'
          uses: actions/checkout@v3
          with:
              ref: ${{ github.event.pull_request.head.sha }}
              fetch-depth: 0
        - name: Get User Commits
          uses: actions/checkout@v3
          with:
              ref: ${{ github.ref }}
              fetch-depth: 0
        - name: Get PR Merge Target Branch
          id: gettargetbranch
          run: |
            if  [[ ${{ github.event_name }} == 'pull_request' ]];
            then
              echo "target_branch=${{ github.base_ref }}" >> "$GITHUB_ENV"
              echo "target_branch=${{ github.base_ref }}" >> "$GITHUB_OUTPUT"
            else
              echo "target_branch=${{ github.ref_name }}" >>  "$GITHUB_ENV"
              echo "target_branch=${{ github.ref_name }}" >>  "$GITHUB_OUTPUT"
            fi
          # Create a list (matrix) of workflow IDs to trigger based on folders impacted by file changes in current branch
          # Convert workflow shell array into a stringified JSON so it can be bound to matrix workflow_id property used in invoke job
          # Autodeploy on Push (PR merge) to develop or main branch. All other Push events targeting feature branches will be trated as
          # Pull_Request event and will trigger CI (unit test) workflow
        - name: Determine HL7 Workflow(s) to Trigger
          id: set-matrix
          run: |
            workflows=()
            commitfldrs=$(git log -m -1 --name-only --pretty="format:"${{ github.sha }})
            echo " Files Changed in PR commit: $commitfldrs"
            if  [[ ${{ github.event_name }} == 'push' && (${{ github.ref_name }} == 'develop' || ${{ github.ref_name }} == 'main' ) ]];
            then
              case $commitfldrs in
              *fn-lake-segs-transformer*) workflows+=("deploy-lake-segs-transformer.yml") ;;&
              *fn-receiver-debatcher*) workflows+=("deploy-receiver-debatcher.yml") ;;&
              *fn-redactor*) workflows+=("deploy-redactor.yml") ;;&
              *fn-structure-validator*) workflows+=("deploy-structure-validator.yml") ;;&
              *fn-hl7-json-lake*) workflows+=("deploy-json-lake.yml") ;;&
              *svc-cloud-transport*) workflows+=("deploy-svc-cloud-transport.yml") ;;&
              *lib-bumblebee*) workflows+=("publish-bumblebee-lib.yml") ;;&
              *lib-cloud-proxy*) workflows+=("publish-cloud-proxy-lib.yml") ;;&
              *lib-dex-commons*) workflows+=("publish-dex-commons-lib.yml") ;;&
              *lib-nist-validator*) workflows+=("publish-nist-validator-lib.yml") ;;&
              *) ;;
              esac
            else
              case $commitfldrs in
              *fn-lake-segs-transformer*) workflows+=("ci-lake-segs-transformer.yml") ;;&
              *fn-receiver-debatcher*) workflows+=("ci-receiver-debatcher.yml") ;;&
              *fn-redactor*) workflows+=("ci-redactor.yml") ;;&
              *fn-structure-validator*) workflows+=("ci-structure-validator.yml") ;;&
              *fn-hl7-json-lake*) workflows+=("ci-json-lake.yml") ;;&
              *lib-bumblebee*) workflows+=("ci-lib-bumblebee.yml") ;;&
              *lib-cloud-proxy*) workflows+=("ci-lib-cloud-proxy.yml") ;;&
              *lib-dex-commons*) workflows+=("ci-lib-dex-commons.yml") ;;&
              *lib-nist-validator*) workflows+=("ci-lib-nist-validator.yml") ;;&
              *) ;;
              esac
            fi
            for value in "${workflows[@]}"
            do
              echo "$value will be triggered as part of this PR"
              echo "matrix=${workflows[@]}" >> "$GITHUB_ENV"
              echo "matrix=${workflows[@]}" >> "$GITHUB_OUTPUT"
            done
             echo "matrix=$(printf '%s\n' "${workflows[@]}" | jq -R . | jq -cs )" >> "$GITHUB_OUTPUT"
             echo "matrix=$(printf '%s\n' "${workflows[@]}" | jq -R . | jq -cs )" >> "$GITHUB_ENV"
             echo "deploy workflows=${workflows[@]}"
        - name: No CI/CD Notification
          id: no-cicd-notice
          if: fromJson(env.matrix)[0] == null
          run: |
              echo "No testable,deployable changes Detected in HL7 Validation Build Workspace"

  trigger-remote-cicd:
    if: ${{ github.event_name != 'workflow_dispatch' && fromJson(needs.prepare-remote-cicd.outputs.matrix)[0] != null }}
    needs: prepare-remote-cicd
    runs-on: ubuntu-latest
    name: Dispatch ${{ matrix.workflow_id }} Workflow
    strategy:
      fail-fast: false
      matrix:
        workflow_id: ${{fromJson(needs.prepare-remote-cicd.outputs.matrix)}}
    environment: dev
    steps:
        - name: Gen GitHub App Access Token for Automated Trigger
          id: github-app-token
          run: |
            echo ${{ github.workspace }}
            if [ ! -d github-app-token ]; then git clone https://github.com/kave/github-app-token.git; fi;
            sudo tree -df
            cd github-app-token
            sudo gem install jwt
            echo "${{ secrets.CDC_COE_BOTFREY_PEM }}" > app-private-key.pem
            chmod +x ./get-github-app-access-token.sh;
            . ./get-github-app-access-token.sh;
            echo "access_token=${TOKEN}" >> "$GITHUB_ENV"
        - name: Get Commit SHA
          id: getsha
          run: |
            echo "commitID=$(echo ${GITHUB_SHA})" >> $GITHUB_OUTPUT
        - name: Automatically Dispatch Remote CICD Trigger Event
          id: auto-devops-wkflow-dispatch
          if: ${{ matrix.workflow_id != '' }}
          uses: aurelien-baudet/workflow-dispatch@v2.1.1
          with:
              workflow: ${{ matrix.workflow_id }}
              repo: cdcent/data-exchange-hl7-devops
              token: ${{ env.access_token }}
              inputs: '{ "targetEnv": "dev", "commitID": "${{ steps.getsha.outputs.commitID }}", "data-exchange-hl7-branch": "${{ needs.prepare-remote-cicd.outputs.merge_branch }}" }'
              ref: 'main'
              wait-for-completion: true
              wait-for-completion-timeout: 120m
              wait-for-completion-interval: 300s
              display-workflow-run-url: true

        # workflow-logs: print
        #   uses: actions/github-script@v6.4.1
        #   with:
        #     debug: ${{ secrets.ACTIONS_RUNNER_DEBUG }}
        #     github-token: '${{ env.access_token }}'
        #     script: |
        #       try {
        #         const result = await github.rest.actions.createWorkflowDispatch({
        #           owner: 'cdcent',
        #           repo: 'data-exchange-hl7-devops',
        #           workflow_id: '${{ matrix.workflow_id }}',
        #           ref: 'main',
        #           inputs: {
        #             commitID: '${{ steps.getsha.outputs.commitID }}',
        #             'data-exchange-hl7-branch': '${{ needs.prepare-remote-cicd.outputs.merge_branch }}'
        #           }
        #         })
        #         console.log(result);
        #       } catch(error) {
        #         console.error(error);
        #         core.setFailed(error);
        #       }


Run Test hl7-structural-validator

name: Run Test hl7-structural-validator

on:
  push:
    paths:
      - hl7-structural-validator/**
  pull_request:
    branches: [ "master" ]

permissions:
  contents: read

jobs:
  run_test:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'
        cache: 'sbt'
    - name: Run tests
      run: sbt test


Code Scan Workflow

# Fortify code scan required when merging to Main
env:
    nestedFolders: fns-hl7-pipeline,fns-sidecars,local_libs

name: Code Scan Workflow

defaults:
  run:
    shell: bash

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

permissions:
  contents: read
  pull-requests: write # required for `comment-summary-in-pr`

jobs:
  invoke-manual-code-scan:
    environment: dev
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - name: Gen GitHub App Access Token For Manual Trigger
      id: github-app-token
      run: |
        echo ${{ github.workspace }}
        if [ ! -d data-exchange-hl7 ]; then git clone https://github.com/kave/github-app-token.git; fi;
        sudo tree -df
        cd github-app-token
        sudo gem install jwt
        echo "${{ secrets.CDC_COE_BOTFREY_PEM }}" > app-private-key.pem
        chmod +x ./get-github-app-access-token.sh;
        . ./get-github-app-access-token.sh;
        echo "access_token=${TOKEN}" >> "$GITHUB_ENV"

    - name: List unique top-level directories of changed files
      id: getdirs2scan
      run: |
        unique_paths=$(python3 tools/codeScan/gitDiffAnalysis.py '${{ env.nestedFolders }}')
        echo "dirs=$unique_paths" >> $GITHUB_OUTPUT

    - name: Dispatch Remote Code Scan Event
      id: manual-devops-wkflow-dispatch
      uses: aurelien-baudet/workflow-dispatch@v2.1.1
      with:
        workflow: 'pull-request-code-scan.yml'
        repo: cdcent/data-exchange-hl7-devops
        token: ${{ env.access_token }}
        inputs: '{ "pathsToScan": ${{ steps.getdirs2scan.outputs.dirs }}, "repositoryToScan": "${{ github.repository }}", "prToScan": "${{ github.head_ref || github.ref_name }}" }'
        ref: 'main'
        wait-for-completion: true
        wait-for-completion-timeout: 120m
        wait-for-completion-interval: 300s
        display-workflow-run-url: true


Scan with Detekt

# This workflow performs a static analysis of your Kotlin source code using
# Detekt.
#
# Scans are triggered:
# 1. On every push to default and protected branches
# 2. On every Pull Request targeting the default branch
# 3. On a weekly schedule
# 4. Manually, on demand, via the "workflow_dispatch" event
#
# The workflow should work with no modifications, but you might like to use a
# later version of the Detekt CLI by modifing the $DETEKT_RELEASE_TAG
# environment variable.
name: Scan with Detekt

on:
  # Triggers the workflow on push or pull request events but only for default and protected branches
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  schedule:
     - cron: '25 8 * * 5'

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

env:
  # Release tag associated with version of Detekt to be installed
  # SARIF support (required for this workflow) was introduced in Detekt v1.15.0
  DETEKT_RELEASE_TAG: v1.15.0

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "scan"
  scan:
    name: Scan
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
    # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
    - uses: actions/checkout@v4

    # Gets the download URL associated with the $DETEKT_RELEASE_TAG
    - name: Get Detekt download URL
      id: detekt_info
      env:
        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
        DETEKT_DOWNLOAD_URL=$( gh api graphql --field tagName=$DETEKT_RELEASE_TAG --raw-field query='
          query getReleaseAssetDownloadUrl($tagName: String!) {
            repository(name: "detekt", owner: "detekt") {
              release(tagName: $tagName) {
                releaseAssets(name: "detekt", first: 1) {
                  nodes {
                    downloadUrl
                  }
                }
              }
            }
          }
        ' | \
        jq --raw-output '.data.repository.release.releaseAssets.nodes[0].downloadUrl' )
        echo "::set-output name=download_url::$DETEKT_DOWNLOAD_URL"

    # Sets up the detekt cli
    - name: Setup Detekt
      run: |
        dest=$( mktemp -d )
        curl --request GET \
          --url ${{ steps.detekt_info.outputs.download_url }} \
          --silent \
          --location \
          --output $dest/detekt
        chmod a+x $dest/detekt
        echo $dest >> $GITHUB_PATH

    # Performs static analysis using Detekt
    - name: Run Detekt
      continue-on-error: true
      run: |
        detekt --input ${{ github.workspace }} --report sarif:${{ github.workspace }}/detekt.sarif.json

    # Modifies the SARIF output produced by Detekt so that absolute URIs are relative
    # This is so we can easily map results onto their source files
    # This can be removed once relative URI support lands in Detekt: https://git.io/JLBbA
    - name: Make artifact location URIs relative
      continue-on-error: true
      run: |
        echo "$(
          jq \
            --arg github_workspace ${{ github.workspace }} \
            '. | ( .runs[].results[].locations[].physicalLocation.artifactLocation.uri |= if test($github_workspace) then .[($github_workspace | length | . + 1):] else . end )' \
            ${{ github.workspace }}/detekt.sarif.json
        )" > ${{ github.workspace }}/detekt.sarif.json

    # Uploads results to GitHub repository using the upload-sarif action
    - uses: github/codeql-action/upload-sarif@v3
      with:
        # Path to SARIF file relative to the root of the repository
        sarif_file: ${{ github.workspace }}/detekt.sarif.json
        checkout_path: ${{ github.workspace }}


Pull Request CI

name: Pull Request CI

on:
  pull_request:

jobs:
  pr_check_wrapper:
    name: Validate Gradle Wrapper
    runs-on: ubuntu-latest
    steps:
      - name: Clone repo
        uses: actions/checkout@v4

      - name: Validate Gradle Wrapper
        uses: gradle/wrapper-validation-action@v3.3.2

  pr_build:
    runs-on: ubuntu-latest
    steps:
      - name: clone repo
        uses: actions/checkout@v4

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

      - name: Build app
        uses: eskatos/gradle-command-action@v3.3.2
        with:
          arguments: assembleDebug


Release app

name: Release app
on:
  push:
    branches:
      - main

jobs:
  check_wrapper:
    name: Validate Gradle Wrapper
    runs-on: ubuntu-latest
    steps:
      - name: Clone repo
        uses: actions/checkout@v4

      - name: Validate Gradle Wrapper
        uses: gradle/wrapper-validation-action@v3.3.2

  build:
    name: Build app
    needs: check_wrapper
    runs-on: ubuntu-latest

    steps:
      - name: Cancel previous runs
        uses: styfle/cancel-workflow-action@0.12.1
        with:
          access_token: ${{ github.token }}

      - name: Setup Android SDK
        run: |
          ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager  "build-tools;29.0.3"

      - name: Clone repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

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

      - name: Write google-services.json
        uses: DamianReeves/write-file-action@v1.3
        with:
          path: app/google-services.json
          contents: ${{ secrets.GOOGLE_SERVICE_JSON }}
          write-mode: overwrite # optional, default is preserve

      - name: Build app
        uses: eskatos/gradle-command-action@v3
        with:
          arguments: assembleStandardRelease

      - name: Sign APK
        id: sign_app
        uses: r0adkll/sign-android-release@v1
        with:
          releaseDirectory: app/build/outputs/apk/standard/release
          signingKeyBase64: ${{ secrets.SIGNING_KEY }}
          alias: ${{ secrets.KEY_ALIAS }}
          keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
          keyPassword: ${{ secrets.KEY_PASSWORD }}

      - name: Get previous release
        id: last_release
        uses: pozetroninc/github-action-get-latest-release@master
        with:
          repository: ${{ github.repository }}
          excludes: prerelease, draft

      - name: Prepare build
        run: |
          set -e

          current_sha=$(git rev-parse --short HEAD)
          echo "CURRENT_SHA=$current_sha"
          echo "CURRENT_SHA=$current_sha" >> $GITHUB_ENV
          prev_release_sha=$(git rev-list -n 1 ${{ steps.last_release.outputs.release }})
          echo "PREV_RELEASE_SHA=$prev_release_sha"
          echo "PREV_RELEASE_SHA=$prev_release_sha" >> $GITHUB_ENV
          echo "Url to compare: https://api.github.com/repos/nekomangaorg/neko/compare/$prev_release_sha...$current_sha"

          echo "COMMIT_LOGS<<{delimiter}
          $(curl -H "Accept: application/vnd.github.v3+json" \
            "https://api.github.com/repos/nekomangaorg/neko/compare/$prev_release_sha...$current_sha" \
            | jq '[.commits[]|{message:(.commit.message | split("\n")), username:.author.login}]' \
            | jq -r '.[]|"- \(.message | first) (@\(.username))"')
          {delimiter}" >> $GITHUB_ENV

      - name: Prep build artifacts for release
        run: |
          set -e
          mv app/build/outputs/apk/standard/release/Neko-standard-universal-release-unsigned-signed.apk neko-universal.apk
          sha=`sha256sum neko-universal.apk | awk '{ print $1 }'`
          echo "APK_UNIVERSAL_SHA=$sha" >> $GITHUB_ENV
          echo "| Universal | $sha" >> CurrentChangeLog.MD

          cp app/build/outputs/apk/standard/release/Neko-standard-arm64-v8a-release-unsigned-signed.apk neko-arm64-v8a.apk
          sha=`sha256sum neko-arm64-v8a.apk | awk '{ print $1 }'`
          echo "APK_ARM64_V8A_SHA=$sha" >> $GITHUB_ENV

          cp app/build/outputs/apk/standard/release/Neko-standard-armeabi-v7a-release-unsigned-signed.apk neko-armeabi-v7a.apk
          sha=`sha256sum neko-armeabi-v7a.apk | awk '{ print $1 }'`
          echo "APK_ARMEABI_V7A_SHA=$sha" >> $GITHUB_ENV

          cp app/build/outputs/apk/standard/release/Neko-standard-x86-release-unsigned-signed.apk neko-x86.apk
          sha=`sha256sum neko-x86.apk | awk '{ print $1 }'`
          echo "APK_X86_SHA=$sha" >> $GITHUB_ENV

          cp app/build/outputs/apk/standard/release/Neko-standard-x86_64-release-unsigned-signed.apk neko-x86_64.apk
          sha=`sha256sum neko-x86_64.apk | awk '{ print $1 }'`
          echo "APK_X86_64_SHA=$sha" >> $GITHUB_ENV

      - name: Delete release draft
        uses: hugo19941994/delete-draft-releases@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create Release
        uses: ncipollo/release-action@v1.14.0
        with:
          allowUpdates: true
          body: |
            ## 🥳 New
            ## 🏗 Changes
            ## 🐜 Fixes
            ## 🛠 Other

            ${{ env.COMMIT_LOGS }}

            | Variant | SHA-256 |
            | ------- | ------- |
            | Universal | ${{ env.APK_UNIVERSAL_SHA }}
            | arm64-v8a | ${{ env.APK_ARM64_V8A_SHA }}
            | armeabi-v7a | ${{ env.APK_ARMEABI_V7A_SHA }}
            | x86 | ${{ env.APK_X86_SHA }}
            | x86_64 | ${{ env.APK_X86_64_SHA }}

          token: ${{ secrets.GITHUB_TOKEN }}
          draft: true
          replacesArtifacts: true
          tag: "latest"
          artifacts: "*.apk"


Close issues

name: Close issues
on:
  push:
    tags:
      - '*'
jobs:
  close_isssues:
    name: Close old issues
    runs-on: ubuntu-latest
    steps:
      - uses: nonproto/auto-closer@1.0.0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          AC_LABEL: "staged for next release"


Batch close stale issues

name: "Batch close stale issues"

on:
  # Monthly
  schedule:
    - cron: '0 0 1 * *'
  # Manual trigger
  workflow_dispatch:
    inputs:

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          # Close everything older than a year
          days-before-issue-stale: 365
          days-before-issue-close: 0
          exempt-issue-labels: "do-not-autoclose,Meta request"
          close-issue-message: "In an effort to have a more manageable issue backlog, we're closing older requests that weren't addressed since there's a low chance of it being addressed if it hasn't already. If your request is still relevant, please [open a new request](https://github.com/keiyoushi/extensions-source/issues/new/choose)."
          close-issue-reason: not_planned
          ascending: true
          operations-per-run: 250


PR build check

name: PR build check

on:
  pull_request:
    paths:
      - '**'
      - '!**.md'
      - '!.github/**'
      - '.github/workflows/build_pull_request.yml'

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

env:
  CI_CHUNK_SIZE: 65

jobs:
  prepare:
    name: Prepare job
    runs-on: ubuntu-latest
    outputs:
      individualMatrix: ${{ steps.generate-matrices.outputs.individualMatrix }}
    steps:
      - name: Clone repo
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Validate Gradle Wrapper
        uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2

      - name: Get number of modules
        run: |
          set -x
          projects=(src/*/*)

          echo "NUM_INDIVIDUAL_MODULES=${#projects[@]}" >> $GITHUB_ENV

      - id: generate-matrices
        name: Create output matrices
        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
        with:
          script: |
            const numIndividualModules = process.env.NUM_INDIVIDUAL_MODULES;
            const chunkSize = process.env.CI_CHUNK_SIZE;

            const numIndividualChunks = Math.ceil(numIndividualModules / chunkSize);

            console.log(`Individual modules: ${numIndividualModules} (${numIndividualChunks} chunks of ${chunkSize})`);

            core.setOutput('individualMatrix', { 'chunk': [...Array(numIndividualChunks).keys()] });

  build_individual:
    name: Build individual modules
    needs: prepare
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{ fromJSON(needs.prepare.outputs.individualMatrix) }}
    steps:
      - name: Checkout PR
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Set up JDK
        uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1
        with:
          java-version: 17
          distribution: temurin

      - name: Set up Gradle
        uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2
        with:
          cache-read-only: true

      - name: Build extensions (chunk ${{ matrix.chunk }})
        env:
          CI_CHUNK_NUM: ${{ matrix.chunk }}
        run: ./gradlew -p src assembleDebug


CI

name: CI

on:
  push:
    branches:
      - main
    paths:
      - '**'
      - '!**.md'
      - '!.github/**'
      - '.github/scripts/**'
      - '.github/workflows/build_push.yml'

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

env:
  CI_CHUNK_SIZE: 65

jobs:
  prepare:
    name: Prepare job
    runs-on: ubuntu-latest
    outputs:
      individualMatrix: ${{ steps.generate-matrices.outputs.individualMatrix }}
    steps:
      - name: Clone repo
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Validate Gradle Wrapper
        uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2

      - name: Get number of modules
        run: |
          set -x
          projects=(src/*/*)

          echo "NUM_INDIVIDUAL_MODULES=${#projects[@]}" >> $GITHUB_ENV

      - id: generate-matrices
        name: Create output matrices
        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
        with:
          script: |
            const numIndividualModules = process.env.NUM_INDIVIDUAL_MODULES;
            const chunkSize = process.env.CI_CHUNK_SIZE;

            const numIndividualChunks = Math.ceil(numIndividualModules / chunkSize);

            console.log(`Individual modules: ${numIndividualModules} (${numIndividualChunks} chunks of ${chunkSize})`);

            core.setOutput('individualMatrix', { 'chunk': [...Array(numIndividualChunks).keys()] });

  build_individual:
    name: Build individual modules
    needs: prepare
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{ fromJSON(needs.prepare.outputs.individualMatrix) }}
    steps:
      - name: Checkout main branch
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Set up JDK
        uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1
        with:
          java-version: 17
          distribution: temurin

      - name: Prepare signing key
        run: |
          echo ${{ secrets.SIGNING_KEY }} | base64 -d > signingkey.jks

      - name: Set up Gradle
        uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2
        with:
          cache-read-only: ${{ matrix.chunk != 0 }}

      - name: Build extensions (chunk ${{ matrix.chunk }})
        env:
          CI_CHUNK_NUM: ${{ matrix.chunk }}
          ALIAS: ${{ secrets.ALIAS }}
          KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
          KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
        run: ./gradlew -p src assembleRelease

      - name: Upload APKs (chunk ${{ matrix.chunk }})
        uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
        if: "github.repository == 'keiyoushi/extensions-source'"
        with:
          name: "individual-apks-${{ matrix.chunk }}"
          path: "**/*.apk"
          retention-days: 1

      - name: Clean up CI files
        run: rm signingkey.jks

  publish_repo:
    name: Publish repo
    needs:
      - build_individual
    if: "github.repository == 'keiyoushi/extensions-source'"
    runs-on: ubuntu-latest
    steps:
      - name: Download APK artifacts
        uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
        with:
          path: ~/apk-artifacts

      - name: Set up JDK
        uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1
        with:
          java-version: 17
          distribution: temurin

      - name: Checkout main branch
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          ref: main
          path: main

      - name: Create repo artifacts
        run: |
          cd main
          python ./.github/scripts/move-apks.py
          INSPECTOR_LINK="$(curl -s "https://api.github.com/repos/keiyoushi/extensions-inspector/releases/latest" | jq -r '.assets[0].browser_download_url')"
          curl -L "$INSPECTOR_LINK" -o ./Inspector.jar
          java -jar ./Inspector.jar "repo/apk" "output.json" "tmp"
          python ./.github/scripts/create-repo.py

      - name: Checkout repo branch
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          repository: keiyoushi/extensions
          token: ${{ secrets.BOT_PAT }}
          ref: repo
          path: repo

      - name: Deploy repo
        run: |
          cd repo
          ../main/.github/scripts/commit-repo.sh


Mirror Sync

# Sync repo to the Codeberg mirror
name: Mirror Sync

on:
  push:
    branches: [ "main" ]
  workflow_dispatch: # Manual dispatch
  schedule:
    - cron: "0 */8 * * *"

jobs:
  codeberg:
    if: "github.repository == 'keiyoushi/extensions-source'"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 0
      - uses: pixta-dev/repository-mirroring-action@674e65a7d483ca28dafaacba0d07351bdcc8bd75 # v1.1.1
        with:
          target_repo_url: "git@codeberg.org:keiyoushi/extensions-source.git"
          ssh_private_key: ${{ secrets.CODEBERG_SSH }}


Issue moderator

name: Issue moderator

on:
  issues:
    types: [ opened, edited, reopened ]
  issue_comment:
    types: [ created ]

jobs:
  autoclose:
    runs-on: ubuntu-latest
    steps:
      - name: Moderate issues
        uses: keiyoushi/issue-moderator-action@a017be83547db6e107431ce7575f53c1dfa3296a
        with:
          repo-token: ${{ secrets.ISSUE_MODERATOR_PAT }}
          duplicate-label: Duplicate

          blurbs: |
            [
              {
                "keywords": ["cf", "cloudflare"],
                "message": "Refer to the **Solving Cloudflare issues** section at https://keiyoushi.github.io/docs/guides/troubleshooting#cloudflare. If it doesn't work, migrate to other sources or wait until they lower their protection."
              },
              {
                "keywords": ["uninstall"],
                "message": "Uninstall the extension before updating. If that does not work, uninstall it from your device's settings by navigating to your device's Settings -> Apps and uninstall it from there by looking for `Tachiyomi: <extension name>`.\n\nThis is usually caused your previous extension having a different signature from the updated extension, making Android refuse to update it."
              }
            ]

          duplicate-check-enabled: true
          duplicate-check-labels: |
            ["Source request", "Domain changed"]

          existing-check-enabled: true
          existing-check-labels: |
            ["Source request", "Domain changed"]
          existing-check-repo-url: https://raw.githubusercontent.com/keiyoushi/extensions/repo/index.min.json

          auto-close-rules: |
            [
              {
                "type": "both",
                "regex": ".*(?:fail(?:ed|ure|s)?|can\\s*(?:no|')?t|(?:not|un).*able|(?<!n[o']?t )blocked by|error) (?:to )?(?:get past|by ?pass|penetrate)?.*cl[oa]ud ?fl?[ai]re.*",
                "ignoreCase": true,
                "labels": ["Cloudflare protected"],
                "message": "Refer to the **Solving Cloudflare issues** section at https://keiyoushi.github.io/docs/guides/troubleshooting#cloudflare. If it doesn't work, migrate to other sources or wait until they lower their protection."
              },
              {
                "type": "both",
                "regex": "remanga\\.org",
                "ignoreCase": true,
                "labels": ["invalid"],
                "message": "ReManga (Russian) will not be added back as it has been removed [due to legal reasons](https://github.com/github/dmca)."
              },
              {
                "type": "both",
                "regex": "(kumanga\\.com)",
                "ignoreCase": true,
                "labels": ["invalid"],
                "message": "{match} will not be added back as it is too difficult to maintain."
              }
            ]
          auto-close-ignore-label: do-not-autoclose


Lock threads

name: Lock threads

on:
  # Daily
  schedule:
    - cron: '0 0 * * *'
  # Manual trigger
  workflow_dispatch:
    inputs:

jobs:
  lock:
    runs-on: ubuntu-latest
    steps:
      - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
        with:
          github-token: ${{ github.token }}
          issue-inactive-days: '2'
          pr-inactive-days: '2'


PR build check

name: PR build check
on:
  pull_request:
    paths-ignore:
      - '**.md'
      - 'i18n/src/commonMain/moko-resources/**/strings.xml'
      - 'i18n/src/commonMain/moko-resources/**/plurals.xml'

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

permissions:
  contents: read

jobs:
  build:
    name: Build app
    runs-on: ubuntu-latest

    steps:
      - name: Clone repo
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Validate Gradle Wrapper
        uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2

      - name: Dependency Review
        uses: actions/dependency-review-action@72eb03d02c7872a771aacd928f3123ac62ad6d3a # v4.3.3

      - name: Set up JDK
        uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1
        with:
          java-version: 17
          distribution: adopt

      - name: Set up gradle
        uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2

      - name: Build app and run unit tests
        run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest

      - name: Upload APK
        uses: actions/upload-artifact@v4
        with:
          name: arm64-v8a-${{ github.sha }}
          path: app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned.apk

      - name: Upload mapping
        uses: actions/upload-artifact@v4
        with:
          name: mapping-${{ github.sha }}
          path: app/build/outputs/mapping/standardRelease


CI

name: CI
on:
  push:
    branches:
      - main
    tags:
      - v*

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

jobs:
  build:
    name: Build app
    runs-on: ubuntu-latest

    steps:
      - name: Clone repo
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Validate Gradle Wrapper
        uses: gradle/actions/wrapper-validation@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2

      - name: Setup Android SDK
        run: |
          ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "build-tools;29.0.3"

      - name: Set up JDK
        uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1
        with:
          java-version: 17
          distribution: adopt

      - name: Set up gradle
        uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda # v3.4.2

      - name: Build app and run unit tests
        run: ./gradlew detekt assembleStandardRelease testReleaseUnitTest testStandardReleaseUnitTest

      - name: Upload APK
        uses: actions/upload-artifact@v4
        with:
          name: arm64-v8a-${{ github.sha }}
          path: app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned.apk

      - name: Upload mapping
        uses: actions/upload-artifact@v4
        with:
          name: mapping-${{ github.sha }}
          path: app/build/outputs/mapping/standardRelease

      # Sign APK and create release for tags

      - name: Get tag name
        if: startsWith(github.ref, 'refs/tags/') && github.repository == 'mihonapp/mihon'
        run: |
          set -x
          echo "VERSION_TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV

      - name: Sign APK
        if: startsWith(github.ref, 'refs/tags/') && github.repository == 'mihonapp/mihon'
        uses: r0adkll/sign-android-release@349ebdef58775b1e0d8099458af0816dc79b6407 # v1
        with:
          releaseDirectory: app/build/outputs/apk/standard/release
          signingKeyBase64: ${{ secrets.SIGNING_KEY }}
          alias: ${{ secrets.ALIAS }}
          keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
          keyPassword: ${{ secrets.KEY_PASSWORD }}

      - name: Clean up build artifacts
        if: startsWith(github.ref, 'refs/tags/') && github.repository == 'mihonapp/mihon'
        run: |
          set -e

          mv app/build/outputs/apk/standard/release/app-standard-universal-release-unsigned-signed.apk mihon-${{ env.VERSION_TAG }}.apk
          sha=`sha256sum mihon-${{ env.VERSION_TAG }}.apk | awk '{ print $1 }'`
          echo "APK_UNIVERSAL_SHA=$sha" >> $GITHUB_ENV

          cp app/build/outputs/apk/standard/release/app-standard-arm64-v8a-release-unsigned-signed.apk mihon-arm64-v8a-${{ env.VERSION_TAG }}.apk
          sha=`sha256sum mihon-arm64-v8a-${{ env.VERSION_TAG }}.apk | awk '{ print $1 }'`
          echo "APK_ARM64_V8A_SHA=$sha" >> $GITHUB_ENV

          cp app/build/outputs/apk/standard/release/app-standard-armeabi-v7a-release-unsigned-signed.apk mihon-armeabi-v7a-${{ env.VERSION_TAG }}.apk
          sha=`sha256sum mihon-armeabi-v7a-${{ env.VERSION_TAG }}.apk | awk '{ print $1 }'`
          echo "APK_ARMEABI_V7A_SHA=$sha" >> $GITHUB_ENV

          cp app/build/outputs/apk/standard/release/app-standard-x86-release-unsigned-signed.apk mihon-x86-${{ env.VERSION_TAG }}.apk
          sha=`sha256sum mihon-x86-${{ env.VERSION_TAG }}.apk | awk '{ print $1 }'`
          echo "APK_X86_SHA=$sha" >> $GITHUB_ENV

          cp app/build/outputs/apk/standard/release/app-standard-x86_64-release-unsigned-signed.apk mihon-x86_64-${{ env.VERSION_TAG }}.apk
          sha=`sha256sum mihon-x86_64-${{ env.VERSION_TAG }}.apk | awk '{ print $1 }'`
          echo "APK_X86_64_SHA=$sha" >> $GITHUB_ENV

      - name: Create Release
        if: startsWith(github.ref, 'refs/tags/') && github.repository == 'mihonapp/mihon'
        uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v2.0.6
        with:
          tag_name: ${{ env.VERSION_TAG }}
          name: Mihon ${{ env.VERSION_TAG }}
          body: |
            ---

            ### Checksums

            | Variant | SHA-256 |
            | ------- | ------- |
            | Universal | ${{ env.APK_UNIVERSAL_SHA }}
            | arm64-v8a | ${{ env.APK_ARM64_V8A_SHA }}
            | armeabi-v7a | ${{ env.APK_ARMEABI_V7A_SHA }}
            | x86 | ${{ env.APK_X86_SHA }} |
            | x86_64 | ${{ env.APK_X86_64_SHA }} |

            ## If you are unsure which version to choose then go with mihon-${{ env.VERSION_TAG }}.apk
          files: |
            mihon-${{ env.VERSION_TAG }}.apk
            mihon-arm64-v8a-${{ env.VERSION_TAG }}.apk
            mihon-armeabi-v7a-${{ env.VERSION_TAG }}.apk
            mihon-x86-${{ env.VERSION_TAG }}.apk
            mihon-x86_64-${{ env.VERSION_TAG }}.apk
          draft: true
          prerelease: false
        env:
          GITHUB_TOKEN: ${{ secrets.PAT }}


name: CI

on:
  workflow_dispatch: {}
  push:
    branches:
      - main
      - 'v*'
  pull_request: {}
  schedule:
    - cron:  '0 3 * * *' # daily, at 3am

jobs:
  test:
    name: Tests
    runs-on: ${{ matrix.os }}

    strategy:
       matrix:
         os: [ubuntu-latest, windows-latest]

    steps:
      - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
        with:
          submodules: true

          token: ${{ github.token }}

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

      - uses: actions/cache@v4
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - run: chmod +x ./gradlew
      - run: ./gradlew assemble
      - run: ./gradlew check
  release:
    name: Update Changelog, Create Tag and Release
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
        with:
          submodules: true
          fetch-depth: 0
          token: ${{ github.token }}
      - name: Use Node.js 18
        uses: actions/setup-node@v4
        with:
          node-version: 18
      - run: sudo apt-get install markdown -y
      - uses: actions/setup-java@v4.2.1
        with:
          java-version: '17'
          distribution: 'zulu'

      - name: verify tag exists
        id: tag-exists
        run: |
          version=$(sh ./gradlew -q printVersion)
          TAG=v$version
          if git rev-parse "$TAG" >/dev/null 2>&1; then
            echo "tag exists";
            echo "exists=true" >> "$GITHUB_OUTPUT"
          else
            echo "exists=false" >> "$GITHUB_OUTPUT"
          fi
      - name: verify release already published
        id: already-published
        run: |
          version=$(sh ./gradlew -q printVersion)
          released=$(echo "$version" | sh ./gradlew verifyAlreadyReleased -q)
          echo "exists=$released" >> "$GITHUB_OUTPUT"
      - name: create changelog
        id: changelog
        env:
          TAG_EXISTS: ${{ steps.tag-exists.outputs.exists }}
          GITHUB_AUTH: ${{ github.token }}
          GITHUB_REPO: ${{ github.repository }}
        run: |
          version=$(sh ./gradlew -q printVersion)
          TAG=v$version
          if [[ "$TAG_EXISTS" == "true" ]]; then
            from=$(git tag --sort=-creatordate | grep -A 1 $TAG | tail -n 1)
            changelog=$(npx lerna-changelog --repo $GITHUB_REPO --from="$from" --to="$TAG")
            echo "$changelog" > new_changelog.txt
          else
            changelog=$(npx lerna-changelog --repo $GITHUB_REPO --next-version=$TAG)
            echo "$changelog" > new_changelog.txt
          fi
          echo "$changelog"
          echo "::debug::changelog $changelog"

          html=$(echo "$changelog" | markdown)
          echo "html: $html"
          echo "::debug::html $html"

      - name: create tag
        id: tag
        if: steps.tag-exists.outputs.exists == 'false'
        env:
          GITHUB_TOKEN: ${{ github.token }}
          GITHUB_ACTOR: ${{ github.actor }}
          GITHUB_COMMIT: ${{ github.sha }}
          GITHUB_REPO: ${{ github.repository }}

        run: |
          set -e
          CHANGELOG=$(cat new_changelog.txt)
          echo "$CHANGELOG"
          version=$(sh ./gradlew -q printVersion)
          TAG=v$version
          echo -e "# Changelog\n\n$CHANGELOG\n$(tail --lines=+2 CHANGELOG.md)" > CHANGELOG.md
          git add CHANGELOG.md
          git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
          git config --local user.name "$GITHUB_ACTOR"
          git commit -m "update changelog"
          git tag $TAG
          git fetch --all
          git rebase origin/main
          git push
          git push --tags
          echo "tag=created" >> "$GITHUB_OUTPUT"
      - if: (steps.tag.outputs.tag == 'created' || steps.tag-exists.outputs.exists == 'true') && steps.already-published.outputs.exists == 'false'
        env:
          ORG_GRADLE_PROJECT_intellijPublishToken: ${{ secrets.ORG_GRADLE_PROJECT_intellijPublishToken }}

        run: |
          chmod +x ./gradlew
          CHANGELOG=$(cat new_changelog.txt | markdown)
          echo "$CHANGELOG" | sh ./gradlew updateChangelog
          ./gradlew buildPlugin
          ./gradlew publishPlugin

  upload:
    name: Upload
    runs-on: ubuntu-latest
    needs: test
    steps:
      - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
        with:
          submodules: true

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

      - uses: actions/cache@v4
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
          restore-keys: |
            ${{ runner.os }}-gradle-
      - run: chmod +x ./gradlew
      - run: ./gradlew buildPlugin && ls ./build/distributions
      - uses: actions/upload-artifact@v4
        with:
          name: EmberExperimental.zip
          path: ./build/distributions/EmberExperimental.js-*.zip


Build

# GitHub Actions Workflow created for testing and preparing the plugin release in following steps:
# - validate Gradle Wrapper,
# - run 'test' and 'verifyPlugin' tasks,
# - run Qodana inspections,
# - run 'buildPlugin' task and prepare artifact for the further tests,
# - run 'runPluginVerifier' task,
# - create a draft release.
#
# Workflow is triggered on push and pull_request events.
#
# GitHub Actions reference: https://help.github.com/en/actions
#
## JBIJPPTPL

name: Build
on:
  # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g. for dependabot pull requests)
  push:
    branches: [main]
  # Trigger the workflow on any pull request
  pull_request:

jobs:
  ktlint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: |
          curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.44.0/ktlint && chmod a+x ktlint && sudo mv ktlint /usr/local/bin/
      - name: run ktlint
        run: |
          ktlint
        continue-on-error: false

# Run Gradle Wrapper Validation Action to verify the wrapper's checksum
  # Run verifyPlugin, IntelliJ Plugin Verifier, and test Gradle tasks
  # Build plugin and provide the artifact for the next workflow jobs
  build:
    name: Build
    needs: ktlint
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.properties.outputs.version }}
      changelog: ${{ steps.properties.outputs.changelog }}
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2.4.0

      # Validate wrapper
      - name: Gradle Wrapper Validation
        uses: gradle/wrapper-validation-action@v1.0.4

      # Setup Java 17 environment for the next steps
      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          distribution: zulu
          java-version: 17
#          cache: gradle

      # Set environment variables
      - name: Export Properties
        id: properties
        shell: bash
        run: |
          PROPERTIES="$(./gradlew properties --console=plain -q)"
          VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
          NAME="$(echo "$PROPERTIES" | grep "^pluginName:" | cut -f2- -d ' ')"
          CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)"
          CHANGELOG="${CHANGELOG//'%'/'%25'}"
          CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
          CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"

          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "name=$NAME" >> $GITHUB_OUTPUT
          echo "changelog=$CHANGELOG" >> $GITHUB_OUTPUT
          echo "pluginVerifierHomeDir=~/.pluginVerifier" >> $GITHUB_OUTPUT

          ./gradlew listProductsReleases # prepare list of IDEs for Plugin Verifier

      # Run tests
      - name: Run Tests
        run: ./gradlew test

      # Collect Tests Result of failed tests
      - name: Collect Tests Result
        if: ${{ failure() }}
        uses: actions/upload-artifact@v2
        with:
          name: tests-result
          path: ${{ github.workspace }}/build/reports/tests

      # Cache Plugin Verifier IDEs
      - name: Setup Plugin Verifier IDEs Cache
        uses: actions/cache@v2.1.7
        with:
          path: ${{ steps.properties.outputs.pluginVerifierHomeDir }}/ides
          key: plugin-verifier-${{ hashFiles('build/listProductsReleases.txt') }}

      # Run Verify Plugin task and IntelliJ Plugin Verifier tool
      - name: Run Plugin Verification tasks
        run: ./gradlew runPluginVerifier -Pplugin.verifier.home.dir=${{ steps.properties.outputs.pluginVerifierHomeDir }}

      # Collect Plugin Verifier Result
      - name: Collect Plugin Verifier Result
        if: ${{ always() }}
        uses: actions/upload-artifact@v2
        with:
          name: pluginVerifier-result
          path: ${{ github.workspace }}/build/reports/pluginVerifier

#      # Run Qodana inspections
#      - name: Qodana - Code Inspection
#        uses: JetBrains/qodana-action@v2023.2.6

      # Prepare plugin archive content for creating artifact
      - name: Prepare Plugin Artifact
        id: artifact
        shell: bash
        run: |
          cd ${{ github.workspace }}/build/distributions
          FILENAME=`ls *.zip`
          unzip "$FILENAME" -d content

          echo "::set-output name=filename::${FILENAME:0:-4}"

      # Store already-built plugin as an artifact for downloading
      - name: Upload artifact
        uses: actions/upload-artifact@v2.2.4
        with:
          name: ${{ steps.artifact.outputs.filename }}
          path: ./build/distributions/content/*/*

  # Prepare a draft release for GitHub Releases page for the manual verification
  # If accepted and published, release workflow would be triggered
  releaseDraft:
    name: Release Draft
    if: github.event_name != 'pull_request'
    needs: build
    runs-on: ubuntu-latest
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2.4.0

      # Remove old release drafts by using the curl request for the available releases with draft flag
      - name: Remove Old Release Drafts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh api repos/{owner}/{repo}/releases \
            --jq '.[] | select(.draft == true) | .id' \
            | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{}

      # Create new release draft - which is not publicly visible and requires manual acceptance
      - name: Create Release Draft
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh release create v${{ needs.build.outputs.version }} \
            --draft \
            --title "v${{ needs.build.outputs.version }}" \
            --notes "$(cat << 'EOM'
          ${{ needs.build.outputs.changelog }}
          EOM
          )"


Release

# GitHub Actions Workflow created for handling the release process based on the draft release prepared
# with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided.

name: Release
on:
  release:
    types: [prereleased, released]

jobs:

  # Prepare and publish the plugin to the Marketplace repository
  release:
    name: Publish Plugin
    runs-on: ubuntu-latest
    steps:

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

      # Setup Java 17 environment for the next steps
      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          distribution: zulu
          java-version: 17
          cache: gradle

      # 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
          )"

          CHANGELOG="${CHANGELOG//'%'/'%25'}"
          CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
          CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"

          echo "::set-output name=changelog::$CHANGELOG"

      # 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 Marketplace
      - name: Publish Plugin
        env:
          PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
          CERTIFICATE_CHAIN: ${{ secrets.CERTIFICATE_CHAIN }}
          PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
          PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
        run: ./gradlew publishPlugin -Dspace.username=${{ secrets.SPACE_USERNAME }} -Dspace.pass=${{ secrets.SPACE_PASS }}

      # 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/distributions/*

      # 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"

          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 pr create \
            --title "Changelog update - \`$VERSION\`" \
            --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \
            --base main \
            --head $BRANCH


Run UI Tests

name: Run UI Tests
on:
  workflow_dispatch
jobs:
  build-for-ui-test-windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          distribution: zulu
          java-version: 17
      - name: Setup FFmpeg
        uses: FedericoCarboni/setup-ffmpeg@v1
        with:
          # Not strictly necessary, but it may prevent rate limit
          # errors especially on GitHub-hosted macos machines.
          token: ${{ secrets.GITHUB_TOKEN }}
      - name: Clean
        run: gradle clean
      - name: Run Idea
        run: start gradlew.bat runIdeForUiTests
      - name: Wait for Idea started
        uses: jtalk/url-health-check-action@v1.5
        with:
          url: http://localhost:8082
          max-attempts: 30
          retry-delay: 30s
      - name: Tests
        run: gradle test
      - name: Move video
        if: ${{ failure() }}
        run: mv video build/reports
      - name: Save fails report
        if: ${{ failure() }}
        uses: actions/upload-artifact@v3
        with:
          name: ui-test-fails-report-windows
          path: |
            build/reports
  build-for-ui-test-linux:
    runs-on: ubuntu-latest
    container: fxnm/intellij.docker:0.0.8
    steps:
      - uses: actions/checkout@v2
      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          distribution: zulu
          java-version: 11
      - name: Setup FFmpeg
        uses: FedericoCarboni/setup-ffmpeg@v1
        with:
          # Not strictly necessary, but it may prevent rate limit
          # errors especially on GitHub-hosted macos machines.
          token: ${{ secrets.GITHUB_TOKEN }}
      - name: Clean
        run: gradle clean
      - name: Run Idea
        run: |
          export DISPLAY=:99.0
          Xvfb -ac :99 -screen 0 1920x1080x24 &
          sleep 10
          mkdir -p build/reports
          gradle runIdeForUiTests > build/reports/idea.log &
      - name: Wait for Idea started
        uses: jtalk/url-health-check-action@v2
        with:
          url: http://127.0.0.1:8082
          max-attempts: 30
          retry-delay: 30s
      - name: Tests
        run: |
          export DISPLAY=:99.0
          gradle test
      - name: Move video
        if: ${{ failure() }}
        run: mv video build/reports
      - name: Save fails report
        if: ${{ failure() }}
        uses: actions/upload-artifact@v3
        with:
          name: ui-test-fails-report-linux
          path: |
            build/reports
  build-for-ui-test-mac-os:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          distribution: zulu
          java-version: 11
      - name: Setup FFmpeg
        uses: FedericoCarboni/setup-ffmpeg@v1
        with:
          # Not strictly necessary, but it may prevent rate limit
          # errors especially on GitHub-hosted macos machines.
          token: ${{ secrets.GITHUB_TOKEN }}
      - name: Clean
        run: gradle clean
      - name: Run Idea
        run: |
          mkdir -p build/reports
          gradle runIdeForUiTests > build/reports/idea.log &
      - name: Wait for Idea started
        uses: jtalk/url-health-check-action@v2
        with:
          url: http://127.0.0.1:8082
          max-attempts: 30
          retry-delay: 30s
      - name: Tests
        run: gradle test
      - name: Move video
        if: ${{ failure() }}
        run: mv video build/reports
      - name: Save fails report
        if: ${{ failure() }}
        uses: actions/upload-artifact@v3
        with:
          name: ui-test-fails-report-mac
          path: |
            build/reports


Build

name: Build
on:
  # Trigger the workflow on pushes to only the 'master' branch (this avoids duplicate checks being run, e.g. for dependabot pull requests)
  push:
    branches: [ 'main' ]
    paths-ignore: [ '**.md', '.teamcity/**' ]
  # Trigger the workflow on any pull request
  pull_request:
    paths-ignore: [ '**.md', '.teamcity/**' ]

# TODO disabled for now
# This allows a subsequently queued workflow run to interrupt previous runs
#concurrency:
#  group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
#  cancel-in-progress: true

jobs:

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

  unitTests:
    name: Unit Tests
    needs: gradleValidation
    uses: ./.github/workflows/reusable-unitTests.yml

  integrationTests:
    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:
    name: Code Inspection
    needs: integrationTests
    uses: ./.github/workflows/reusable-codeInspection.yml

  build:
    name: Build
    needs:
      - unitTests
    # - integrationTests
    # - integrationTestsEAP
    # - codeInspection
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.properties.outputs.version }}
      changelog: ${{ steps.properties.outputs.changelog }}
    steps:

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

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

      - 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: |
          PROPERTIES="$(./gradlew properties --console=plain -q)"
          VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
          NAME="$(echo "$PROPERTIES" | grep "^name:" | cut -f2- -d ' ')"
          ARTIFACT="$NAME-$VERSION.jar"
          CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)"

          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "name=$NAME" >> $GITHUB_OUTPUT
          echo "artifact=$ARTIFACT" >> $GITHUB_OUTPUT

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

      - name: Build Plugin
        run: ./gradlew build -x test

      # Store already-built plugin as an artifact for downloading
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ steps.properties.outputs.artifact }}
          path: ./build/libs/${{ steps.properties.outputs.artifact }}

  # Prepare a draft release for GitHub Releases page for the manual verification
  # If accepted and published, release workflow would be triggered
  releaseDraft:
    name: Release Draft
    if: github.event_name != 'pull_request'
    needs: build
    runs-on: ubuntu-latest
    steps:

      # Check out the current repository
      - name: Fetch Sources
        uses: actions/checkout@v4

      # Remove old release drafts by using the curl request for the available releases with a draft flag
      - name: Remove Old Release Drafts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh api repos/{owner}/{repo}/releases \
            --jq '.[] | select(.draft == true) | select(.tag_name | startswith("v2")) | .id' \
            | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{}

      # Create a new release draft which is not publicly visible and requires manual acceptance
      - name: Create Release Draft
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh release create v${{ needs.build.outputs.version }} \
            --draft \
            --title "v${{ needs.build.outputs.version }}" \
            --notes "$(cat << 'EOM'
          ${{ needs.build.outputs.changelog }}
          EOM
          )"


Integration Tests

name: Integration Tests

on: [ workflow_dispatch ]

jobs:

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

  integrationTests:
    name: Integration Tests
    needs: gradleValidation
    uses: ./.github/workflows/reusable-integrationTests.yml

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


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/intellij-platform-gradle-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: 17

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3
        with:
          gradle-home-cache-cleanup: true
          cache-read-only: 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