Skip to content

Commit 4b452b3

Browse files
authored
configuration cache: fix exposing environment variables and system properies via isRequiredBy() (#498)
* configuration cache: expose via isRequiredBy() * copilot feedback * small whitespace fix
1 parent 1372e23 commit 4b452b3

File tree

7 files changed

+88
-26
lines changed

7 files changed

+88
-26
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ repositories {
2323

2424
dependencies {
2525
implementation gradleApi()
26+
implementation 'com.fasterxml.jackson.core:jackson-databind:2.20.0'
2627
implementation 'org.yaml:snakeyaml:2.5'
2728
testImplementation gradleTestKit()
2829
testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'

src/main/groovy/com/avast/gradle/dockercompose/ContainerInfo.groovy

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package com.avast.gradle.dockercompose
22

3+
import com.fasterxml.jackson.annotation.JsonIgnore
34
import groovy.transform.Immutable
45

5-
//@Immutable // see ServiceHost.groovy
6+
@Immutable
67
class ContainerInfo {
78
/* For example serviceName_1 */
89
String instanceName
@@ -12,14 +13,14 @@ class ContainerInfo {
1213
Map<Integer, Integer> udpPorts
1314
/* Docker inspection */
1415
Map<String, Object> inspection
15-
String getContainerId() { inspection.Id }
16-
String getContainerHostname() { inspection.Config.Hostname }
16+
@JsonIgnore String getContainerId() { inspection.Id }
17+
@JsonIgnore String getContainerHostname() { inspection.Config.Hostname }
1718

18-
String getHost() { serviceHost.host }
19-
Map<Integer, Integer> getPorts() { tcpPorts }
20-
Integer getPort() { ports.values().find() }
21-
Integer getTcpPort() { tcpPorts.values().find() }
22-
Integer getUdpPort() { udpPorts.values().find() }
19+
@JsonIgnore String getHost() { serviceHost.host }
20+
@JsonIgnore Map<Integer, Integer> getPorts() { tcpPorts }
21+
@JsonIgnore Integer getPort() { ports.values().find() }
22+
@JsonIgnore Integer getTcpPort() { tcpPorts.values().find() }
23+
@JsonIgnore Integer getUdpPort() { udpPorts.values().find() }
2324

2425

2526
@Override

src/main/groovy/com/avast/gradle/dockercompose/ServiceHost.groovy

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,7 @@ package com.avast.gradle.dockercompose
22

33
import groovy.transform.Immutable
44

5-
// @Immutable annotation generates a code that uses ImmutableASTTransformation class from Groovy library.
6-
// When compiling for Gradle 5+ (so Groovy 2.5+) then the generated code uses a new method that was added in Groovy 2.5.
7-
// Therefore this method is not available in Groovy 2.4, so in Gradle 4.x.
8-
// So we disabled the @Immutable annotations because we want to support also Gradle 4.x users.
9-
// We can uncomment them if one of these conditions were met:
10-
// 1. Groovy of the latest Gradle fixes this forward compatibility.
11-
// 2. There is almost no users of Gradle 4.x.
12-
13-
//@Immutable
5+
@Immutable
146
class ServiceHost {
157
String host
168
ServiceHostType type

src/main/groovy/com/avast/gradle/dockercompose/ServiceInfo.groovy

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.avast.gradle.dockercompose
22

3+
import com.fasterxml.jackson.annotation.JsonIgnore
34
import groovy.transform.Immutable
45

56
@Immutable(knownImmutableClasses = [ContainerInfo], copyWith = true)
@@ -8,15 +9,15 @@ class ServiceInfo {
89
/* Key is instance name, for example service_1 */
910
Map<String, ContainerInfo> containerInfos = [:]
1011

11-
String getHost() { firstContainer?.serviceHost.host }
12-
Map<Integer, Integer> getPorts() { tcpPorts }
13-
Map<Integer, Integer> getTcpPorts() { firstContainer?.tcpPorts ?: [:] }
14-
Map<Integer, Integer> getUdpPorts() { firstContainer?.udpPorts ?: [:] }
15-
Integer getPort() { firstContainer?.port }
16-
Integer getTcpPort() { firstContainer?.tcpPort }
17-
Integer getUdpPort() { firstContainer?.udpPort }
12+
@JsonIgnore String getHost() { firstContainer?.serviceHost.host }
13+
@JsonIgnore Map<Integer, Integer> getPorts() { tcpPorts }
14+
@JsonIgnore Map<Integer, Integer> getTcpPorts() { firstContainer?.tcpPorts ?: [:] }
15+
@JsonIgnore Map<Integer, Integer> getUdpPorts() { firstContainer?.udpPorts ?: [:] }
16+
@JsonIgnore Integer getPort() { firstContainer?.port }
17+
@JsonIgnore Integer getTcpPort() { firstContainer?.tcpPort }
18+
@JsonIgnore Integer getUdpPort() { firstContainer?.udpPort }
1819

19-
ContainerInfo getFirstContainer() {
20+
@JsonIgnore ContainerInfo getFirstContainer() {
2021
containerInfos.values()?.find()
2122
}
2223

src/main/groovy/com/avast/gradle/dockercompose/TasksConfigurator.groovy

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.avast.gradle.dockercompose
22

33
import com.avast.gradle.dockercompose.tasks.*
4+
import com.fasterxml.jackson.core.type.TypeReference
5+
import com.fasterxml.jackson.databind.ObjectMapper
46
import groovy.transform.CompileStatic
57
import groovy.transform.PackageScope
68
import org.gradle.api.Project
@@ -130,7 +132,9 @@ class TasksConfigurator {
130132

131133
// composeSettings.tasksConfigurator is null when the doFirst actions run with the configuration cache enabled.
132134
def composeSettings = this.composeSettings
133-
def servicesInfos = upTask.map { it.servicesInfos }
135+
def servicesInfos = upTask.flatMap { it.servicesInfosFile }.map {
136+
new ObjectMapper().readValue(it.asFile, new TypeReference<Map<String, ServiceInfo>>() {})
137+
}
134138
if (task instanceof ProcessForkOptions) task.doFirst {
135139
composeSettings.exposeAsEnvironmentInternal(task as ProcessForkOptions, servicesInfos.get())
136140
}

src/main/groovy/com/avast/gradle/dockercompose/tasks/ComposeUp.groovy

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.avast.gradle.dockercompose.DockerExecutor
66
import com.avast.gradle.dockercompose.ServiceHost
77
import com.avast.gradle.dockercompose.ServiceInfo
88
import com.avast.gradle.dockercompose.ServiceInfoCache
9+
import com.fasterxml.jackson.databind.ObjectMapper
910
import groovy.json.JsonSlurper
1011
import org.gradle.api.DefaultTask
1112
import org.gradle.api.file.DirectoryProperty
@@ -14,13 +15,18 @@ import org.gradle.api.provider.ListProperty
1415
import org.gradle.api.provider.MapProperty
1516
import org.gradle.api.provider.Property
1617
import org.gradle.api.tasks.Internal
18+
import org.gradle.api.tasks.OutputFile
1719
import org.gradle.api.tasks.TaskAction
1820

21+
import java.nio.file.Paths
1922
import java.time.Duration
2023
import java.time.Instant
2124

2225
abstract class ComposeUp extends DefaultTask {
2326

27+
@OutputFile
28+
abstract RegularFileProperty getServicesInfosFile()
29+
2430
@Internal
2531
Boolean wasReconnected = false // for tests
2632

@@ -100,6 +106,8 @@ abstract class ComposeUp extends DefaultTask {
100106
ComposeUp() {
101107
group = 'docker'
102108
description = 'Builds and starts containers of docker-compose project'
109+
setServicesInfosFile()
110+
outputs.upToDateWhen { false }
103111
}
104112

105113
@TaskAction
@@ -156,6 +164,7 @@ abstract class ComposeUp extends DefaultTask {
156164
} else {
157165
serviceInfoCache.get().clear()
158166
}
167+
writeServicesInfosFile()
159168
}
160169
catch (Exception e) {
161170
logger.debug("Failed to start-up Docker containers", e)
@@ -366,4 +375,17 @@ abstract class ComposeUp extends DefaultTask {
366375
}
367376
servicesInfos.collect { it -> it.copyWith(containerInfos: it.containerInfos.values().collect { newContainerInfos.getOrDefault(it.instanceName, it) }.collectEntries { [(it.instanceName): it] }) }
368377
}
378+
379+
void setServicesInfosFile() {
380+
def normalName = 'composeUp'
381+
def suffix = (name == normalName) ? '' : "-${name.take(name.size() - normalName.size())}"
382+
def path = Paths.get('tmp', 'com.avast.gradle.docker-compose', "services-infos${suffix}.json")
383+
servicesInfosFile.set(project.layout.buildDirectory.file(path.toString()))
384+
}
385+
386+
void writeServicesInfosFile() {
387+
def f = servicesInfosFile.get().asFile
388+
f.parentFile.mkdirs()
389+
new ObjectMapper().writeValue(f, servicesInfos)
390+
}
369391
}

src/test/groovy/com/avast/gradle/dockercompose/DockerComposePluginTest.groovy

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ import com.avast.gradle.dockercompose.tasks.ComposeLogs
77
import com.avast.gradle.dockercompose.tasks.ComposePull
88
import com.avast.gradle.dockercompose.tasks.ComposePush
99
import com.avast.gradle.dockercompose.tasks.ComposeUp
10+
import com.fasterxml.jackson.core.type.TypeReference
11+
import com.fasterxml.jackson.databind.ObjectMapper
1012
import org.gradle.api.Task
1113
import org.gradle.api.tasks.TaskProvider
1214
import org.gradle.api.tasks.testing.Test
1315
import org.gradle.testfixtures.ProjectBuilder
1416
import spock.lang.IgnoreIf
1517
import spock.lang.Specification
1618

19+
import java.nio.file.Paths
20+
1721
import static com.avast.gradle.dockercompose.util.VersionNumber.parse
1822

1923
class DockerComposePluginTest extends Specification {
@@ -602,4 +606,41 @@ class DockerComposePluginTest extends Specification {
602606
network_mode: service:gw
603607
''']
604608
}
609+
610+
def "deserialize servicesInfosFile and compare to original"() {
611+
def f = Fixture.withNginx()
612+
when:
613+
f.project.tasks.composeBuild.build()
614+
f.project.tasks.composeUp.up()
615+
def mapper = new ObjectMapper()
616+
def file = f.project.tasks.composeUp.servicesInfosFile.get().asFile
617+
def deserializedServicesInfos = mapper.readValue(file, new TypeReference<Map<String, ServiceInfo>>() {})
618+
then:
619+
noExceptionThrown()
620+
deserializedServicesInfos == f.project.tasks.composeUp.servicesInfos
621+
cleanup:
622+
f.project.tasks.composeDown.down()
623+
f.close()
624+
}
625+
626+
def "verify servicesInfosFile path"() {
627+
def project = ProjectBuilder.builder().build()
628+
when:
629+
project.plugins.apply 'docker-compose'
630+
project.dockerCompose {}
631+
File file = project.tasks.composeUp.servicesInfosFile.get().asFile
632+
then:
633+
file.toPath().endsWith(Paths.get('build', 'tmp', 'com.avast.gradle.docker-compose', 'services-infos.json'))
634+
}
635+
636+
def "verify servicesInfosFile path for nested configuration"() {
637+
def project = ProjectBuilder.builder().build()
638+
when:
639+
project.plugins.apply 'docker-compose'
640+
project.dockerCompose {
641+
nested {}
642+
}
643+
def file = project.tasks.nestedComposeUp.servicesInfosFile.get().asFile
644+
then:file.toPath().endsWith(Paths.get('build', 'tmp', 'com.avast.gradle.docker-compose', 'services-infos-nested.json'))
645+
}
605646
}

0 commit comments

Comments
 (0)