Gradle build of new branch fails with UnexpectedCharacterException SemVer in nebula.release plugin
The best articles and links to interesting posts for technical team leaders building sophisticated websites, applications and mobile apps. Think about: software architecture, hardware architecture, design, programming, frameworks, scalability, performance, quality assurance, security, resolving issues, fixing bugs and Android.
Geplaatst door
Techie
op
2:42 PM
0
reacties
Labels: branch, branch name, exception, gradle, kotlin, nebula, nebula.release, new branch, plugin, semver, Spring Boot 4, UnexpectedCharacterException
Add to:
Del.icio.us
DZone
Reddit
Digg
Since around 20 March 2026 the company behind LocalStack decided to not support the community edition of LocalStack anymore, only paid versions are now available.
Several options exist for full AWS stack replacements.
Floci is a free, open-source local AWS emulator which can be found at https://github.com/floci-io/floci
It is a very recently created project , but got quite some traction already.
A week ago Floci changed into a separate organisation, see this LinkedIn post
It is not a ful drop-in replacement in TestContainers, but it comes close. Below shows what needs changing in a Kotlin Spring Boot application if you are currently using LocalStack.
You probably have something like this currently configured with LocalStack:
@TestConfiguration
class TestConfig {
@Bean
fun localStackContainer(): LocalStackContainer {
return LocalStackContainer(DockerImageName.parse("localstack/localstack:4:14:0"))
.withServices(LocalStackContainer.Service.DYNAMODB)
}
Basically changing it by replacing the docker image name and the environment variables should get it working already you’d think, so like this:
@TestConfiguration
class TestConfig {
@Bean
fun localStackContainer(): LocalStackContainer {
return LocalStackContainer(DockerImageName.parse(hectorvent/floci:1.5.2).asCompatibleSubstituteFor("localstack/localstack"))
.withEnv("AWS_ENDPOINT_URL", "http://localhost:4566")
.withEnv("AWS_DEFAULT_REGION", "us-east-1")
.withEnv("AWS_ACCESS_KEY_ID", "test")
.withEnv("AWS_SECRET_ACCESS_KEY", "test")
}
But no it is not that easy. You’ll need to insert a different startup-script.
For example like this:
class FlociContainer(dockerImageName: DockerImageName) : LocalStackContainer(dockerImageName) {
override fun containerIsStarting(containerInfo: InspectContainerResponse) {
var shell: String
var executable: String
if (dockerImageName.contains("jvm")) {
shell = "/bin/sh"
executable = "java -jar quarkus-app/quarkus-run.jar"
} else {
shell = "/bin/bash"
executable = "./application"
}
var command = shell + "\n" + executable + "\n"
try {
copyFileToContainer(Transferable.of(command, 511), STARTER_SCRIPT)
} catch (e: Throwable) {
logger.error("Failed to copy startup script to container: ${e.message}", e)
throw e
}
}
…
}
Note the logic to determine the correct command for the startup-script to use in the Docker image. Floci has a native version which has a different startup-script than the JVM version.
You’ll also need to parse for a different startup string than LocalStack has.
TestContainers has a module for LocalStack that looks for this string: ".*Ready\\.\n"
But Floci does not log that string, so one to search for is: ".*started in.*"
So you need to override that for the Floci version.
Then the test configuration becomes this:
@TestConfiguration
class TestConfig {
@Bean
fun localStackContainer(): LocalStackContainer {
val flociImage: DockerImageName =
DockerImageName.parse(hectorvent/floci:1.5.2).asCompatibleSubstituteFor("localstack/localstack")
return FlociContainer(flociImage)
// Floci settings
.withEnv("AWS_ENDPOINT_URL", "http://localhost:4566")
.withEnv("AWS_DEFAULT_REGION", "us-east-1")
.withEnv("AWS_ACCESS_KEY_ID", "test")
.withEnv("AWS_SECRET_ACCESS_KEY", "test")
// Disable services you don’t need
.withEnv("FLOCI_SERVICES_SSM_ENABLED", "false")
.withEnv("FLOCI_SERVICES_ELASTICSEARCH_ENABLED", "false")
// Floci container has different log-text to look for
.waitingFor(LogMessageWaitStrategy().withRegEx(".*started in.*").withTimes(1))
}
That should do it!
For building a Docker image for the JVM version, you can run these commands in the root directory of the Floci project:
To start the JVM image of Floci locally you can run this command in the root directory:
docker-compose -f docker-compose-fix-001.xml up
With this in that docker compose file:
services:
floci:
image: floci-jvm-package:1.5.1-fix-001
ports:
- "4566:4566"
volumes:
- ./data:/app/data
- ./init/start.d:/etc/floci/init/start.d:ro
- ./init/stop.d:/etc/floci/init/stop.d:ro
The output will look something like this then:
✔ Container common-adapters-floci-1 Recreated 0.1s
Attaching to floci-1
floci-1 | ______ _ ____ _____ _____
floci-1 | | ____| | / __ \ / ____|_ _|
floci-1 | | |__ | | | | | | | | |
floci-1 | | __| | | | | | | | | |
floci-1 | | | | |___| |__| | |____ _| |_
floci-1 | |_| |______\____/ \_____|_____|
floci-1 |
floci-1 |
floci-1 | Powered by Quarkus 3.32.3
floci-1 | 2026-04-11 15:51:14,012 INFO [io.github.hectorvent.floci.lifecycle.EmulatorLifecycle] (main) === AWS Local Emulator Starting ===
floci-1 | 2026-04-11 15:51:14,012 INFO [io.github.hectorvent.floci.lifecycle.EmulatorLifecycle] (main) Storage mode: memory
floci-1 | 2026-04-11 15:51:14,012 INFO [io.github.hectorvent.floci.lifecycle.EmulatorLifecycle] (main) Persistent path: ./data
floci-1 | 2026-04-11 15:51:14,012 INFO [io.github.hectorvent.floci.core.common.ServiceRegistry] (main) Enabled services: [ssm, sqs, s3, dynamodb, sns, lambda, apigateway, iam, elasticache, rds, events, scheduler, logs, monitoring, secretsmanager, apigatewayv2, kinesis, kms, cognito-idp, states, cloudformation, acm, email, es]
floci-1 | 2026-04-11 15:51:14,013 INFO [io.github.hectorvent.floci.lifecycle.EmulatorLifecycle] (main) === AWS Local Emulator Ready ===
floci-1 | 2026-04-11 15:51:14,021 INFO [io.quarkus] (main) floci 1.4.0 native (powered by Quarkus 3.32.3) started in 0.085s. Listening on: http://0.0.0.0:4566
floci-1 | 2026-04-11 15:51:14,021 INFO [io.quarkus] (main) Profile prod activated.
floci-1 | 2026-04-11 15:51:14,021 INFO [io.quarkus] (main) Installed features: [cdi, config-yaml, rest, rest-jackson, smallrye-context-propagation, vertx]
Notice also the ‘started in 0.085s’, which contains the string for which the above example FlociContainer is looking for to see if the container started successfully.
To run your tests against a locally running Floci instance directly, for example to see its logging, started up with Docker like mentioned above, you override the endpoint when creating the DynamoDBClient:
return DynamoDbClient.builder()
.endpointOverride(URI.create("http://localhost:4566"))
.credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(localStackContainer.accessKey, localStackContainer.secretKey)))
.region(Region.of(localStackContainer.region))
.build()
}
There’s now also a testcontainers module available for floci so you should not need all above manual changes: https://testcontainers.com/modules/floci/
I did not test this module yet.
Multiple options exist, this list might not be listing all options.
Geplaatst door
Techie
op
2:13 PM
0
reacties
Labels: aws, docker, DynamoDB, floci, integration testing, localstack, sns, spring boot, SQS, testcontainers
Add to:
Del.icio.us
DZone
Reddit
Digg