Skip to content

Commit

Permalink
feat!: Spring Cloud 2024.0 and Spring Boot 3.4.1 (#3411)
Browse files Browse the repository at this point in the history
* chore: test Spring Cloud 2024 upgrade

* fix datastore tests

* fix kotlin sample test

* fix spanner autoconfig

* use latest spring-cloud-config in pubsub bus sample

* wip pubsub stream binder test

* update spring boot to 3.4.0

* adapt data-spanner to spring boot 3.4

* fix value evaluation for SqlSpannerQuery

* use value expression delegate in datastore

* restore unnecessary changes

* fix datastore tests

* format

* Revert "format"

This reverts commit 290c7a2.

* fix style violations

* remove unused imports

* remove unused imports in autoconfigure

* fix imports in pubsub emulator

* fix gql datastore query test

* remove spring boot 3.2 compatibility check

* remove config module

* remove unused module

* fix secretmanager sample

* fix whitespace in it

* add native config for alloydb sample

* update libraries bom

* remove unused method in pubsub

* fix 2sa usage

* fix spanner units

* fix units in pubsub

* try new native config

* use custom placeholder configurer in secretmanager

* fix style in secretmanager

* use static bean

* add default value for secret manager sample config file

* configure netty for firestore sample

* fix netty usage for native image building in pubsub sample

* fix native tests for data-firestore

This approach avoids using @Autowired given its close-world assumption.
We instead rely on @value to resolve for the database-id property in the
now fixed integration test.

* fix storage sample test

This uses the same approach as of data-firestore: we will not rely on autowired constructors

* restore secret manager to latest of `main`

We will wait for
https://github.com/spring-projects/spring-framework/milestone/388 to be
finished. This will translate into spring-framework:6.2.2 that will fix
the regression disallowing normal use of `${sm://secret}` placeholders.

* fix pubsub binder units

this fix changes the way the extended properties bean is injected into the tests. With the upgrade, the bean is no
w detected as two beans, producing a collision. In this new way we declare a user configuration with a custom bean.

* add recommended netty config for postgress samples

* fix pubsub binder tests

We set a base configuration bean with mock credentials, project ID provider and extended properties

* upgrade to spring-boot 3.4.1

* remove placeholder configurer from secret manager

* restore datastore autoconfig

this had an unintended/unnecessary change

* restore graalvm config in main pom.xml

This change was unnecessary

* remove unused import in stream binder

* cleanup of pubsub binder tests

* use spring boot 3.4.1 in samples

* remove native config for alloydb sample

* remove unused whitespace in poms

* Revert "fix storage sample test"

This reverts commit dd81242.

* try using unchanged firestore IT config

* Revert "fix pubsub binder tests"

This reverts commit 7b82400.

* Reapply "fix pubsub binder tests"

This reverts commit be28c72.

* test reverting changes in pubsub binder

* Revert "test reverting changes in pubsub binder"

This reverts commit 4eae5e7.

* add support for value expressions and query method evaluators in datastore

* test both value expressions and query method expressions in datastore

* fix style

* fix style ii

* introduce support for value expression delegate and query method evaluation context in spanner

* adapt spanner tests

* standardize to parameterized booleans

* add support info on root readme

* add spring cloud 2024 support info in gettin-started

* introduce 5.x to 6.x migration guide

* update project.version to 6.0.0-SNAPSHOT

* Revert "remove config module"

This reverts commit 66b4439.

* update project.version in config integrations

* update versions.txt

* update project.version in spring-cloud-generator

* retrigger tests

* fix checkstyle violations in spanner

* fix checkstyle violations in datastore

* update valkey to 6.x

* fix checkstyle in data-spanner

* replace golden copyright year

* Revert "update valkey to 6.x"

This reverts commit eaf04dc.

* Revert "update project.version in spring-cloud-generator"

This reverts commit 0fabdbf.

* Revert "update versions.txt"

This reverts commit 3eeef1e.

* Revert "update project.version in config integrations"

This reverts commit ce40125.

* Revert "update project.version to 6.0.0-SNAPSHOT"

This reverts commit 4015f3f.

* update secretmanager sample

* update secret manager to support sm@ and sm:// syntax

* add parameterized tests for sm:// and sm@ in secretmanager

* adapt secret manager autoconfig tests to new prefix

* abort full string attempt in secret manager

this prevents attempts of the form sm@my_secret:default as a whole string

* consider sm:// when exiting on full string match attempts

* finish sample code

* add functional interface annotation to PrefixMatcher

* make secret manager dependency non-optional in autoconfigure module

* cleanup

* fix refresh scope for secretmanager sample

This moves the @RefreshScope annotation to method-level in order to
avoid build failures in the native image tests. A good candidate to
prove it as good practice is
https://github.com/spring-cloud/spring-cloud-commons/blob/c0f3a6190c5e636ac5391371b503f7f1e6e24a8e/docs/modules/ROOT/pages/spring-cloud-commons/application-context-services.adoc?plain=1#L211-L215

The native tests script will also override the refresh scope as it's
explained in the docs (see implementation for link).

* update spring-boot to 3.4.2
  • Loading branch information
diegomarquezp authored Jan 24, 2025
1 parent c637e38 commit a72a86b
Show file tree
Hide file tree
Showing 35 changed files with 1,180 additions and 373 deletions.
108 changes: 0 additions & 108 deletions .github/workflows/integrationTests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,114 +109,6 @@ jobs:
--batch-mode \
--define aggregate=true \
surefire-report:failsafe-report-only
- name: Archive logs
if: always()
continue-on-error: true
uses: actions/upload-artifact@v4
with:
name: Integration Test Logs - ${{ matrix.it}}
path: |
**/target/failsafe-reports/*
**/target/site
spring-boot-3-2-compatibility:
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
matrix:
it:
- alloydb
- bigquery
- cloudsql
- config
- datastore
- firestore
- kms
- kotlin
- logging
- metrics
- multisample
- pubsub
- pubsub-bus
- pubsub-docs
- pubsub-emulator
- pubsub-integration
- secretmanager
- spanner
- storage
# trace excluded
- vision
steps:
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d' --utc)" >> $GITHUB_OUTPUT
- uses: actions/checkout@v2
- name: Setup Java 17
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: 17
- name: Set Up Authentication
uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.SPRING_CLOUD_GCP_CI_SA_KEY }}
- name: Setup gcloud
uses: google-github-actions/setup-gcloud@v1
with:
version: latest
project_id: spring-cloud-gcp-ci
export_default_credentials: true
- name: Install pubsub-emulator
if: ${{ matrix.it == 'pubsub-emulator' }}
run: |
gcloud components install pubsub-emulator beta && \
gcloud components update
- name: Mvn install # Need this when the directory/pom structure changes
id: install
run: |
./mvnw \
--batch-mode \
--no-transfer-progress \
--threads 1.5C \
--define maven.test.skip=true \
--define maven.javadoc.skip=true \
--define org.slf4j.simpleLogger.showDateTime=true \
--define org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss:SSS \
install
- name: Update samples to use Spring Boot Starter 3.2.5
working-directory: ./spring-cloud-gcp-samples
run: |
sudo apt-get update && sudo apt-get install -y xmlstarlet
xmlstarlet ed -L -N x=http://maven.apache.org/POM/4.0.0 \
-u '/x:project/x:parent/x:version' -v '3.2.5' pom.xml
- name: Integration Tests
id: intTest
env:
DB_PASSWORD: ${{ secrets.SPRING_CLOUD_GCP_CI_DB_ROOT_PASSWORD }}
run: |
./mvnw \
--batch-mode \
--no-transfer-progress \
--activate-profiles spring-cloud-gcp-ci-it \
--define maven.javadoc.skip=true \
--define skip.surefire.tests=true \
--define org.slf4j.simpleLogger.showDateTime=true \
--define org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss:SSS \
--define "spring.datasource.password=${DB_PASSWORD}" \
--define "spring.r2dbc.password=${DB_PASSWORD}" \
--define "spring.cloud.gcp.sql.database-name=code_samples_test_db2" \
--define it.${{ matrix.it }}=true \
verify
- name: Aggregate Report
run: |
./mvnw \
--batch-mode \
--define aggregate=true \
surefire-report:failsafe-report-only
- name: Archive logs
if: always()
continue-on-error: true
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/scripts/native-image-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,17 @@ run_sample_tests () {

else
project_names="$(echo "${module_samples[@]}" | sed 's/ /,/g')"
# Note that spring.cloud.refresh is disabled in native image mode. This affects samples
# that use @RefreshScope.
# See https://docs.spring.io/spring-cloud-config/reference/client.html#aot-and-native-image-support
mvn clean test \
--activate-profiles native-sample-config,nativeTest \
--define notAllModules=true \
--define maven.javadoc.skip=true \
-pl="${project_names}" \
--define org.slf4j.simpleLogger.showDateTime=true \
--define org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss:SSS
--define org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss:SSS \
--define spring-boot.run.arguments="--spring.cloud.refresh.enabled=false"
fi
popd
}
Expand Down
6 changes: 6 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ This project has dependency and transitive dependencies on Spring Projects. The
|===
| Spring Framework on Google Cloud | Spring Cloud | Spring Boot | Spring Framework | Supported

