From ac030c0fe86f46a17feb68d76e90e8311fa28853 Mon Sep 17 00:00:00 2001 From: Tony Robalik Date: Thu, 10 Oct 2024 14:23:29 -0700 Subject: [PATCH] fix: suggest fix action based on invocation context. Gradle or CLI. Resolves issue 89 --- .../kotlin/com/squareup/sort/SortCommand.kt | 64 ++++++++++++------- .../squareup/sort/SortDependenciesPlugin.kt | 6 +- .../com/squareup/sort/SortDependenciesTask.kt | 29 +++++++-- .../com/squareup/sort/FunctionalSpec.groovy | 5 ++ 4 files changed, 74 insertions(+), 30 deletions(-) diff --git a/app/src/main/kotlin/com/squareup/sort/SortCommand.kt b/app/src/main/kotlin/com/squareup/sort/SortCommand.kt index 03573a1..cb94c9b 100644 --- a/app/src/main/kotlin/com/squareup/sort/SortCommand.kt +++ b/app/src/main/kotlin/com/squareup/sort/SortCommand.kt @@ -17,7 +17,6 @@ import com.squareup.parse.BuildScriptParseException import com.squareup.sort.Status.NOT_SORTED import com.squareup.sort.Status.PARSE_ERROR import com.squareup.sort.Status.SUCCESS -import com.squareup.sort.groovy.GroovySorter import org.slf4j.Logger import org.slf4j.LoggerFactory import java.nio.file.FileSystem @@ -28,9 +27,7 @@ import kotlin.io.path.createTempFile import kotlin.io.path.pathString import kotlin.io.path.writeText -/** - * Parent command or entry point into the dependencies-sorter. - */ +/** Parent command or entry point into the dependencies-sorter. */ class SortCommand( private val fileSystem: FileSystem = FileSystems.getDefault(), private val buildFileFinder: BuildDotGradleFinder.Factory = object : BuildDotGradleFinder.Factory {} @@ -51,8 +48,14 @@ class SortCommand( } } - private val verbose by option("-v", "--verbose", help = "Verbose mode. All logs are printed.") - .flag("--quiet", default = false) + val paths: List by argument(help = "Path(s) to sort. Required.") + .path(mustExist = false, canBeDir = true, canBeFile = true) + .multiple(required = true) + + private val verbose by option( + "-v", "--verbose", + help = "Verbose mode. All logs are printed." + ).flag("--quiet", default = false) private val skipHiddenAndBuildDirs by option( "--skip-hidden-and-build-dirs", @@ -60,15 +63,14 @@ class SortCommand( ).flag("--no-skip-hidden-and-build-dirs", default = true) val mode by option( - "-m", - "--mode", - help = "Mode: [sort, check]. Defaults to 'sort'. Check will report if a file is already sorted" - ) - .enum().default(Mode.SORT) + "-m", "--mode", + help = "Mode: [sort, check]. Defaults to 'sort'. Check will report if a file is already sorted." + ).enum().default(Mode.SORT) - val paths: List by argument(help = "Path(s) to sort. Required.") - .path(mustExist = false, canBeDir = true, canBeFile = true) - .multiple(required = true) + val context by option( + "--context", + help = "Context: [cli, gradle]. Defaults to 'cli'. Used for more helpful error messages.", + ).enum().default(Context.CLI) override fun run() { // Use `use()` to ensure the logger is closed + dumps any close-time diagnostics @@ -191,16 +193,23 @@ class SortCommand( if (!success) { appendLine() appendLine("Fix by running") - appendLine( - notSorted.joinToString( - prefix = "./scripts/sort ", - separator = " ", - transform = { - // Log relative path of the unsorted file. - pwd.relativize(it.normalize()).pathString - }, - ) - ) + + when (context) { + Context.GRADLE -> appendLine("./gradlew sortDependencies") + + Context.CLI -> { + appendLine( + notSorted.joinToString( + prefix = "./scripts/sort ", + separator = " ", + transform = { + // Log relative path of the unsorted file. + pwd.relativize(it.normalize()).pathString + }, + ) + ) + } + } } appendLine() @@ -219,9 +228,16 @@ class SortCommand( } } +enum class Context { + CLI, + GRADLE, + ; +} + enum class Mode { SORT, CHECK, + ; } enum class Status(val value: Int) { diff --git a/sort-dependencies-gradle-plugin/src/main/kotlin/com/squareup/sort/SortDependenciesPlugin.kt b/sort-dependencies-gradle-plugin/src/main/kotlin/com/squareup/sort/SortDependenciesPlugin.kt index b64ce55..4263384 100644 --- a/sort-dependencies-gradle-plugin/src/main/kotlin/com/squareup/sort/SortDependenciesPlugin.kt +++ b/sort-dependencies-gradle-plugin/src/main/kotlin/com/squareup/sort/SortDependenciesPlugin.kt @@ -12,8 +12,11 @@ class SortDependenciesPlugin : Plugin { const val VERSION_FILENAME = "com-squareup-sort-version.txt" } + private lateinit var extension: SortDependenciesExtension + override fun apply(target: Project): Unit = target.run { - val extension = SortDependenciesExtension.create(this) + extension = SortDependenciesExtension.create(this) + // nb: Can't use a detached configuration because that needs a Dependency, not a dependency notation. The latter can // be lazily evaluated (as below) while the former needs to (e.g.) know its version eagerly: it is more constrained. val sortApp = configurations.maybeCreate("sortDependencies").apply { @@ -49,6 +52,7 @@ class SortDependenciesPlugin : Plugin { ) { buildScript.set(project.buildFile) sortProgram.setFrom(sortApp) + version.set(extension.version) this.mode.set(mode) } } diff --git a/sort-dependencies-gradle-plugin/src/main/kotlin/com/squareup/sort/SortDependenciesTask.kt b/sort-dependencies-gradle-plugin/src/main/kotlin/com/squareup/sort/SortDependenciesTask.kt index e3ddcaa..b3452b2 100644 --- a/sort-dependencies-gradle-plugin/src/main/kotlin/com/squareup/sort/SortDependenciesTask.kt +++ b/sort-dependencies-gradle-plugin/src/main/kotlin/com/squareup/sort/SortDependenciesTask.kt @@ -37,6 +37,10 @@ abstract class SortDependenciesTask @Inject constructor( @get:InputFiles abstract val sortProgram: ConfigurableFileCollection + /** The app version limits what options we can pass it. */ + @get:Input + abstract val version: Property + @get:Input abstract val mode: Property @@ -45,8 +49,7 @@ abstract class SortDependenciesTask @Inject constructor( @get:Input abstract val verbose: Property - @TaskAction - fun action() { + @TaskAction fun action() { val buildScript = buildScript.get().asFile.absolutePath val mode = mode.getOrElse("sort") val verbose = verbose.getOrElse(false) @@ -57,19 +60,35 @@ abstract class SortDependenciesTask @Inject constructor( logger.info("Sorting '$buildScript' using mode '$mode'.") + val version = version.get().removeSuffix("-SNAPSHOT").toDouble() + execOps.javaexec { javaExecSpec -> with(javaExecSpec) { mainClass.set("com.squareup.sort.MainKt") classpath = sortProgram args = buildList { add(buildScript) - add("--mode") - add(mode) + option("--mode", mode) + + // Not really intended to be user-specified + if (version > 0.8) { + option("--context", "gradle") + } + if (verbose) { - add("--verbose") + if (version < 0.3) { + logger.warn("--verbose specified by version < 0.3. Ignoring flag.") + } else { + add("--verbose") + } } } } } } + + private fun MutableList.option(name: String, value: String) { + add(name) + add(value) + } } diff --git a/sort-dependencies-gradle-plugin/src/test/groovy/com/squareup/sort/FunctionalSpec.groovy b/sort-dependencies-gradle-plugin/src/test/groovy/com/squareup/sort/FunctionalSpec.groovy index 1ac8bfb..6232a93 100644 --- a/sort-dependencies-gradle-plugin/src/test/groovy/com/squareup/sort/FunctionalSpec.groovy +++ b/sort-dependencies-gradle-plugin/src/test/groovy/com/squareup/sort/FunctionalSpec.groovy @@ -122,6 +122,11 @@ final class FunctionalSpec extends Specification { then: 'Dependencies are not sorted' result.output.contains('1 scripts are not ordered correctly.') + result.output.contains( + '''\ + Fix by running + ./gradlew sortDependencies'''.stripIndent() + ) } def "checks sort order when executing 'check' task"() {