Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(git): Redesign API to align with config cache requirements #149

Merged
merged 2 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 16 additions & 3 deletions indra-git/src/main/java/net/kyori/indra/git/GitPlugin.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of indra, licensed under the MIT License.
*
* Copyright (c) 2020-2023 KyoriPowered
* Copyright (c) 2020-2024 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -24,6 +24,8 @@
package net.kyori.indra.git;

import java.io.File;
import javax.inject.Inject;
import net.kyori.indra.git.internal.GitCache;
import net.kyori.indra.git.internal.IndraGitExtensionImpl;
import net.kyori.indra.git.internal.IndraGitService;
import net.kyori.indra.git.task.RepositoryTask;
Expand All @@ -37,18 +39,26 @@
import org.gradle.api.plugins.PluginContainer;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.build.event.BuildEventsListenerRegistry;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

/**
* A plugin that exposes any git repository that might be in a project.
*
* <p>This plugin requires at least Gradle 8.0.</p>
*
* @since 2.0.0
*/
public class GitPlugin implements ProjectOrSettingsPlugin {
@ApiStatus.NonExtendable
public abstract class GitPlugin implements ProjectOrSettingsPlugin {
private static final String EXTENSION_NAME = "indraGit";
public static final String REQUIRE_CLEAN_TASK = "requireClean";
public static final String REQUIRE_TAGGED_TASK = "requireTagged";

@Inject
protected abstract BuildEventsListenerRegistry getListenerRegistry();

@Override
public void applyToProject(
final @NotNull Project target,
Expand All @@ -69,6 +79,7 @@ public void applyToProject(
tasks.register(REQUIRE_TAGGED_TASK, RequireTagged.class);
tasks.withType(RepositoryTask.class).configureEach(task -> {
task.getGit().set(service);
task.usesService(service);
});
}

Expand All @@ -92,7 +103,9 @@ private Provider<IndraGitService> applyCommon(final @NotNull Gradle gradle, fina
final Provider<IndraGitService> service = gradle.getSharedServices().registerIfAbsent(IndraGitService.SERVICE_NAME, IndraGitService.class, params -> {
params.getParameters().getBaseDirectory().set(rootDir);
});
extensions.create(IndraGitExtension.class, EXTENSION_NAME, IndraGitExtensionImpl.class, projectDir, displayName, service);
this.getListenerRegistry().onTaskCompletion(service);
GitCache.getOrCreate(rootDir);
extensions.create(IndraGitExtension.class, EXTENSION_NAME, IndraGitExtensionImpl.class, rootDir, projectDir, displayName);
return service;
}
}
70 changes: 43 additions & 27 deletions indra-git/src/main/java/net/kyori/indra/git/IndraGitExtension.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of indra, licensed under the MIT License.
*
* Copyright (c) 2020-2022 KyoriPowered
* Copyright (c) 2020-2024 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -24,16 +24,23 @@
package net.kyori.indra.git;

import java.util.List;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.gradle.api.Action;
import org.gradle.api.java.archives.Manifest;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ValueSourceSpec;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* An extension exposing git information.
*
* <p>To find the appropriate repository, indra-git will look for a git repository in the root project directory.</p>
*
* <p>This will search in the current project's directory, and if the
* project is not a git checkout, will traverse parent directories until
* a {@code .git} folder is found.</p>
*
* @since 2.0.0
*/
public interface IndraGitExtension {
Expand All @@ -57,39 +64,48 @@ public interface IndraGitExtension {
* @return whether or not a git repository is present for the current project.
* @since 2.0.0
*/
default boolean isPresent() {
return this.git() != null;
}
boolean isPresent();

/**
* Access the underlying Git repository.
*
* <p>This will look for a git repository in the root project directory.</p>
*
* <p>This will search in the current project's directory, and if the
* project is not a git checkout, will traverse parent directories until
* a {@code .git} folder is found.</p>
* Create a parameterless which uses a value from a git repository.
*
* @return the git repository
* @since 2.0.0
* @param valueSource the value source type
* @param <V> the value type
* @param <P> the value source type
* @return the value provider
* @since 4.0.0
*/
default <V, P extends RepositoryValueSource.Parameters, S extends RepositoryValueSource<V, P>> Provider<V> repositoryValue(final Class<S> valueSource) {
return this.repositoryValue(valueSource, $ -> {});
}

/**
* Create a provider which uses a value from a git repository.
*
* @param valueSource the value source type
* @param configureAction an action to configure any additional parameters on the value source
* @param <V> the value type
* @param <P> the value source type
* @return the value provider
* @since 4.0.0
*/
@Nullable Git git();
<V, P extends RepositoryValueSource.Parameters, S extends RepositoryValueSource<V, P>> Provider<V> repositoryValue(final Class<S> valueSource, final Action<? super ValueSourceSpec<P>> configureAction);

/**
* Get all tags created on this repository.
*
* @return the tags on this repository, or an empty list if this project is not in a git repository
* @since 2.0.0
*/
@NotNull List<Ref> tags();
@NotNull Provider<? extends List<? extends Ref>> tags();

/**
* Get the tag pointing to the commit checked out as {@code HEAD}.
*
* @return the tag at {@code HEAD}, or {@code null} if the project is not in a git repository or is not checked out to a tag
* @since 2.0.0
*/
@Nullable Ref headTag();
@NotNull Provider<Ref> headTag();

/**
* Get a <a href="https://git-scm.com/docs/git-describe">{@code git describe}</a> string for the project's repository.
Expand All @@ -99,31 +115,31 @@ default boolean isPresent() {
* @return the describe string, or {@code null} if this project is not in a git repository or if there are no tags in the project's history
* @since 2.0.0
*/
@Nullable String describe();
@NotNull Provider<String> describe();

/**
* Get the name of the current branch.
*
* @return the name of the active branch, or {@code null} if the project is not in a git repository or is checked out to a detached {@code HEAD}.
* @since 2.0.0
*/
@Nullable String branchName();
@NotNull Provider<String> branchName();

/**
* Get an object pointing to the current branch.
*
* @return the active branch, or {@code null} if the project is not in a git repository or is checked out to a detached {@code HEAD}.
* @since 2.0.0
*/
@Nullable Ref branch();
@NotNull Provider<Ref> branch();

/**
* Get the ID of the current commit.
*
* @return the commit id, or {@code null} if the project is not in a git repository or has not had its initial commit
* @since 2.0.0
*/
@Nullable ObjectId commit();
@NotNull Provider<ObjectId> commit();

/**
* Apply metadata about the current git state to the provided manifest.
Expand All @@ -142,12 +158,12 @@ default boolean isPresent() {
* @since 2.0.0
*/
default void applyVcsInformationToManifest(final Manifest manifest) {
if(this.isPresent()) {
if (this.isPresent()) {
// Git-Commit and Git-Branch
final @Nullable ObjectId commit = this.commit();
final @Nullable String branchName = this.branchName();
if(commit != null) manifest.getAttributes().put(MANIFEST_ATTRIBUTE_GIT_COMMIT, commit.name());
if(branchName != null) manifest.getAttributes().put(MANIFEST_ATTRIBUTE_GIT_BRANCH, branchName);
final Provider<ObjectId> commit = this.commit();
final Provider<String> branchName = this.branchName();
if (commit.isPresent()) manifest.getAttributes().put(MANIFEST_ATTRIBUTE_GIT_COMMIT, commit.get().name());
if (branchName.isPresent()) manifest.getAttributes().put(MANIFEST_ATTRIBUTE_GIT_BRANCH, branchName.get());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* This file is part of indra, licensed under the MIT License.
*
* Copyright (c) 2024 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.kyori.indra.git;

import javax.inject.Inject;
import net.kyori.indra.git.internal.GitCache;
import org.eclipse.jgit.api.Git;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.ValueSource;
import org.gradle.api.provider.ValueSourceParameters;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* An implementation of {@link ValueSource} which queries the project's git repository for info.
*
* <p>This value source must be configured via {@link IndraGitExtension#repositoryValue(Class, org.gradle.api.Action)} to ensure it is populated with repository information.</p>
*
* <p>Implementations must be abstract, and only implement {@link #obtain(Git)}.</p>
*
* @param <V> the value type
* @param <P> the parameter type
* @since 4.0.0
*/
public abstract class RepositoryValueSource<V, P extends RepositoryValueSource.Parameters> implements ValueSource<V, P> {
public interface Parameters extends ValueSourceParameters {
@ApiStatus.Internal
DirectoryProperty getRootDir();
@ApiStatus.Internal
DirectoryProperty getProjectDir();
@ApiStatus.Internal
Property<String> getDisplayName();
}

@Inject
public RepositoryValueSource() {
}

@Override
public final @Nullable V obtain() {
final Parameters params = this.getParameters();
final Git git = GitCache.get(params.getRootDir().get().getAsFile()).git(params.getProjectDir().get().getAsFile(), params.getDisplayName().get());
if (git == null) return null;

return this.obtain(git);
}

protected abstract @Nullable V obtain(final @NotNull Git repository);

/**
* A value source that requires no extra parameters.
* @param <V>
*/
public static abstract class Parameterless<V> extends RepositoryValueSource<V, RepositoryValueSource.Parameters> {
}
}
Loading
Loading