Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ buildscript {
repositories {
mavenCentral() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } }
gradlePluginPortal() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } }
mavenLocal()
}

dependencies {
classpath 'com.palantir.jakartapackagealignment:jakarta-package-alignment:0.6.0'
classpath 'com.palantir.gradle.externalpublish:gradle-external-publish-plugin:1.11.0'
classpath 'com.palantir.javaformat:gradle-palantir-java-format:2.47.0'
classpath 'com.palantir.gradle.plugintesting:gradle-plugin-testing:999'
}
}

Expand All @@ -23,6 +25,7 @@ plugins {

repositories {
mavenCentral() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } }
mavenLocal()
}

group 'org.revapi'
Expand All @@ -33,6 +36,7 @@ apply plugin: 'java-gradle-plugin'
apply plugin: 'java-library'
apply plugin: 'groovy'
apply plugin: 'com.palantir.external-publish-jar'
apply plugin: 'com.palantir.gradle-plugin-testing'

sourceCompatibility = 1.8

Expand All @@ -48,10 +52,12 @@ dependencies {

testImplementation platform('org.junit:junit-bom')
testImplementation 'com.netflix.nebula:nebula-test'
testImplementation "org.junit.jupiter:junit-jupiter"
testImplementation 'org.mockito:mockito-core'
testImplementation 'org.assertj:assertj-core'
testRuntimeOnly "org.junit.vintage:junit-vintage-engine"
testImplementation 'org.junit.jupiter:junit-jupiter'
testRuntimeOnly 'org.junit.platform:junit-platform-engine'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'

annotationProcessor "org.immutables:value"
annotationProcessor "org.immutables:serial"
Expand All @@ -68,6 +74,7 @@ test {
environment = System.getenv().entrySet().stream()
.filter { entry -> entry.key != 'CIRCLE_TEST_REPORTS' }
.collect(Collectors.toMap({ it.key }, { it.value }))
systemProperty 'ignoreDeprecations', 'true'
}

gradlePlugin {
Expand Down
9 changes: 2 additions & 7 deletions src/main/java/org/revapi/gradle/ConjureProjectFilters.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import com.fasterxml.jackson.databind.node.ArrayNode;
import java.util.Optional;
import org.gradle.api.Project;

final class ConjureProjectFilters {
private static final ArrayNode CHECKS_FOR_CLIENT_PROJECTS = RevapiConfig.createArrayNode()
Expand All @@ -29,16 +28,12 @@ final class ConjureProjectFilters {

private ConjureProjectFilters() {}

public static RevapiConfig forProject(Project project) {
boolean isConjure = Optional.ofNullable(project.getParent())
.map(parentProject -> parentProject.getPluginManager().hasPlugin("com.palantir.conjure"))
.orElse(false);

public static RevapiConfig forProject(String projectName, boolean isConjure) {
if (!isConjure) {
return RevapiConfig.empty();
}

return checksForProjectName(project.getName())
return checksForProjectName(projectName)
.map(checks -> RevapiConfig.empty().withExtension(CheckWhitelist.EXTENSION_ID, checks))
.orElseGet(RevapiConfig::empty);
}
Expand Down
137 changes: 40 additions & 97 deletions src/main/java/org/revapi/gradle/GitVersionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,56 +16,47 @@

package org.revapi.gradle;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.gradle.api.Project;
import javax.inject.Inject;
import org.gradle.api.file.ProjectLayout;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.process.ExecOutput;
import org.gradle.process.ExecResult;
import org.immutables.value.Value;

final class GitVersionUtils {
private GitVersionUtils() {}
public abstract class GitVersionUtils {

public static Stream<String> previousGitTags(Project project) {
return StreamSupport.stream(new PreviousGitTags(project), false)
.filter(tag -> !isInitial000Tag(project, tag))
.map(GitVersionUtils::stripVFromTag);
}

private static Optional<String> previousGitTagFromRef(Project project, String ref) {
String beforeLastRef = ref + "^";
@Inject
protected abstract ProviderFactory getProviderFactory();

GitResult beforeLastRefTypeResult = execute(project, "git", "cat-file", "-t", beforeLastRef);

boolean thereIsNoCommitBeforeTheRef = !beforeLastRefTypeResult.stdout().equals("commit");
if (thereIsNoCommitBeforeTheRef) {
return Optional.empty();
}
@Inject
protected abstract ProjectLayout getProjectLayout();

GitResult describeResult = execute(project, "git", "describe", "--tags", "--abbrev=0", beforeLastRef);
public final Provider<Stream<String>> previousGitTags() {
return execute("git", "tag", "-l", "--merged", "HEAD^", "--sort=-committerdate")
.map(tagsResult -> {
if (tagsResult.exitCode() != 0 || tagsResult.stdout().isEmpty()) {
return Stream.empty();
}

if (describeResult.stderr().contains("No tags can describe")
|| describeResult.stderr().contains("No names found, cannot describe anything")) {
return Optional.empty();
}

return Optional.of(describeResult.stdoutOrThrowIfNonZero());
return Arrays.stream(tagsResult.stdout().split("\n"))
.filter(tag -> !isInitial000Tag(tag))
.map(GitVersionUtils::stripVFromTag);
});
}

private static boolean isInitial000Tag(Project project, String tag) {
private boolean isInitial000Tag(String tag) {
if (!tag.equals("0.0.0")) {
return false;
}

GitResult foo = execute(project, "git", "rev-parse", "--verify", "--quiet", "0.0.0^");
boolean parentDoesNotExist = foo.exitCode() != 0;
return parentDoesNotExist;
return execute("git", "rev-parse", "--verify", "--quiet", "0.0.0^")
.get()
.exitCode()
!= 0;
}

private static String stripVFromTag(String tag) {
Expand All @@ -76,22 +67,23 @@ private static String stripVFromTag(String tag) {
}
}

private static GitResult execute(Project project, String... command) {
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
ByteArrayOutputStream stderr = new ByteArrayOutputStream();

ExecResult execResult = project.exec(spec -> {
spec.setCommandLine(Arrays.asList(command));
spec.setStandardOutput(stdout);
spec.setErrorOutput(stderr);
spec.setIgnoreExitValue(true);
private Provider<GitResult> execute(String... command) {
ExecOutput output = getProviderFactory().exec(execSpec -> {
execSpec.commandLine((Object[]) command);
execSpec.setIgnoreExitValue(true);
execSpec.setWorkingDir(getProjectLayout().getProjectDirectory());
});

return GitResult.builder()
.exitCode(execResult.getExitValue())
.stdout(new String(stdout.toByteArray(), StandardCharsets.UTF_8).trim())
.stderr(new String(stderr.toByteArray(), StandardCharsets.UTF_8).trim())
.build();
Provider<String> stdout = output.getStandardOutput().getAsText();
Provider<String> stderr = output.getStandardError().getAsText();
Provider<ExecResult> result = output.getResult();

return stdout.zip(stderr, (out, err) -> new Object[] {out, err})
.zip(result, (outErr, res) -> GitResult.builder()
.exitCode(res.getExitValue())
.stdout(((String) outErr[0]).trim())
.stderr(((String) outErr[1]).trim())
.build());
}

@Value.Immutable
Expand All @@ -104,59 +96,10 @@ interface GitResult {

List<String> command();

default String stdoutOrThrowIfNonZero() {
if (exitCode() == 0) {
return stdout();
}

throw new RuntimeException("Failed running command:\n"
+ "\tCommand:" + command() + "\n"
+ "\tExit code: " + exitCode() + "\n"
+ "\tStdout:" + stdout() + "\n"
+ "\tStderr:" + stderr() + "\n");
}

class Builder extends ImmutableGitResult.Builder {}

static Builder builder() {
return new Builder();
}
}

private static final class PreviousGitTags implements Spliterator<String> {
private final Project project;
private String lastSeenRef = "HEAD";

PreviousGitTags(Project project) {
this.project = project;
}

@Override
public boolean tryAdvance(Consumer<? super String> action) {
Optional<String> tag = previousGitTagFromRef(project, lastSeenRef);

if (!tag.isPresent()) {
return false;
}

lastSeenRef = tag.get();
action.accept(lastSeenRef);
return true;
}

@Override
public Spliterator<String> trySplit() {
return null;
}

@Override
public long estimateSize() {
return Long.MAX_VALUE;
}

@Override
public int characteristics() {
return 0;
}
}
}
22 changes: 7 additions & 15 deletions src/main/java/org/revapi/gradle/RevapiAcceptBreakTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,31 @@
import java.util.Optional;
import org.gradle.api.DefaultTask;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.options.Option;
import org.revapi.gradle.config.AcceptedBreak;
import org.revapi.gradle.config.GroupNameVersion;
import org.revapi.gradle.config.Justification;

public class RevapiAcceptBreakTask extends DefaultTask {
public abstract class RevapiAcceptBreakTask extends DefaultTask {
private static final String CODE_OPTION = "code";
private static final String OLD_OPTION = "old";
private static final String NEW_OPTION = "new";
private static final String JUSTIFICATION_OPTION = "justification";

private final Property<ConfigManager> configManager =
getProject().getObjects().property(ConfigManager.class);
private final Property<String> code = getProject().getObjects().property(String.class);
private final Property<String> oldElement = getProject().getObjects().property(String.class);
private final Property<String> newElement = getProject().getObjects().property(String.class);
private final Property<Justification> justification =
getProject().getObjects().property(Justification.class);

public RevapiAcceptBreakTask() {
getOutputs().upToDateWhen(_ignored -> false);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to doNotTrackState in RevapiPlugin.java

}
@Input
protected abstract Property<GroupNameVersion> getGroupNameVersion();

@Internal
final Property<ConfigManager> getConfigManager() {
return configManager;
}
protected abstract Property<ConfigManager> getConfigManager();

@Option(option = CODE_OPTION, description = "Revapi change code")
public final void setCode(String codeString) {
Expand All @@ -75,10 +71,10 @@ public final void addVersionOverride() {
ensurePresent(code, CODE_OPTION);
ensurePresent(justification, JUSTIFICATION_OPTION);

configManager
getConfigManager()
.get()
.modifyConfigFile(revapiConfig -> revapiConfig.addAcceptedBreaks(
oldGroupNameVersion(),
getGroupNameVersion().get(),
Collections.singleton(AcceptedBreak.builder()
.code(code.get())
.oldElement(Optional.ofNullable(oldElement.getOrNull()))
Expand All @@ -92,8 +88,4 @@ private void ensurePresent(Property<?> prop, String option) {
throw new IllegalArgumentException("Please supply the --" + option + " param to this task");
}
}

private GroupNameVersion oldGroupNameVersion() {
return getProject().getExtensions().getByType(RevapiExtension.class).oldGroupNameVersion();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the use of getProject that was breaking configuration cache the rest of the changes are just about converting to an abstract class - can just remove this if we want a minimum PR

}
}
Loading