Skip to content

Commit

Permalink
Cache results of git commands
Browse files Browse the repository at this point in the history
  • Loading branch information
pkoenig10 committed May 1, 2024
1 parent 300eb72 commit f8e8d4d
Show file tree
Hide file tree
Showing 14 changed files with 458 additions and 340 deletions.
37 changes: 19 additions & 18 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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() } }
Expand All @@ -42,9 +41,6 @@ sourceSets {
}

dependencies {
implementation gradleApi()
implementation 'com.google.guava:guava'

groovyImplementation localGroovy()
groovyImplementation gradleApi()

Expand All @@ -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) {
Expand Down
54 changes: 54 additions & 0 deletions src/main/java/com/palantir/gradle/gitversion/CachingGit.java
Original file line number Diff line number Diff line change
@@ -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<String> currentBranch;
private final Supplier<String> currentHeadFullHash;
private final Supplier<Boolean> isClean;
private final Supplier<String> 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();
}
}
174 changes: 6 additions & 168 deletions src/main/java/com/palantir/gradle/gitversion/Git.java
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<String, String> envvars, String... commands) throws IOException, InterruptedException {
List<String> cmdInput = new ArrayList<>();
cmdInput.add("git");
cmdInput.addAll(Arrays.asList(commands));
ProcessBuilder pb = new ProcessBuilder(cmdInput);
Map<String, String> 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<String, String> 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 protected]");
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();
}
Loading

0 comments on commit f8e8d4d

Please sign in to comment.