Skip to content

Commit 6a97fc5

Browse files
authored
Extract go-docker-environment into a separate script (#37)
1 parent c9f2c94 commit 6a97fc5

4 files changed

Lines changed: 158 additions & 97 deletions

File tree

gradle-modules/src/main/kotlin/org.sonarsource.cloud-native.go-binary-builder.gradle.kts

Lines changed: 20 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,39 @@
1515
* along with this program; if not, see https://sonarsource.com/license/ssal/
1616
*/
1717
import org.gradle.kotlin.dsl.registering
18-
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
1918
import org.sonarsource.cloudnative.gradle.GO_BINARY_OUTPUT_DIR
2019
import org.sonarsource.cloudnative.gradle.GoBuild
2120
import org.sonarsource.cloudnative.gradle.allGoSourcesAndMakeScripts
2221
import org.sonarsource.cloudnative.gradle.callMake
2322
import org.sonarsource.cloudnative.gradle.getArchitecture
2423
import org.sonarsource.cloudnative.gradle.getPlatform
2524
import org.sonarsource.cloudnative.gradle.goSources
25+
import org.sonarsource.cloudnative.gradle.goVersion
26+
import org.sonarsource.cloudnative.gradle.isCi
27+
import org.sonarsource.cloudnative.gradle.isCrossCompile
28+
29+
plugins {
30+
id("org.sonarsource.cloud-native.go-docker-environment")
31+
}
2632

2733
val goBinaries: Configuration by configurations.creating
2834
val goBinariesJar by tasks.registering(Jar::class) {
2935
group = "build"
30-
dependsOn("compileGo")
3136
archiveClassifier.set("binaries")
3237
from(GO_BINARY_OUTPUT_DIR)
3338
}
3439
artifacts.add(goBinaries.name, goBinariesJar)
3540

36-
val goVersion = providers.environmentVariable("GO_VERSION")
37-
.orElse(providers.gradleProperty("goVersion"))
38-
.orNull ?: error("Either `GO_VERSION` env variable or `goVersion` Gradle property must be set")
39-
val isCrossCompile = providers.environmentVariable("GO_CROSS_COMPILE").orElse("0")
40-
val isCi: Boolean = System.getenv("CI")?.equals("true") == true
41-
val goBuildExtension = extensions.create("goBuild", GoBuild::class)
41+
val goBuildExtension = extensions.findByType<GoBuild>() ?: extensions.create<GoBuild>("goBuild")
4242
goBuildExtension.dockerWorkDir.convention("/home/sonarsource/${project.name}")
4343
goBuildExtension.additionalOutputFiles.convention(emptySet())
44+
goBuildExtension.dockerCommands.convention(
45+
mapOf(
46+
"dockerCompileGo" to "./make.sh clean && ./make.sh build ${getPlatform()} ${getArchitecture()} && ./make.sh test"
47+
)
48+
)
4449

45-
if (isCi) {
50+
if (isCi()) {
4651
val cleanGoCode by tasks.registering(Exec::class) {
4752
description = "Clean all compiled version of the go code."
4853
group = "build"
@@ -63,6 +68,7 @@ if (isCi) {
6368

6469
callMake("build")
6570
}
71+
goBinariesJar.configure { dependsOn(compileGo) }
6672

6773
val goLangCiLint by tasks.registering(Exec::class) {
6874
description = "Run an external Go linter."
@@ -116,94 +122,11 @@ if (isCi) {
116122
dependsOn(goLangCiLint)
117123
}
118124
} else {
119-
val buildDockerImage by tasks.registering(Exec::class) {
120-
description = "Build the docker image to build the Go code."
121-
group = "build"
122-
123-
inputs.file(goBuildExtension.dockerfile)
124-
inputs.file("$projectDir/go.mod")
125-
inputs.file("$projectDir/go.sum")
126-
// Task outputs are not set, because it is too difficult to check if image is built;
127-
// We can ignore Gradle caches here, because Docker takes care of its own caches anyway.
128-
errorOutput = System.out
129-
130-
val uidProvider = objects.property<Long>()
131-
val os = DefaultNativePlatform.getCurrentOperatingSystem()
132-
if (os.isLinux || os.isMacOsX) {
133-
// UID of the user inside the container should match this of the host user, otherwise files from the host will be not accessible by the container.
134-
val uid = com.sun.security.auth.module.UnixSystem().uid
135-
uidProvider.set(uid)
136-
}
137-
138-
val noTrafficInspection = "false" == System.getProperty("trafficInspection")
139-
140-
val arguments = buildList {
141-
add("docker")
142-
add("buildx")
143-
add("build")
144-
add("--file")
145-
add(goBuildExtension.dockerfile.asFile.get().absolutePath)
146-
if (noTrafficInspection) {
147-
add("--build-arg")
148-
add("BUILD_ENV=dev")
149-
} else {
150-
add("--network=host")
151-
add("--build-arg")
152-
add("BUILD_ENV=dev_custom_cert")
153-
}
154-
if (uidProvider.isPresent) {
155-
add("--build-arg")
156-
add("UID=${uidProvider.get()}")
157-
}
158-
add("--build-arg")
159-
add("GO_VERSION=$goVersion")
160-
add("--platform")
161-
add("linux/amd64")
162-
add("-t")
163-
add("${project.name}-builder")
164-
add("--progress")
165-
add("plain")
166-
add("${project.projectDir}")
167-
}
168-
169-
commandLine(arguments)
170-
}
171-
172-
val compileGo by tasks.registering(Exec::class) {
173-
description = "Build the Go executable inside a Docker container."
174-
group = "build"
175-
dependsOn(buildDockerImage)
176-
errorOutput = System.out
177-
178-
inputs.files(allGoSourcesAndMakeScripts())
179-
inputs.property("goCrossCompile", isCrossCompile)
180-
outputs.files(goBuildExtension.additionalOutputFiles)
181-
outputs.dir(GO_BINARY_OUTPUT_DIR)
182-
outputs.cacheIf { true }
183-
184-
val platform = getPlatform()
185-
val arch = getArchitecture()
186-
187-
val workDir = goBuildExtension.dockerWorkDir.get()
188-
commandLine(
189-
"docker",
190-
"run",
191-
"--rm",
192-
"--network=host",
193-
"--platform",
194-
"linux/amd64",
195-
"--mount",
196-
"type=bind,source=${project.projectDir},target=$workDir",
197-
"--env",
198-
"GO_CROSS_COMPILE=${inputs.properties["goCrossCompile"]}",
199-
"${project.name}-builder",
200-
"bash",
201-
"-c",
202-
"cd $workDir && ./make.sh clean && ./make.sh build $platform $arch && ./make.sh test"
203-
)
204-
}
205-
125+
val dockerTaskNames = goBuildExtension.dockerCommands.map { it.keys }
206126
tasks.named("assemble") {
207-
dependsOn(compileGo)
127+
dependsOn(dockerTaskNames)
128+
}
129+
goBinariesJar.configure {
130+
dependsOn(dockerTaskNames)
208131
}
209132
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* SonarSource Cloud Native Gradle Modules
3+
* Copyright (C) 2024-2025 SonarSource SA
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the Sonar Source-Available License for more details.
13+
*
14+
* You should have received a copy of the Sonar Source-Available License
15+
* along with this program; if not, see https://sonarsource.com/license/ssal/
16+
*/
17+
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
18+
import org.sonarsource.cloudnative.gradle.GO_BINARY_OUTPUT_DIR
19+
import org.sonarsource.cloudnative.gradle.GoBuild
20+
import org.sonarsource.cloudnative.gradle.allGoSourcesAndMakeScripts
21+
import org.sonarsource.cloudnative.gradle.goVersion
22+
import org.sonarsource.cloudnative.gradle.isCi
23+
import org.sonarsource.cloudnative.gradle.isCrossCompile
24+
25+
val goBuildExtension = extensions.findByType<GoBuild>() ?: extensions.create<GoBuild>("goBuild")
26+
27+
val buildDockerImage by tasks.registering(Exec::class) {
28+
description = "Build the docker image for a pre-configured Go environment."
29+
group = "build"
30+
onlyIf { isCi().not() }
31+
32+
inputs.file(goBuildExtension.dockerfile)
33+
inputs.file("$projectDir/go.mod")
34+
inputs.file("$projectDir/go.sum")
35+
// Task outputs are not set, because it is too difficult to check if image is built;
36+
// We can ignore Gradle caches here, because Docker takes care of its own caches anyway.
37+
errorOutput = System.out
38+
39+
val uidProvider = objects.property<Long>()
40+
val os = DefaultNativePlatform.getCurrentOperatingSystem()
41+
if (os.isLinux || os.isMacOsX) {
42+
// UID of the user inside the container should match this of the host user, otherwise files from the host will be not accessible by the container.
43+
val uid = com.sun.security.auth.module.UnixSystem().uid
44+
uidProvider.set(uid)
45+
}
46+
47+
val noTrafficInspection = "false" == System.getProperty("trafficInspection")
48+
49+
val arguments = buildList {
50+
add("docker")
51+
add("buildx")
52+
add("build")
53+
add("--file")
54+
add(goBuildExtension.dockerfile.asFile.get().absolutePath)
55+
if (noTrafficInspection) {
56+
add("--build-arg")
57+
add("BUILD_ENV=dev")
58+
} else {
59+
add("--network=host")
60+
add("--build-arg")
61+
add("BUILD_ENV=dev_custom_cert")
62+
}
63+
if (uidProvider.isPresent) {
64+
add("--build-arg")
65+
add("UID=${uidProvider.get()}")
66+
}
67+
add("--build-arg")
68+
add("GO_VERSION=$goVersion")
69+
add("--build-context")
70+
add("root=${project.rootDir.absolutePath}")
71+
add("--platform")
72+
add("linux/amd64")
73+
add("-t")
74+
add("${project.name}-builder")
75+
add("--progress")
76+
add("plain")
77+
add("${project.projectDir}")
78+
}
79+
80+
commandLine(arguments)
81+
}
82+
83+
val dockerTasks = goBuildExtension.dockerCommands.map { tasksToCommands ->
84+
tasksToCommands.forEach { taskName, command ->
85+
tasks.register<Exec>(taskName) {
86+
description = "Build the Go executable inside a Docker container."
87+
group = "build"
88+
onlyIf { isCi().not() }
89+
dependsOn(buildDockerImage)
90+
errorOutput = System.out
91+
92+
inputs.files(allGoSourcesAndMakeScripts())
93+
inputs.property("goCrossCompile", isCrossCompile)
94+
outputs.files(goBuildExtension.additionalOutputFiles)
95+
outputs.dir(GO_BINARY_OUTPUT_DIR)
96+
outputs.cacheIf { true }
97+
98+
val workDir = goBuildExtension.dockerWorkDir.get()
99+
commandLine(
100+
"docker",
101+
"run",
102+
"--rm",
103+
"--network=host",
104+
"--platform",
105+
"linux/amd64",
106+
"--mount",
107+
"type=bind,source=${project.projectDir},target=$workDir",
108+
"--env",
109+
"GO_CROSS_COMPILE=${inputs.properties["goCrossCompile"]}",
110+
"${project.name}-builder",
111+
"bash",
112+
"-c",
113+
"cd $workDir && $command"
114+
)
115+
}
116+
}
117+
}
118+
119+
project.afterEvaluate {
120+
// Register the tasks after value of `dockerCommands` is known
121+
dockerTasks.get()
122+
}

gradle-modules/src/main/kotlin/org/sonarsource/cloudnative/gradle/BuildUtils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import org.gradle.api.provider.ProviderFactory
2929
import org.gradle.api.tasks.Exec
3030
import org.gradle.internal.os.OperatingSystem
3131

32+
fun isCi() = System.getenv("CI")?.equals("true") == true
33+
3234
fun Project.signingCondition(): Boolean {
3335
val branch = System.getenv()["CIRRUS_BRANCH"] ?: ""
3436
return (branch == "master" || branch.matches("branch-.+".toRegex())) &&

gradle-modules/src/main/kotlin/org/sonarsource/cloudnative/gradle/GoBuild.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import org.gradle.api.Project
2020
import org.gradle.api.file.FileTree
2121
import org.gradle.api.file.RegularFile
2222
import org.gradle.api.file.RegularFileProperty
23+
import org.gradle.api.provider.MapProperty
2324
import org.gradle.api.provider.Property
25+
import org.gradle.api.provider.Provider
2426
import org.gradle.api.provider.SetProperty
2527

2628
const val GO_BINARY_OUTPUT_DIR = "build/executable"
@@ -33,9 +35,21 @@ interface GoBuild {
3335
*/
3436
val dockerWorkDir: Property<String>
3537

38+
/**
39+
* Commands to run inside the container after `cd`-ing to the `dockerWorkDir`.
40+
* For each command in this list, a separate Gradle task wrapping `docker run` will be created.
41+
*/
42+
val dockerCommands: MapProperty<String, String>
43+
3644
val additionalOutputFiles: SetProperty<RegularFile>
3745
}
3846

47+
val Project.goVersion get() = providers.environmentVariable("GO_VERSION")
48+
.orElse(providers.gradleProperty("goVersion"))
49+
.orNull ?: error("Either `GO_VERSION` env variable or `goVersion` Gradle property must be set")
50+
51+
val Project.isCrossCompile: Provider<String> get() = providers.environmentVariable("GO_CROSS_COMPILE").orElse("0")
52+
3953
fun Project.allGoSourcesAndMakeScripts(): FileTree =
4054
fileTree(projectDir).matching {
4155
include(

0 commit comments

Comments
 (0)