All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.diffplug.gradle.spotless.SpotlessExtension Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016-2024 DiffPlug
 *
 * 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.diffplug.gradle.spotless;

import static java.util.Objects.requireNonNull;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.annotation.Nullable;

import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.language.base.plugins.LifecycleBasePlugin;

import com.diffplug.spotless.LineEnding;

public abstract class SpotlessExtension {
	final Project project;
	private final RegisterDependenciesTask registerDependenciesTask;

	protected static final String TASK_GROUP = LifecycleBasePlugin.VERIFICATION_GROUP;
	protected static final String CHECK_DESCRIPTION = "Checks that sourcecode satisfies formatting steps.";
	protected static final String APPLY_DESCRIPTION = "Applies code formatting steps to sourcecode in-place.";

	static final String EXTENSION = "spotless";
	static final String EXTENSION_PREDECLARE = "spotlessPredeclare";
	static final String CHECK = "Check";
	static final String APPLY = "Apply";
	static final String DIAGNOSE = "Diagnose";

	protected SpotlessExtension(Project project) {
		this.project = requireNonNull(project);
		this.registerDependenciesTask = findRegisterDepsTask().get();
	}

	RegisterDependenciesTask getRegisterDependenciesTask() {
		return registerDependenciesTask;
	}

	/** Line endings (if any). */
	LineEnding lineEndings = LineEnding.GIT_ATTRIBUTES_FAST_ALLSAME;

	public LineEnding getLineEndings() {
		return lineEndings;
	}

	public void setLineEndings(LineEnding lineEndings) {
		if (lineEndings == LineEnding.GIT_ATTRIBUTES) {
			throw new IllegalArgumentException("GIT_ATTRIBUTES not supported in Gradle, use GIT_ATTRIBUTES_FAST_ALLSAME instead. See https://github.com/diffplug/spotless/issues/1274 for more details.");
		}
		this.lineEndings = requireNonNull(lineEndings);
	}

	Charset encoding = StandardCharsets.UTF_8;

	/** Returns the encoding to use. */
	public Charset getEncoding() {
		return encoding;
	}

	/** Sets encoding to use (defaults to UTF_8). */
	public void setEncoding(Charset charset) {
		encoding = requireNonNull(charset);
	}

	/** Sets encoding to use (defaults to UTF_8). */
	public void setEncoding(String name) {
		requireNonNull(name);
		setEncoding(Charset.forName(name));
	}

	/** Sets encoding to use (defaults to UTF_8). */
	public void encoding(Charset charset) {
		setEncoding(charset);
	}

	/** Sets encoding to use (defaults to UTF_8). */
	public void encoding(String charset) {
		setEncoding(charset);
	}

	private @Nullable String ratchetFrom;

	/**
	 * Limits the target to only the files which have changed since the given git reference,
	 * which is resolved according to this
	 */
	public void setRatchetFrom(String ratchetFrom) {
		this.ratchetFrom = ratchetFrom;
	}

	/** @see #setRatchetFrom(String) */
	public @Nullable String getRatchetFrom() {
		return ratchetFrom;
	}

	/** @see #setRatchetFrom(String) */
	public void ratchetFrom(String ratchetFrom) {
		setRatchetFrom(ratchetFrom);
	}

	final Map formats = new LinkedHashMap<>();

	/** Configures the special java-specific extension. */
	public void java(Action closure) {
		requireNonNull(closure);
		format(JavaExtension.NAME, JavaExtension.class, closure);
	}

	/** Configures the special scala-specific extension. */
	public void scala(Action closure) {
		requireNonNull(closure);
		format(ScalaExtension.NAME, ScalaExtension.class, closure);
	}

	/** Configures the special kotlin-specific extension. */
	public void kotlin(Action closure) {
		requireNonNull(closure);
		format(KotlinExtension.NAME, KotlinExtension.class, closure);
	}

	/** Configures the special Gradle Kotlin DSL specific extension. */
	public void kotlinGradle(Action closure) {
		requireNonNull(closure);
		format(KotlinGradleExtension.NAME, KotlinGradleExtension.class, closure);
	}

	/** Configures the special freshmark-specific extension. */
	public void freshmark(Action closure) {
		requireNonNull(closure);
		format(FreshMarkExtension.NAME, FreshMarkExtension.class, closure);
	}

	/** Configures the special flexmark-specific extension. */
	public void flexmark(Action closure) {
		requireNonNull(closure);
		format(FlexmarkExtension.NAME, FlexmarkExtension.class, closure);
	}

	/** Configures the special groovy-specific extension. */
	public void groovy(Action closure) {
		format(GroovyExtension.NAME, GroovyExtension.class, closure);
	}

	/** Configures the special groovy-specific extension for Gradle files. */
	public void groovyGradle(Action closure) {
		format(GroovyGradleExtension.NAME, GroovyGradleExtension.class, closure);
	}

	/** Configures the special sql-specific extension for SQL files. */
	public void sql(Action closure) {
		format(SqlExtension.NAME, SqlExtension.class, closure);
	}

	/** Configures the special C/C++-specific extension. */
	public void cpp(Action closure) {
		format(CppExtension.NAME, CppExtension.class, closure);
	}

