diff --git a/build.gradle b/build.gradle index a2097e2a..0cb8a4c5 100644 --- a/build.gradle +++ b/build.gradle @@ -14,23 +14,22 @@ buildscript { plugins { id 'com.gradle.plugin-publish' version '0.21.0' -id 'com.palantir.git-version' version '3.0.0' + id 'com.palantir.git-version' version '3.0.0' id 'com.palantir.idea-test-fix' version '0.1.0' - id 'com.palantir.baseline' version '4.147.0' -id 'com.palantir.consistent-versions' version '2.22.0' + id 'com.palantir.baseline' version '4.147.0' + id 'com.palantir.consistent-versions' version '2.22.0' id 'java-gradle-plugin' id 'groovy' } -allprojects { - apply plugin: 'com.palantir.jakarta-package-alignment' -} +apply plugin: 'com.palantir.baseline-java-versions' apply plugin: 'com.palantir.external-publish-jar' +apply plugin: 'com.palantir.jakarta-package-alignment' apply plugin: 'com.palantir.java-format' apply plugin: 'com.palantir.failure-reports' group 'com.palantir.gradle.gitversion' -version System.env.CIRCLE_TAG ?: gitVersion() +version gitVersion() repositories { mavenCentral() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } } @@ -42,9 +41,6 @@ sourceSets { } dependencies { - implementation gradleApi() - implementation 'com.google.guava:guava' - groovyImplementation localGroovy() groovyImplementation gradleApi() @@ -54,23 +50,28 @@ dependencies { implementation sourceSets.groovy.output annotationProcessor 'org.immutables:value' + compileOnly 'org.immutables:value::annotations' + implementation gradleApi() + implementation 'com.google.guava:guava' + testImplementation gradleTestKit() - testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'com.fasterxml.jackson.core:jackson-databind' testImplementation 'junit:junit' - testRuntimeOnly("org.junit.vintage:junit-vintage-engine") { - because 'allows JUnit 3 and JUnit 4 tests to run' - } testImplementation 'org.assertj:assertj-core' - testImplementation('org.spockframework:spock-core') { + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.spockframework:spock-core', { exclude module: 'groovy-all' } - testImplementation 'com.fasterxml.jackson.core:jackson-databind' + + testRuntimeOnly 'org.junit.vintage:junit-vintage-engine', { + because 'allows JUnit 3 and JUnit 4 tests to run' + } } -java { - sourceCompatibility JavaVersion.VERSION_1_8 +javaVersions { + libraryTarget = 11 } tasks.withType(JavaCompile) { diff --git a/src/main/java/com/palantir/gradle/gitversion/CachingGit.java b/src/main/java/com/palantir/gradle/gitversion/CachingGit.java new file mode 100644 index 00000000..6db49c38 --- /dev/null +++ b/src/main/java/com/palantir/gradle/gitversion/CachingGit.java @@ -0,0 +1,54 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * 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 com.palantir.gradle.gitversion; + +import com.google.common.base.Suppliers; +import java.util.function.Supplier; + +final class CachingGit implements Git { + + private final Supplier currentBranch; + private final Supplier currentHeadFullHash; + private final Supplier isClean; + private final Supplier describe; + + CachingGit(Git delegate) { + this.currentBranch = Suppliers.memoize(delegate::getCurrentBranch); + this.currentHeadFullHash = Suppliers.memoize(delegate::getCurrentHeadFullHash); + this.isClean = Suppliers.memoize(delegate::isClean); + this.describe = Suppliers.memoize(delegate::describe); + } + + @Override + public String getCurrentBranch() { + return currentBranch.get(); + } + + @Override + public String getCurrentHeadFullHash() { + return currentHeadFullHash.get(); + } + + @Override + public Boolean isClean() { + return isClean.get(); + } + + @Override + public String describe() { + return describe.get(); + } +} diff --git a/src/main/java/com/palantir/gradle/gitversion/Git.java b/src/main/java/com/palantir/gradle/gitversion/Git.java index fcc417eb..bee15d4f 100644 --- a/src/main/java/com/palantir/gradle/gitversion/Git.java +++ b/src/main/java/com/palantir/gradle/gitversion/Git.java @@ -1,5 +1,5 @@ /* - * (c) Copyright 2019 Palantir Technologies Inc. All rights reserved. + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,177 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.palantir.gradle.gitversion; -import com.google.common.annotations.VisibleForTesting; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class Git { - private static final Logger log = LoggerFactory.getLogger(Git.class); - - private final File directory; - - Git(File directory) { - this(directory, false); - } - - @VisibleForTesting - Git(File directory, boolean testing) { - if (!gitCommandExists()) { - throw new RuntimeException("Git not found in project"); - } - this.directory = directory; - if (testing && !checkIfUserIsSet()) { - setGitUser(); - } - } - - private String runGitCmd(String... commands) throws IOException, InterruptedException { - return runGitCmd(new HashMap<>(), commands); - } - - private String runGitCmd(Map envvars, String... commands) throws IOException, InterruptedException { - List cmdInput = new ArrayList<>(); - cmdInput.add("git"); - cmdInput.addAll(Arrays.asList(commands)); - ProcessBuilder pb = new ProcessBuilder(cmdInput); - Map environment = pb.environment(); - environment.putAll(envvars); - pb.directory(directory); - pb.redirectErrorStream(true); - - Process process = pb.start(); - BufferedReader reader = - new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)); - - StringBuilder builder = new StringBuilder(); - String line = null; - while ((line = reader.readLine()) != null) { - builder.append(line); - builder.append(System.getProperty("line.separator")); - } - - int exitCode = process.waitFor(); - if (exitCode != 0) { - return ""; - } - - return builder.toString().trim(); - } - - public String runGitCommand(Map envvar, String... command) { - try { - return runGitCmd(envvar, command); - } catch (IOException | InterruptedException | RuntimeException e) { - log.debug("Native git command {} failed.\n", command, e); - return null; - } - } - - public String runGitCommand(String... command) { - return runGitCommand(new HashMap<>(), command); - } - - private boolean checkIfUserIsSet() { - try { - String userEmail = runGitCmd("config", "user.email"); - if (userEmail.isEmpty()) { - return false; - } - return true; - } catch (IOException | InterruptedException | RuntimeException e) { - log.debug("Native git config user.email failed", e); - return false; - } - } - - private void setGitUser() { - try { - runGitCommand("config", "--global", "user.email", "email@example.com"); - runGitCommand("config", "--global", "user.name", "name"); - } catch (RuntimeException e) { - log.debug("Native git set user failed", e); - } - } - - public String getCurrentBranch() { - try { - String branch = runGitCmd("branch", "--show-current"); - if (branch.isEmpty()) { - return null; - } - return branch; - } catch (IOException | InterruptedException | RuntimeException e) { - log.debug("Native git branch --show-current failed", e); - return null; - } - } +interface Git { - public String getCurrentHeadFullHash() { - try { - return runGitCmd("rev-parse", "HEAD"); - } catch (IOException | InterruptedException | RuntimeException e) { - log.debug("Native git rev-parse HEAD failed", e); - return null; - } - } + String getCurrentBranch(); - public Boolean isClean() { - try { - String result = runGitCmd("status", "--porcelain"); - if (result.isEmpty()) { - return true; - } - return false; - } catch (IOException | InterruptedException | RuntimeException e) { - log.debug("Native git status --porcelain failed", e); - return null; - } - } + String getCurrentHeadFullHash(); - public String describe(String prefix) { - try { - String result = runGitCmd( - "describe", - "--tags", - "--always", - "--first-parent", - "--abbrev=7", - "--match=" + prefix + "*", - "HEAD"); - if (result.isEmpty()) { - return null; - } - return result; - } catch (IOException | InterruptedException | RuntimeException e) { - log.debug("Native git describe failed", e); - return null; - } - } + Boolean isClean(); - private boolean gitCommandExists() { - try { - // verify that "git" command exists (throws exception if it does not) - Process gitVersionProcess = new ProcessBuilder("git", "version").start(); - if (gitVersionProcess.waitFor() != 0) { - throw new IllegalStateException("error invoking git command"); - } - return true; - } catch (IOException | InterruptedException | RuntimeException e) { - log.debug("Native git command not found", e); - return false; - } - } + String describe(); } diff --git a/src/main/java/com/palantir/gradle/gitversion/GitImpl.java b/src/main/java/com/palantir/gradle/gitversion/GitImpl.java new file mode 100644 index 00000000..aa4c730e --- /dev/null +++ b/src/main/java/com/palantir/gradle/gitversion/GitImpl.java @@ -0,0 +1,185 @@ +/* + * (c) Copyright 2019 Palantir Technologies Inc. All rights reserved. + * + * 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 com.palantir.gradle.gitversion; + +import com.google.common.annotations.VisibleForTesting; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class GitImpl implements Git { + + private static final Logger log = LoggerFactory.getLogger(GitImpl.class); + + private final File directory; + private final GitVersionArgs args; + + GitImpl(File directory, GitVersionArgs args) { + this(directory, args, false); + } + + @VisibleForTesting + GitImpl(File directory, GitVersionArgs args, boolean testing) { + if (!gitCommandExists()) { + throw new RuntimeException("Git not found in project"); + } + this.directory = directory; + this.args = args; + if (testing && !checkIfUserIsSet()) { + setGitUser(); + } + } + + @VisibleForTesting + String runGitCommand(String... commands) throws IOException, InterruptedException { + return runGitCommand(new HashMap<>(), commands); + } + + @VisibleForTesting + String runGitCommand(Map envvars, String... commands) throws IOException, InterruptedException { + List cmdInput = new ArrayList<>(); + cmdInput.add("git"); + cmdInput.addAll(Arrays.asList(commands)); + ProcessBuilder pb = new ProcessBuilder(cmdInput); + Map environment = pb.environment(); + environment.putAll(envvars); + pb.directory(directory); + pb.redirectErrorStream(true); + + Process process = pb.start(); + BufferedReader reader = + new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)); + + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line); + builder.append(System.getProperty("line.separator")); + } + + int exitCode = process.waitFor(); + if (exitCode != 0) { + return ""; + } + + return builder.toString().trim(); + } + + private boolean checkIfUserIsSet() { + try { + String userEmail = runGitCommand("config", "user.email"); + if (userEmail.isEmpty()) { + return false; + } + return true; + } catch (IOException | InterruptedException | RuntimeException e) { + log.debug("git config user.email failed", e); + return false; + } + } + + private void setGitUser() { + try { + runGitCommand("config", "--global", "user.email", "email@example.com"); + runGitCommand("config", "--global", "user.name", "name"); + } catch (IOException | InterruptedException | RuntimeException e) { + log.debug("git set user failed", e); + } + } + + @Override + public String getCurrentBranch() { + try { + String branch = runGitCommand("branch", "--show-current"); + if (branch.isEmpty()) { + return null; + } + return branch; + } catch (IOException | InterruptedException | RuntimeException e) { + log.debug("git branch --show-current failed", e); + return null; + } + } + + @Override + public String getCurrentHeadFullHash() { + try { + return runGitCommand("rev-parse", "HEAD"); + } catch (IOException | InterruptedException | RuntimeException e) { + log.debug("git rev-parse HEAD failed", e); + return null; + } + } + + @Override + public Boolean isClean() { + try { + String result = runGitCommand("status", "--porcelain"); + if (result.isEmpty()) { + return true; + } + return false; + } catch (IOException | InterruptedException | RuntimeException e) { + log.debug("git status --porcelain failed", e); + return null; + } + } + + @Override + public String describe() { + try { + String result = runGitCommand( + "describe", + "--tags", + "--always", + "--first-parent", + "--abbrev=7", + "--match=" + args.getPrefix() + "*", + "HEAD"); + if (result.isEmpty()) { + return null; + } + return result; + } catch (IOException | InterruptedException | RuntimeException e) { + log.debug("git describe failed", e); + return null; + } + } + + private boolean gitCommandExists() { + try { + // verify that "git" command exists (throws exception if it does not) + Process gitVersionProcess = new ProcessBuilder("git", "version").start(); + if (gitVersionProcess.waitFor() != 0) { + throw new IllegalStateException("error invoking git command"); + } + return true; + } catch (IOException | InterruptedException | RuntimeException e) { + log.debug("git command not found", e); + return false; + } + } +} diff --git a/src/main/java/com/palantir/gradle/gitversion/GitVersionArgs.java b/src/main/java/com/palantir/gradle/gitversion/GitVersionArgs.java index f661edcb..1f6117ee 100644 --- a/src/main/java/com/palantir/gradle/gitversion/GitVersionArgs.java +++ b/src/main/java/com/palantir/gradle/gitversion/GitVersionArgs.java @@ -18,37 +18,36 @@ import com.google.common.base.Preconditions; import java.util.Map; +import java.util.regex.Pattern; -class GitVersionArgs { - private static final String PREFIX_REGEX = "[/@]?([A-Za-z]+[/@-])+"; +final class GitVersionArgs { - private String prefix = ""; + private static final Pattern PREFIX_PATTERN = Pattern.compile("[/@]?([A-Za-z]+[/@-])+"); - public String getPrefix() { - return prefix; - } + private final String prefix; - public void setPrefix(String prefix) { + GitVersionArgs(String prefix) { Preconditions.checkNotNull(prefix, "prefix must not be null"); Preconditions.checkState( - prefix.matches(PREFIX_REGEX), + prefix.isEmpty() || PREFIX_PATTERN.matcher(prefix).matches(), "Specified prefix `%s` does not match the allowed format regex `%s`.", prefix, - PREFIX_REGEX); + PREFIX_PATTERN); this.prefix = prefix; } + public String getPrefix() { + return prefix; + } + // groovy closure invocation allows any number of args - @SuppressWarnings("rawtypes") static GitVersionArgs fromGroovyClosure(Object... objects) { if (objects != null && objects.length > 0 && objects[0] instanceof Map) { - GitVersionArgs instance = new GitVersionArgs(); - instance.setPrefix(((Map) objects[0]).get("prefix").toString()); - return instance; + return new GitVersionArgs(((Map) objects[0]).get("prefix").toString()); } - return new GitVersionArgs(); + return new GitVersionArgs(""); } } diff --git a/src/main/java/com/palantir/gradle/gitversion/GitVersionCacheService.java b/src/main/java/com/palantir/gradle/gitversion/GitVersionCacheService.java index 2072fa02..9ed4aade 100644 --- a/src/main/java/com/palantir/gradle/gitversion/GitVersionCacheService.java +++ b/src/main/java/com/palantir/gradle/gitversion/GitVersionCacheService.java @@ -22,37 +22,25 @@ import org.gradle.api.provider.Provider; import org.gradle.api.services.BuildService; import org.gradle.api.services.BuildServiceParameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public abstract class GitVersionCacheService implements BuildService { - private static final Logger log = LoggerFactory.getLogger(GitVersionCacheService.class); - private final Timer timer = new Timer(); private final ConcurrentMap versionDetailsMap = new ConcurrentHashMap<>(); public final String getGitVersion(File project, Object args) { - File gitDir = getRootGitDir(project); - GitVersionArgs gitVersionArgs = GitVersionArgs.fromGroovyClosure(args); - String key = gitDir.toPath() + "|" + gitVersionArgs.getPrefix(); - String gitVersion = versionDetailsMap - .computeIfAbsent(key, _k -> createVersionDetails(gitDir, gitVersionArgs)) - .getVersion(); - return gitVersion; + return getVersionDetails(project, args).getVersion(); } public final VersionDetails getVersionDetails(File project, Object args) { File gitDir = getRootGitDir(project); GitVersionArgs gitVersionArgs = GitVersionArgs.fromGroovyClosure(args); String key = gitDir.toPath() + "|" + gitVersionArgs.getPrefix(); - VersionDetails versionDetails = - versionDetailsMap.computeIfAbsent(key, _k -> createVersionDetails(gitDir, gitVersionArgs)); - return versionDetails; + return versionDetailsMap.computeIfAbsent(key, _k -> createVersionDetails(gitDir, gitVersionArgs)); } private VersionDetails createVersionDetails(File gitDir, GitVersionArgs args) { - return TimingVersionDetails.wrap(timer, new VersionDetailsImpl(gitDir, args)); + return new TimedVersionDetails(new VersionDetailsImpl(gitDir, args), timer); } public final Timer timer() { diff --git a/src/main/java/com/palantir/gradle/gitversion/TimedVersionDetails.java b/src/main/java/com/palantir/gradle/gitversion/TimedVersionDetails.java new file mode 100644 index 00000000..798855eb --- /dev/null +++ b/src/main/java/com/palantir/gradle/gitversion/TimedVersionDetails.java @@ -0,0 +1,80 @@ +/* + * (c) Copyright 2020 Palantir Technologies Inc. All rights reserved. + * + * 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 com.palantir.gradle.gitversion; + +import com.palantir.gradle.gitversion.Timer.Context; +import java.io.IOException; + +final class TimedVersionDetails implements VersionDetails { + + private final VersionDetails delegate; + private final Timer timer; + + TimedVersionDetails(VersionDetails delegate, Timer timer) { + this.delegate = delegate; + this.timer = timer; + } + + @Override + public String getBranchName() throws IOException { + try (Context context = timer.start("getBranchName")) { + return delegate.getBranchName(); + } + } + + @Override + public String getGitHashFull() throws IOException { + try (Context context = timer.start("getGitHashFull")) { + return delegate.getGitHashFull(); + } + } + + @Override + public String getGitHash() throws IOException { + try (Context context = timer.start("getGitHash")) { + return delegate.getGitHash(); + } + } + + @Override + public String getLastTag() { + try (Context context = timer.start("getLastTag")) { + return delegate.getLastTag(); + } + } + + @Override + public int getCommitDistance() { + try (Context context = timer.start("getCommitDistance")) { + return delegate.getCommitDistance(); + } + } + + @Override + public boolean getIsCleanTag() { + try (Context context = timer.start("getIsCleanTag")) { + return delegate.getIsCleanTag(); + } + } + + @Override + public String getVersion() { + try (Context context = timer.start("getVersion")) { + return delegate.getVersion(); + } + } +} diff --git a/src/main/java/com/palantir/gradle/gitversion/Timer.java b/src/main/java/com/palantir/gradle/gitversion/Timer.java index 0606d24a..b049411a 100644 --- a/src/main/java/com/palantir/gradle/gitversion/Timer.java +++ b/src/main/java/com/palantir/gradle/gitversion/Timer.java @@ -18,31 +18,30 @@ import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableMap; +import com.google.errorprone.annotations.MustBeClosed; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; final class Timer { - private final ConcurrentMap totalTimesTakenMillis = new ConcurrentHashMap<>(); + private final ConcurrentMap totalElapsedMillis = new ConcurrentHashMap<>(); - public T record(String name, Supplier codeToTime) { + @MustBeClosed + public Context start(String name) { Stopwatch stopwatch = Stopwatch.createStarted(); - try { - return codeToTime.get(); - } finally { - stopwatch.stop(); - long timeTakenMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS); - - totalTimesTakenMillis.compute( - name, (_ignored, previousValue) -> timeTakenMillis + (previousValue == null ? 0 : previousValue)); - } + + return () -> { + long elapsedMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS); + + totalElapsedMillis.compute( + name, (_ignored, previousValue) -> elapsedMillis + (previousValue == null ? 0 : previousValue)); + }; } public String toJson() { Map withTotal = ImmutableMap.builder() - .putAll(totalTimesTakenMillis) + .putAll(totalElapsedMillis) .put("total", totalMillis()) .build(); @@ -50,6 +49,11 @@ public String toJson() { } public long totalMillis() { - return totalTimesTakenMillis.values().stream().mapToLong(time -> time).sum(); + return totalElapsedMillis.values().stream().mapToLong(time -> time).sum(); + } + + interface Context extends AutoCloseable { + @Override + void close(); } } diff --git a/src/main/java/com/palantir/gradle/gitversion/TimingVersionDetails.java b/src/main/java/com/palantir/gradle/gitversion/TimingVersionDetails.java deleted file mode 100644 index ee7afd22..00000000 --- a/src/main/java/com/palantir/gradle/gitversion/TimingVersionDetails.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * (c) Copyright 2020 Palantir Technologies Inc. All rights reserved. - * - * 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 com.palantir.gradle.gitversion; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Proxy; - -final class TimingVersionDetails { - private TimingVersionDetails() {} - - public static VersionDetails wrap(Timer timer, VersionDetails versionDetails) { - return (VersionDetails) Proxy.newProxyInstance( - VersionDetails.class.getClassLoader(), new Class[] {VersionDetails.class}, (_proxy, method, args) -> { - return timer.record(method.getName(), () -> { - try { - return method.invoke(versionDetails, args); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException("Failed in invoke method", e); - } - }); - }); - } -} diff --git a/src/main/java/com/palantir/gradle/gitversion/VersionDetailsImpl.java b/src/main/java/com/palantir/gradle/gitversion/VersionDetailsImpl.java index 7c14fe05..58a89f3e 100644 --- a/src/main/java/com/palantir/gradle/gitversion/VersionDetailsImpl.java +++ b/src/main/java/com/palantir/gradle/gitversion/VersionDetailsImpl.java @@ -21,52 +21,38 @@ import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; final class VersionDetailsImpl implements VersionDetails { - private static final Logger log = LoggerFactory.getLogger(VersionDetailsImpl.class); + private static final Pattern NOT_PLAIN_TAG_PATTERN = Pattern.compile(".*g.?[0-9a-fA-F]{3,}"); + private static final int VERSION_ABBR_LENGTH = 10; private static final String DOT_GIT_DIR_PATH = "/.git"; - private final GitVersionArgs args; - private Git nativeGitInvoker; + private final Git git; + private final GitVersionArgs args; VersionDetailsImpl(File gitDir, GitVersionArgs args) { String gitDirStr = gitDir.toString(); String projectDir = gitDirStr.substring(0, gitDirStr.length() - DOT_GIT_DIR_PATH.length()); - this.nativeGitInvoker = new Git(new File(projectDir)); + this.git = new CachingGit(new GitImpl(new File(projectDir), args)); this.args = args; } @Override public String getVersion() { - if (description() == null) { + String description = description(); + if (description == null) { return "unspecified"; } - return description() + (isClean() ? "" : ".dirty"); - } - private boolean isClean() { - return nativeGitInvoker.isClean(); - } - - private String description() { - String rawDescription = nativeGitInvoker.describe(args.getPrefix()); - String processedDescription = - rawDescription == null ? null : rawDescription.replaceFirst("^" + args.getPrefix(), ""); - return processedDescription; + return description + (git.isClean() ? "" : ".dirty"); } @Override public boolean getIsCleanTag() { - return isClean() && descriptionIsPlainTag(); - } - - private boolean descriptionIsPlainTag() { - return !Pattern.matches(".*g.?[0-9a-fA-F]{3,}", description()); + return git.isClean() && descriptionIsPlainTag(); } @Override @@ -92,7 +78,7 @@ public String getLastTag() { @Override public String getGitHash() throws IOException { - String gitHashFull = getGitHashFull(); + String gitHashFull = git.getCurrentHeadFullHash(); if (gitHashFull == null) { return null; } @@ -102,12 +88,12 @@ public String getGitHash() throws IOException { @Override public String getGitHashFull() throws IOException { - return nativeGitInvoker.getCurrentHeadFullHash(); + return git.getCurrentHeadFullHash(); } @Override public String getBranchName() throws IOException { - return nativeGitInvoker.getCurrentBranch(); + return git.getCurrentBranch(); } @Override @@ -120,4 +106,21 @@ public String toString() { return ""; } } + + private String description() { + String describe = git.describe(); + if (describe == null) { + return null; + } + + if (describe.startsWith(args.getPrefix())) { + return describe.substring(args.getPrefix().length()); + } + + return describe; + } + + private boolean descriptionIsPlainTag() { + return !NOT_PLAIN_TAG_PATTERN.matcher(description()).matches(); + } } diff --git a/src/test/groovy/com/palantir/gradle/gitversion/GitVersionPluginTests.groovy b/src/test/groovy/com/palantir/gradle/gitversion/GitVersionPluginTests.groovy index 194e717c..38a5fb49 100644 --- a/src/test/groovy/com/palantir/gradle/gitversion/GitVersionPluginTests.groovy +++ b/src/test/groovy/com/palantir/gradle/gitversion/GitVersionPluginTests.groovy @@ -76,7 +76,7 @@ class GitVersionPluginTests extends Specification { '''.stripIndent() gitIgnoreFile << 'build' new File(projectDir, 'settings.gradle').createNewFile() - Git git = new Git(rootFolder, true) + GitImpl git = new GitImpl(rootFolder, new GitVersionArgs(""), true) git.runGitCommand("init", rootFolder.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit","-m", "'initial commit'") @@ -107,7 +107,7 @@ class GitVersionPluginTests extends Specification { File originalGitIgnoreFile = new File(originalDir, ".gitignore") originalGitIgnoreFile.createNewFile() originalGitIgnoreFile << '.gradle\n' - Git git = new Git(originalDir, true) + GitImpl git = new GitImpl(originalDir, new GitVersionArgs(""), true) git.runGitCommand("init", originalDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit","-m", "'initial commit'") @@ -139,7 +139,7 @@ class GitVersionPluginTests extends Specification { include 'submodule' '''.stripIndent() - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit","-m", "'initial commit'") @@ -161,7 +161,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) when: @@ -180,7 +180,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -202,7 +202,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -226,7 +226,7 @@ class GitVersionPluginTests extends Specification { gitIgnoreFile << 'build' // create repository with a single commit tagged as 1.0.0 - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -260,7 +260,7 @@ class GitVersionPluginTests extends Specification { gitIgnoreFile << 'build' // create repository with a single commit tagged as 1.0.0 - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -297,7 +297,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -329,7 +329,7 @@ class GitVersionPluginTests extends Specification { }} '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -355,7 +355,7 @@ class GitVersionPluginTests extends Specification { }} '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -385,7 +385,7 @@ class GitVersionPluginTests extends Specification { '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -412,7 +412,7 @@ class GitVersionPluginTests extends Specification { '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -441,7 +441,7 @@ class GitVersionPluginTests extends Specification { '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -469,7 +469,7 @@ class GitVersionPluginTests extends Specification { }} '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -493,7 +493,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -519,7 +519,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -554,14 +554,14 @@ class GitVersionPluginTests extends Specification { gitIgnoreFile << 'build\n' gitIgnoreFile << 'sub\n' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") git.runGitCommand("tag", "-a", "1.0.0", "-m", "1.0.0") File subDir = Files.createDirectory(temporaryFolder.toPath().resolve('sub')).toFile() - Git subGit = new Git(subDir, true) + GitImpl subGit = new GitImpl(subDir, new GitVersionArgs(""), true) subGit.runGitCommand("init", subDir.toString()) File subDirty = new File(subDir, 'subDirty') subDirty.createNewFile() @@ -590,7 +590,7 @@ class GitVersionPluginTests extends Specification { } '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -618,7 +618,7 @@ class GitVersionPluginTests extends Specification { } '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -655,7 +655,7 @@ class GitVersionPluginTests extends Specification { } '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -679,7 +679,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -715,7 +715,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -741,7 +741,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") @@ -766,7 +766,7 @@ class GitVersionPluginTests extends Specification { version gitVersion() '''.stripIndent() gitIgnoreFile << 'build' - Git git = new Git(projectDir, true) + GitImpl git = new GitImpl(projectDir, new GitVersionArgs(""), true) git.runGitCommand("init", projectDir.toString()) git.runGitCommand("add", ".") git.runGitCommand("commit", "-m", "'initial commit'") diff --git a/src/test/java/com/palantir/gradle/gitversion/GitVersionArgsTest.java b/src/test/java/com/palantir/gradle/gitversion/GitVersionArgsTest.java index 71a4201d..cb420284 100644 --- a/src/test/java/com/palantir/gradle/gitversion/GitVersionArgsTest.java +++ b/src/test/java/com/palantir/gradle/gitversion/GitVersionArgsTest.java @@ -16,29 +16,27 @@ package com.palantir.gradle.gitversion; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.Test; public class GitVersionArgsTest { @Test - public void allowed_prefixes() throws Exception { - new GitVersionArgs().setPrefix("@Product@"); - new GitVersionArgs().setPrefix("abc@"); - new GitVersionArgs().setPrefix("abc@test@"); - new GitVersionArgs().setPrefix("Abc-aBc-abC@"); - new GitVersionArgs().setPrefix("foo-bar@"); - new GitVersionArgs().setPrefix("foo-bar/"); - new GitVersionArgs().setPrefix("foo-bar-"); - new GitVersionArgs().setPrefix("foo/bar@"); - new GitVersionArgs().setPrefix("Foo/Bar@"); + public void allowed_prefixes() { + assertThatCode(() -> new GitVersionArgs("@Product@")).doesNotThrowAnyException(); + assertThatCode(() -> new GitVersionArgs("abc@")).doesNotThrowAnyException(); + assertThatCode(() -> new GitVersionArgs("abc@test@")).doesNotThrowAnyException(); + assertThatCode(() -> new GitVersionArgs("Abc-aBc-abC@")).doesNotThrowAnyException(); + assertThatCode(() -> new GitVersionArgs("foo-bar@")).doesNotThrowAnyException(); + assertThatCode(() -> new GitVersionArgs("foo-bar/")).doesNotThrowAnyException(); + assertThatCode(() -> new GitVersionArgs("foo-bar-")).doesNotThrowAnyException(); + assertThatCode(() -> new GitVersionArgs("foo/bar@")).doesNotThrowAnyException(); + assertThatCode(() -> new GitVersionArgs("Foo/Bar@")).doesNotThrowAnyException(); } @Test - public void require_dash_or_at_symbol_at_prefix_end() throws Exception { - assertThatThrownBy(() -> { - new GitVersionArgs().setPrefix("v"); - }) - .isInstanceOf(IllegalStateException.class); + public void require_dash_or_at_symbol_at_prefix_end() { + assertThatThrownBy(() -> new GitVersionArgs("v")).isInstanceOf(IllegalStateException.class); } } diff --git a/src/test/java/com/palantir/gradle/gitversion/TimerTest.java b/src/test/java/com/palantir/gradle/gitversion/TimerTest.java index 970cf415..83b5f4f9 100644 --- a/src/test/java/com/palantir/gradle/gitversion/TimerTest.java +++ b/src/test/java/com/palantir/gradle/gitversion/TimerTest.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.palantir.gradle.gitversion.Timer.Context; import org.junit.jupiter.api.Test; class TimerTest { @@ -29,8 +30,12 @@ class TimerTest { @Test void generate_correct_json_with_total() throws JsonProcessingException { Timer timer = new Timer(); - assertThat(timer.record("something", () -> 4)).isEqualTo(4); - assertThat(timer.record("another", () -> "foo")).isEqualTo("foo"); + try (Context context = timer.start("something")) { + // Empty + } + try (Context context = timer.start("another")) { + // Empty + } ObjectNode objectNode = OBJECT_MAPPER.readValue(timer.toJson(), ObjectNode.class); long something = objectNode.get("something").asLong(); diff --git a/src/test/java/com/palantir/gradle/gitversion/VersionDetailsTest.java b/src/test/java/com/palantir/gradle/gitversion/VersionDetailsTest.java index fd67a34c..19aaef87 100644 --- a/src/test/java/com/palantir/gradle/gitversion/VersionDetailsTest.java +++ b/src/test/java/com/palantir/gradle/gitversion/VersionDetailsTest.java @@ -33,13 +33,13 @@ public class VersionDetailsTest { @TempDir public File temporaryFolder; - private Git git; + private GitImpl git; final String formattedTime = "'2005-04-07T22:13:13'"; @BeforeEach - public void before() { - this.git = new Git(temporaryFolder, true); + public void before() throws Exception { + this.git = new GitImpl(temporaryFolder, new GitVersionArgs(""), true); git.runGitCommand("init", temporaryFolder.toString()); } @@ -61,7 +61,7 @@ public void symlinks_should_result_in_clean_git_tree() throws Exception { } @Test - public void short_sha_when_no_annotated_tags_are_present() { + public void short_sha_when_no_annotated_tags_are_present() throws Exception { git.runGitCommand("add", "."); Map envvar = new HashMap<>(); envvar.put("GIT_COMMITTER_DATE", formattedTime); @@ -124,6 +124,6 @@ private File write(File file) throws IOException { private VersionDetails versionDetails() { String gitDir = temporaryFolder.toString() + "/.git"; - return new VersionDetailsImpl(new File(gitDir), new GitVersionArgs()); + return new VersionDetailsImpl(new File(gitDir), new GitVersionArgs("")); } }