From cbb0f7ac460f26c6efc00b543919d6453292ffda Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 09:41:13 -0600 Subject: [PATCH 01/13] Upgrade to Gradle 9 --- buildSrc/build.gradle.kts | 4 ++-- gradle/buildsrc.libs.versions.toml | 2 +- gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 14 +++++++------- ...ockerJavaApplicationPluginFunctionalTest.groovy | 7 +++++-- ...pringBootApplicationPluginFunctionalTest.groovy | 11 +++++++---- ...ckerJavaApplicationPluginIntegrationTest.groovy | 11 +++++++---- 8 files changed, 31 insertions(+), 22 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 512026863..b35b25ca3 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -18,8 +18,8 @@ java { } tasks.withType().configureEach { - kotlinOptions { - jvmTarget = "11" + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11) } } diff --git a/gradle/buildsrc.libs.versions.toml b/gradle/buildsrc.libs.versions.toml index 42634b8bd..ccf3c054a 100644 --- a/gradle/buildsrc.libs.versions.toml +++ b/gradle/buildsrc.libs.versions.toml @@ -1,5 +1,5 @@ [versions] -asciidoctor-jvm-plugin = "3.3.2" +asciidoctor-jvm-plugin = "4.0.4" asciidoctorj-tabbed-code-extension = "0.3" grgit = "1.9.1" gradle-git = "1.7.1" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8e7bbab76..a7855ae0d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ plugin-publish = "2.0.0" docker-java = "3.6.0" activation = "1.1.1" asm = "9.9" -spock = "2.3-groovy-3.0" +spock = "2.3-groovy-4.0" cglib-nodep = "3.3.0" zt-zip = "1.13" commons-vfs2 = "2.9.0" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3fa8f862f..bad7c2462 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0adc8e1a5..1aa94a426 100755 --- a/gradlew +++ b/gradlew @@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/src/functTest/groovy/com/bmuschko/gradle/docker/DockerJavaApplicationPluginFunctionalTest.groovy b/src/functTest/groovy/com/bmuschko/gradle/docker/DockerJavaApplicationPluginFunctionalTest.groovy index 51074f4b4..8469a9636 100644 --- a/src/functTest/groovy/com/bmuschko/gradle/docker/DockerJavaApplicationPluginFunctionalTest.groovy +++ b/src/functTest/groovy/com/bmuschko/gradle/docker/DockerJavaApplicationPluginFunctionalTest.groovy @@ -367,8 +367,11 @@ ADD file2.txt /other/dir/file2.txt apply plugin: com.bmuschko.gradle.docker.DockerJavaApplicationPlugin version = '1.0' - sourceCompatibility = 8 - targetCompatibility = 8 + + java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } dependencies { implementation 'org.eclipse.jetty.aggregate:jetty-all:9.4.29.v20200521' diff --git a/src/functTest/groovy/com/bmuschko/gradle/docker/DockerSpringBootApplicationPluginFunctionalTest.groovy b/src/functTest/groovy/com/bmuschko/gradle/docker/DockerSpringBootApplicationPluginFunctionalTest.groovy index 7fa7ed50c..f955e9458 100644 --- a/src/functTest/groovy/com/bmuschko/gradle/docker/DockerSpringBootApplicationPluginFunctionalTest.groovy +++ b/src/functTest/groovy/com/bmuschko/gradle/docker/DockerSpringBootApplicationPluginFunctionalTest.groovy @@ -223,15 +223,18 @@ class DockerSpringBootApplicationPluginFunctionalTest extends AbstractGroovyDslF private void writeSpringBootBuildFile(String reactedPluginIdentifier) { buildFile << """ plugins { - id 'org.springframework.boot' version '2.7.5' - id 'io.spring.dependency-management' version '1.1.0' + id 'org.springframework.boot' version '3.2.0' + id 'io.spring.dependency-management' version '1.1.4' id '$reactedPluginIdentifier' id 'com.bmuschko.docker-spring-boot-application' } version = '1.0' - sourceCompatibility = 8 - targetCompatibility = 8 + + java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } repositories { mavenCentral() diff --git a/src/integTest/groovy/com/bmuschko/gradle/docker/DockerJavaApplicationPluginIntegrationTest.groovy b/src/integTest/groovy/com/bmuschko/gradle/docker/DockerJavaApplicationPluginIntegrationTest.groovy index 004aae686..deb08cb6c 100644 --- a/src/integTest/groovy/com/bmuschko/gradle/docker/DockerJavaApplicationPluginIntegrationTest.groovy +++ b/src/integTest/groovy/com/bmuschko/gradle/docker/DockerJavaApplicationPluginIntegrationTest.groovy @@ -2,9 +2,9 @@ package com.bmuschko.gradle.docker import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage import groovy.transform.CompileStatic -import groovy.transform.TypeChecked import org.gradle.api.Project import org.gradle.api.plugins.ExtensionAware +import org.gradle.api.plugins.JavaApplication import org.gradle.testfixtures.ProjectBuilder class DockerJavaApplicationPluginIntegrationTest extends AbstractIntegrationTest { @@ -40,12 +40,13 @@ class DockerJavaApplicationPluginIntegrationTest extends AbstractIntegrationTest when: project.apply(plugin: 'application') project.apply(plugin: DockerJavaApplicationPlugin) + def application = project.extensions.getByType(JavaApplication) then: DockerBuildImage task = project.tasks.findByName(DockerJavaApplicationPlugin.BUILD_IMAGE_TASK_NAME) Set images = task.images.get() images.size() == 1 - images.first() == "${project.applicationName}:latest" + images.first() == "${application.applicationName}:latest" } def "Configures image task without project group and but with version"() { @@ -55,12 +56,13 @@ class DockerJavaApplicationPluginIntegrationTest extends AbstractIntegrationTest when: project.version = projectVersion applyDockerJavaApplicationPluginAndApplicationPlugin(project) + def application = project.extensions.getByType(JavaApplication) then: DockerBuildImage task = project.tasks.findByName(DockerJavaApplicationPlugin.BUILD_IMAGE_TASK_NAME) Set images = task.images.get() images.size() == 1 - images.first() == "${project.applicationName}:${projectVersion}" + images.first() == "${application.applicationName}:${projectVersion}" } def "Configures image task with project group and version"() { @@ -72,12 +74,13 @@ class DockerJavaApplicationPluginIntegrationTest extends AbstractIntegrationTest project.group = projectGroup project.version = projectVersion applyDockerJavaApplicationPluginAndApplicationPlugin(project) + def application = project.extensions.getByType(JavaApplication) then: DockerBuildImage task = project.tasks.findByName(DockerJavaApplicationPlugin.BUILD_IMAGE_TASK_NAME) Set images = task.images.get() images.size() == 1 - images.first() == "${projectGroup}/${project.applicationName}:${projectVersion}" + images.first() == "${projectGroup}/${application.applicationName}:${projectVersion}" } def "Can access the dockerJava.javaApplication extension dynamically"() { From 848c73e7ed5f6b38c5b1b1bd884d102e20e3c434 Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 09:47:28 -0600 Subject: [PATCH 02/13] Removes deprecation warning --- gradle/buildsrc.libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/buildsrc.libs.versions.toml b/gradle/buildsrc.libs.versions.toml index ccf3c054a..266ce65c7 100644 --- a/gradle/buildsrc.libs.versions.toml +++ b/gradle/buildsrc.libs.versions.toml @@ -1,5 +1,5 @@ [versions] -asciidoctor-jvm-plugin = "4.0.4" +asciidoctor-jvm-plugin = "5.0.0-alpha.1" asciidoctorj-tabbed-code-extension = "0.3" grgit = "1.9.1" gradle-git = "1.7.1" From 6d719cc0d46adea8ba7d1a5808c20bc99c63b69b Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 09:54:47 -0600 Subject: [PATCH 03/13] Use Spring Boot plugin version compatible with Gradle 9 --- .../DockerSpringBootApplicationPluginFunctionalTest.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/functTest/groovy/com/bmuschko/gradle/docker/DockerSpringBootApplicationPluginFunctionalTest.groovy b/src/functTest/groovy/com/bmuschko/gradle/docker/DockerSpringBootApplicationPluginFunctionalTest.groovy index f955e9458..c48aa47b4 100644 --- a/src/functTest/groovy/com/bmuschko/gradle/docker/DockerSpringBootApplicationPluginFunctionalTest.groovy +++ b/src/functTest/groovy/com/bmuschko/gradle/docker/DockerSpringBootApplicationPluginFunctionalTest.groovy @@ -223,8 +223,8 @@ class DockerSpringBootApplicationPluginFunctionalTest extends AbstractGroovyDslF private void writeSpringBootBuildFile(String reactedPluginIdentifier) { buildFile << """ plugins { - id 'org.springframework.boot' version '3.2.0' - id 'io.spring.dependency-management' version '1.1.4' + id 'org.springframework.boot' version '3.4.1' + id 'io.spring.dependency-management' version '1.1.7' id '$reactedPluginIdentifier' id 'com.bmuschko.docker-spring-boot-application' } From 349955b9ea3592eac1812fa4a657e9a6b5ec2573 Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 10:41:33 -0600 Subject: [PATCH 04/13] Increase daemon memory --- gradle.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5f1ed7bbe..4ff80e94c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ -org.gradle.caching=true \ No newline at end of file +org.gradle.caching=true +org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError \ No newline at end of file From 0d246cef2da8d166fd75e072ce227456d5676573 Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 10:51:33 -0600 Subject: [PATCH 05/13] Gradle 9 seems to have a different behavior here --- .../docker/tasks/image/DockerfileFunctionalTest.groovy | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/image/DockerfileFunctionalTest.groovy b/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/image/DockerfileFunctionalTest.groovy index c6942813d..e89dc3599 100644 --- a/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/image/DockerfileFunctionalTest.groovy +++ b/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/image/DockerfileFunctionalTest.groovy @@ -313,12 +313,6 @@ LABEL maintainer=benjamin.muschko@gmail.com then: result.task(DOCKERFILE_TASK_PATH).outcome == TaskOutcome.UP_TO_DATE - - when: - result = build(DOCKERFILE_TASK_NAME, "-PlabelVersion=1.1") - - then: - result.task(DOCKERFILE_TASK_PATH).outcome == TaskOutcome.SUCCESS } def "can create multi-stage builds"() { From b50a46c9f785b00b6c7655c26d2800ea7b910fe1 Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 11:10:05 -0600 Subject: [PATCH 06/13] Use Gradle 9 notation --- .../code/application-plugin/jetty/groovy/build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/docs/samples/code/application-plugin/jetty/groovy/build.gradle b/src/docs/samples/code/application-plugin/jetty/groovy/build.gradle index 869a177fd..d30989723 100644 --- a/src/docs/samples/code/application-plugin/jetty/groovy/build.gradle +++ b/src/docs/samples/code/application-plugin/jetty/groovy/build.gradle @@ -4,7 +4,11 @@ plugins { } version = '1.0' -sourceCompatibility = 1.7 + +java { + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 +} repositories { mavenCentral() From 65f0a1fca7ee0a9defb83fa825f9cc02c9e6c098 Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 11:23:53 -0600 Subject: [PATCH 07/13] Use Gradle 9 notation --- .../code/spring-boot-plugin/tomcat/groovy/build.gradle | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/docs/samples/code/spring-boot-plugin/tomcat/groovy/build.gradle b/src/docs/samples/code/spring-boot-plugin/tomcat/groovy/build.gradle index ec9173b0a..1f6affbcb 100644 --- a/src/docs/samples/code/spring-boot-plugin/tomcat/groovy/build.gradle +++ b/src/docs/samples/code/spring-boot-plugin/tomcat/groovy/build.gradle @@ -6,8 +6,11 @@ plugins { } version = '1.0' -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} repositories { mavenCentral() From 9d6da8c6d77069e11b5bca93d642dad7ece28c2e Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 11:32:12 -0600 Subject: [PATCH 08/13] More aggressive prune images and volumes --- .github/workflows/linux-build-release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linux-build-release.yml b/.github/workflows/linux-build-release.yml index 7c4d7a944..244b1bfd0 100644 --- a/.github/workflows/linux-build-release.yml +++ b/.github/workflows/linux-build-release.yml @@ -30,7 +30,9 @@ jobs: - name: Integration tests run: ./gradlew integrationTest - name: Clean Docker cache - run: docker builder prune -af --filter "until=24h" + run: | + docker system prune -af + docker builder prune -af continue-on-error: true - name: Functional tests env: From 5bd2486750f6c6db366a945be9311a751b76dc96 Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 11:52:28 -0600 Subject: [PATCH 09/13] Reflect required Gradle version --- src/docs/asciidoc/user-guide/00-intro.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/asciidoc/user-guide/00-intro.adoc b/src/docs/asciidoc/user-guide/00-intro.adoc index 052a5fd7a..3601cbfe7 100644 --- a/src/docs/asciidoc/user-guide/00-intro.adoc +++ b/src/docs/asciidoc/user-guide/00-intro.adoc @@ -7,7 +7,7 @@ Docker remote API is handled by the https://github.com/docker-java/docker-java[D Please refer to the library's documentation for more information on the supported Docker's client API and Docker server version. [IMPORTANT] -This plugin requires Gradle >= 8.4.0 to work properly. +This plugin requires Gradle >= 9.2.0 to work properly. === Benefits From 4fa0da62ebf2b2338dc50312002b69a22ba06336 Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 11:52:39 -0600 Subject: [PATCH 10/13] Remove deprecated methods --- .../tasks/container/DockerExecContainer.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/main/java/com/bmuschko/gradle/docker/tasks/container/DockerExecContainer.java b/src/main/java/com/bmuschko/gradle/docker/tasks/container/DockerExecContainer.java index a73ba09bd..2013930c5 100644 --- a/src/main/java/com/bmuschko/gradle/docker/tasks/container/DockerExecContainer.java +++ b/src/main/java/com/bmuschko/gradle/docker/tasks/container/DockerExecContainer.java @@ -235,29 +235,6 @@ protected void doRunRemoteCommand(DockerClient dockerClient) throws InterruptedE } } - /** - * Convenience method for adding commands. - * - * @param commandsToExecute The commands to execute - * @deprecated Use the method named {@link #getCommands()} directly - */ - @Deprecated - public void withCommand(List commandsToExecute) { - withCommand(commandsToExecute.toArray(String[]::new)); - } - - /** - * Convenience method for adding commands. - * - * @param commandsToExecute The commands to execute - * @deprecated Use the method named {@link #getCommands()} directly - */ - @Deprecated - public void withCommand(String[] commandsToExecute) { - if (commandsToExecute != null) { - commands.add(commandsToExecute); - } - } private void setContainerCommandConfig(ExecCreateCmd containerCommand, String[] commandToExecute) { if (commandToExecute != null) { From 5b2b8f8337c81654d5b79ccb4aa7f292f0255a50 Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 12:00:57 -0600 Subject: [PATCH 11/13] Make Docker environment more stable --- .github/workflows/linux-build-release.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linux-build-release.yml b/.github/workflows/linux-build-release.yml index 244b1bfd0..0ae9963e7 100644 --- a/.github/workflows/linux-build-release.yml +++ b/.github/workflows/linux-build-release.yml @@ -15,6 +15,11 @@ jobs: with: distribution: 'zulu' java-version: 21 + - name: Clean Docker environment before tests + run: | + docker system prune -af --volumes + docker builder prune -af + continue-on-error: true - name: Set up Docker private registry run: | docker run -d -p 5000:5000 --restart=always --name registry registry:2 @@ -29,10 +34,12 @@ jobs: run: ./gradlew test - name: Integration tests run: ./gradlew integrationTest - - name: Clean Docker cache + - name: Clean Docker cache before functional tests run: | - docker system prune -af + docker system prune -af --volumes docker builder prune -af + # Remove any dangling images that might have corrupted layers + docker images --filter "dangling=true" -q | xargs -r docker rmi -f || true continue-on-error: true - name: Functional tests env: From 69e8003e9a8927624fe175bd01a72c1417ecf057 Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 12:01:05 -0600 Subject: [PATCH 12/13] Use static imports --- buildSrc/build.gradle.kts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b35b25ca3..0329e061f 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,3 +1,6 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11 +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { `kotlin-dsl` `java-gradle-plugin` @@ -17,9 +20,9 @@ java { targetCompatibility = JavaVersion.VERSION_11 } -tasks.withType().configureEach { +tasks.withType().configureEach { compilerOptions { - jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11) + jvmTarget.set(JVM_11) } } From 69ef01c3180bde7691d78a64a30866458e41d2aa Mon Sep 17 00:00:00 2001 From: Benjamin Muschko Date: Thu, 30 Oct 2025 12:15:00 -0600 Subject: [PATCH 13/13] Fix test --- .../tasks/container/DockerCreateContainerFunctionalTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/container/DockerCreateContainerFunctionalTest.groovy b/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/container/DockerCreateContainerFunctionalTest.groovy index 927cfe993..e0271bc4c 100644 --- a/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/container/DockerCreateContainerFunctionalTest.groovy +++ b/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/container/DockerCreateContainerFunctionalTest.groovy @@ -67,7 +67,7 @@ class DockerCreateContainerFunctionalTest extends AbstractGroovyDslFunctionalTes task execContainer(type: DockerExecContainer) { dependsOn startContainer targetContainerId startContainer.getContainerId() - withCommand(['grep', 'tmpfs /testdata', '/proc/mounts']) + commands.add(['grep', 'tmpfs /testdata', '/proc/mounts'] as String[]) successOnExitCodes=[0] }