Backend

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the 'License'); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: Backend

on:
  workflow_call:

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

jobs:
  license-header:
    name: License header
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
      - name: Check license header
        uses: apache/skywalking-eyes@985866ce7e324454f61e22eb2db2e998db09d6f3

  code-style:
    name: Code style
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
      - name: Check code style
        run: ./mvnw --batch-mode --quiet --no-snapshot-updates clean spotless:check

  dead-link:
    name: Dead links
    runs-on: ubuntu-latest
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - run: sudo npm install -g markdown-link-check@3.8.7
      - run: |
          for file in $(find . -name "*.md"); do
            markdown-link-check -c .dlc.json -q "$file"
          done

  sanity-check:
    name: Sanity check results
    needs: [ license-header, code-style, dead-link ]
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Check results
        run: |
          [[ ${{ needs.license-header.result }} == 'success' ]] || exit 1;
          [[ ${{ needs.code-style.result }} == 'success' ]] || exit 1;
          [[ ${{ needs.dead-link.result }} == 'success' ]] || exit 1;

  changes:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    outputs:
      api: ${{ steps.filter.outputs.api }}
      engine: ${{ steps.filter.outputs.engine }}
      ut-modules: ${{ steps.ut-modules.outputs.modules }}
      it-modules: ${{ steps.it-modules.outputs.modules }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: '2000'
      - name: checkout apache seatunnel dev branch
        id: git_init
        run: |
          /usr/bin/git remote add apache https://github.com/apache/seatunnel
          /usr/bin/git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=2000 apache +refs/heads/dev*:refs/remotes/apache/dev* +refs/tags/dev*:refs/tags/dev*
          /usr/bin/git checkout apache/dev
          /usr/bin/git checkout '${{ github.ref }}'
          echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11.0'
      - name: Check for file changes by python
        id: filter
        run: |
          current_branch='${{ steps.git_init.outputs.branch }}'
          pip install GitPython
          workspace="${GITHUB_WORKSPACE}"
          repository_owner="${GITHUB_REPOSITORY_OWNER}"
          cv2_files=`python tools/update_modules_check/check_file_updates.py ua $workspace apache/dev origin/$current_branch "seatunnel-connectors-v2/**"`
          true_or_false=${cv2_files%%$'\n'*}
          file_list=${cv2_files#*$'\n'}
          echo "cv2=$true_or_false" >> $GITHUB_OUTPUT
          echo "cv2_files=$file_list" >> $GITHUB_OUTPUT

          cv2_e2e_files=`python tools/update_modules_check/check_file_updates.py ua $workspace apache/dev origin/$current_branch "seatunnel-e2e/seatunnel-connector-v2-e2e/**"`
          true_or_false=${cv2_e2e_files%%$'\n'*}
          file_list=${cv2_e2e_files#*$'\n'}
          echo "cv2-e2e=$true_or_false" >> $GITHUB_OUTPUT
          echo "cv2-e2e_files=$file_list" >> $GITHUB_OUTPUT

          engine_files=`python tools/update_modules_check/check_file_updates.py ua $workspace apache/dev origin/$current_branch "seatunnel-engine/**"`
          true_or_false=${engine_files%%$'\n'*}
          file_list=${engine_files#*$'\n'}
          echo "engine=$true_or_false" >> $GITHUB_OUTPUT
          echo "engine_files=$file_list" >> $GITHUB_OUTPUT

          deleted_poms_files=`python tools/update_modules_check/check_file_updates.py d $workspace apache/dev origin/$current_branch "**/pom.xml"`
          true_or_false=${deleted_poms_files%%$'\n'*}
          file_list=${deleted_poms_files#*$'\n'}
          echo "deleted-poms=$true_or_false" >> $GITHUB_OUTPUT
          echo "deleted-poms_files=$file_list" >> $GITHUB_OUTPUT

          engine_e2e_files=`python tools/update_modules_check/check_file_updates.py ua $workspace apache/dev origin/$current_branch "seatunnel-e2e/seatunnel-engine-e2e/**"`
          true_or_false=${engine_e2e_files%%$'\n'*}
          file_list=${engine_e2e_files#*$'\n'}
          echo "engine-e2e=$true_or_false" >> $GITHUB_OUTPUT
          echo "engine-e2e_files=$file_list" >> $GITHUB_OUTPUT

          api_files=`python tools/update_modules_check/check_file_updates.py ua $workspace apache/dev origin/$current_branch "seatunnel-api/**" "seatunnel-common/**" "seatunnel-config/**" "seatunnel-connectors/**" "seatunnel-core/**" "seatunnel-e2e/seatunnel-e2e-common/**" "seatunnel-formats/**" "seatunnel-plugin-discovery/**" "seatunnel-transforms-v2/**" "seatunnel-translation/**" "seatunnel-e2e/seatunnel-transforms-v2-e2e/**" "seatunnel-connectors/**" "pom.xml" "**/workflows/**" "tools/**" "seatunnel-dist/**"`
          true_or_false=${api_files%%$'\n'*}
          file_list=${api_files#*$'\n'}
          if [[ $repository_owner == 'apache' ]];then
            true_or_false='true'
          fi
          echo "api=$true_or_false" >> $GITHUB_OUTPUT
          echo "api_files=$file_list" >> $GITHUB_OUTPUT

      - name: Check Connector V2 Update
        id: cv2-modules
        if: ${{ steps.filter.outputs.cv2 == 'true' }}
        run: |
          update_files='${{ steps.filter.outputs.cv2_files }}'
          modules=`python tools/update_modules_check/update_modules_check.py cv2 "$update_files"`
          echo $modules
          echo "modules=$modules" >> $GITHUB_OUTPUT

      - name: Check Connector V2 E2E Update
        id: cv2-e2e-modules
        if: ${{ steps.filter.outputs.cv2-e2e == 'true' }}
        run: |
          update_files='${{ steps.filter.outputs.cv2-e2e_files }}'
          modules=`python tools/update_modules_check/update_modules_check.py cv2-e2e "$update_files"`
          echo $modules
          echo "modules=$modules" >> $GITHUB_OUTPUT

      - name: Check Engine Update
        id: engine-modules
        if: ${{ steps.filter.outputs.engine == 'true' }}
        run: |
          update_files='${{ steps.filter.outputs.engine_files }}'
          modules=`python tools/update_modules_check/update_modules_check.py engine "$update_files"`
          echo $modules
          echo "modules=$modules" >> $GITHUB_OUTPUT

      - name: Check Engine E2E Update
        id: engine-e2e-modules
        if: ${{ steps.filter.outputs.engine-e2e == 'true' }}
        run: |
          update_files='${{ steps.filter.outputs.engine-e2e_files }}'
          modules=`python tools/update_modules_check/update_modules_check.py engine-e2e "$update_files"`
          echo $modules
          echo "modules=$modules" >> $GITHUB_OUTPUT

      - name: Check Deleted Modules
        id: deleted-modules
        if: ${{ steps.filter.outputs.deleted-poms == 'true' }}
        run: |
          update_files='${{ steps.filter.outputs.deleted-poms_files }}'
          modules=`python tools/update_modules_check/update_modules_check.py delete "$update_files"`
          echo $modules
          echo "modules=$modules" >> $GITHUB_OUTPUT

      - name: Make unit test modules
        id: ut-modules
        timeout-minutes: 60
        if: ${{ steps.filter.outputs.api == 'false' && (steps.engine-modules.outputs.modules != '' || steps.cv2-modules.outputs.modules != '') }}
        run: |
          modules='${{ steps.engine-modules.outputs.modules }}${{ steps.cv2-modules.outputs.modules }}'
          modules=${modules: 1}
          pl_modules=`python tools/update_modules_check/update_modules_check.py replace "$modules"`
          # remove deleted modules
          delete_modules='${{ steps.deleted-modules.outputs.modules }}'
          if [[ "zz"$delete_modules != "zz" ]];then
            pl_modules=`python tools/update_modules_check/update_modules_check.py rm "$pl_modules" "$delete_modules"`
          fi

          if [[ "zz"$pl_modules == "zz" ]];then
            exit 0
          fi

          ./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout -pl $pl_modules > /tmp/sub_module.txt
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub /tmp/sub_module.txt`
          tree_modules="$modules$sub_modules"
          includes=`python tools/update_modules_check/update_modules_check.py tree "$tree_modules"`
          ./mvnw -Pci -D"e2e.dependency.skip"=false  dependency:tree $includes -DoutputType=text -DoutputFile=/tmp/tree_out.txt
          build_modules=`python tools/update_modules_check/update_modules_check.py final_ut /tmp/tree_out.txt`
          if [[ "zz"$build_modules == "zz" ]];then
            build_modules=$pl_modules
          fi
          echo $build_modules
          echo "modules=$build_modules" >> $GITHUB_OUTPUT

      - name: Make integration test modules
        id: it-modules
        timeout-minutes: 60
        if: ${{ steps.filter.outputs.api == 'false' && (steps.engine-modules.outputs.modules != '' || steps.cv2-modules.outputs.modules != '' || steps.cv2-e2e-modules.outputs.modules != '' || steps.cv2-flink-e2e-modules.outputs.modules != '' || steps.cv2-spark-e2e-modules.outputs.modules != '' || steps.engine-e2e-modules.outputs.modules != '') }}
        run: |
          modules='${{ steps.cv2-e2e-modules.outputs.modules }}${{ steps.cv2-flink-e2e-modules.outputs.modules }}${{ steps.cv2-spark-e2e-modules.outputs.modules }}${{ steps.engine-e2e-modules.outputs.modules }}${{ steps.engine-modules.outputs.modules }}${{ steps.cv2-modules.outputs.modules }}'
          modules=${modules: 1}
          pl_modules=`python tools/update_modules_check/update_modules_check.py replace "$modules"`
          # remove deleted modules
          delete_modules='${{ steps.deleted-modules.outputs.modules }}'
          if [[ "zz"$delete_modules != "zz" ]];then
            pl_modules=`python tools/update_modules_check/update_modules_check.py rm "$pl_modules" "$delete_modules"`
          fi

          if [[ "zz"$pl_modules == "zz" ]];then
            exit 0
          fi

          ./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout -pl $pl_modules > /tmp/sub_module.txt
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub /tmp/sub_module.txt`
          tree_modules="$modules$sub_modules"
          includes=`python tools/update_modules_check/update_modules_check.py tree "$tree_modules"`
          ./mvnw -Pci -D"e2e.dependency.skip"=false  dependency:tree $includes -DoutputType=text -DoutputFile=/tmp/tree_out.txt
          build_modules=`python tools/update_modules_check/update_modules_check.py final_it /tmp/tree_out.txt`
          echo $build_modules
          echo "modules=$build_modules" >> $GITHUB_OUTPUT

  dependency-license:
    if: needs.changes.outputs.api == 'true' || needs.changes.outputs.engine == 'true'
    name: Dependency licenses
    needs: [ changes, sanity-check ]
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
      - uses: actions/setup-java@v3
        with:
          distribution: 'temurin'
          java-version: '8'
          cache: 'maven'
      - name: Install
        uses: nick-fields/retry@v2
        with:
          timeout_minutes: 40
          max_attempts: 3
          retry_on: error
          command: |
            ./mvnw -B -q install -DskipTests -D"maven.test.skip"=true -D"maven.javadoc.skip"=true -D"license.skipAddThirdParty"
      - name: Check Dependencies Licenses
        run: tools/dependencies/checkLicense.sh

  unit-test:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true' || (needs.changes.outputs.api == 'false' && needs.changes.outputs.ut-modules != '')
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest', 'windows-latest' ]
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run all modules unit test
        run: |
          ./mvnw -B -T 1 clean verify -D"maven.test.skip"=false -D"license.skipAddThirdParty"=true --no-snapshot-updates
        env:
          MAVEN_OPTS: -Xmx4096m

  updated-modules-integration-test-part-1:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run updated modules integration test (part-1)
        if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
        run: |
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub_update_it_module ${{needs.changes.outputs.it-modules}} 8 0`
          if [ ! -z $sub_modules ]; then
            ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $sub_modules -am -Pci
          else
            echo "sub modules is empty, skipping"
          fi
        env:
          MAVEN_OPTS: -Xmx2048m

  updated-modules-integration-test-part-2:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run updated modules integration test (part-2)
        if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
        run: |
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub_update_it_module ${{needs.changes.outputs.it-modules}} 8 1`
          if [ ! -z $sub_modules ]; then
            ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $sub_modules -am -Pci
          else
            echo "sub modules is empty, skipping"
          fi
        env:
          MAVEN_OPTS: -Xmx2048m

  updated-modules-integration-test-part-3:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run updated modules integration test (part-3)
        if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
        run: |
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub_update_it_module ${{needs.changes.outputs.it-modules}} 8 2`
          if [ ! -z $sub_modules ]; then
            ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $sub_modules -am -Pci
          else
            echo "sub modules is empty, skipping"
          fi
        env:
          MAVEN_OPTS: -Xmx2048m

  updated-modules-integration-test-part-4:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run updated modules integration test (part-4)
        if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
        run: |
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub_update_it_module ${{needs.changes.outputs.it-modules}} 8 3`
          if [ ! -z $sub_modules ]; then
            ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $sub_modules -am -Pci
          else
            echo "sub modules is empty, skipping"
          fi
        env:
          MAVEN_OPTS: -Xmx2048m
  updated-modules-integration-test-part-5:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 120
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run updated modules integration test (part-5)
        if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
        run: |
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub_update_it_module ${{needs.changes.outputs.it-modules}} 8 4`
          if [ ! -z $sub_modules ]; then
            ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $sub_modules -am -Pci
          else
            echo "sub modules is empty, skipping"
          fi
        env:
          MAVEN_OPTS: -Xmx2048m
  updated-modules-integration-test-part-6:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run updated modules integration test (part-6)
        if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
        run: |
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub_update_it_module ${{needs.changes.outputs.it-modules}} 8 5`
          if [ ! -z $sub_modules ]; then
            ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $sub_modules -am -Pci
          else
            echo "sub modules is empty, skipping"
          fi
        env:
          MAVEN_OPTS: -Xmx2048m
  updated-modules-integration-test-part-7:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run updated modules integration test (part-7)
        if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
        run: |
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub_update_it_module ${{needs.changes.outputs.it-modules}} 8 6`
          if [ ! -z $sub_modules ]; then
            ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $sub_modules -am -Pci
          else
            echo "sub modules is empty, skipping"
          fi
        env:
          MAVEN_OPTS: -Xmx2048m

  updated-modules-integration-test-part-8:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run updated modules integration test (part-8)
        if: needs.changes.outputs.api == 'false' && needs.changes.outputs.it-modules != ''
        run: |
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub_update_it_module ${{needs.changes.outputs.it-modules}} 8 7`
          if [ ! -z $sub_modules ]; then
            ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $sub_modules -am -Pci
          else
            echo "sub modules is empty, skipping"
          fi
        env:
          MAVEN_OPTS: -Xmx2048m

  engine-v2-it:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run seatunnel zeta integration test
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-seatunnel-e2e-base,:connector-console-seatunnel-e2e -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m
  engine-k8s-it:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true' || contains(needs.changes.outputs.it-modules, 'seatunnel-engine-k8s-e2e')
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 45
    steps:
      - name: install k8s
        run: |
          curl -sfL https://get.k3s.io | K3S_KUBECONFIG_MODE=777 sh -s - --docker
          cat /etc/rancher/k3s/k3s.yaml
          mkdir -p ~/.kube
          cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
        env:
          KUBECONFIG: /etc/rancher/k3s/k3s.yaml
      - uses: actions/checkout@v2
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run seatunnel zeta on k8s test
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -T 1 -B verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :seatunnel-engine-k8s-e2e -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m
          KUBECONFIG: /etc/rancher/k3s/k3s.yaml
  transform-v2-it-part-1:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run transform-v2 integration test (part-1)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :seatunnel-transforms-v2-e2e-part-1 -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  transform-v2-it-part-2:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run transform-v2 integration test (part-2)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :seatunnel-transforms-v2-e2e-part-2 -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  all-connectors-it-1:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run connector-v2 integration test (part-1)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout -pl :seatunnel-connector-v2-e2e >> /tmp/sub_module.txt
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub /tmp/sub_module.txt`
          run_it_modules=`python tools/update_modules_check/update_modules_check.py sub_it_module "$sub_modules" 7 0`
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $run_it_modules -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  all-connectors-it-2:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run connector-v2 integration test (part-2)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout -pl :seatunnel-connector-v2-e2e >> /tmp/sub_module.txt
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub /tmp/sub_module.txt`
          run_it_modules=`python tools/update_modules_check/update_modules_check.py sub_it_module "$sub_modules" 7 1`
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $run_it_modules -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  all-connectors-it-3:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run connector-v2 integration test (part-3)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout -pl :seatunnel-connector-v2-e2e >> /tmp/sub_module.txt
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub /tmp/sub_module.txt`
          run_it_modules=`python tools/update_modules_check/update_modules_check.py sub_it_module "$sub_modules" 7 2`
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $run_it_modules -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  all-connectors-it-4:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 150
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run connector-v2 integration test (part-4)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout -pl :seatunnel-connector-v2-e2e >> /tmp/sub_module.txt
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub /tmp/sub_module.txt`
          run_it_modules=`python tools/update_modules_check/update_modules_check.py sub_it_module "$sub_modules" 7 3`
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $run_it_modules -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  all-connectors-it-5:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run connector-v2 integration test (part-5)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout -pl :seatunnel-connector-v2-e2e >> /tmp/sub_module.txt
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub /tmp/sub_module.txt`
          run_it_modules=`python tools/update_modules_check/update_modules_check.py sub_it_module "$sub_modules" 7 4`
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $run_it_modules -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  all-connectors-it-6:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run connector-v2 integration test (part-6)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout -pl :seatunnel-connector-v2-e2e >> /tmp/sub_module.txt
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub /tmp/sub_module.txt`
          run_it_modules=`python tools/update_modules_check/update_modules_check.py sub_it_module "$sub_modules" 7 5`
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $run_it_modules -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  all-connectors-it-7:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run connector-v2 integration test (part-7)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout -pl :seatunnel-connector-v2-e2e >> /tmp/sub_module.txt
          sub_modules=`python tools/update_modules_check/update_modules_check.py sub /tmp/sub_module.txt`
          run_it_modules=`python tools/update_modules_check/update_modules_check.py sub_it_module "$sub_modules" 7 6`
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl $run_it_modules -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  jdbc-connectors-it-part-1:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run jdbc connectors integration test (part-1)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-jdbc-e2e-part-1 -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  jdbc-connectors-it-part-2:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run jdbc connectors integration test (part-2)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-jdbc-e2e-part-2 -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  jdbc-connectors-it-part-3:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run jdbc connectors integration test (part-3)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-jdbc-e2e-part-3 -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  jdbc-connectors-it-part-4:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run jdbc connectors integration test (part-4)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-jdbc-e2e-part-4 -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  jdbc-connectors-it-part-5:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run jdbc connectors integration test (part-5)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-jdbc-e2e-part-5 -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  jdbc-connectors-it-part-6:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run jdbc connectors integration test (part-6)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-jdbc-e2e-part-6 -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  jdbc-connectors-it-part-7:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run jdbc connectors integration test (part-7)
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-jdbc-e2e-part-7 -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  kudu-connector-it:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true' || contains(needs.changes.outputs.it-modules, 'connector-kudu-e2e')
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run kudu connector integration test
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-kudu-e2e -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  amazonSqs-connector-it:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true' || contains(needs.changes.outputs.it-modules, 'connector-amazonsqs-e2e')
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run amazonsqs connector integration test
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-amazonsqs-e2e -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  kafka-connector-it:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run kafka connector integration test
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-kafka-e2e -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  rocketmq-connector-it:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run rocket connector integration test
        if: needs.changes.outputs.api == 'true'
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-rocketmq-e2e -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  doris-connector-it:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true' || contains(needs.changes.outputs.it-modules, 'connector-doris-e2e')
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: free disk space
        run: tools/github/free_disk_space.sh
      - name: run doris connector integration test
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-doris-e2e -am -Pci
        env:
          MAVEN_OPTS: -Xmx4096m

  oracle-cdc-connector-it:
    needs: [ changes, sanity-check ]
    if: needs.changes.outputs.api == 'true' || contains(needs.changes.outputs.it-modules, 'connector-cdc-oracle-e2e')
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run oracle cdc connector integration test
        run: |
          ./mvnw -B -T 1 verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-cdc-oracle-e2e -am -Pci


Build

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

name: "Build"

on:
  push:
    branches:
    - '**'

jobs:
  call-build-and-test:
    permissions:
      packages: write
    name: Run
    uses: ./.github/workflows/backend.yml


CodeQL

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: "CodeQL"

on:
  schedule:
    - cron: '0 0 12 * *'

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    timeout-minutes: 120
    env:
      JAVA_TOOL_OPTIONS: -Xmx2G -Xms2G -Dhttp.keepAlive=false -Dmaven.test.skip=true -Dlicense.skipAddThirdParty=true -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.http.retryHandler.count=3 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120

    strategy:
      fail-fast: false
      matrix:
        language: ['java']

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
        with:
          submodules: true
      - name: Set up JDK 1.8
        uses: actions/setup-java@v2
        with:
          java-version:  8
          distribution: 'adopt'
      - name: Cache local Maven repository
        uses: actions/cache@v2
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-maven-
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v1
        with:
          languages: ${{ matrix.language }}
      - name: Autobuild
        uses: github/codeql-action/autobuild@v1
      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v1


Documents

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the 'License'); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: Documents

on:
  pull_request:
    paths:
      - 'docs/**'

jobs:
  build:
    name: Build website
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - name: Checkout PR
        uses: actions/checkout@v3
        with:
          path: seatunnel-pr

      - name: Checkout website repo
        uses: actions/checkout@v3
        with:
          repository: apache/seatunnel-website
          path: seatunnel-website

      - name: Sync PR changes to website
        run: |
          bash seatunnel-pr/tools/documents/sync.sh seatunnel-pr seatunnel-website

      - uses: actions/setup-node@v2
        with:
          node-version: 16.19.0

      - name: Run docusaurus build
        run: |
          cd seatunnel-website
          npm set strict-ssl false
          npm install
          npm run build

  code-style:
    name: Code style
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
      - name: Check code style
        run: ./mvnw --batch-mode --quiet --no-snapshot-updates clean spotless:check


On pull request update

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

# Intentionally has a general name.
# because the test status check created in GitHub Actions
# currently randomly picks any associated workflow.
# So, the name was changed to make sense in that context too.
# See also https://github.community/t/specify-check-suite-when-creating-a-checkrun/118380/10
name: On pull request update
on:
  pull_request_target:
    types: [opened, reopened, synchronize]

jobs:
  notify:
    name: Notify test workflow
    runs-on: ubuntu-20.04
    permissions:
      actions: read
      checks: write
    steps:
      - name: "Notify test workflow"
        uses: actions/github-script@v6
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const endpoint = 'GET /repos/:owner/:repo/actions/workflows/:id/runs?&branch=:branch'
            const check_run_endpoint = 'GET /repos/:owner/:repo/commits/:ref/check-runs?per_page=100'

            // TODO: Should use pull_request.user and pull_request.user.repos_url?
            // If a different person creates a commit to another forked repo,
            // it wouldn't be able to detect.
            const params = {
              owner: context.payload.pull_request.head.repo.owner.login,
              repo: context.payload.pull_request.head.repo.name,
              id: 'build_main.yml',
              branch: context.payload.pull_request.head.ref,
            }
            const check_run_params = {
              owner: context.payload.pull_request.head.repo.owner.login,
              repo: context.payload.pull_request.head.repo.name,
              ref: context.payload.pull_request.head.ref,
            }

            console.log('Ref: ' + context.payload.pull_request.head.ref)
            console.log('SHA: ' + context.payload.pull_request.head.sha)

            // Wait 3 seconds to make sure the fork repository triggered a workflow.
            await new Promise(r => setTimeout(r, 3000))

            let runs
            try {
              runs = await github.request(endpoint, params)
            } catch (error) {
              console.error(error)
              // Assume that runs were not found.
            }

            const name = 'Build'
            const head_sha = context.payload.pull_request.head.sha
            let status = 'queued'
            console.log('runs: ' + JSON.stringify(runs))
            if (!runs || runs.data.workflow_runs.length === 0) {
              status = 'completed'
              const conclusion = 'action_required'

              github.rest.checks.create({
                owner: context.repo.owner,
                repo: context.repo.repo,
                name: name,
                head_sha: head_sha,
                status: status,
                conclusion: conclusion,
                output: {
                  title: 'Workflow run detection failed',
                  summary: `
            Unable to detect the workflow run for testing the changes in your PR.

            1. If you did not enable GitHub Actions in your forked repository, please enable it by clicking the button as shown in the image below. See also [Disabling or limiting GitHub Actions for a repository](https://docs.github.com/en/github/administering-a-repository/disabling-or-limiting-github-actions-for-a-repository) for more details.
            2. It is possible your branch is based on the old \`dev\` branch in Apache SeaTunnel, please sync your branch to the latest dev branch. For example as below:
                \`\`\`bash
                git fetch upstream
                git rebase upstream/dev
                git push origin YOUR_BRANCH --force
                \`\`\``,
                  images: [
                    {
                      alt: 'enabling workflows button',
                      image_url: 'https://raw.githubusercontent.com/apache/spark/master/.github/workflows/images/workflow-enable-button.png'
                    }
                  ]
                }
              })
            } else {
              const run_id = runs.data.workflow_runs[0].id

              if (runs.data.workflow_runs[0].head_sha != context.payload.pull_request.head.sha) {
                throw new Error('There was a new unsynced commit pushed. Please retrigger the workflow.');
              }

              // Here we get check run ID to provide Check run view instead of Actions view, see also SPARK-37879.
              const check_runs = await github.request(check_run_endpoint, check_run_params)
              console.log('check_runs: ' + JSON.stringify(check_runs))
              const check_run_head = check_runs.data.check_runs.filter(r => r.name === "Run / License header")[0]

              console.log('check_run_head: ' + JSON.stringify(check_run_head))
              if (check_run_head.head_sha != context.payload.pull_request.head.sha) {
                throw new Error('There was a new unsynced commit pushed. Please retrigger the workflow.');
              }

              const check_run_url = 'https://github.com/'
                + context.payload.pull_request.head.repo.full_name
                + '/runs/'
                + check_run_head.id

              const actions_url = 'https://github.com/'
                + context.payload.pull_request.head.repo.full_name
                + '/actions/runs/'
                + run_id

              await github.rest.checks.create({
                owner: context.repo.owner,
                repo: context.repo.repo,
                name: name,
                head_sha: head_sha,
                status: status,
                output: {
                  title: 'Test results',
                  summary: '[See test results](' + check_run_url + ')',
                  text: JSON.stringify({
                    owner: context.payload.pull_request.head.repo.owner.login,
                    repo: context.payload.pull_request.head.repo.name,
                    run_id: run_id
                  })
                },
                details_url: actions_url,
              })
            }


publish-docker

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: publish-docker

on:
  push:
    branches:
      - dev
      - docker
    paths-ignore:
      - 'docs/**'
      - '**/*.md'
      - 'seatunnel-ui/**'

env:
  HUB: ghcr.io/${{ github.repository }}

jobs:
  build:
    if: github.repository == 'apache/seatunnel'
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v2
      - name: Cache local Maven repository
        uses: actions/cache@v2
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-maven-
      - name: Set up JDK 1.8
        uses: actions/setup-java@v2
        with:
          java-version:  8
          distribution: 'adopt'
      - name: Log in to the Container registry
        uses: docker/login-action@v1.10.0
        with:
          registry: ${{ env.HUB }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Build and push docker images
        env:
          MAVEN_OPTS: -Xmx2G -Xms2G
        run: |
          ./mvnw -B clean deploy \
          -Dmaven.test.skip \
          -Dmaven.javadoc.skip \
          -Dlicense.skipAddThirdParty=true \
          -Dmaven.deploy.skip \
          -Ddocker.tag=${{ github.sha }} \
          -Ddocker.hub=${{ env.HUB }} \
          -Pdocker \
          --no-snapshot-updates


Schedule Backend

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the 'License'); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: Schedule Backend
on:
  schedule:
    - cron: '0 0 03 * *'

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

jobs:
  license-header:
    if: github.repository == 'apache/seatunnel'
    name: License header
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
      - name: Check license header
        uses: apache/skywalking-eyes@985866ce7e324454f61e22eb2db2e998db09d6f3

  code-style:
    if: github.repository == 'apache/seatunnel'
    name: Code style
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
      - name: Check code style
        run: ./mvnw --batch-mode --quiet --no-snapshot-updates clean spotless:check

  dead-link:
    if: github.repository == 'apache/seatunnel'
    name: Dead links
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v2
      - run: sudo npm install -g markdown-link-check@3.8.7
      - run: |
          for file in $(find . -name "*.md"); do
            markdown-link-check -c .dlc.json -q "$file"
          done

  sanity-check:
    if: github.repository == 'apache/seatunnel'
    name: Sanity check results
    needs: [ license-header, code-style, dead-link ]
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Check results
        run: |
          [[ ${{ needs.license-header.result }} == 'success' ]] || exit 1;
          [[ ${{ needs.code-style.result }} == 'success' ]] || exit 1;
          [[ ${{ needs.dead-link.result }} == 'success' ]] || exit 1;

  dependency-license:
    name: Dependency licenses
    needs: [ sanity-check ]
    runs-on: ubuntu-latest
    timeout-minutes: 40
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
      - uses: actions/setup-java@v3
        with:
          distribution: 'temurin'
          java-version: '8'
          cache: 'maven'
      - name: Install
        run: >-
          ./mvnw -B -q install -DskipTests
          -D"maven.test.skip"=true
          -D"maven.javadoc.skip"=true
          -D"scalastyle.skip"=true
          -D"license.skipAddThirdParty"
      - name: Check Dependencies Licenses
        run: tools/dependencies/checkLicense.sh

  unit-test:
    needs: [ sanity-check ]
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest', 'windows-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run all modules unit test
        run: |
          ./mvnw -B -T 1C clean verify -D"maven.test.skip"=false -D"scalastyle.skip"=true -D"license.skipAddThirdParty"=true --no-snapshot-updates
        env:
          MAVEN_OPTS: -Xmx2048m

  integration-test:
    needs: [ sanity-check ]
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '8', '11' ]
        os: [ 'ubuntu-latest' ]
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK ${{ matrix.java }}
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java }}
          distribution: 'temurin'
          cache: 'maven'
      - name: run all modules integration test
        run: |
          ./mvnw -T 1C -B verify -DskipUT=true -DskipIT=false -D"scalastyle.skip"=true -D"license.skipAddThirdParty"=true --no-snapshot-updates
        env:
          MAVEN_OPTS: -Xmx2048m


Close stale issues and PRs

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# https://github.com/actions/stale
name: 'Close stale issues and PRs'
on:
  schedule:
    - cron: '0 0 * * *'
permissions:
  # Stale recommended permissions
  pull-requests: write
  issues: write
jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@v4
        with:
          # Stale Issues
          days-before-issue-stale: 30
          days-before-issue-close: 7
          # We do not stale Issues with label `Waiting for reply`, `Waiting for code update`,`Waiting for users feedback`, `New feature` and `STIP`
          exempt-issue-labels: 'Waiting for reply,Waiting for code update,Waiting for users feedback,New feature,STIP,security'
          stale-issue-message: >
            This issue has been automatically marked as stale because it has not had recent activity
            for 30 days. It will be closed in next 7 days if no further activity occurs.
          close-issue-message: >
            This issue has been closed because it has not received response for too long time. You could
            reopen it if you encountered similar problems in the future.
          # Stale PRs
          days-before-pr-stale: 120
          days-before-pr-close: 7
          stale-pr-message: >
            This pull request has been automatically marked as stale because it has not had recent
            activity for 120 days. It will be closed in 7 days if no further activity occurs.
          close-pr-message: >
            This pull request has been closed because it has not had recent activity. You could reopen it
            if you try to continue your work, and anyone who are interested in it are encouraged to continue
            work on this pull request.
          remove-pr-stale-when-updated: true
          remove-issue-stale-when-updated: true
          labels-to-add-when-unstale: 'waiting for review'


Update build status workflow

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

name: Update build status workflow

on:
  schedule:
  - cron: "*/15 * * * *"

jobs:
  update:
    name: Update build status
    runs-on: ubuntu-20.04
    permissions:
      actions: read
      checks: write
    steps:
      - name: "Update build status"
        uses: actions/github-script@v6
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const endpoint = 'GET /repos/:owner/:repo/pulls?state=:state'
            const params = {
              owner: context.repo.owner,
              repo: context.repo.repo,
              state: 'open'
            }

            // See https://docs.github.com/en/graphql/reference/enums#mergestatestatus
            const maybeReady = ['behind', 'clean', 'draft', 'has_hooks', 'unknown', 'unstable'];

            // Iterate open PRs
            for await (const prs of github.paginate.iterator(endpoint,params)) {
              // Each page
              for await (const pr of prs.data) {
                console.log('SHA: ' + pr.head.sha)
                console.log('  Mergeable status: ' + pr.mergeable_state)
                if (pr.mergeable_state == null || maybeReady.includes(pr.mergeable_state)) {
                  const checkRuns = await github.request('GET /repos/{owner}/{repo}/commits/{ref}/check-runs', {
                    owner: context.repo.owner,
                    repo: context.repo.repo,
                    ref: pr.head.sha
                  })

                  // Iterator GitHub Checks in the PR
                  for await (const cr of checkRuns.data.check_runs) {
                    if (cr.name == 'Build' && cr.conclusion != "action_required") {
                      // text contains parameters to make request in JSON.
                      const params = JSON.parse(cr.output.text)

                      // Get the workflow run in the forked repository
                      let run
                      try {
                        run = await github.request('GET /repos/{owner}/{repo}/actions/runs/{run_id}', params)
                      } catch (error) {
                        console.error(error)
                        // Run not found. This can happen when the PR author removes GitHub Actions runs or
                        // disalbes GitHub Actions.
                        continue
                      }

                      // Keep syncing the status of the checks
                      if (run.data.status == 'completed') {
                        console.log('    Run ' + cr.id + ': set status (' + run.data.status + ') and conclusion (' + run.data.conclusion + ')')
                        const response = await github.request('PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}', {
                          owner: context.repo.owner,
                          repo: context.repo.repo,
                          check_run_id: cr.id,
                          output: cr.output,
                          status: run.data.status,
                          conclusion: run.data.conclusion,
                          details_url: run.data.details_url
                        })
                      } else {
                        console.log('    Run ' + cr.id + ': set status (' + run.data.status + ')')
                        const response = await github.request('PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}', {
                          owner: context.repo.owner,
                          repo: context.repo.repo,
                          check_run_id: cr.id,
                          output: cr.output,
                          status: run.data.status,
                          details_url: run.data.details_url
                        })
                      }

                      break
                    }
                  }
                }
              }
            }


develop status

name: develop status

on:
  push:
    branches:
      - develop

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        jdk: [11, 17]

    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK
      uses: actions/setup-java@v1
      with:
        java-version: ${{ matrix.jdk }}
    - name: Cache local Maven repository
      uses: actions/cache@v2
      with:
        path: ~/.m2/repository
        key: ${{ runner.os }}-jdk${{ matrix.jdk }}-maven-${{ hashFiles('**/pom.xml') }}
        restore-keys: |
          ${{ runner.os }}-jdk${{ matrix.jdk }}-maven-
    - name: Build
      run: mvn -B -U clean install -Pquick,\!formatting
    - name: Verify
      run: mvn -B verify -P\!skipSlowTests,\!formatting -Dmaven.javadoc.skip=true -Djapicmp.skip -Denforcer.skip=true -Danimal.sniffer.skip=true
    - name: Publish Test Report
      if: failure()
      uses: scacap/action-surefire-report@v1
      with:
        check_name: Test report - develop status - ${{ matrix.jdk }}


PR verify

name: PR verify

on: pull_request

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        jdk: [11, 21]
    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK
      uses: actions/setup-java@v1
      with:
        java-version: ${{ matrix.jdk }}
    - name: Cache local Maven repository
      uses: actions/cache@v2
      with:
        path: ~/.m2/repository
        key: ${{ runner.os }}-jdk${{ matrix.jdk }}-maven-${{ hashFiles('**/pom.xml') }}
        restore-keys: |
          ${{ runner.os }}-jdk${{ matrix.jdk }}-maven-
    - name: Check formatting
      run: mvn -B formatter:validate impsort:check xml-format:xml-check
    - name: Build
      run: mvn -B -U -T 2 clean install -Pquick,-formatting -Dmaven.javadoc.skip=true -Djapicmp.skip -Denforcer.skip=true -Danimal.sniffer.skip=true
    - name: Test
      run: mvn -B test -P-formatting -DskipITs -Dmaven.javadoc.skip=true
    - name: Publish Test Report
      if: failure()
      uses: scacap/action-surefire-report@v1
      with:
        check_name: Test report - build - ${{ matrix.jdk }}
    - name: Cancel workflow on failure
      uses: vishnudxb/cancel-workflow@v1.2
      if: failure()
      with:
        repo: eclipse/rdf4j
        workflow_id: ${{ github.run_id }}
        access_token: ${{ github.token }}
  integration-tests:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK
      uses: actions/setup-java@v1
      with:
        java-version: 11
    - name: Cache local Maven repository
      uses: actions/cache@v2
      with:
        path: ~/.m2/repository
        key: ${{ runner.os }}-jdk11-maven-${{ hashFiles('**/pom.xml') }}
        restore-keys: |
          ${{ runner.os }}-jdk11-maven-
    - name: Check formatting
      run: mvn -B formatter:validate impsort:check xml-format:xml-check
    - name: Build
      run: mvn -B -U -T 2 clean install -Pquick,-formatting -Dmaven.javadoc.skip=true -Djapicmp.skip -Denforcer.skip=true -Danimal.sniffer.skip=true
    - name: Verify
      run: mvn -B verify -PskipUnitTests,-formatting -Dmaven.javadoc.skip=true -Denforcer.skip=true -Danimal.sniffer.skip=true
    - name: Publish Test Report
      if: failure()
      uses: scacap/action-surefire-report@v1
      with:
        check_name: Test report - integration-tests
    - name: Cancel workflow on failure
      uses: vishnudxb/cancel-workflow@v1.2
      if: failure()
      with:
        repo: eclipse/rdf4j
        workflow_id: ${{ github.run_id }}
        access_token: ${{ github.token }}
  slow-tests:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK
      uses: actions/setup-java@v1
      with:
        java-version: 11
    - name: Cache local Maven repository
      uses: actions/cache@v2
      with:
        path: ~/.m2/repository
        key: ${{ runner.os }}-jdk11-maven-${{ hashFiles('**/pom.xml') }}
        restore-keys: |
          ${{ runner.os }}-jdk11-maven-
    - name: Check formatting
      run: mvn -B formatter:validate impsort:check xml-format:xml-check
    - name: Build
      run: mvn -B -U -T 2 clean install -Pquick,-formatting -Dmaven.javadoc.skip=true -Djapicmp.skip -Denforcer.skip=true -Danimal.sniffer.skip=true
    - name: Verify
      run: mvn -B verify -PslowTestsOnly,-skipSlowTests,-formatting -Dmaven.javadoc.skip=true -Djapicmp.skip -Denforcer.skip=true -Danimal.sniffer.skip=true
    - name: Publish Test Report
      if: failure()
      uses: scacap/action-surefire-report@v1
      with:
        check_name: Test report - slow-tests
  package-assembly:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK
        uses: actions/setup-java@v1
        with:
          java-version: 11
      - name: Cache local Maven repository
        uses: actions/cache@v2
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-jdk11-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-jdk11-maven-
      - name: Run install
        run: mvn -B install -DskipTests
      - name: Package assembly
        run: mvn package -Passembly -DskipTests
      - name: Cancel workflow on failure
        uses: vishnudxb/cancel-workflow@v1.2
        if: failure()
        with:
          repo: eclipse/rdf4j
          workflow_id: ${{ github.run_id }}
          access_token: ${{ github.token }}
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK
        uses: actions/setup-java@v1
        with:
          java-version: 11
      - name: Cache local Maven repository
        uses: actions/cache@v2
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-jdk11-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-jdk11-maven-
      - name: Install dependencies
        run: sudo apt-get update && sudo apt-get install -y libxml2-utils
      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18
      - name: Run end-to-end tests of RDF4J Server and Workbench
        working-directory: ./e2e
        run: ./run.sh
      - name: Cancel workflow on failure
        uses: vishnudxb/cancel-workflow@v1.2
        if: failure()
        with:
          repo: eclipse/rdf4j
          workflow_id: ${{ github.run_id }}
          access_token: ${{ github.token }}
  copyright-check:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: check copyright header present
      run: scripts/checkCopyrightPresent.sh


main status

name: main status

on:
  push:
    branches:
      - main

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        jdk: [11, 17]

    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK
      uses: actions/setup-java@v1
      with:
        java-version: ${{ matrix.jdk }}
    - name: Cache local Maven repository
      uses: actions/cache@v2
      with:
        path: ~/.m2/repository
        key: ${{ runner.os }}-jdk${{ matrix.jdk }}-maven-${{ hashFiles('**/pom.xml') }}
        restore-keys: |
          ${{ runner.os }}-jdk${{ matrix.jdk }}-maven-
    - name: Build
      run: mvn -B -U -T 2 clean install -Pquick,-formatting
    - name: Run all tests
      run: mvn -B verify -P-skipSlowTests,-formatting -Dmaven.javadoc.skip=true -Djapicmp.skip -Denforcer.skip=true -Danimal.sniffer.skip=true
    - name: Publish Test Report
      if: failure()
      uses: scacap/action-surefire-report@v1
      with:
        check_name: Test report - main status - ${{ matrix.jdk }}


merge main to develop

name: merge main to develop

on:
  push:
    branches:
    - "main"

jobs:
  pull-request:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: pull-request
      uses: repo-sync/pull-request@v2.6.2
      with:
        destination_branch: "develop"         # If blank, default: main
        pr_title: "Merge main into develop"
        pr_body: "Automatically generated PR to keep develop in sync with main.\n\n **USE MERGE COMMIT TO MERGE THIS PR**.\n\nSee [merge_main_to_develop.yml](/eclipse/rdf4j/.github/workflows/merge_main_to_develop.yml)."  # Full markdown support, requires pr_title to be set
        github_token: ${{ secrets.GITHUB_TOKEN }}


dash license

name: dash license

on:
  pull_request:
  workflow_dispatch:

jobs:
  license-check:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK
        uses: actions/setup-java@v1
        with:
          java-version: '21'
      - name: Cache local Maven repository
        uses: actions/cache@v3
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-jdk21-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-jdk20-maven-
      - name: Run license-check
        run: mvn -B -Plicence-check org.eclipse.dash:license-tool-plugin:license-check -Ddash.summary=DEPENDENCIES
      - name: Print Dash Summary
        if: always()
        run: cat DEPENDENCIES


Add new issue to project board

name: Add new issue to project board
on:
  issues:
    types:
      - opened
jobs:
  add-to-project:
    name: Add issue to project
    runs-on: ubuntu-latest
    steps:
      - uses: actions/add-to-project@v0.4.0
        with:
          project-url: https://github.com/orgs/eclipse/projects/36
          github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}


Update epics

name: Update epics
on:
  issues:
    types: [opened, created, closed, reopened, deleted]
jobs:
  epics:
    runs-on: ubuntu-latest
    name: Update epic issues
    steps:
      - name: Run epics action
        uses: cloudaper/epics-action@v1
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          epic-label-name: epic


Release a new version

name: Release a new version
run-name: Release a new version ${{ github.event.release.tag_name }}

on:
  release:
    types: [ created ]

jobs:
  build-and-push:
    name: Build and push Docker images
    runs-on: ubuntu-latest
    outputs:
      releaseBranch: ${{ steps.determine_release_branch.outputs.releaseBranch }}
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.release.target_commitish }}
          fetch-depth: 0

      - name: Validate release tag and determine previous tag
        id: validate_tag
        run: |
          OUTPUT="$(.github/workflows/scripts/prev_tag.sh ${{ github.event.release.tag_name }})"
          if [ $? -ne 0 ]; then
            echo "Script failed"
            exit 1
          fi
          echo "type=$( echo $OUTPUT | cut -d ' ' -f1 )" >> $GITHUB_OUTPUT
          echo "previousTag=$( echo $OUTPUT | cut -d ' ' -f2 )" >> $GITHUB_OUTPUT

      # We will update this branch by setting the new version and pushing it
      - name: Determine release branch name
        id: determine_release_branch
        run: |
          releaseBranch=$( git branch --contains ${RELEASE_VERSION} --format='%(refname:short)' )
          git checkout "$releaseBranch"
          echo "releaseBranch=$releaseBranch" >> $GITHUB_OUTPUT
        env:
          RELEASE_VERSION: ${{ github.event.release.tag_name }}

      - name: Import Secrets
        id: secrets
        uses: hashicorp/vault-action@v3.0.0
        with:
          url: ${{ secrets.VAULT_ADDR }}
          method: approle
          roleId: ${{ secrets.VAULT_ROLE_ID }}
          secretId: ${{ secrets.VAULT_SECRET_ID }}
          exportEnv: false # we rely on step outputs, no need for environment variables
          secrets: |
            secret/data/products/connectors/ci/common DOCKERHUB_USER;
            secret/data/products/connectors/ci/common DOCKERHUB_PASSWORD;
            secret/data/products/connectors/ci/common ARTIFACTORY_USR;
            secret/data/products/connectors/ci/common ARTIFACTORY_PSW;
            secret/data/github.com/organizations/camunda MAVEN_CENTRAL_DEPLOYMENT_USR;
            secret/data/github.com/organizations/camunda MAVEN_CENTRAL_DEPLOYMENT_PSW;
            secret/data/github.com/organizations/camunda MAVEN_CENTRAL_GPG_SIGNING_KEY_PASSPHRASE;
            secret/data/github.com/organizations/camunda MAVEN_CENTRAL_GPG_SIGNING_KEY_SEC;

      - name: Import GPG key
        id: import_gpg
        uses: crazy-max/ghaction-import-gpg@v6
        with:
          gpg_private_key: ${{ steps.secrets.outputs.MAVEN_CENTRAL_GPG_SIGNING_KEY_SEC }}
          passphrase: ${{ steps.secrets.outputs.MAVEN_CENTRAL_GPG_SIGNING_KEY_PASSPHRASE }}

      - name: Restore cache
        uses: actions/cache@v4
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-maven-

      - name: Prepare Java and Maven settings
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '21'

      # Use CI Nexus as co-located pull-through cache for Maven artifacts via ~/.m2/settings.xml
      - name: 'Create settings.xml'
        uses: s4u/maven-settings-action@v3.0.0
        with:
          githubServer: false
          servers: |
            [{
               "id": "camunda-nexus",
               "username": "${{ steps.secrets.outputs.ARTIFACTORY_USR }}",
               "password": "${{ steps.secrets.outputs.ARTIFACTORY_PSW }}"
             },
            {
               "id": "central",
               "username": "${{ steps.secrets.outputs.MAVEN_CENTRAL_DEPLOYMENT_USR }}",
               "password": "${{ steps.secrets.outputs.MAVEN_CENTRAL_DEPLOYMENT_PSW }}"
             }
            ]
          mirrors: '[{"url": "https://repository.nexus.camunda.cloud/content/groups/internal/", "id": "camunda-nexus", "mirrorOf": "camunda-nexus", "name": "camunda Nexus"}]'

      - name: Configure git user
        run: |
          # https://github.com/actions/checkout/issues/13#issuecomment-724415212
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

      - name: Install element templates CLI
        run: npm install --global element-templates-cli

      # Maven build & version bump

      - name: Set Connectors release version
        run: mvn -B versions:set -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false -f parent
        env:
          RELEASE_VERSION: ${{ github.event.release.tag_name }}

      - name: Deploy artifacts to Artifactory and Maven Central (Staging)
        run: mvn -B compile generate-sources source:jar javadoc:jar deploy -PcheckFormat -Psonatype-oss-release
        env:
          NEXUS_USR: ${{ steps.secrets.outputs.ARTIFACTORY_USR }}
          NEXUS_PSW: ${{ steps.secrets.outputs.ARTIFACTORY_PSW }}
          MAVEN_USR: ${{ steps.secrets.outputs.MAVEN_CENTRAL_DEPLOYMENT_USR }}
          MAVEN_PSW: ${{ steps.secrets.outputs.MAVEN_CENTRAL_DEPLOYMENT_PSW }}
          MAVEN_GPG_PASSPHRASE: ${{ steps.secrets.outputs.MAVEN_CENTRAL_GPG_SIGNING_KEY_PASSPHRASE }}

      - name: Generate sbom reports
        run: |
          mvn cyclonedx:makeAggregateBom -pl bundle/default-bundle

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
        with:
          platforms: 'arm64,arm'

      - name: Set up Docker Build
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ steps.secrets.outputs.DOCKERHUB_USER }}
          password: ${{ steps.secrets.outputs.DOCKERHUB_PASSWORD }}

      # Build & push bundle docker images (with version tag)

      - name: Build and Push Docker Image tag ${{ github.event.release.tag_name }} - connector-runtime
        uses: docker/build-push-action@v5
        with:
          context: connector-runtime/connector-runtime-application/
          push: true
          tags: camunda/connectors:${{ github.event.release.tag_name }}
          platforms: linux/amd64,linux/arm64
          provenance: false

      - name: Build and Push Docker Image tag ${{ github.event.release.tag_name }} - bundle-default
        uses: docker/build-push-action@v5
        with:
          context: bundle/default-bundle/
          push: true
          tags: camunda/connectors-bundle:${{ github.event.release.tag_name }}
          platforms: linux/amd64,linux/arm64
          provenance: false

      - name: Build and Push Docker Image tag ${{ github.event.release.tag_name }} - bundle-saas
        uses: docker/build-push-action@v5
        with:
          context: bundle/camunda-saas-bundle/
          push: true
          tags: camunda/connectors-bundle-saas:${{ github.event.release.tag_name }}
          platforms: linux/amd64,linux/arm64
          provenance: false

      # Build & push bundle docker images (with 'latest' tag)

      - name: Build and Push Docker Image tag latest - connector-runtime
        uses: docker/build-push-action@v5
        with:
          context: connector-runtime/connector-runtime-application/
          push: true
          tags: camunda/connectors:latest
          platforms: linux/amd64,linux/arm64
          provenance: false

      - name: Build and Push Docker Image tag latest - bundle-default
        if: ${{ steps.validate_tag.outputs.type == 'NORMAL' }}
        uses: docker/build-push-action@v5
        with:
          context: bundle/default-bundle/
          push: true
          tags: camunda/connectors-bundle:latest
          platforms: linux/amd64,linux/arm64
          provenance: false

      - name: Build and Push Docker Image tag latest - bundle-saas
        if: ${{ steps.validate_tag.outputs.type == 'NORMAL' }}
        uses: docker/build-push-action@v5
        with:
          context: bundle/camunda-saas-bundle/
          push: true
          tags: camunda/connectors-bundle-saas:latest
          platforms: linux/amd64,linux/arm64
          provenance: false

      # Update README in Dockerhub

      - name: Push README to Dockerhub - bundle-default
        if: ${{ steps.validate_tag.outputs.type == 'NORMAL' }}
        uses: christian-korneck/update-container-description-action@v1
        env:
          DOCKER_USER: ${{ steps.secrets.outputs.DOCKERHUB_USER }}
          DOCKER_PASS: ${{ steps.secrets.outputs.DOCKERHUB_PASSWORD }}
        with:
          destination_container_repo: camunda/connectors-bundle
          provider: dockerhub
          readme_file: bundle/README.md
          short_description: 'Camunda out-of-the-box Connectors Bundle'

      - name: Push README to Dockerhub - bundle-saas
        if: ${{ steps.validate_tag.outputs.type == 'NORMAL' }}
        uses: christian-korneck/update-container-description-action@v1
        env:
          DOCKER_USER: ${{ steps.secrets.outputs.DOCKERHUB_USER }}
          DOCKER_PASS: ${{ steps.secrets.outputs.DOCKERHUB_PASSWORD }}
        with:
          destination_container_repo: camunda/connectors-bundle-saas
          provider: dockerhub
          readme_file: bundle/README.md
          short_description: 'Camunda out-of-the-box Connectors Bundle for SaaS'

      # Update GitHub release

      - name: Bundle element templates
        run: bash bundle/bundle-templates.sh ${RELEASE_VERSION}
        env:
          RELEASE_VERSION: ${{ github.event.release.tag_name }}

      - name: Build Changelog
        id: changelog
        uses: Requarks/changelog-action@v1
        with:
          token: ${{ github.token }}
          fromTag: ${{ github.event.release.tag_name }}
          toTag: ${{ steps.validate_tag.outputs.previousTag }}
          writeToFile: false
          excludeTypes: build,docs,other,style,ci
          excludeScopes: deps

      - name: Commit and tag
        run: |
          git commit -am "ci: release version ${RELEASE_VERSION}"
          git push origin ${RELEASE_BRANCH}
          git tag -fa ${RELEASE_VERSION} -m "ci: release version ${RELEASE_VERSION}"
          git push --force origin ${RELEASE_VERSION}

        env:
          RELEASE_VERSION: ${{ github.event.release.tag_name }}
          RELEASE_BRANCH: ${{ steps.determine_release_branch.outputs.releaseBranch }}

      - name: Update GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          prerelease: ${{ steps.validate_tag.outputs.type != 'NORMAL' }}
          body: ${{ steps.changelog.outputs.changes }}
          tag_name: ${{ github.event.release.tag_name }}
          files: |
            bundle/default-bundle/target/connectors-bundle-sbom.json
            bundle/default-bundle/target/connectors-bundle-sbom.xml
            connectors-bundle-templates-${{ github.event.release.tag_name }}.tar.gz
            connectors-bundle-templates-${{ github.event.release.tag_name }}.zip

  helm-deploy:
    needs: build-and-push
    name: Run Helm Integration Tests
    uses: ./.github/workflows/INTEGRATION_TEST.yml
    secrets: inherit
    with:
      connectors-version: ${{ github.event.release.tag_name }}
      release-branch: ${{ needs.build-and-push.outputs.releaseBranch }}


