diff --git a/build.gradle.kts b/build.gradle.kts index 23403868..9470ebda 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,10 +19,6 @@ plugins { `kotlin-dsl` } -tasks.named("compileGroovy", GroovyCompile::class.java) { - groovyOptions.configurationScript = file("src/groovyCompile/groovycConfig.groovy") -} - description = "Gradle plugin collect and provide information about the environment" contacts { diff --git a/src/groovyCompile/groovycConfig.groovy b/src/groovyCompile/groovycConfig.groovy deleted file mode 100644 index 19ca2df5..00000000 --- a/src/groovyCompile/groovycConfig.groovy +++ /dev/null @@ -1,6 +0,0 @@ -import org.codehaus.groovy.control.customizers.builder.CompilerCustomizationBuilder -import groovy.transform.CompileStatic - -CompilerCustomizationBuilder.withConfig(configuration) { - ast(CompileStatic) -} \ No newline at end of file diff --git a/src/main/groovy/nebula/plugin/info/ci/AbstractContinuousIntegrationProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/AbstractContinuousIntegrationProvider.groovy index 5b20cf87..7a1dc675 100644 --- a/src/main/groovy/nebula/plugin/info/ci/AbstractContinuousIntegrationProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/AbstractContinuousIntegrationProvider.groovy @@ -16,44 +16,26 @@ package nebula.plugin.info.ci -import com.sun.jna.platform.win32.Kernel32Util -import groovy.util.logging.Log +import groovy.transform.CompileStatic +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory -import org.gradle.internal.os.OperatingSystem +import org.jspecify.annotations.NullMarked -import java.util.logging.Level - -@Log +@NullMarked +@CompileStatic abstract class AbstractContinuousIntegrationProvider implements ContinuousIntegrationInfoProvider { - private final ProviderFactory providerFactory + protected final ProviderFactory providerFactory AbstractContinuousIntegrationProvider(ProviderFactory providerFactory) { this.providerFactory = providerFactory } - protected String getEnvironmentVariable(String envKey) { - return providerFactory.environmentVariable(envKey).getOrElse(null) + protected Provider environmentVariable(String envKey) { + return providerFactory.environmentVariable(envKey) } - protected static String hostname() { - OperatingSystem currentOs = OperatingSystem.current() - if (currentOs.isWindows()) { - try { - return Kernel32Util.getComputerName() - } catch (Throwable t) { - // with variations in Gradle versions and JVMs, this can sometimes break - log.log(Level.FINEST, "Unable to determine the host name on this Windows instance", t) - } - } else if (currentOs.isUnix()) { - try { - return POSIXUtil.getHostName() - } catch (Throwable t) { - log.log(Level.FINEST, "Unable to determine the host name", t) - } - } else { - log.log(Level.FINEST, "Unknown operating system $currentOs, could not detect hostname") - } - return 'localhost' + protected Provider hostname() { + return providerFactory.of(HostnameValueSource) {} } } diff --git a/src/main/groovy/nebula/plugin/info/ci/CircleCIProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/CircleCIProvider.groovy index 58d90e89..a78250e6 100644 --- a/src/main/groovy/nebula/plugin/info/ci/CircleCIProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/CircleCIProvider.groovy @@ -15,7 +15,7 @@ */ package nebula.plugin.info.ci -import org.gradle.api.Project +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory class CircleCIProvider extends AbstractContinuousIntegrationProvider { @@ -24,32 +24,32 @@ class CircleCIProvider extends AbstractContinuousIntegrationProvider { } @Override - boolean supports(Project project) { - getEnvironmentVariable('CIRCLECI') + boolean supports() { + environmentVariable('CIRCLECI').isPresent() } @Override - String calculateHost(Project project) { + Provider host() { return hostname() } @Override - String calculateJob(Project project) { - getEnvironmentVariable("CIRCLE_JOB") + Provider job() { + environmentVariable("CIRCLE_JOB") } @Override - String calculateBuildNumber(Project project) { - getEnvironmentVariable("CIRCLE_BUILD_NUM") + Provider buildNumber() { + environmentVariable("CIRCLE_BUILD_NUM") } @Override - String calculateBuildId(Project project) { - getEnvironmentVariable("CIRCLE_BUILD_NUM") + Provider buildId() { + environmentVariable("CIRCLE_BUILD_NUM") } @Override - String calculateBuildUrl(Project project) { - getEnvironmentVariable("CIRCLE_BUILD_URL") + Provider buildUrl() { + environmentVariable("CIRCLE_BUILD_URL") } } diff --git a/src/main/groovy/nebula/plugin/info/ci/CirrusCIProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/CirrusCIProvider.groovy index 7b608abf..3358ae06 100644 --- a/src/main/groovy/nebula/plugin/info/ci/CirrusCIProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/CirrusCIProvider.groovy @@ -15,41 +15,49 @@ */ package nebula.plugin.info.ci -import org.gradle.api.Project +import groovy.transform.CompileStatic +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory +import org.jspecify.annotations.NullMarked +@NullMarked +@CompileStatic class CirrusCIProvider extends AbstractContinuousIntegrationProvider { CirrusCIProvider(ProviderFactory providerFactory) { super(providerFactory) } @Override - boolean supports(Project project) { - getEnvironmentVariable("CIRRUS_CI") + boolean supports() { + environmentVariable("CIRRUS_CI").isPresent() } @Override - String calculateHost(Project project) { + Provider host() { return hostname() } @Override - String calculateJob(Project project) { - getEnvironmentVariable("CIRRUS_REPO_FULL_NAME") + Provider job() { + environmentVariable("CIRRUS_REPO_FULL_NAME") } @Override - String calculateBuildNumber(Project project) { - getEnvironmentVariable("CIRRUS_CHANGE_IN_REPO") + Provider buildNumber() { + environmentVariable("CIRRUS_CHANGE_IN_REPO") } @Override - String calculateBuildId(Project project) { - getEnvironmentVariable("CIRRUS_BUILD_ID") + Provider buildId() { + environmentVariable("CIRRUS_BUILD_ID") } @Override - String calculateBuildUrl(Project project) { - "${hostname()}/build/${getEnvironmentVariable("CIRRUS_BUILD_ID")}" + Provider buildUrl() { + return host().flatMap { host -> + buildId().map { id -> + "${host}/build/${id}".toString() + } + } } } diff --git a/src/main/groovy/nebula/plugin/info/ci/ContinuousIntegrationInfoPlugin.groovy b/src/main/groovy/nebula/plugin/info/ci/ContinuousIntegrationInfoPlugin.groovy index 323e5d0e..791150fc 100644 --- a/src/main/groovy/nebula/plugin/info/ci/ContinuousIntegrationInfoPlugin.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/ContinuousIntegrationInfoPlugin.groovy @@ -61,11 +61,11 @@ class ContinuousIntegrationInfoPlugin implements Plugin, InfoCollectorP } private void configureExtMapping(Project project, ContinuousIntegrationInfoExtension extension) { - extension.host.convention(providerFactory.provider { selectedProvider.calculateHost(project) }) - extension.job.convention(providerFactory.provider { selectedProvider.calculateJob(project) }) - extension.buildNumber.convention(providerFactory.provider { selectedProvider.calculateBuildNumber(project) }) - extension.buildId.convention(providerFactory.provider { selectedProvider.calculateBuildId(project) }) - extension.buildUrl.convention(providerFactory.provider { selectedProvider.calculateBuildUrl(project) }) + extension.host.convention(selectedProvider.host()) + extension.job.convention(selectedProvider.job()) + extension.buildNumber.convention(selectedProvider.buildNumber()) + extension.buildId.convention(selectedProvider.buildId()) + extension.buildUrl.convention(selectedProvider.buildUrl()) } ContinuousIntegrationInfoProvider findProvider(Project project) { diff --git a/src/main/groovy/nebula/plugin/info/ci/ContinuousIntegrationInfoProvider.java b/src/main/groovy/nebula/plugin/info/ci/ContinuousIntegrationInfoProvider.java index 978c5454..33511c25 100644 --- a/src/main/groovy/nebula/plugin/info/ci/ContinuousIntegrationInfoProvider.java +++ b/src/main/groovy/nebula/plugin/info/ci/ContinuousIntegrationInfoProvider.java @@ -17,20 +17,65 @@ package nebula.plugin.info.ci; import org.gradle.api.Project; +import org.gradle.api.provider.Provider; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * Could contribute to idea plugin, once we know the right SCM */ +@NullMarked public interface ContinuousIntegrationInfoProvider { /** * Determine support. Attempt to not use a library, to reduce impact and side effect of calling + * * @param project project to validate support against * @return boolean of the provider's availibility to support the current environment. */ - boolean supports(Project project); - String calculateHost(Project project); - String calculateJob(Project project); - String calculateBuildNumber(Project project); - String calculateBuildId(Project project); - String calculateBuildUrl(Project project); + @Deprecated + default boolean supports(Project project) { + return supports(); + } + + boolean supports(); + + @Deprecated + @Nullable + default String calculateHost(Project project) { + return host().getOrNull(); + } + + @Deprecated + @Nullable + default String calculateJob(Project project) { + return job().getOrNull(); + } + + @Deprecated + @Nullable + default String calculateBuildNumber(Project project) { + return buildNumber().getOrNull(); + } + + @Deprecated + @Nullable + default String calculateBuildId(Project project) { + return buildId().getOrNull(); + } + + @Deprecated + @Nullable + default String calculateBuildUrl(Project project) { + return buildUrl().getOrNull(); + } + + Provider host(); + + Provider job(); + + Provider buildNumber(); + + Provider buildId(); + + Provider buildUrl(); } diff --git a/src/main/groovy/nebula/plugin/info/ci/DroneProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/DroneProvider.groovy index 410f82db..1d9ab4f1 100644 --- a/src/main/groovy/nebula/plugin/info/ci/DroneProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/DroneProvider.groovy @@ -15,10 +15,9 @@ */ package nebula.plugin.info.ci -import org.gradle.api.Project +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory - class DroneProvider extends AbstractContinuousIntegrationProvider { DroneProvider(ProviderFactory providerFactory) { @@ -26,32 +25,36 @@ class DroneProvider extends AbstractContinuousIntegrationProvider { } @Override - boolean supports(Project project) { - getEnvironmentVariable('DRONE') + boolean supports() { + environmentVariable('DRONE').isPresent() } @Override - String calculateHost(Project project) { + Provider host() { return hostname() } @Override - String calculateJob(Project project) { - getEnvironmentVariable("DRONE_REPO") + Provider job() { + environmentVariable("DRONE_REPO") } @Override - String calculateBuildNumber(Project project) { - getEnvironmentVariable("DRONE_BUILD_NUMBER") + Provider buildNumber() { + environmentVariable("DRONE_BUILD_NUMBER") } @Override - String calculateBuildId(Project project) { - getEnvironmentVariable("DRONE_BUILD_NUMBER") + Provider buildId() { + environmentVariable("DRONE_BUILD_NUMBER") } @Override - String calculateBuildUrl(Project project) { - return "http://${hostname()}/build/${getEnvironmentVariable("DRONE_BUILD_NUMBER")}" + Provider buildUrl() { + return host().flatMap { host -> + buildNumber().map { number -> + "http://${host}/build/${number}".toString() + } + } } } diff --git a/src/main/groovy/nebula/plugin/info/ci/GithubActionsProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/GithubActionsProvider.groovy index b63e4a83..5d29f418 100644 --- a/src/main/groovy/nebula/plugin/info/ci/GithubActionsProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/GithubActionsProvider.groovy @@ -16,9 +16,13 @@ package nebula.plugin.info.ci -import org.gradle.api.Project +import groovy.transform.CompileStatic +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory +import org.jspecify.annotations.NullMarked +@CompileStatic +@NullMarked class GithubActionsProvider extends AbstractContinuousIntegrationProvider { GithubActionsProvider(ProviderFactory providerFactory) { @@ -26,8 +30,8 @@ class GithubActionsProvider extends AbstractContinuousIntegrationProvider { } @Override - boolean supports(Project project) { - getEnvironmentVariable('CI') && getEnvironmentVariable('GITHUB_ACTION') && getEnvironmentVariable('GITHUB_RUN_ID') + boolean supports() { + environmentVariable('CI').isPresent() && environmentVariable('GITHUB_ACTION').isPresent() && environmentVariable('GITHUB_RUN_ID').isPresent() } /** @@ -37,8 +41,8 @@ class GithubActionsProvider extends AbstractContinuousIntegrationProvider { * @return */ @Override - String calculateBuildNumber(Project project) { - getEnvironmentVariable('GITHUB_RUN_NUMBER') + Provider buildNumber() { + environmentVariable('GITHUB_RUN_NUMBER') } /** @@ -47,8 +51,8 @@ class GithubActionsProvider extends AbstractContinuousIntegrationProvider { * @return */ @Override - String calculateBuildId(Project project) { - getEnvironmentVariable('GITHUB_RUN_ID') + Provider buildId() { + environmentVariable('GITHUB_RUN_ID') } /** @@ -57,8 +61,8 @@ class GithubActionsProvider extends AbstractContinuousIntegrationProvider { * @return */ @Override - String calculateHost(Project project) { - getEnvironmentVariable('GITHUB_SERVER_URL') + Provider host() { + environmentVariable('GITHUB_SERVER_URL') } /** @@ -67,12 +71,19 @@ class GithubActionsProvider extends AbstractContinuousIntegrationProvider { * @return */ @Override - String calculateJob(Project project) { - getEnvironmentVariable('GITHUB_ACTION') + Provider job() { + environmentVariable('GITHUB_ACTION') } @Override - String calculateBuildUrl(Project project) { - return "${getEnvironmentVariable('GITHUB_SERVER_URL')}/${getEnvironmentVariable('GITHUB_REPOSITORY')}/actions/runs/${getEnvironmentVariable('GITHUB_RUN_ID')}" + Provider buildUrl() { + return environmentVariable('GITHUB_SERVER_URL') + .flatMap { host -> + environmentVariable("GITHUB_REPOSITORY") + .flatMap { repo -> + environmentVariable("GITHUB_RUN_ID") + .map { runId -> "${host}/${repo}/actions/runs/${runId}".toString() } + } + } } } diff --git a/src/main/groovy/nebula/plugin/info/ci/GitlabProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/GitlabProvider.groovy index 8dc2c4e9..1df6410a 100644 --- a/src/main/groovy/nebula/plugin/info/ci/GitlabProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/GitlabProvider.groovy @@ -16,9 +16,13 @@ package nebula.plugin.info.ci -import org.gradle.api.Project +import groovy.transform.CompileStatic +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory +import org.jspecify.annotations.NullMarked +@NullMarked +@CompileStatic class GitlabProvider extends AbstractContinuousIntegrationProvider { GitlabProvider(ProviderFactory providerFactory) { @@ -26,32 +30,32 @@ class GitlabProvider extends AbstractContinuousIntegrationProvider { } @Override - boolean supports(Project project) { - getEnvironmentVariable('GITLAB_CI') + boolean supports() { + environmentVariable('GITLAB_CI').isPresent() } @Override - String calculateBuildNumber(Project project) { - getEnvironmentVariable('CI_BUILD_ID') + Provider buildNumber() { + environmentVariable('CI_BUILD_ID') } @Override - String calculateBuildId(Project project) { - getEnvironmentVariable('CI_BUILD_ID') + Provider buildId() { + environmentVariable('CI_BUILD_ID') } @Override - String calculateBuildUrl(Project project) { - getEnvironmentVariable('CI_JOB_URL') + Provider buildUrl() { + environmentVariable('CI_JOB_URL') } @Override - String calculateHost(Project project) { + Provider host() { return hostname() } @Override - String calculateJob(Project project) { - getEnvironmentVariable('CI_BUILD_NAME') + Provider job() { + environmentVariable('CI_BUILD_NAME') } } diff --git a/src/main/groovy/nebula/plugin/info/ci/JenkinsProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/JenkinsProvider.groovy index d17d2c47..a9c5b933 100644 --- a/src/main/groovy/nebula/plugin/info/ci/JenkinsProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/JenkinsProvider.groovy @@ -16,7 +16,7 @@ package nebula.plugin.info.ci -import org.gradle.api.Project +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory class JenkinsProvider extends AbstractContinuousIntegrationProvider { @@ -26,32 +26,32 @@ class JenkinsProvider extends AbstractContinuousIntegrationProvider { } @Override - boolean supports(Project project) { - getEnvironmentVariable('BUILD_NUMBER') && getEnvironmentVariable('JOB_NAME') + boolean supports() { + environmentVariable('BUILD_NUMBER').isPresent() && environmentVariable('JOB_NAME').isPresent() } @Override - String calculateBuildNumber(Project project) { - getEnvironmentVariable('BUILD_NUMBER') + Provider buildNumber() { + environmentVariable('BUILD_NUMBER') } @Override - String calculateBuildId(Project project) { - getEnvironmentVariable('BUILD_ID') + Provider buildId() { + environmentVariable('BUILD_ID') } @Override - String calculateBuildUrl(Project project) { - getEnvironmentVariable('BUILD_URL') + Provider buildUrl() { + environmentVariable('BUILD_URL') } @Override - String calculateHost(Project project) { - getEnvironmentVariable('JENKINS_URL') + Provider host() { + environmentVariable('JENKINS_URL') } @Override - String calculateJob(Project project) { - getEnvironmentVariable('JOB_NAME') + Provider job() { + environmentVariable('JOB_NAME') } } diff --git a/src/main/groovy/nebula/plugin/info/ci/TitusProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/TitusProvider.groovy index 89b3e831..ef02b5d2 100644 --- a/src/main/groovy/nebula/plugin/info/ci/TitusProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/TitusProvider.groovy @@ -16,7 +16,7 @@ package nebula.plugin.info.ci -import org.gradle.api.Project +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory /** @@ -31,32 +31,36 @@ class TitusProvider extends AbstractContinuousIntegrationProvider { } @Override - boolean supports(Project project) { - getEnvironmentVariable('TITUS_JOB_ID') && getEnvironmentVariable('TITUS_TASK_ID') + boolean supports() { + environmentVariable('TITUS_JOB_ID').isPresent() && environmentVariable('TITUS_TASK_ID').isPresent() } @Override - String calculateBuildNumber(Project project) { - getEnvironmentVariable('TITUS_JOB_ID') + Provider buildNumber() { + environmentVariable('TITUS_JOB_ID') } @Override - String calculateBuildId(Project project) { - getEnvironmentVariable('TITUS_JOB_ID') + Provider buildId() { + environmentVariable('TITUS_JOB_ID') } @Override - String calculateBuildUrl(Project project) { - return "${getEnvironmentVariable('NETFLIX_INSTANCE_ID')}/${getEnvironmentVariable('TITUS_JOB_ID')}" + Provider buildUrl() { + return environmentVariable('NETFLIX_INSTANCE_ID').flatMap { instance -> + buildId().map { buildId -> + "${instance}/${buildId}".toString() + } + } } @Override - String calculateHost(Project project) { - getEnvironmentVariable('NETFLIX_INSTANCE_ID') + Provider host() { + environmentVariable('NETFLIX_INSTANCE_ID') } @Override - String calculateJob(Project project) { - getEnvironmentVariable('NETFLIX_APP') + Provider job() { + environmentVariable('NETFLIX_APP') } } diff --git a/src/main/groovy/nebula/plugin/info/ci/TravisProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/TravisProvider.groovy index 9e13fc00..07e052c0 100644 --- a/src/main/groovy/nebula/plugin/info/ci/TravisProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/TravisProvider.groovy @@ -15,7 +15,7 @@ */ package nebula.plugin.info.ci -import org.gradle.api.Project +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory class TravisProvider extends AbstractContinuousIntegrationProvider { @@ -24,32 +24,32 @@ class TravisProvider extends AbstractContinuousIntegrationProvider { } @Override - boolean supports(Project project) { - getEnvironmentVariable('TRAVIS') + boolean supports() { + environmentVariable('TRAVIS').isPresent() } @Override - String calculateHost(Project project) { + Provider host() { return hostname() } @Override - String calculateJob(Project project) { - getEnvironmentVariable("TRAVIS_REPO_SLUG") + Provider job() { + environmentVariable("TRAVIS_REPO_SLUG") } @Override - String calculateBuildNumber(Project project) { - getEnvironmentVariable("TRAVIS_BUILD_NUMBER") + Provider buildNumber() { + environmentVariable("TRAVIS_BUILD_NUMBER") } @Override - String calculateBuildId(Project project) { - getEnvironmentVariable("TRAVIS_BUILD_ID") + Provider buildId() { + environmentVariable("TRAVIS_BUILD_ID") } @Override - String calculateBuildUrl(Project project) { - getEnvironmentVariable("TRAVIS_BUILD_WEB_URL") + Provider buildUrl() { + environmentVariable("TRAVIS_BUILD_WEB_URL") } } diff --git a/src/main/groovy/nebula/plugin/info/ci/UnknownContinuousIntegrationProvider.groovy b/src/main/groovy/nebula/plugin/info/ci/UnknownContinuousIntegrationProvider.groovy index 5759e016..00b77a2e 100644 --- a/src/main/groovy/nebula/plugin/info/ci/UnknownContinuousIntegrationProvider.groovy +++ b/src/main/groovy/nebula/plugin/info/ci/UnknownContinuousIntegrationProvider.groovy @@ -16,7 +16,7 @@ package nebula.plugin.info.ci -import org.gradle.api.Project +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory class UnknownContinuousIntegrationProvider extends AbstractContinuousIntegrationProvider { @@ -27,32 +27,32 @@ class UnknownContinuousIntegrationProvider extends AbstractContinuousIntegration } @Override - boolean supports(Project project) { + boolean supports() { return true } @Override - String calculateBuildUrl(Project project) { - return "${hostname()}/${LOCAL}" + Provider buildUrl() { + return host().map { "${it}/${LOCAL}".toString() } } @Override - String calculateBuildNumber(Project project) { - return LOCAL + Provider buildNumber() { + return providerFactory.provider { LOCAL } } @Override - String calculateBuildId(Project project) { - return LOCAL + Provider buildId() { + return providerFactory.provider { LOCAL } } @Override - String calculateHost(Project project) { + Provider host() { return hostname() } @Override - String calculateJob(Project project) { - return LOCAL + Provider job() { + return providerFactory.provider { LOCAL } } } diff --git a/src/main/java/nebula/plugin/info/ci/HostnameValueSource.java b/src/main/java/nebula/plugin/info/ci/HostnameValueSource.java new file mode 100644 index 00000000..72e7e7f4 --- /dev/null +++ b/src/main/java/nebula/plugin/info/ci/HostnameValueSource.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014-2026 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package nebula.plugin.info.ci; + +import com.sun.jna.platform.win32.Kernel32Util; +import org.gradle.api.provider.ValueSource; +import org.gradle.api.provider.ValueSourceParameters; +import org.gradle.internal.os.OperatingSystem; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@NullMarked +public abstract class HostnameValueSource implements ValueSource { + private static final Logger log = LoggerFactory.getLogger(HostnameValueSource.class); + + @Override + @Nullable + public String obtain() { + return hostname(); + } + + public static String hostname() { + OperatingSystem currentOs = OperatingSystem.current(); + if (currentOs.isWindows()) { + try { + return Kernel32Util.getComputerName(); + } catch (Throwable t) { + // with variations in Gradle versions and JVMs, this can sometimes break + log.debug("Unable to determine the host name on this Windows instance", t); + } + } else if (currentOs.isUnix()) { + try { + return POSIXUtil.getHostName(); + } catch (Throwable t) { + log.debug("Unable to determine the host name", t); + } + } else { + log.debug("Unknown operating system $currentOs, could not detect hostname"); + } + return "localhost"; + } +} diff --git a/src/main/groovy/nebula/plugin/info/ci/POSIXUtil.groovy b/src/main/java/nebula/plugin/info/ci/POSIXUtil.java similarity index 67% rename from src/main/groovy/nebula/plugin/info/ci/POSIXUtil.groovy rename to src/main/java/nebula/plugin/info/ci/POSIXUtil.java index 7c1875c4..7ac2f749 100644 --- a/src/main/groovy/nebula/plugin/info/ci/POSIXUtil.groovy +++ b/src/main/java/nebula/plugin/info/ci/POSIXUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 Netflix, Inc. + * Copyright 2014-2026 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,21 +14,22 @@ * limitations under the License. */ -package nebula.plugin.info.ci +package nebula.plugin.info.ci; + +import com.sun.jna.LastErrorException; +import com.sun.jna.Library; +import com.sun.jna.Native; -import com.sun.jna.LastErrorException -import com.sun.jna.Library -import com.sun.jna.Native class POSIXUtil { - private static final C c = (C) Native.loadLibrary("c", C.class); + private static final C c = Native.loadLibrary("c", C.class); - private static interface C extends Library { + private interface C extends Library { int gethostname(byte[] name, int size_t) throws LastErrorException; } static String getHostName() { byte[] hostname = new byte[256]; - c.gethostname(hostname, hostname.length) - return Native.toString(hostname) + c.gethostname(hostname, hostname.length); + return Native.toString(hostname); } } diff --git a/src/test/groovy/nebula/plugin/info/ci/UnknownContinuousIntegrationProviderTest.groovy b/src/test/groovy/nebula/plugin/info/ci/UnknownContinuousIntegrationProviderTest.groovy deleted file mode 100644 index 3fef2f0a..00000000 --- a/src/test/groovy/nebula/plugin/info/ci/UnknownContinuousIntegrationProviderTest.groovy +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014-2019 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package nebula.plugin.info.ci - -import spock.lang.IgnoreIf -import spock.lang.Specification - -/** - * Tests for {@link UnknownContinuousIntegrationProvider}. - */ -@IgnoreIf({ Boolean.valueOf(env['TRAVIS']) }) -class UnknownContinuousIntegrationProviderTest extends Specification { - def 'calculated hostname matches resolved local host'() { - given: - def hostname = InetAddress.getLocalHost().getHostName() - - expect: - new UnknownContinuousIntegrationProvider().calculateHost(null) == hostname - } -} diff --git a/src/test/kotlin/nebula/plugin/info/ci/ContinuousIntegrationInfoPluginTest.kt b/src/test/kotlin/nebula/plugin/info/ci/ContinuousIntegrationInfoPluginTest.kt index ff12a617..3beb7e3f 100644 --- a/src/test/kotlin/nebula/plugin/info/ci/ContinuousIntegrationInfoPluginTest.kt +++ b/src/test/kotlin/nebula/plugin/info/ci/ContinuousIntegrationInfoPluginTest.kt @@ -91,6 +91,59 @@ internal class ContinuousIntegrationInfoPluginTest { assertThat(attributes.getKey("Build-Host")).isEqualTo("http://leeroy-jenkins") } + @Test + fun `test GitLab`() { + val runner = testProject(projectDir) { + exampleProject() + } + val result = runner.run("jar", "-Pversion=1.0") { + withEnvironment( + mapOf( + "GITLAB_CI" to "true", + "CI_BUILD_ID" to "1", + "CI_JOB_URL" to "http://some-gitlab", + "CI_BUILD_NAME" to "org/my-repo" + ) + ) + } + + assertThat(result) + .hasNoDeprecationWarnings() + .hasNoMutableStateWarnings() + + val attributes = readJarAttributes() + assertThat(attributes.getKey("Build-Job")).isEqualTo("org/my-repo") + assertThat(attributes.getKey("Build-Number")).isEqualTo("1") + assertThat(attributes.getKey("Build-Id")).isEqualTo("1") + assertThat(attributes.getKey("Build-Url")).isEqualTo("http://some-gitlab") + assertThat(attributes.getKey("Build-Host")).isEqualTo(HostnameValueSource.hostname()) + } + + @Test + fun `test Unknown or local`() { + val runner = testProject(projectDir) { + exampleProject() + } + val result = runner.run("jar", "-Pversion=1.0") { + withEnvironment( + mapOf( + "RANDOM" to "need at least 1 variable to make testkit have a clean env", + ) + ) + } + + assertThat(result) + .hasNoDeprecationWarnings() + .hasNoMutableStateWarnings() + + val attributes = readJarAttributes() + assertThat(attributes.getKey("Build-Job")).isEqualTo("LOCAL") + assertThat(attributes.getKey("Build-Number")).isEqualTo("LOCAL") + assertThat(attributes.getKey("Build-Id")).isEqualTo("LOCAL") + assertThat(attributes.getKey("Build-Url")).isEqualTo("${HostnameValueSource.hostname()}/LOCAL") + assertThat(attributes.getKey("Build-Host")).isEqualTo(HostnameValueSource.hostname()) + } + fun Attributes.getKey(key: String): Any? { return get(Attributes.Name(key)) } @@ -98,4 +151,4 @@ internal class ContinuousIntegrationInfoPluginTest { fun readJarAttributes(): Attributes { return JarFile(projectDir.resolve("build/libs/module-1.0.jar")).manifest.mainAttributes } -} \ No newline at end of file +}