diff --git a/.github/workflows/delta-conversion-ci.yml b/.github/workflows/delta-conversion-ci.yml index cd16847cf95a..9326d9d533fd 100644 --- a/.github/workflows/delta-conversion-ci.yml +++ b/.github/workflows/delta-conversion-ci.yml @@ -35,6 +35,7 @@ on: - '.github/workflows/hive-ci.yml' - '.github/workflows/java-ci.yml' - '.github/workflows/jmh-benchmarks-ci.yml' + - '.github/workflows/kafka-connect-ci.yml' - '.github/workflows/labeler.yml' - '.github/workflows/licence-check.yml' - '.github/workflows/open-api.yml' @@ -51,6 +52,7 @@ on: - 'hive3-orc-bundle/**' - 'hive-runtime/**' - 'flink/**' + - 'kafka-connect/**' - 'pig/**' - 'docs/**' - 'site/**' @@ -88,7 +90,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: ${{ runner.os }}-gradle- - run: echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - - run: ./gradlew -DsparkVersions=3.5 -DscalaVersion=2.12 -DhiveVersions= -DflinkVersions= :iceberg-delta-lake:check -Pquick=true -x javadoc + - run: ./gradlew -DsparkVersions=3.5 -DscalaVersion=2.12 -DhiveVersions= -DkafkaVersions= -DflinkVersions= :iceberg-delta-lake:check -Pquick=true -x javadoc - uses: actions/upload-artifact@v4 if: failure() with: @@ -117,7 +119,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: ${{ runner.os }}-gradle- - run: echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - - run: ./gradlew -DsparkVersions=3.5 -DscalaVersion=2.13 -DhiveVersions= -DflinkVersions= :iceberg-delta-lake:check -Pquick=true -x javadoc + - run: ./gradlew -DsparkVersions=3.5 -DscalaVersion=2.13 -DhiveVersions= -DkafkaVersions= -DflinkVersions= :iceberg-delta-lake:check -Pquick=true -x javadoc - uses: actions/upload-artifact@v4 if: failure() with: diff --git a/.github/workflows/flink-ci.yml b/.github/workflows/flink-ci.yml index 370375783cc2..8ed555847861 100644 --- a/.github/workflows/flink-ci.yml +++ b/.github/workflows/flink-ci.yml @@ -35,6 +35,7 @@ on: - '.github/workflows/hive-ci.yml' - '.github/workflows/java-ci.yml' - '.github/workflows/jmh-benchmarks-ci.yml' + - '.github/workflows/kafka-connect-ci.yml' - '.github/workflows/labeler.yml' - '.github/workflows/licence-check.yml' - '.github/workflows/open-api.yml' @@ -50,6 +51,7 @@ on: - 'hive3/**' - 'hive3-orc-bundle/**' - 'hive-runtime/**' + - 'kafka-connect/**' - 'spark/**' - 'pig/**' - 'docs/**' @@ -91,7 +93,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: ${{ runner.os }}-gradle- - run: echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - - run: ./gradlew -DsparkVersions= -DhiveVersions= -DflinkVersions=${{ matrix.flink }} :iceberg-flink:iceberg-flink-${{ matrix.flink }}:check :iceberg-flink:iceberg-flink-runtime-${{ matrix.flink }}:check -Pquick=true -x javadoc + - run: ./gradlew -DsparkVersions= -DhiveVersions= -DkafkaVersions= -DflinkVersions=${{ matrix.flink }} :iceberg-flink:iceberg-flink-${{ matrix.flink }}:check :iceberg-flink:iceberg-flink-runtime-${{ matrix.flink }}:check -Pquick=true -x javadoc - uses: actions/upload-artifact@v4 if: failure() with: diff --git a/.github/workflows/hive-ci.yml b/.github/workflows/hive-ci.yml index 6ad9f58410d6..bcaf62cc07f8 100644 --- a/.github/workflows/hive-ci.yml +++ b/.github/workflows/hive-ci.yml @@ -35,6 +35,7 @@ on: - '.github/workflows/flink-ci.yml' - '.github/workflows/java-ci.yml' - '.github/workflows/jmh-benchmarks-ci.yml' + - '.github/workflows/kafka-connect-ci.yml' - '.github/workflows/labeler.yml' - '.github/workflows/licence-check.yml' - '.github/workflows/open-api.yml' @@ -49,6 +50,7 @@ on: - 'arrow/**' - 'spark/**' - 'flink/**' + - 'kafka-connect/**' - 'pig/**' - 'docs/**' - 'site/**' @@ -86,7 +88,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: ${{ runner.os }}-gradle- - run: echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - - run: ./gradlew -DsparkVersions= -DhiveVersions=2 -DflinkVersions= -Pquick=true :iceberg-mr:check :iceberg-hive-runtime:check -x javadoc + - run: ./gradlew -DsparkVersions= -DhiveVersions=2 -DflinkVersions= -DkafkaVersions= -Pquick=true :iceberg-mr:check :iceberg-hive-runtime:check -x javadoc - uses: actions/upload-artifact@v4 if: failure() with: @@ -115,7 +117,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: ${{ runner.os }}-gradle- - run: echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - - run: ./gradlew -DsparkVersions= -DhiveVersions=3 -DflinkVersions= -Pquick=true :iceberg-hive3-orc-bundle:check :iceberg-hive3:check :iceberg-hive-runtime:check -x javadoc + - run: ./gradlew -DsparkVersions= -DhiveVersions=3 -DflinkVersions= -DkafkaVersions= -Pquick=true :iceberg-hive3-orc-bundle:check :iceberg-hive3:check :iceberg-hive-runtime:check -x javadoc - uses: actions/upload-artifact@v4 if: failure() with: diff --git a/.github/workflows/java-ci.yml b/.github/workflows/java-ci.yml index 0d39ee8646ad..1da7a673a865 100644 --- a/.github/workflows/java-ci.yml +++ b/.github/workflows/java-ci.yml @@ -35,6 +35,7 @@ on: - '.github/workflows/flink-ci.yml' - '.github/workflows/hive-ci.yml' - '.github/workflows/jmh-benchmarks-ci.yml' + - '.github/workflows/kafka-connect-ci.yml' - '.github/workflows/labeler.yml' - '.github/workflows/licence-check.yml' - '.github/workflows/open-api.yml' @@ -82,7 +83,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: ${{ runner.os }}-gradle- - run: echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - - run: ./gradlew check -DsparkVersions= -DhiveVersions= -DflinkVersions= -Pquick=true -x javadoc + - run: ./gradlew check -DsparkVersions= -DhiveVersions= -DflinkVersions= -DkafkaVersions= -Pquick=true -x javadoc - uses: actions/upload-artifact@v4 if: failure() with: diff --git a/.github/workflows/kafka-connect-ci.yml b/.github/workflows/kafka-connect-ci.yml new file mode 100644 index 000000000000..98ec18a77953 --- /dev/null +++ b/.github/workflows/kafka-connect-ci.yml @@ -0,0 +1,105 @@ +# +# 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: "Kafka Connect CI" +on: + push: + branches: + - 'main' + - '0.*' + - '1.*' + - '2.*' + tags: + - 'apache-iceberg-**' + pull_request: + paths-ignore: + - '.github/ISSUE_TEMPLATE/**' + - '.github/workflows/api-binary-compatibility.yml' + - '.github/workflows/delta-conversion-ci.yml' + - '.github/workflows/flink-ci.yml' + - '.github/workflows/hive-ci.yml' + - '.github/workflows/java-ci.yml' + - '.github/workflows/jmh-benchmarks-ci.yml' + - '.github/workflows/labeler.yml' + - '.github/workflows/licence-check.yml' + - '.github/workflows/open-api.yml' + - '.github/workflows/publish-snapshot.yml' + - '.github/workflows/recurring-jmh-benchmarks.yml' + - '.github/workflows/site-ci.yml' + - '.github/workflows/spark-ci.yml' + - '.github/workflows/stale.yml' + - '.gitignore' + - '.asf.yml' + - 'dev/**' + - 'mr/**' + - 'flink/**' + - 'hive3/**' + - 'hive3-orc-bundle/**' + - 'hive-runtime/**' + - 'spark/**' + - 'pig/**' + - 'docs/**' + - 'site/**' + - 'open-api/**' + - 'format/**' + - '.gitattributes' + - 'README.md' + - 'CONTRIBUTING.md' + - 'LICENSE' + - 'NOTICE' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + + kafka-connect-tests: + runs-on: ubuntu-22.04 + strategy: + matrix: + jvm: [11, 17, 21] + env: + SPARK_LOCAL_IP: localhost + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: zulu + java-version: ${{ matrix.jvm }} + - uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-gradle- + - run: echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + - run: | + ./gradlew -DsparkVersions= -DhiveVersions= -DflinkVersions= -DkafkaVersions=3 \ + :iceberg-kafka-connect:iceberg-kafka-connect-events:check \ + :iceberg-kafka-connect:iceberg-kafka-connect:check \ + :iceberg-kafka-connect:iceberg-kafka-connect-runtime:check \ + -Pquick=true -x javadoc + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: test logs + path: | + **/build/testlogs diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index 6acee54bde3e..7ff6b56da576 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -41,4 +41,4 @@ jobs: - run: | ./gradlew printVersion ./gradlew -DallModules publishApachePublicationToMavenRepository -PmavenUser=${{ secrets.NEXUS_USER }} -PmavenPassword=${{ secrets.NEXUS_PW }} - ./gradlew -DflinkVersions= -DsparkVersions=3.3,3.4,3.5 -DscalaVersion=2.13 -DhiveVersions= publishApachePublicationToMavenRepository -PmavenUser=${{ secrets.NEXUS_USER }} -PmavenPassword=${{ secrets.NEXUS_PW }} + ./gradlew -DflinkVersions= -DsparkVersions=3.3,3.4,3.5 -DscalaVersion=2.13 -DkafkaVersions=3 -DhiveVersions= publishApachePublicationToMavenRepository -PmavenUser=${{ secrets.NEXUS_USER }} -PmavenPassword=${{ secrets.NEXUS_PW }} diff --git a/.github/workflows/spark-ci.yml b/.github/workflows/spark-ci.yml index 1cc0425b73a3..b5d91d3cc76c 100644 --- a/.github/workflows/spark-ci.yml +++ b/.github/workflows/spark-ci.yml @@ -36,6 +36,7 @@ on: - '.github/workflows/hive-ci.yml' - '.github/workflows/java-ci.yml' - '.github/workflows/jmh-benchmarks-ci.yml' + - '.github/workflows/kafka-connect-ci.yml' - '.github/workflows/labeler.yml' - '.github/workflows/licence-check.yml' - '.github/workflows/open-api.yml' @@ -52,6 +53,7 @@ on: - 'hive3-orc-bundle/**' - 'hive-runtime/**' - 'flink/**' + - 'kafka-connect/**' - 'pig/**' - 'docs/**' - 'open-api/**' @@ -101,7 +103,7 @@ jobs: tool-cache: false - run: echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - run: | - ./gradlew -DsparkVersions=${{ matrix.spark }} -DscalaVersion=${{ matrix.scala }} -DhiveVersions= -DflinkVersions= \ + ./gradlew -DsparkVersions=${{ matrix.spark }} -DscalaVersion=${{ matrix.scala }} -DhiveVersions= -DflinkVersions= -DkafkaVersions= \ :iceberg-spark:iceberg-spark-${{ matrix.spark }}_${{ matrix.scala }}:check \ :iceberg-spark:iceberg-spark-extensions-${{ matrix.spark }}_${{ matrix.scala }}:check \ :iceberg-spark:iceberg-spark-runtime-${{ matrix.spark }}_${{ matrix.scala }}:check \ diff --git a/dev/stage-binaries.sh b/dev/stage-binaries.sh index 29cf31e5f423..fa09b76c38e9 100755 --- a/dev/stage-binaries.sh +++ b/dev/stage-binaries.sh @@ -22,8 +22,9 @@ SCALA_VERSION=2.12 FLINK_VERSIONS=1.18,1.19,1.20 SPARK_VERSIONS=3.3,3.4,3.5 HIVE_VERSIONS=2,3 +KAFKA_VERSIONS=3 -./gradlew -Prelease -DscalaVersion=$SCALA_VERSION -DflinkVersions=$FLINK_VERSIONS -DsparkVersions=$SPARK_VERSIONS -DhiveVersions=$HIVE_VERSIONS publishApachePublicationToMavenRepository +./gradlew -Prelease -DscalaVersion=$SCALA_VERSION -DflinkVersions=$FLINK_VERSIONS -DsparkVersions=$SPARK_VERSIONS -DhiveVersions=$HIVE_VERSIONS -DkafkaVersions=$KAFKA_VERSIONS publishApachePublicationToMavenRepository # Also publish Scala 2.13 Artifacts for versions that support it. # Flink does not yet support 2.13 (and is largely dropping a user-facing dependency on Scala). Hive doesn't need a Scala specification. diff --git a/gradle.properties b/gradle.properties index fcbe7d8de012..dc1e1a509b01 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,6 +22,8 @@ systemProp.defaultHiveVersions=2 systemProp.knownHiveVersions=2,3 systemProp.defaultSparkVersions=3.5 systemProp.knownSparkVersions=3.3,3.4,3.5 +systemProp.defaultKafkaVersions=3 +systemProp.knownKafkaVersions=3 systemProp.defaultScalaVersion=2.12 systemProp.knownScalaVersions=2.12,2.13 # enable the Gradle build cache - speeds up builds! diff --git a/kafka-connect/kafka-connect-runtime/src/integration/java/org/apache/iceberg/connect/IntegrationTestBase.java b/kafka-connect/kafka-connect-runtime/src/integration/java/org/apache/iceberg/connect/IntegrationTestBase.java index f90d4da0379e..247211edb01f 100644 --- a/kafka-connect/kafka-connect-runtime/src/integration/java/org/apache/iceberg/connect/IntegrationTestBase.java +++ b/kafka-connect/kafka-connect-runtime/src/integration/java/org/apache/iceberg/connect/IntegrationTestBase.java @@ -40,11 +40,13 @@ import org.apache.kafka.clients.producer.ProducerRecord; import org.assertj.core.api.Condition; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; public class IntegrationTestBase { - private final TestContext context = TestContext.INSTANCE; + private static TestContext context; + private Catalog catalog; private Admin admin; private String connectorName; @@ -70,12 +72,16 @@ protected String testTopic() { return testTopic; } + @BeforeAll + public static void baseBeforeAll() { + context = TestContext.instance(); + } + @BeforeEach public void baseBefore() { - catalog = context.initLocalCatalog(); - producer = context.initLocalProducer(); - admin = context.initLocalAdmin(); - + this.catalog = context.initLocalCatalog(); + this.producer = context.initLocalProducer(); + this.admin = context.initLocalAdmin(); this.connectorName = "test_connector-" + UUID.randomUUID(); this.testTopic = "test-topic-" + UUID.randomUUID(); } @@ -98,7 +104,7 @@ protected void assertSnapshotProps(TableIdentifier tableIdentifier, String branc Map props = latestSnapshot(table, branch).summary(); assertThat(props) .hasKeySatisfying( - new Condition() { + new Condition<>() { @Override public boolean matches(String str) { return str.startsWith("kafka.connect.offsets."); diff --git a/kafka-connect/kafka-connect-runtime/src/integration/java/org/apache/iceberg/connect/TestContext.java b/kafka-connect/kafka-connect-runtime/src/integration/java/org/apache/iceberg/connect/TestContext.java index 729d4bb264e5..2a1ded6cd8a1 100644 --- a/kafka-connect/kafka-connect-runtime/src/integration/java/org/apache/iceberg/connect/TestContext.java +++ b/kafka-connect/kafka-connect-runtime/src/integration/java/org/apache/iceberg/connect/TestContext.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; +import java.time.Duration; import java.util.Map; import java.util.UUID; import org.apache.iceberg.CatalogProperties; @@ -37,7 +38,8 @@ public class TestContext { - public static final TestContext INSTANCE = new TestContext(); + private static volatile TestContext instance; + public static final ObjectMapper MAPPER = new ObjectMapper(); public static final int CONNECT_PORT = 8083; @@ -48,9 +50,17 @@ public class TestContext { private static final String AWS_SECRET_KEY = "minioadmin"; private static final String AWS_REGION = "us-east-1"; + public static synchronized TestContext instance() { + if (instance == null) { + instance = new TestContext(); + } + return instance; + } + private TestContext() { ComposeContainer container = new ComposeContainer(new File("./docker/docker-compose.yml")) + .withStartupTimeout(Duration.ofMinutes(2)) .waitingFor("connect", Wait.forHttp("/connectors")); container.start(); } diff --git a/settings.gradle b/settings.gradle index 1e6d92bf1e1f..56a68c384c5f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -41,7 +41,6 @@ include 'gcp-bundle' include 'dell' include 'snowflake' include 'delta-lake' -include 'kafka-connect' include 'open-api' project(':bom').name = 'iceberg-bom' @@ -67,13 +66,13 @@ project(':gcp-bundle').name = 'iceberg-gcp-bundle' project(':dell').name = 'iceberg-dell' project(':snowflake').name = 'iceberg-snowflake' project(':delta-lake').name = 'iceberg-delta-lake' -project(':kafka-connect').name = 'iceberg-kafka-connect' project(':open-api').name = 'iceberg-open-api' if (null != System.getProperty("allModules")) { System.setProperty("flinkVersions", System.getProperty("knownFlinkVersions")) System.setProperty("sparkVersions", System.getProperty("knownSparkVersions")) System.setProperty("hiveVersions", System.getProperty("knownHiveVersions")) + System.setProperty("kafkaVersions", System.getProperty("knownKafkaVersions")) } List knownFlinkVersions = System.getProperty("knownFlinkVersions").split(",") @@ -100,6 +99,14 @@ if (!knownSparkVersions.containsAll(sparkVersions)) { throw new GradleException("Found unsupported Spark versions: " + (sparkVersions - knownSparkVersions)) } +List knownKafkaVersions = System.getProperty("knownKafkaVersions").split(",") +String kafkaVersionsString = System.getProperty("kafkaVersions") != null ? System.getProperty("kafkaVersions") : System.getProperty("defaultKafkaVersions") +List kafkaVersions = kafkaVersionsString != null && !kafkaVersionsString.isEmpty() ? kafkaVersionsString.split(",") : [] + +if (!knownKafkaVersions.containsAll(kafkaVersions)) { + throw new GradleException("Found unsupported Kafka versions: " + (kafkaVersions - knownKafkaVersions)) +} + List knownScalaVersions = System.getProperty("knownScalaVersions").split(",") String scalaVersion = System.getProperty("scalaVersion") != null ? System.getProperty("scalaVersion") : System.getProperty("defaultScalaVersion") @@ -191,14 +198,19 @@ if (hiveVersions.contains("3")) { project(':hive3-orc-bundle').name = 'iceberg-hive3-orc-bundle' } -include ":iceberg-kafka-connect:kafka-connect-events" -project(":iceberg-kafka-connect:kafka-connect-events").projectDir = file('kafka-connect/kafka-connect-events') -project(":iceberg-kafka-connect:kafka-connect-events").name = "iceberg-kafka-connect-events" +if (kafkaVersions.contains("3")) { + include 'kafka-connect' + project(':kafka-connect').name = 'iceberg-kafka-connect' -include ":iceberg-kafka-connect:kafka-connect" -project(":iceberg-kafka-connect:kafka-connect").projectDir = file('kafka-connect/kafka-connect') -project(":iceberg-kafka-connect:kafka-connect").name = "iceberg-kafka-connect" + include ":iceberg-kafka-connect:kafka-connect-events" + project(":iceberg-kafka-connect:kafka-connect-events").projectDir = file('kafka-connect/kafka-connect-events') + project(":iceberg-kafka-connect:kafka-connect-events").name = "iceberg-kafka-connect-events" -include ":iceberg-kafka-connect:kafka-connect-runtime" -project(":iceberg-kafka-connect:kafka-connect-runtime").projectDir = file('kafka-connect/kafka-connect-runtime') -project(":iceberg-kafka-connect:kafka-connect-runtime").name = "iceberg-kafka-connect-runtime" + include ":iceberg-kafka-connect:kafka-connect" + project(":iceberg-kafka-connect:kafka-connect").projectDir = file('kafka-connect/kafka-connect') + project(":iceberg-kafka-connect:kafka-connect").name = "iceberg-kafka-connect" + + include ":iceberg-kafka-connect:kafka-connect-runtime" + project(":iceberg-kafka-connect:kafka-connect-runtime").projectDir = file('kafka-connect/kafka-connect-runtime') + project(":iceberg-kafka-connect:kafka-connect-runtime").name = "iceberg-kafka-connect-runtime" +}