name: ADD_TO_PROJECT

on:
  issues:
    types:
      - opened
      - transferred
      - labeled
  pull_request:
    types:
      - opened
      - labeled

jobs:
  Exec:
    name: Add issue to project
    runs-on: ubuntu-latest
    steps:
      - uses: actions/add-to-project@v1.0.1
        with:
          project-url: https://github.com/orgs/camunda/projects/23/views/1
          github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}


Test branch

name: Test branch

on:
  push:
    branches:
      - '**'
      - '!main'
  merge_group:
    branches: [ main ]

jobs:
  run-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Import Secrets
        id: secrets
        uses: hashicorp/vault-action@v3.0.0
        with:
          url: ${{ secrets.VAULT_ADDR }}
          method: approle
          roleId: ${{ secrets.VAULT_ROLE_ID }}
          secretId: ${{ secrets.VAULT_SECRET_ID }}
          exportEnv: false # we rely on step outputs, no need for environment variables
          secrets: |
            secret/data/products/connectors/ci/common ARTIFACTORY_USR | CI_LDAP_USER;
            secret/data/products/connectors/ci/common ARTIFACTORY_PSW | CI_LDAP_PASSWORD;

      - name: Restore cache
        uses: actions/cache@v4
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-maven-

      - uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '21'

      # Use CI Nexus as co-located pull-through cache for Maven artifacts via ~/.m2/settings.xml
      - name: 'Create settings.xml'
        uses: s4u/maven-settings-action@v3.0.0
        with:
          githubServer: false
          servers: |
            [{
               "id": "camunda-nexus",
               "username": "${{ steps.secrets.outputs.CI_LDAP_USER }}",
               "password": "${{ steps.secrets.outputs.CI_LDAP_PASSWORD }}"
             }]
          mirrors: '[{"url": "https://repository.nexus.camunda.cloud/content/groups/internal/", "id": "camunda-nexus", "mirrorOf": "camunda-nexus", "name": "camunda Nexus"}]'

      - uses: actions/setup-node@v4
        with:
          node-version: '16'

      - name: Install element templates CLI
        run: npm install --global element-templates-cli

      - name: Build Connectors
        run: mvn --batch-mode clean test -PcheckFormat

      - name: Lint Dockerfile - connector-runtime
        uses: hadolint/hadolint-action@v3.1.0
        with:
          dockerfile: connector-runtime/connector-runtime-application/Dockerfile

      - name: Lint Dockerfile - SaaS
        uses: hadolint/hadolint-action@v3.1.0
        with:
          dockerfile: bundle/camunda-saas-bundle/Dockerfile

      - name: Lint Dockerfile - default-bundle
        uses: hadolint/hadolint-action@v3.1.0
        with:
          dockerfile: bundle/default-bundle/Dockerfile

      - name: Package Connectors
        env:
          PROJECTS: bundle/default-bundle
        run: mvn --batch-mode compile generate-sources package -DskipTests --projects "${PROJECTS}" --also-make

      - name: Set up Docker Build
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          registry: registry.camunda.cloud
          username: ${{ steps.secrets.outputs.CI_LDAP_USER }}
          password: ${{ steps.secrets.outputs.CI_LDAP_PASSWORD }}

      # Publish Docker images for Preview environments
      - name: Build and Push Docker Image tag ${{ env.TAG }} - bundle-default
        env:
          TAG: pr-${{ github.sha }}
        uses: docker/build-push-action@v5
        with:
          context: bundle/default-bundle/
          provenance: false
          push: true
          tags: registry.camunda.cloud/team-connectors/connectors-bundle:${{ env.TAG }}