Skip to content

Commit

Permalink
Add flag to disable blank lines between configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
jonapoul committed Aug 2, 2024
1 parent 855c841 commit fba8f1d
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 10 deletions.
10 changes: 9 additions & 1 deletion app/src/main/kotlin/com/squareup/sort/SortCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class SortCommand(
help = "Flag to control whether file tree walking looks in build and hidden directories. True by default.",
).flag("--no-skip-hidden-and-build-dirs", default = true)

private val noBlankLines by option(
"--no-blank-lines",
help = "When enabled, blank lines will not be inserted between different dependency configurations. False by default",
).flag(default = false)

val mode by option("-m", "--mode", help = "Mode: [sort, check]. Defaults to 'sort'. Check will report if a file is already sorted")
.enum<Mode>().default(Mode.SORT)

Expand Down Expand Up @@ -100,9 +105,11 @@ class SortCommand(
var successCount = 0
var parseErrorCount = 0
var alreadySortedCount = 0
val insertBlankLines = !noBlankLines

filesToSort.parallelStream().forEach { file ->
try {
val newContent = Sorter.sorterFor(file).rewritten()
val newContent = Sorter.sorterFor(file, insertBlankLines).rewritten()
file.writeText(newContent, Charsets.UTF_8, StandardOpenOption.TRUNCATE_EXISTING)
logger.trace("Successfully sorted: ${file.pathString} ")
successCount++
Expand Down Expand Up @@ -141,6 +148,7 @@ class SortCommand(
val notSorted = mutableListOf<Path>()
var parseErrorCount = 0
var alreadySortedCount = 0
val insertBlankLines = !noBlankLines

filesToSort.parallelStream().forEach { file ->
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ abstract class SortDependenciesExtension @Inject constructor(
?: error("Can't find '$VERSION_FILENAME'")
)

/**
* When true, a blank line will be inserted between dependencies of different configurations
* (`api`, `implementation`, etc.). Enabled by default.
*/
val insertBlankLines: Property<Boolean> = objects
.property(Boolean::class.java)
.convention(true)

internal val check: Property<Boolean> = objects.property(Boolean::class.java).convention(true)

fun check(shouldCheck: Boolean) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ class SortDependenciesPlugin : Plugin<Project> {
}

tasks.register("sortDependencies", SortDependenciesTask::class.java) { t ->
t.configure("sort", target, sortApp)
t.configure("sort", target, sortApp, extension)
}
val checkTask = tasks.register("checkSortDependencies", SortDependenciesTask::class.java) { t ->
t.configure("check", target, sortApp)
t.configure("check", target, sortApp, extension)
}

afterEvaluate {
Expand All @@ -45,10 +45,12 @@ class SortDependenciesPlugin : Plugin<Project> {
private fun SortDependenciesTask.configure(
mode: String,
project: Project,
sortApp: Configuration
sortApp: Configuration,
extension: SortDependenciesExtension,
) {
buildScript.set(project.buildFile)
sortProgram.setFrom(sortApp)
this.mode.set(mode)
insertBlankLines.set(extension.insertBlankLines)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,16 @@ abstract class SortDependenciesTask @Inject constructor(
@get:Input
abstract val verbose: Property<Boolean>

@get:Optional
@get:Input
abstract val insertBlankLines: Property<Boolean>

@TaskAction
fun action() {
val buildScript = buildScript.get().asFile.absolutePath
val mode = mode.getOrElse("sort")
val verbose = verbose.getOrElse(false)
val insertBlankLines = insertBlankLines.getOrElse(true)

if (mode != "check" && mode != "sort") {
throw InvalidUserDataException("Mode must be 'sort' or 'check'. Was '$mode'.")
Expand All @@ -65,9 +70,8 @@ abstract class SortDependenciesTask @Inject constructor(
add(buildScript)
add("--mode")
add(mode)
if (verbose) {
add("--verbose")
}
if (verbose) add("--verbose")
if (!insertBlankLines) add("--no-blank-lines")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,108 @@ final class FunctionalSpec extends Specification {
build(dir, 'sortDependencies', '--verbose')
}

def "no blank lines between different configurations when flag is disabled"() {
given: 'A build script with unsorted dependencies and multiple configurations'
def buildScript = dir.resolve('build.gradle.kts')
Files.writeString(buildScript,
"""\
plugins {
`java-library`
id("com.squareup.sort-dependencies")
}
sortDependencies {
insertBlankLines = false
}
repositories {
mavenCentral()
maven { url = uri("$REPO") }
}
dependencies {
implementation("com.squareup.okio:okio:3.2.0")
api("com.squareup.okhttp3:okhttp:4.10.0")
testImplementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
}
""".stripIndent()
)

when: 'We sort dependencies in the build folder'
build(dir, 'sortDependencies')

then: 'The build script is sorted with no blank lines between api and implementation'
buildScript.text == """\
plugins {
`java-library`
id("com.squareup.sort-dependencies")
}
sortDependencies {
insertBlankLines = false
}
repositories {
mavenCentral()
maven { url = uri("$REPO") }
}
dependencies {
api("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.squareup.okio:okio:3.2.0")
testImplementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
}
""".stripIndent()
}

def "insert blank lines between different configurations when flag is omitted"() {
given: 'A build script with unsorted dependencies and multiple configurations'
def buildScript = dir.resolve('build.gradle.kts')
Files.writeString(buildScript,
"""\
plugins {
`java-library`
id("com.squareup.sort-dependencies")
}
repositories {
mavenCentral()
maven { url = uri("$REPO") }
}
dependencies {
implementation("com.squareup.okio:okio:3.2.0")
api("com.squareup.okhttp3:okhttp:4.10.0")
testImplementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
}
""".stripIndent()
)

when: 'We sort dependencies in the build folder'
build(dir, 'sortDependencies')

then: 'The build script is sorted with a blank line between api and implementation'
buildScript.text == """\
plugins {
`java-library`
id("com.squareup.sort-dependencies")
}
repositories {
mavenCentral()
maven { url = uri("$REPO") }
}
dependencies {
api("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.squareup.okio:okio:3.2.0")
testImplementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
}
""".stripIndent()
}

private static final BUILD_SCRIPT = """\
plugins {
id 'java-library'
Expand Down
13 changes: 10 additions & 3 deletions sort/src/main/kotlin/com/squareup/sort/Sorter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class Sorter private constructor(
private val rewriter: TokenStreamRewriter,
private val errorListener: RewriterErrorListener,
private val filePath: String,
private val insertBlankLines: Boolean,
) : GradleScriptBaseListener() {

// We use a default of two spaces, but update it at most once later on.
Expand Down Expand Up @@ -130,7 +131,9 @@ public class Sorter private constructor(
appendLine("dependencies {")
dependenciesByConfiguration.entries.sortedWith(ConfigurationComparator)
.forEachIndexed { i, entry ->
if (i != 0) appendLine()
// Place a blank line between chunks of the same configuration, if configured
if (i != 0 && insertBlankLines) appendLine()

entry.value.sortedWith(dependencyComparator)
.map { dependency ->
dependency to Texts(
Expand Down Expand Up @@ -165,7 +168,10 @@ public class Sorter private constructor(

public companion object {
@JvmStatic
public fun sorterFor(file: Path): Sorter {
public fun sorterFor(file: Path): Sorter = sorterFor(file, insertBlankLines = true)

@JvmStatic
public fun sorterFor(file: Path, insertBlankLines: Boolean): Sorter {
val input = Files.newInputStream(file, StandardOpenOption.READ).use {
CharStreams.fromStream(it)
}
Expand All @@ -186,7 +192,8 @@ public class Sorter private constructor(
tokens = tokens,
rewriter = TokenStreamRewriter(tokens),
errorListener = errorListener,
filePath = file.absolutePathString()
filePath = file.absolutePathString(),
insertBlankLines = insertBlankLines,
)
val tree = parser.script()
walker.walk(listener, tree)
Expand Down
35 changes: 35 additions & 0 deletions sort/src/test/groovy/com/squareup/sort/SorterSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,41 @@ final class SorterSpec extends Specification {
)).inOrder()
}

def "sort without inserting newlines between different configurations"() {
given:
def buildScript = dir.resolve('build.gradle')
Files.writeString(buildScript,
'''\
dependencies {
implementation(projects.foo)
implementation(projects.bar)
implementation(projects.foo)
api(projects.foo)
api(projects.bar)
api(projects.foo)
}
'''.stripIndent())

when:
def newScript = Sorter.sorterFor(buildScript, false).rewritten()

then:
notThrown(BuildScriptParseException)

and:
assertThat(trimmedLinesOf(newScript)).containsExactlyElementsIn(trimmedLinesOf(
'''\
dependencies {
api(projects.bar)
api(projects.foo)
implementation(projects.bar)
implementation(projects.foo)
}
'''.stripIndent()
)).inOrder()
}

def "sort add function call in dependencies"() {
given:
def buildScript = dir.resolve('build.gradle')
Expand Down

0 comments on commit fba8f1d

Please sign in to comment.