diff --git a/.github/workflows/NativeTests.yaml b/.github/workflows/NativeTests.yaml
new file mode 100644
index 0000000000..0fbcc96def
--- /dev/null
+++ b/.github/workflows/NativeTests.yaml
@@ -0,0 +1,116 @@
+name: NativeTests
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ types: [opened, synchronize, reopened]
+ paths-ignore:
+ - 'spring-cloud-generator/**'
+ - 'spring-cloud-previews/**'
+ workflow_dispatch:
+
+
+jobs:
+ NativeTests:
+ if: |
+ github.actor != 'dependabot[bot]' && ((
+ github.event_name == 'pull_request' && github.repository == github.event.pull_request.head.repo.full_name
+ ) || (github.event_name != 'pull_request'))
+ runs-on: ubuntu-20.04
+ strategy:
+ fail-fast: false
+ steps:
+ - name: Get current date
+ id: date
+ run: echo "date=$(date +'%Y-%m-%d' --utc)" >> $GITHUB_OUTPUT
+ - uses: actions/checkout@v3
+ - uses: actions/setup-java@v3
+ with:
+ java-version: 17
+ distribution: 'temurin'
+ - name: Set Up Authentication
+ uses: google-github-actions/auth@v1
+ with:
+ credentials_json: ${{ secrets.SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY }}
+ - name: Setup gcloud
+ uses: google-github-actions/setup-gcloud@v1
+ with:
+ project_id: spring-cloud-gcp-ci-native
+ - name: Maven go offline
+ id: mvn-offline
+ if: steps.mvn-cache.outputs.cache-hit != 'true'
+ run: ./mvnw compile dependency:go-offline
+ - name: Mvn install # Need this when the directory/pom structure changes
+ id: install1
+ continue-on-error: true
+ run: |
+ ./mvnw \
+ --batch-mode \
+ --threads 1.5C \
+ --define maven.test.skip=true \
+ --define maven.javadoc.skip=true \
+ install
+ - name: Retry install on failure
+ id: install2
+ if: steps.install1.outcome == 'failure'
+ run: |
+ ./mvnw \
+ --batch-mode \
+ --threads 1.5C \
+ --define maven.test.skip=true \
+ --define maven.javadoc.skip=true \
+ install
+ - name: Wait our turn for running native tests
+ uses: softprops/turnstyle@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ continue-after-seconds: 3600 # 60 min
+ same-branch-only: false
+ - uses: graalvm/setup-graalvm@v1
+ with:
+ version: '22.3.0'
+ java-version: '17'
+ components: 'native-image'
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ native-image-job-reports: 'true'
+ - name: Native Tests in Samples
+ id: intTest1
+ continue-on-error: true
+ run: |
+ ../mvnw \
+ --batch-mode \
+ --activate-profiles native-sample-config,nativeTest \
+ --define notAllModules=true \
+ --define maven.javadoc.skip=true \
+ test
+ working-directory: ./spring-cloud-gcp-samples
+ - name: Retry on Failure
+ id: intTest2
+ if: steps.intTest1.outcome == 'failure'
+ run: |
+ ../mvnw \
+ --batch-mode \
+ --activate-profiles native-sample-config,nativeTest \
+ --define notAllModules=true \
+ --define maven.javadoc.skip=true \
+ test
+ working-directory: ./spring-cloud-gcp-samples
+ - name: Aggregate Report
+ run: |
+ ../mvnw \
+ --batch-mode \
+ --define aggregate=true \
+ surefire-report:report-only
+ working-directory: ./spring-cloud-gcp-samples
+ - name: Archive logs
+ if: always()
+ continue-on-error: true
+ uses: actions/upload-artifact@v3
+ with:
+ name: Native Test Logs
+ path: |
+ **/target/failsafe-reports/*
+ **/target/site
diff --git a/spring-cloud-gcp-logging/src/main/java/com/google/cloud/spring/logging/aot/LoggingRuntimeHints.java b/spring-cloud-gcp-logging/src/main/java/com/google/cloud/spring/logging/aot/LoggingRuntimeHints.java
new file mode 100644
index 0000000000..a35f2b8893
--- /dev/null
+++ b/spring-cloud-gcp-logging/src/main/java/com/google/cloud/spring/logging/aot/LoggingRuntimeHints.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed 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
+ *
+ * https://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.
+ */
+
+package com.google.cloud.spring.logging.aot;
+
+import com.google.cloud.spring.logging.LoggingAppender;
+import com.google.cloud.spring.logging.StackdriverJsonLayout;
+import com.google.cloud.spring.logging.TraceIdLoggingEnhancer;
+import java.util.Arrays;
+import org.springframework.aot.hint.MemberCategory;
+import org.springframework.aot.hint.RuntimeHints;
+import org.springframework.aot.hint.RuntimeHintsRegistrar;
+import org.springframework.aot.hint.TypeReference;
+
+public class LoggingRuntimeHints implements RuntimeHintsRegistrar {
+ @Override
+ public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
+ hints
+ .reflection()
+ .registerTypes(
+ Arrays.asList(
+ TypeReference.of(LoggingAppender.class),
+ TypeReference.of(TraceIdLoggingEnhancer.class),
+ TypeReference.of(StackdriverJsonLayout.class)),
+ hint ->
+ hint.withMembers(
+ MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
+ MemberCategory.INVOKE_PUBLIC_METHODS));
+ }
+}
diff --git a/spring-cloud-gcp-logging/src/main/resources/META-INF/spring/aot.factories b/spring-cloud-gcp-logging/src/main/resources/META-INF/spring/aot.factories
new file mode 100644
index 0000000000..80e12af31a
--- /dev/null
+++ b/spring-cloud-gcp-logging/src/main/resources/META-INF/spring/aot.factories
@@ -0,0 +1,2 @@
+org.springframework.aot.hint.RuntimeHintsRegistrar=\
+ com.google.cloud.spring.logging.aot.LoggingRuntimeHints
\ No newline at end of file
diff --git a/spring-cloud-gcp-logging/src/test/java/com/google/cloud/spring/logging/aot/LoggingRuntimeHintsTest.java b/spring-cloud-gcp-logging/src/test/java/com/google/cloud/spring/logging/aot/LoggingRuntimeHintsTest.java
new file mode 100644
index 0000000000..bb85a6528c
--- /dev/null
+++ b/spring-cloud-gcp-logging/src/test/java/com/google/cloud/spring/logging/aot/LoggingRuntimeHintsTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed 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
+ *
+ * https://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.
+ */
+
+package com.google.cloud.spring.logging.aot;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection;
+
+import com.google.cloud.spring.logging.LoggingAppender;
+import com.google.cloud.spring.logging.StackdriverJsonLayout;
+import com.google.cloud.spring.logging.TraceIdLoggingEnhancer;
+import org.junit.jupiter.api.Test;
+import org.springframework.aot.hint.RuntimeHints;
+
+class LoggingRuntimeHintsTest {
+
+ @Test
+ void shouldRegisterHints() {
+ RuntimeHints hints = new RuntimeHints();
+ new LoggingRuntimeHints().registerHints(hints, getClass().getClassLoader());
+
+ assertThat(hints)
+ .matches(reflection().onType(LoggingAppender.class))
+ .matches(reflection().onType(TraceIdLoggingEnhancer.class))
+ .matches(reflection().onType(StackdriverJsonLayout.class));
+ }
+}
diff --git a/spring-cloud-gcp-samples/pom.xml b/spring-cloud-gcp-samples/pom.xml
index 780f25de70..120ca1e5b2 100644
--- a/spring-cloud-gcp-samples/pom.xml
+++ b/spring-cloud-gcp-samples/pom.xml
@@ -42,44 +42,55 @@
true
-
- spring-cloud-gcp-config-sample
- spring-cloud-gcp-trace-sample
- spring-cloud-gcp-logging-sample
- spring-cloud-gcp-sql-mysql-sample
- spring-cloud-gcp-integration-pubsub-sample
- spring-cloud-gcp-storage-resource-sample
- spring-cloud-gcp-data-spanner-repository-sample
- spring-cloud-gcp-data-spanner-template-sample
- spring-cloud-gcp-data-datastore-sample
- spring-cloud-gcp-data-datastore-basic-sample
- spring-cloud-gcp-pubsub-sample
- spring-cloud-gcp-data-jpa-sample
- spring-cloud-gcp-vision-api-sample
- spring-cloud-gcp-integration-storage-sample
- spring-cloud-gcp-pubsub-bus-config-sample
- spring-cloud-gcp-pubsub-stream-dead-letter-sample
- spring-cloud-gcp-pubsub-stream-functional-sample
- spring-cloud-gcp-pubsub-reactive-sample
- spring-cloud-gcp-integration-pubsub-json-sample
- spring-cloud-gcp-security-iap-sample
- spring-cloud-gcp-sql-postgres-sample
- spring-cloud-gcp-sql-postgres-r2dbc-sample
- spring-cloud-gcp-vision-ocr-demo
- spring-cloud-gcp-firestore-sample
- spring-cloud-gcp-data-multi-sample
- spring-cloud-gcp-data-firestore-sample
- spring-cloud-gcp-bigquery-sample
- spring-cloud-gcp-security-firebase-sample
- spring-cloud-gcp-secretmanager-sample
- spring-cloud-gcp-kotlin-samples
- spring-cloud-gcp-metrics-sample
- spring-cloud-gcp-kms-sample
-
+
+ default
+
+
+ !notAllModules
+
+
+
+ spring-cloud-gcp-config-sample
+ spring-cloud-gcp-trace-sample
+ spring-cloud-gcp-logging-sample
+ spring-cloud-gcp-sql-mysql-sample
+ spring-cloud-gcp-integration-pubsub-sample
+ spring-cloud-gcp-storage-resource-sample
+ spring-cloud-gcp-data-spanner-repository-sample
+ spring-cloud-gcp-data-spanner-template-sample
+ spring-cloud-gcp-data-datastore-sample
+ spring-cloud-gcp-data-datastore-basic-sample
+ spring-cloud-gcp-pubsub-sample
+ spring-cloud-gcp-data-jpa-sample
+ spring-cloud-gcp-vision-api-sample
+ spring-cloud-gcp-integration-storage-sample
+ spring-cloud-gcp-pubsub-bus-config-sample
+ spring-cloud-gcp-pubsub-stream-dead-letter-sample
+ spring-cloud-gcp-pubsub-stream-functional-sample
+ spring-cloud-gcp-pubsub-reactive-sample
+ spring-cloud-gcp-integration-pubsub-json-sample
+ spring-cloud-gcp-security-iap-sample
+ spring-cloud-gcp-sql-postgres-sample
+ spring-cloud-gcp-sql-postgres-r2dbc-sample
+ spring-cloud-gcp-vision-ocr-demo
+ spring-cloud-gcp-firestore-sample
+ spring-cloud-gcp-data-multi-sample
+ spring-cloud-gcp-data-firestore-sample
+ spring-cloud-gcp-bigquery-sample
+ spring-cloud-gcp-security-firebase-sample
+ spring-cloud-gcp-secretmanager-sample
+ spring-cloud-gcp-kotlin-samples
+ spring-cloud-gcp-metrics-sample
+ spring-cloud-gcp-kms-sample
+
+
native-sample-config
+
+ spring-cloud-gcp-logging-sample
+
@@ -168,7 +179,6 @@
org.graalvm.buildtools
native-maven-plugin
- 0.9.23
true
diff --git a/spring-cloud-gcp-samples/spring-cloud-gcp-logging-sample/src/test/java/com.example/LoggingSampleApplicationIntegrationTests.java b/spring-cloud-gcp-samples/spring-cloud-gcp-logging-sample/src/test/java/com.example/LoggingSampleApplicationIntegrationTests.java
index 59a7d3b08e..6f88f365dc 100644
--- a/spring-cloud-gcp-samples/spring-cloud-gcp-logging-sample/src/test/java/com.example/LoggingSampleApplicationIntegrationTests.java
+++ b/spring-cloud-gcp-samples/spring-cloud-gcp-logging-sample/src/test/java/com.example/LoggingSampleApplicationIntegrationTests.java
@@ -40,6 +40,7 @@
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
@@ -52,6 +53,7 @@
@SpringBootTest(
webEnvironment = WebEnvironment.RANDOM_PORT,
classes = {Application.class})
+@ImportRuntimeHints(TestRuntimeHints.class)
class LoggingSampleApplicationIntegrationTests {
private static final String LOG_FILTER_FORMAT =
diff --git a/spring-cloud-gcp-samples/spring-cloud-gcp-logging-sample/src/test/java/com.example/TestRuntimeHints.java b/spring-cloud-gcp-samples/spring-cloud-gcp-logging-sample/src/test/java/com.example/TestRuntimeHints.java
new file mode 100644
index 0000000000..5669dda7dc
--- /dev/null
+++ b/spring-cloud-gcp-samples/spring-cloud-gcp-logging-sample/src/test/java/com.example/TestRuntimeHints.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed 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
+ *
+ * https://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.
+ */
+
+package com.example;
+
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.core.ConsoleAppender;
+import java.util.Arrays;
+import org.springframework.aot.hint.MemberCategory;
+import org.springframework.aot.hint.RuntimeHintsRegistrar;
+import org.springframework.aot.hint.TypeReference;
+
+/** Runtime Hints for GraalVM Native Images * */
+public class TestRuntimeHints implements RuntimeHintsRegistrar {
+ @Override
+ public void registerHints(
+ org.springframework.aot.hint.RuntimeHints hints, ClassLoader classLoader) {
+ hints
+ .reflection()
+ .registerTypes(
+ Arrays.asList(
+ TypeReference.of(ConsoleAppender.class),
+ TypeReference.of(PatternLayoutEncoder.class)),
+ hint ->
+ hint.withMembers(
+ MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
+ MemberCategory.INVOKE_PUBLIC_METHODS));
+ hints.resources().registerPattern("logback-test.xml");
+ hints.resources().registerPattern("com/google/cloud/spring/logging/logback-appender.xml");
+ }
+}