|6.x
|https://github.com/spring-cloud/spring-cloud-release/wiki/Spring-Cloud-2024.0-Release-Notes[2024.0.x] (Moorgate)
|https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes[3.4.x]
|https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-6.2-Release-Notes[6.2.x]
|Yes

|5.x
|https://github.com/spring-cloud/spring-cloud-release/wiki/Spring-Cloud-2023.0-Release-Notes[2023.0.x] (Leyton)
|https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.2-Release-Notes[3.2.x]*, https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.3-Release-Notes[3.3.x]
Expand Down
2 changes: 2 additions & 0 deletions docs/src/main/asciidoc/getting-started.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Spring Framework on Google Cloud has dependency and transitive dependencies on S
|===
| Spring Framework on Google Cloud | Spring Cloud | Spring Boot | Spring Framework | Supported


|6.x |https://github.com/spring-cloud/spring-cloud-release/wiki/Spring-Cloud-2024.0-Release-Notes[2024.0.x] (Moorgate)|https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes[3.4.x]|https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-6.2-Release-Notes[6.2.x]|Yes
|5.x | https://github.com/spring-cloud/spring-cloud-release/wiki/Spring-Cloud-2023.0-Release-Notes[2023.0.x] (Leyton) |https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.2-Release-Notes[3.2.x]*, https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.3-Release-Notes[3.3.x]
| https://github.com/spring-projects/spring-framework/wiki/What%27s-New-in-Spring-Framework-6.x#whats-new-in-version-61[6.1.x]| Yes
|4.x | https://github.com/spring-cloud/spring-cloud-release/wiki/Spring-Cloud-2022.0-Release-Notes[2022.0.x] (Kilburn) |https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Release-Notes[3.0.x], https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.1-Release-Notes[3.1.x]| https://github.com/spring-projects/spring-framework/wiki/What%27s-New-in-Spring-Framework-6.x#whats-new-in-version-60[6.x]| Yes
Expand Down
65 changes: 65 additions & 0 deletions docs/src/main/asciidoc/migration-guide-5.x.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
== Migration Guide from Spring Cloud GCP 5.x to 6.x
=== Before you start
==== Upgrade to the 5.x version
This doc assumes you are running with Spring Cloud GCP 5.x.