	/** Configures the special javascript-specific extension for javascript files. */
	public void javascript(Action closure) {
		format(JavascriptExtension.NAME, JavascriptExtension.class, closure);
	}

	/** Configures the special typescript-specific extension for typescript files. */
	public void typescript(Action closure) {
		format(TypescriptExtension.NAME, TypescriptExtension.class, closure);
	}

	/** Configures the special antlr4-specific extension for antlr4 files. */
	public void antlr4(Action closure) {
		format(Antlr4Extension.NAME, Antlr4Extension.class, closure);
	}

	/** Configures the special python-specific extension for python files. */
	public void python(Action closure) {
		format(PythonExtension.NAME, PythonExtension.class, closure);
	}

	/** Configures the special JSON-specific extension. */
	public void json(Action closure) {
		requireNonNull(closure);
		format(JsonExtension.NAME, JsonExtension.class, closure);
	}

	/** Configures the special protobuf-specific extension. */
	public void protobuf(Action closure) {
		requireNonNull(closure);
		format(ProtobufExtension.NAME, ProtobufExtension.class, closure);
	}

	/** Configures the special shell-specific extension. */
	public void shell(Action closure) {
		requireNonNull(closure);
		format(ShellExtension.NAME, ShellExtension.class, closure);
	}

	/** Configures the special YAML-specific extension. */
	public void yaml(Action closure) {
		requireNonNull(closure);
		format(YamlExtension.NAME, YamlExtension.class, closure);
	}

	/** Configures the special Gherkin-specific extension. */
	public void gherkin(Action closure) {
		requireNonNull(closure);
		format(GherkinExtension.NAME, GherkinExtension.class, closure);
	}

	public void go(Action closure) {
		requireNonNull(closure);
		format(GoExtension.NAME, GoExtension.class, closure);
	}

	/** Configures the special POM-specific extension. */
	public void pom(Action closure) {
		requireNonNull(closure);
		format(PomExtension.NAME, PomExtension.class, closure);
	}

	/** Configures a custom extension. */
	public void format(String name, Action closure) {
		requireNonNull(name, "name");
		requireNonNull(closure, "closure");
		format(name, FormatExtension.class, closure);
	}

	boolean enforceCheck = true;

	/** Returns {@code true} if Gradle's {@code check} task should run {@code spotlessCheck}; {@code false} otherwise. */
	public boolean isEnforceCheck() {
		return enforceCheck;
	}

	/**
	 * Configures Gradle's {@code check} task to run {@code spotlessCheck} if {@code true},
	 * but to not do so if {@code false}.
	 * 

* {@code true} by default. */ public void setEnforceCheck(boolean enforceCheck) { this.enforceCheck = enforceCheck; } @SuppressWarnings("unchecked") public void format(String name, Class clazz, Action configure) { maybeCreate(name, clazz).lazyActions.add((Action) configure); } @SuppressWarnings("unchecked") protected final T maybeCreate(String name, Class clazz) { FormatExtension existing = formats.get(name); if (existing != null) { if (!clazz.isInstance(existing)) { throw new GradleException("Tried to add format named '" + name + "'" + " of type " + clazz + " but one has already been created of type " + existing.getClass()); } else { return (T) existing; } } else { T formatExtension = instantiateFormatExtension(clazz); formats.put(name, formatExtension); createFormatTasks(name, formatExtension); return formatExtension; } } T instantiateFormatExtension(Class clazz) { try { return project.getObjects().newInstance(clazz, this); } catch (Exception e) { throw new GradleException("Must have a constructor " + clazz.getSimpleName() + "(SpotlessExtension root), annotated with @javax.inject.Inject", e); } } protected abstract void createFormatTasks(String name, FormatExtension formatExtension); TaskProvider findRegisterDepsTask() { try { return findRegisterDepsTask(RegisterDependenciesTask.TASK_NAME); } catch (Exception e) { // in a composite build there can be multiple Spotless plugins on the classpath, and they will each try to register // a task on the root project with the same name. That will generate casting errors, which we can catch and try again // with an identity-specific identifier. // https://github.com/diffplug/spotless/pull/1001 for details return findRegisterDepsTask(RegisterDependenciesTask.TASK_NAME + System.identityHashCode(RegisterDependenciesTask.class)); } } private TaskProvider findRegisterDepsTask(String taskName) { TaskContainer rootProjectTasks = project.getRootProject().getTasks(); if (!rootProjectTasks.getNames().contains(taskName)) { return rootProjectTasks.register(taskName, RegisterDependenciesTask.class, RegisterDependenciesTask::setup); } else { return rootProjectTasks.named(taskName, RegisterDependenciesTask.class); } } public void predeclareDepsFromBuildscript() { if (project.getRootProject() != project) { throw new GradleException("predeclareDepsFromBuildscript can only be called from the root project"); } predeclare(GradleProvisioner.Policy.ROOT_BUILDSCRIPT); } public void predeclareDeps() { if (project.getRootProject() != project) { throw new GradleException("predeclareDeps can only be called from the root project"); } predeclare(GradleProvisioner.Policy.ROOT_PROJECT); } protected void predeclare(GradleProvisioner.Policy policy) { project.getExtensions().create(SpotlessExtensionPredeclare.class, EXTENSION_PREDECLARE, SpotlessExtensionPredeclare.class, project, policy); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy