diff --git a/.gitattributes b/.gitattributes index 6c074fe..ae844ac 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ -*.jar binary -* text eol=lf +# Patches are applied on files extracted from a downloaded zip file. All these files use LF line endings. +*.patch text eol=lf diff --git a/.github/workflows/build_config_server.yaml b/.github/workflows/build_config_server.yaml index 995323b..998dc2f 100644 --- a/.github/workflows/build_config_server.yaml +++ b/.github/workflows/build_config_server.yaml @@ -2,18 +2,18 @@ name: Build Config Server on: pull_request: - branches: - - main paths: - '.github/workflows/build_config_server.yaml' - - 'config-server/**' + - 'config-server/metadata/*' + - 'config-server/patches/*' - 'build.ps1' push: branches: - main paths: - '.github/workflows/build_config_server.yaml' - - 'config-server/**' + - 'config-server/metadata/*' + - 'config-server/patches/*' - 'build.ps1' concurrency: diff --git a/.github/workflows/build_eureka_server.yaml b/.github/workflows/build_eureka_server.yaml index 5777ecc..6ac942a 100644 --- a/.github/workflows/build_eureka_server.yaml +++ b/.github/workflows/build_eureka_server.yaml @@ -2,18 +2,18 @@ name: Build Eureka Server on: pull_request: - branches: - - main paths: - '.github/workflows/build_eureka_server.yaml' - - 'eureka-server/**' + - 'eureka-server/metadata/*' + - 'eureka-server/patches/*' - 'build.ps1' push: branches: - main paths: - '.github/workflows/build_eureka_server.yaml' - - 'eureka-server/**' + - 'eureka-server/metadata/*' + - 'eureka-server/patches/*' - 'build.ps1' concurrency: diff --git a/.github/workflows/build_springboot_admin_server.yaml b/.github/workflows/build_springboot_admin_server.yaml index e47e85b..d2ba5cf 100644 --- a/.github/workflows/build_springboot_admin_server.yaml +++ b/.github/workflows/build_springboot_admin_server.yaml @@ -2,18 +2,18 @@ name: Build Spring Boot Admin Server on: pull_request: - branches: - - main paths: - '.github/workflows/build_springboot_admin_server.yaml' - - 'spring-boot-admin/**' + - 'spring-boot-admin/metadata/*' + - 'spring-boot-admin/patches/*' - 'build.ps1' push: branches: - main paths: - '.github/workflows/build_springboot_admin_server.yaml' - - 'spring-boot-admin/**' + - 'spring-boot-admin/metadata/*' + - 'spring-boot-admin/patches/*' - 'build.ps1' concurrency: diff --git a/.github/workflows/build_uaa_server.yaml b/.github/workflows/build_uaa_server.yaml index faff82c..eb7504a 100644 --- a/.github/workflows/build_uaa_server.yaml +++ b/.github/workflows/build_uaa_server.yaml @@ -2,18 +2,22 @@ name: Build UAA Server on: pull_request: - branches: - - main paths: - '.github/workflows/build_uaa_server.yaml' - - 'uaa-server/**' + - 'uaa-server/Dockerfile' + - 'uaa-server/metadata/*' + - 'uaa-server/*.yml' + - 'uaa-server/*.properties' - 'build.ps1' push: branches: - main paths: - '.github/workflows/build_uaa_server.yaml' - - 'uaa-server/**' + - 'uaa-server/Dockerfile' + - 'uaa-server/metadata/*' + - 'uaa-server/*.yml' + - 'uaa-server/*.properties' - 'build.ps1' concurrency: diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f5e7a80 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,59 @@ +# Agent Instructions and Reminders + +This file contains important reminders and guidelines for AI agents working on this codebase. + +## Build Script + +### Avoid `-DisableCache` Flag + +**Do NOT use `-DisableCache`** when running `build.ps1` from agentic contexts. The `start.spring.io` service may block or rate-limit automated traffic, causing connection failures. + +Instead, to get a fresh build: + +1. Delete the expanded project folder (e.g., `workspace/springbootadmin/`) +2. Run `.\build.ps1 ` without the flag + +### Testing Changes + +Before submitting patch changes: + +1. Run a dry-run of each patch: `git apply --check ` +2. If dry-run succeeds, run the full build and verify Java compilation +3. Test the resulting Docker image with a real client app + +## Patch Files + +The build script uses `git apply --unidiff-zero --recount --ignore-whitespace` to apply patches, which is more forgiving than the traditional `patch` command. + +### Patch Format Rules + +1. **Hunk headers should be accurate**: The format is `@@ -old_start,old_count +new_start,new_count @@` + - `old_count` is the number of lines in the hunk from the old file (context lines plus lines with `-` prefix) + - `new_count` is the number of lines in the hunk in the new file (context lines plus lines with `+` prefix) + - For new file patches (`--- /dev/null`), `old_count` is 0 and `new_count` is the total number of lines in the new-file hunk + - Note: `--recount` will automatically correct line counts, but keeping them accurate is still good practice +2. **Trailing newlines are required**: Patch files must end with a newline character. +3. **Preserve exact whitespace**: Context lines must match the target file exactly, including trailing spaces and tabs. The `--ignore-whitespace` flag provides some tolerance but exact matches are preferred. +4. **New file patches**: Use `/dev/null` as the old file: + + ```diff + --- /dev/null + +++ ./path/to/NewFile.java 2026-01-27 00:00:00.000000000 +0000 + @@ -0,0 +1,N @@ + +line 1 + +line 2 + ... + ``` + +### Example + +If a patch adds 1 line, the hunk header should reflect this: + +```diff +-@@ -37,3 +37,10 @@ ++@@ -37,3 +37,11 @@ +``` + +### Why This Matters + +While `git apply --recount` can fix minor line count issues, keeping patches accurate ensures reliable application and easier debugging. diff --git a/README.md b/README.md index ac4dfa1..e4a3e3f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ To build these images you must also have: 1. Access to start.spring.io 1. `patch` available in the path or installed with Git for Windows -1. JDK 21 +1. JDK 25 If you do not already have a JDK installed, consider using [Scoop](https://scoop.sh/): @@ -30,7 +30,7 @@ Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression # Add the Java bucket scoop bucket add java # Install the JDK -scoop install java/openjdk21 +scoop install java/openjdk25 ``` ### Build a specific image diff --git a/build.ps1 b/build.ps1 old mode 100755 new mode 100644 index 9182d20..70676ac --- a/build.ps1 +++ b/build.ps1 @@ -64,7 +64,7 @@ try { $DockerOrg = $Registry } else { - $DockerOrg = "steeltoeoss" + $DockerOrg = "steeltoe.azurecr.io" } if ($Help) { @@ -112,11 +112,11 @@ try { if (!$Tag) { if ($env:GITHUB_ACTIONS -eq "true") { $ImageNameWithTag = "$DockerOrg/${Name}:$Version" - $Revision = Get-Content (Join-Path $ImageDirectory "metadata" "IMAGE_REVISION") - if ($Revision) { + $Revision = (Get-Content (Join-Path $ImageDirectory "metadata" "IMAGE_REVISION") -ErrorAction SilentlyContinue | ForEach-Object { $_.Trim() }) -join "" + if ($Revision -and $Revision -ne "") { $ImageNameWithTag += "-$Revision" } - $AdditionalTags = "$(Get-Content (Join-Path $ImageDirectory "metadata" "ADDITIONAL_TAGS") | ForEach-Object { $_.replace("$Name","$DockerOrg/$Name") })" + $AdditionalTags = "$(Get-Content (Join-Path $ImageDirectory "metadata" "ADDITIONAL_TAGS") -ErrorAction SilentlyContinue | ForEach-Object { $_.replace("$Name","$DockerOrg/$Name") })" } else { $ImageNameWithTag = "$DockerOrg/${Name}:dev" @@ -149,14 +149,8 @@ try { Invoke-Expression $docker_command } else { - if (!(Get-Command "patch" -ErrorAction SilentlyContinue)) { - if (Test-Path "$Env:ProgramFiles\Git\usr\bin\patch.exe") { - Write-Host "'patch' command not found, but Git is installed; adding Git usr\bin to PATH" - $env:Path += ";$Env:ProgramFiles\Git\usr\bin" - } - else { - throw "'patch' command not found" - } + if (!(Get-Command "git" -ErrorAction SilentlyContinue)) { + throw "'git' command not found" } switch ($Name) { @@ -170,7 +164,7 @@ try { } "spring-boot-admin" { $appName = "SpringBootAdmin" - $dependencies = "codecentric-spring-boot-admin-server,native" + $dependencies = "codecentric-spring-boot-admin-server" } Default { Write-Host "$Name is not currently supported by this script" @@ -185,7 +179,7 @@ try { Push-Location $workPath try { $serverName = $Name -replace '-', '' - $JVM = "21" + $JVM = "25" $bootVersion = Get-Content (Join-path $ImageDirectory "metadata" "SPRING_BOOT_VERSION") $serverVersion = Get-Content (Join-Path $ImageDirectory "metadata" "IMAGE_VERSION") $artifactName = "$serverName$serverVersion-boot$bootVersion-jvm$JVM.zip" @@ -207,7 +201,7 @@ try { # Scaffold project on start.spring.io if (!(Test-Path "$artifactName")) { - Write-Host "Using start.spring.io to create project" + Write-Host "Using start.spring.io to create project with dependencies: $dependencies" Invoke-WebRequest ` -Uri "https://start.spring.io/starter.zip" ` -Method Post ` @@ -238,10 +232,11 @@ try { # Apply patches foreach ($patch in Get-ChildItem -Path (Join-Path $ImageDirectory patches) -Filter "*.patch") { Write-Host "Applying patch $($patch.Name)" - Get-Content $patch | & patch -p1 + git apply --unidiff-zero --recount --ignore-whitespace $patch.FullName if ($LASTEXITCODE -ne 0) { - throw "Patch failed with exit code $LASTEXITCODE" + throw "Patch $($patch.Name) failed with exit code $LASTEXITCODE" } + Write-Host "Patch $($patch.Name) applied successfully" } # Build the image diff --git a/config-server/README.md b/config-server/README.md index 0c2107d..269e66d 100644 --- a/config-server/README.md +++ b/config-server/README.md @@ -40,6 +40,6 @@ docker run --publish 8888:8888 steeltoe.azurecr.io/config-server \ | ---- | ----------- | | /_{app}_/_{profile}_ | Configuration data for app in Spring profile | | /_{app}_/_{profile}_/_{label}_ | Add a git label | -| /_{app}_/_{profiles}/{label}_/_{path}_ | Environment-specific plain text config file at _{path}_| +| /_{app}_/_{profiles}/{label}_/_{path}_ | Environment-specific plain text config file at _{path}_ | _Example:_ diff --git a/config-server/metadata/IMAGE_REVISION b/config-server/metadata/IMAGE_REVISION index d00491f..8b13789 100644 --- a/config-server/metadata/IMAGE_REVISION +++ b/config-server/metadata/IMAGE_REVISION @@ -1 +1 @@ -1 + diff --git a/config-server/metadata/IMAGE_VERSION b/config-server/metadata/IMAGE_VERSION index 8089590..f77856a 100644 --- a/config-server/metadata/IMAGE_VERSION +++ b/config-server/metadata/IMAGE_VERSION @@ -1 +1 @@ -4.3.0 +4.3.1 diff --git a/config-server/metadata/SPRING_BOOT_VERSION b/config-server/metadata/SPRING_BOOT_VERSION index c492825..efe3085 100644 --- a/config-server/metadata/SPRING_BOOT_VERSION +++ b/config-server/metadata/SPRING_BOOT_VERSION @@ -1 +1 @@ -3.5.6 +3.5.10 diff --git a/config-server/patches/build.gradle.patch b/config-server/patches/build.gradle.patch index b6d01c6..e72ffbe 100644 --- a/config-server/patches/build.gradle.patch +++ b/config-server/patches/build.gradle.patch @@ -1,6 +1,6 @@ --- ./build.gradle 2025-09-30 14:48:20.000000000 -0500 +++ ./build.gradle 2025-09-30 14:49:16.584226000 -0500 -@@ -41,3 +41,10 @@ +@@ -41,3 +41,11 @@ tasks.named('test') { useJUnitPlatform() } @@ -8,6 +8,7 @@ +bootBuildImage { + createdDate = "now" + environment = [ -+ "BP_SPRING_CLOUD_BINDINGS_DISABLED": "true" ++ "BP_SPRING_CLOUD_BINDINGS_DISABLED": "true", ++ "BP_JVM_AOTCACHE_ENABLED": "true" + ] +} diff --git a/eureka-server/metadata/IMAGE_VERSION b/eureka-server/metadata/IMAGE_VERSION index 8089590..f77856a 100644 --- a/eureka-server/metadata/IMAGE_VERSION +++ b/eureka-server/metadata/IMAGE_VERSION @@ -1 +1 @@ -4.3.0 +4.3.1 diff --git a/eureka-server/metadata/SPRING_BOOT_VERSION b/eureka-server/metadata/SPRING_BOOT_VERSION index c492825..efe3085 100644 --- a/eureka-server/metadata/SPRING_BOOT_VERSION +++ b/eureka-server/metadata/SPRING_BOOT_VERSION @@ -1 +1 @@ -3.5.6 +3.5.10 diff --git a/eureka-server/patches/application.properties.patch b/eureka-server/patches/application.properties.patch index b48a685..ec109cb 100644 --- a/eureka-server/patches/application.properties.patch +++ b/eureka-server/patches/application.properties.patch @@ -1,10 +1,15 @@ --- eurekaserver/src/main/resources/application.properties 2024-02-21 15:43:09.000000000 -0600 -+++ eurekaserver/src/main/resources/application.properties 2024-04-02 13:15:18.461432100 -0500 -@@ -0,0 +1,9 @@ ++++ eurekaserver/src/main/resources/application.properties 2026-01-27 00:00:00.000000000 -0500 +@@ -0,0 +1,14 @@ +server.port = 8761 +eureka.client.fetch-registry = false +eureka.client.register-with-eureka = false ++eureka.client.serviceUrl.defaultZone = ${EUREKA_CLIENT_SERVICEURL_DEFAULTZONE:http://localhost:8761/eureka/} ++eureka.instance.hostname = localhost ++# Set myUrl to match defaultZone so Eureka recognizes itself and skips self-replication ++eureka.server.myUrl = ${EUREKA_CLIENT_SERVICEURL_DEFAULTZONE:http://localhost:8761/eureka/} +eureka.server.enable-self-preservation = false ++eureka.server.numberOfReplicationRetries = 0 +eureka.server.evictionIntervalTimerInMs = 1000 +eureka.server.responseCacheUpdateIntervalMs = 1000 +eureka.server.wait-time-in-ms-when-sync-empty = 0 diff --git a/eureka-server/patches/build.gradle.patch b/eureka-server/patches/build.gradle.patch index b6d01c6..e72ffbe 100644 --- a/eureka-server/patches/build.gradle.patch +++ b/eureka-server/patches/build.gradle.patch @@ -1,6 +1,6 @@ --- ./build.gradle 2025-09-30 14:48:20.000000000 -0500 +++ ./build.gradle 2025-09-30 14:49:16.584226000 -0500 -@@ -41,3 +41,10 @@ +@@ -41,3 +41,11 @@ tasks.named('test') { useJUnitPlatform() } @@ -8,6 +8,7 @@ +bootBuildImage { + createdDate = "now" + environment = [ -+ "BP_SPRING_CLOUD_BINDINGS_DISABLED": "true" ++ "BP_SPRING_CLOUD_BINDINGS_DISABLED": "true", ++ "BP_JVM_AOTCACHE_ENABLED": "true" + ] +} diff --git a/spring-boot-admin/metadata/IMAGE_VERSION b/spring-boot-admin/metadata/IMAGE_VERSION index 7d280e2..3cf5751 100644 --- a/spring-boot-admin/metadata/IMAGE_VERSION +++ b/spring-boot-admin/metadata/IMAGE_VERSION @@ -1 +1 @@ -3.5.5 +3.5.7 diff --git a/spring-boot-admin/metadata/SPRING_BOOT_VERSION b/spring-boot-admin/metadata/SPRING_BOOT_VERSION index c492825..efe3085 100644 --- a/spring-boot-admin/metadata/SPRING_BOOT_VERSION +++ b/spring-boot-admin/metadata/SPRING_BOOT_VERSION @@ -1 +1 @@ -3.5.6 +3.5.10 diff --git a/spring-boot-admin/patches/build.gradle.patch b/spring-boot-admin/patches/build.gradle.patch index afc78c3..05413d3 100644 --- a/spring-boot-admin/patches/build.gradle.patch +++ b/spring-boot-admin/patches/build.gradle.patch @@ -1,6 +1,6 @@ --- ./build.gradle 2025-09-22 14:48:20.000000000 -0500 +++ ./build.gradle 2026-01-27 00:00:00.000000000 -0500 -@@ -38,3 +38,10 @@ +@@ -38,3 +38,11 @@ tasks.named('test') { useJUnitPlatform() } @@ -8,6 +8,7 @@ +bootBuildImage { + createdDate = "now" + environment = [ -+ "BP_SPRING_CLOUD_BINDINGS_DISABLED": "true" ++ "BP_SPRING_CLOUD_BINDINGS_DISABLED": "true", ++ "BP_JVM_AOTCACHE_ENABLED": "true" + ] +} diff --git a/spring-boot-admin/patches/enable-springbootadmin.patch b/spring-boot-admin/patches/enable-springbootadmin.patch index ebd9f14..1208c3f 100644 --- a/spring-boot-admin/patches/enable-springbootadmin.patch +++ b/spring-boot-admin/patches/enable-springbootadmin.patch @@ -1,6 +1,6 @@ --- ./src/main/java/io/steeltoe/docker/springbootadmin/SpringBootAdmin.java 2024-09-20 12:49:35.099908129 -0500 -+++ ./src/main/java/io/steeltoe/docker/springbootadmin/SpringBootAdmin.java 2024-09-20 12:49:59.410273961 -0500 -@@ -2,8 +2,10 @@ ++++ ./src/main/java/io/steeltoe/docker/springbootadmin/SpringBootAdmin.java 2026-01-27 00:00:00.000000000 -0500 +@@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -10,4 +10,3 @@ +@EnableAdminServer public class SpringBootAdmin { - public static void main(String[] args) { diff --git a/uaa-server/README.md b/uaa-server/README.md index 5bd6e0a..3a12b70 100644 --- a/uaa-server/README.md +++ b/uaa-server/README.md @@ -7,26 +7,26 @@ This directory contains resources for building a [CloudFoundry User Account and To run this image locally: ```shell -docker run -it -p 8080:8080 --name steeltoe-uaa steeltoe.azurecr.io/uaa-server:77 +docker run -it -p 8080:8080 --name steeltoe-uaa steeltoe.azurecr.io/uaa-server ``` To run this image locally, overwriting the included `uaa.yml` file: ```shell -docker run -it -p 8080:8080 --name steeltoe-uaa -v $pwd/uaa.yml:/uaa/uaa.yml steeltoe.azurecr.io/uaa-server:77 +docker run -it -p 8080:8080 --name steeltoe-uaa -v $pwd/uaa.yml:/uaa/uaa.yml steeltoe.azurecr.io/uaa-server ``` ## Customizing for your Cloud Foundry environment -These instructions will help you build and deploy a custom image to use as an identity provider for [Single Sign-On for VMware Tanzu Application Service](https://docs.vmware.com/en/Single-Sign-On-for-VMware-Tanzu-Application-Service/index.html): +These instructions will help you build and deploy a custom image to use as an identity provider for [Single Sign-On for VMware Tanzu Application Service](https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/single-sign-on-for-tanzu/1-16/sso-tanzu/index.html): 1. Clone this repository. -1. (Operator task) Create an [identity zone](https://docs.vmware.com/en/VMware-Tanzu-Application-Service/6.0/tas-for-vms/uaa-concepts.html#identity-zones-0) +1. (Operator task) Create an [identity zone](https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/tanzu-platform-for-cloud-foundry/10-3/tpcf/t-uaa-uaa-concepts.html) 1. Change the `redirect-uri` entry for `ssotile` in [uaa.yml](uaa.yml#132) to match your identity zone. 1. (OPTIONAL) Customize the name of the image you're about to build by renaming the `uaa-server` directory 1. `.\build.ps1 uaa-server`. 1. Push the image to an image repository accessible from your Cloud Foundry environment. 1. Deploy the image with a command similar to this: - * `cf push steeltoe-uaa --docker-image steeltoe.azurecr.io/uaa-server:77` -1. (Operator task) [Add the new identity provider with OpenID Connect](https://docs.vmware.com/en/Single-Sign-On-for-VMware-Tanzu-Application-Service/1.14/sso/GUID-configure-external-id.html#config-ext-oidc) + * `cf push steeltoe-uaa --docker-image steeltoe.azurecr.io/uaa-server` +1. (Operator task) [Add the new identity provider with OpenID Connect](https://techdocs.broadcom.com/us/en/vmware-tanzu/platform/single-sign-on/1-16/sso/configure-external-id.html#config-ext-prov) * Use the `ssotile` credentials from uaa.yml