If you are currently running with an earlier major version of Spring Cloud GCP, i.e., 1.x or 2.x, we recommend that you upgrade to [Spring Cloud GCP 5.x] before migrating to Spring Cloud GCP 6.x.

* link:migration-guide-1.x.adoc[Migration guide from Spring Cloud GCP 1.x to 2.x]
* link:migration-guide-3.x.adoc[Migration guide from Spring Cloud GCP 3.x to 4.x]

Note that since Spring Cloud GCP 5.0 has few breaking changes, we have only provided release notes
as reference.

==== Review System requirements
Spring Cloud GCP 6.0 is built on Spring Boot 3.4.x and Spring Framework 6.2.x, which requires Java 17 at minimum.
If you are currently on Java 8 or Java 11, you need to upgrade your JDK before you can develop an application based on Spring Cloud GCP 6.0.

=== Upgrade to Spring Cloud GCP 6.0
==== Update Bill of Materials (BOM)
If you’re a Maven user, add our BOM to your pom.xml `<dependencyManagement>` section.
This will allow you to not specify versions for any of the Maven dependencies and instead delegate versioning to the BOM.

[source, xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-dependencies</artifactId>
<version>6.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----

===== Review Dependencies
Run `mvn dependency:tree` (`gradlew dependencies` for Gradle projects) to see the dependency tree of your project.
Ensure Spring-related dependencies have matching versions:

* Spring Boot 3.4.x
* Spring Cloud 2024.x
** For detailed dependency versions, see "2024.0 (Moorgate)" column in link:https://github.com/spring-cloud/spring-cloud-release/wiki/Supported-Versions#supported-releases[Spring Cloud: Supported Versions] table.

==== Secret Manager
Introduced support for the `${sm@secret_id}` syntax. This new syntax is encouraged over the (still
supported) `${sm://secret_id}` syntax. Users still relying on the `sm://` syntax will be issued a
warning.

For example:
[source, java]
@Value("${sm@my_secret}")
String mySecret;
---

==== Datastore
Introduced support for `ValueExpressionDelegate`. This class is suggested over
`QueryMethodEvaluationContextProvider`.

==== Spanner
Introduced support for `ValueExpressionDelegate`. This class is suggested over
`QueryMethodEvaluationContextProvider`.


4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
<properties>
<project.parent.version>${project.version}</project.parent.version>
<!-- Dependency versions -->
<spring-cloud-dependencies.version>2023.0.5</spring-cloud-dependencies.version>
<spring-boot-dependencies.version>3.3.4</spring-boot-dependencies.version>
<spring-cloud-dependencies.version>2024.0.0</spring-cloud-dependencies.version>
<spring-boot-dependencies.version>3.4.2</spring-boot-dependencies.version>
<spring-cloud-gcp-dependencies.version>${project.parent.version}</spring-cloud-gcp-dependencies.version>
<zipkin-gcp.version>2.2.6</zipkin-gcp.version>
<java-cfenv.version>2.5.0</java-cfenv.version>
Expand Down
5 changes: 4 additions & 1 deletion spring-cloud-gcp-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,10 @@
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-secretmanager</artifactId>
<optional>true</optional>
<!-- A few starters need this dependency to validate secrets -->
<!-- using SecretManagerSyntaxUtils. Making it optional produces runtime failures -->
<!-- of the kind ClassNotFoundError. -->
<optional>false</optional>
</dependency>

<!-- KMS -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package com.google.cloud.spring.autoconfigure.secretmanager;

import static com.google.cloud.spring.secretmanager.SecretManagerSyntaxUtils.getMatchedPrefixes;
import static com.google.cloud.spring.secretmanager.SecretManagerSyntaxUtils.warnIfUsingDeprecatedSyntax;

import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings;
import com.google.cloud.spring.core.DefaultCredentialsProvider;
Expand All @@ -26,7 +29,10 @@
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.apache.arrow.util.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.context.config.ConfigDataLocation;
Expand All @@ -38,10 +44,8 @@
public class SecretManagerConfigDataLocationResolver implements
ConfigDataLocationResolver<SecretManagerConfigDataResource> {

/**
* ConfigData Prefix for Google Cloud Secret Manager.
*/
public static final String PREFIX = "sm://";
private static final Logger logger = LoggerFactory.getLogger(SecretManagerConfigDataLocationResolver.class);

/**
* A static client to avoid creating another client after refreshing.
*/
Expand All @@ -50,7 +54,9 @@ public class SecretManagerConfigDataLocationResolver implements
@Override
public boolean isResolvable(ConfigDataLocationResolverContext context,
ConfigDataLocation location) {
return location.hasPrefix(PREFIX);
Optional<String> matchedPrefix = getMatchedPrefixes(location::hasPrefix);
warnIfUsingDeprecatedSyntax(logger, matchedPrefix.orElse(""));
return matchedPrefix.isPresent();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
import com.google.cloud.secretmanager.v1.SecretPayload;
import com.google.cloud.secretmanager.v1.SecretVersionName;
import com.google.protobuf.ByteString;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.boot.BootstrapRegistry.InstanceSupplier;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
Expand All @@ -28,6 +32,13 @@ class SecretManagerCompatibilityTests {
private SpringApplicationBuilder application;
private SecretManagerServiceClient client;

static Stream<Arguments> prefixes() {
return Stream.of(
Arguments.of("sm://"),
Arguments.of("sm@")
);
}

@BeforeEach
void init() {
application = new SpringApplicationBuilder(SecretManagerCompatibilityTests.class)
Expand Down Expand Up @@ -64,10 +75,11 @@ void init() {
* com.google.cloud.spring.secretmanager.SecretManagerTemplate} autoconfiguration and properties
* resolved.
*/
@Test
void testConfigurationWhenDefaultSecretIsNotAllowed() {
@ParameterizedTest
@MethodSource("prefixes")
void testConfigurationWhenDefaultSecretIsNotAllowed(String prefix) {
application.properties(
"spring.config.import=sm://")
"spring.config.import=" + prefix)
.addBootstrapRegistryInitializer(
(registry) -> registry.registerIfAbsent(
SecretManagerServiceClient.class,
Expand All @@ -76,17 +88,18 @@ void testConfigurationWhenDefaultSecretIsNotAllowed() {
);
try (ConfigurableApplicationContext applicationContext = application.run()) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
assertThat(environment.getProperty("sm://my-secret")).isEqualTo("newSecret");
assertThatThrownBy(() -> environment.getProperty("sm://fake-secret"))
assertThat(environment.getProperty(prefix + "my-secret")).isEqualTo("newSecret");
assertThatThrownBy(() -> environment.getProperty(prefix + "fake-secret"))
.isExactlyInstanceOf(NotFoundException.class);
}
}

@Test
void testConfigurationWhenDefaultSecretIsAllowed() {
@ParameterizedTest
@MethodSource("prefixes")
void testConfigurationWhenDefaultSecretIsAllowed(String prefix) {
application.properties(
"spring.cloud.gcp.secretmanager.allow-default-secret=true",
"spring.config.import=sm://")
"spring.config.import=" + prefix)
.addBootstrapRegistryInitializer(
(registry) -> registry.registerIfAbsent(
SecretManagerServiceClient.class,
Expand All @@ -95,8 +108,8 @@ void testConfigurationWhenDefaultSecretIsAllowed() {
);
try (ConfigurableApplicationContext applicationContext = application.run()) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
assertThat(environment.getProperty("sm://my-secret")).isEqualTo("newSecret");
assertThat(environment.getProperty("sm://fake-secret")).isNull();
assertThat(environment.getProperty(prefix + "my-secret")).isEqualTo("newSecret");
assertThat(environment.getProperty(prefix + "fake-secret")).isNull();
}
}
}
Loading

0 comments on commit a72a86b

Please sign in to comment.