Skip to content

Commit

Permalink
Solves #64 #65 #58 (#66)
Browse files Browse the repository at this point in the history
Solves #64 #65 #58
  • Loading branch information
Jean-Michel Fayard authored Sep 10, 2019
2 parents 687c16d + aa3966a commit ccfabd4
Show file tree
Hide file tree
Showing 27 changed files with 423 additions and 116 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ versionsOnlyMode for simple Gradle projects who just need the versions
5 modes supported: KOTLIN_VAL, KOTLIN_OBJECT, GROOVY_DEF, GROOVY_EXT, GRADLE_PROPERTIES
See https://github.com/jmfayard/buildSrcVersions/issues/55


- Upgrade to Gradle 5.6.2
- Upgrade to gradle-versions-plugins 0.25.0
- Typo useFqdnFor() #64
- Order dependencies by length #65
- Detect ident from EditorConfig file 58
- rejectVersionsIf { ... } from https://github.com/ben-manes/gradle-versions-plugin/issues/325
- Order dependencies by length #65
- Improve code quality
- Write more and better tests
- Use a local maven repo in the samples in order to have a stable output
Expand Down
2 changes: 1 addition & 1 deletion composite/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ tasks.register("publishLocally") {
group = "Custom"
description = "Publish the plugin locally"
dependsOn(":checkAll")
dependsOn(PLUGIN.task(":publish"))
dependsOn(PLUGIN.task(":publishToMavenLocal"))
}

tasks.register("publishPlugins") {
Expand Down
6 changes: 3 additions & 3 deletions plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@ publishing {
}

repositories {
mavenLocal()
mavenCentral()
jcenter()
}

pluginBundle {
website = "https://github.com/jmfayard/buildSrcVersions"
vcsUrl = "https://github.com/jmfayard/buildSrcVersions"
tags = listOf("dependencies", "versions", "buildSrc", "kotlin", "kotlin-dsl")
}

dependencies {
testImplementation("io.kotlintest:kotlintest-runner-junit5:3.1.9")

implementation("com.github.ben-manes:gradle-versions-plugin:0.22.0")

implementation("com.github.ben-manes:gradle-versions-plugin:0.25.0")
implementation("com.squareup.okio:okio:2.1.0")
implementation( "com.squareup.moshi:moshi:1.7.0")
implementation("com.squareup:kotlinpoet:1.3.0")
Expand Down
51 changes: 38 additions & 13 deletions plugin/src/main/kotlin/de/fayard/BuildSrcVersionsExtension.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package de.fayard

interface BuildSrcVersionsExtension {
var useFdqnFor: MutableList<String>
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentFilter

fun useFdqnFor(vararg dependencyName: String)

var rejectedVersionKeywords: MutableList<String>
interface BuildSrcVersionsExtension {
fun useFqdnFor(vararg dependencyName: String)

fun rejectedVersionKeywords(vararg keyword: String)
fun rejectVersionIf(filter: ComponentFilter)

var renameLibs : String

Expand All @@ -19,28 +19,53 @@ interface BuildSrcVersionsExtension {

var versionsOnlyFile : String?


@Deprecated("Deprecated, see #64", ReplaceWith("useFqdnFor()"))
var useFdqnFor: MutableList<String>

@Deprecated("Deprecated, see #64", ReplaceWith("useFqdnFor(dependencyName)"))
fun useFdqnFor(vararg dependencyName: String)


@Deprecated("Remove or use rejectVersionIf { ... }", replaceWith = ReplaceWith(""))
var rejectedVersionKeywords: MutableList<String>

@Deprecated("Remove or use rejectVersionIf { selection -> ... }", replaceWith = ReplaceWith(""))
fun rejectedVersionKeywords(vararg keyword: String)
}

open class BuildSrcVersionsExtensionImpl(
override var useFdqnFor: MutableList<String> = mutableListOf(),
internal open class BuildSrcVersionsExtensionImpl(
override var renameLibs: String = PluginConfig.DEFAULT_LIBS,
override var renameVersions: String = PluginConfig.DEFAULT_VERSIONS,
override var indent: String = PluginConfig.DEFAULT_INDENT,
override var versionsOnlyMode: VersionsOnlyMode? = null,
override var versionsOnlyFile: String? = null,
override var rejectedVersionKeywords: MutableList<String> = PluginConfig.DEFAULT_REJECTED_KEYWORDS
override var versionsOnlyFile: String? = null
) : BuildSrcVersionsExtension {
var useFqqnFor: List<String> = emptyList()

// Use @Transient for fields that should not be present in toString()
override fun toString() : String = PluginConfig.extensionAdapter.toJson(this)

@Transient lateinit var upstream: DependencyUpdatesTask

override fun rejectVersionIf(filter: ComponentFilter) {
upstream.rejectVersionIf(filter)
}

override fun useFqdnFor(vararg dependencyName: String) {
useFqqnFor = dependencyName.toList()
}

override fun rejectedVersionKeywords(vararg keyword: String) {
rejectedVersionKeywords = keyword.toMutableList()
println("Warning: rejectedVersionKeywords is deprecated, see ${PluginConfig.issue53PluginConfiguration}")
}

override fun useFdqnFor(vararg dependencyName: String) {
useFdqnFor = dependencyName.toMutableList()
println("Warning: useFdqnFor is deprecated, use useFqqnFor() instead. ${PluginConfig.issue53PluginConfiguration}")
useFqdnFor(*dependencyName)
}

override fun toString() : String =
PluginConfig.extensionAdapter.toJson(this)
@Transient override var useFdqnFor: MutableList<String> = mutableListOf()
@Transient override var rejectedVersionKeywords: MutableList<String> = mutableListOf()

}
39 changes: 11 additions & 28 deletions plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,51 +1,34 @@
package de.fayard

import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentSelectionWithCurrent
import de.fayard.PluginConfig.isNonStable
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.getByType

open class BuildSrcVersionsPlugin : Plugin<Project> {

override fun apply(project: Project) = project.run {

configureBenManesVersions()

extensions.create(BuildSrcVersionsExtension::class, PluginConfig.EXTENSION_NAME, BuildSrcVersionsExtensionImpl::class)
val extension = extensions.create(BuildSrcVersionsExtension::class, PluginConfig.EXTENSION_NAME, BuildSrcVersionsExtensionImpl::class)
(extension as BuildSrcVersionsExtensionImpl).upstream = configureBenManesVersions()
extension.rejectVersionIf {
isNonStable(candidate.version)
}

tasks.create("buildSrcVersions", BuildSrcVersionsTask::class) {
group = "Help"
description = "Update buildSrc/src/main/kotlin/{Versions.kt,Libs.kt}"
dependsOn(":dependencyUpdates")
outputs.upToDateWhen { false }
}

Unit
}

fun Project.configureBenManesVersions(): DependencyUpdatesTask {
val rejectedKeywordsRegexps: List<Regex> by lazy {
project.extensions.getByType<BuildSrcVersionsExtension>().rejectedVersionKeywords
.map { qualifier -> Regex("(?i).*[.-]$qualifier[.\\d-]*") }
fun Project.configureBenManesVersions(): DependencyUpdatesTask =
tasks.maybeCreate("dependencyUpdates", DependencyUpdatesTask::class.java).also { task: DependencyUpdatesTask ->
task.checkForGradleUpdate = true
task.outputFormatter = "json"
}

val benManesVersions: DependencyUpdatesTask =
tasks.maybeCreate("dependencyUpdates", DependencyUpdatesTask::class.java)

benManesVersions.outputFormatter = "json"
benManesVersions.checkForGradleUpdate = true
benManesVersions.resolutionStrategy {

componentSelection {
all {
if (rejectedKeywordsRegexps.any { it.matches(candidate.version) }) {
reject("Release candidate")
}
}
}

}
return benManesVersions
}
}
27 changes: 21 additions & 6 deletions plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.fayard

import com.squareup.kotlinpoet.CodeBlock
import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.tasks.Input
Expand All @@ -11,12 +11,20 @@ import org.gradle.kotlin.dsl.getByType
@Suppress("UnstableApiUsage")
open class BuildSrcVersionsTask : DefaultTask() {

fun configure(action: Action<BuildSrcVersionsExtension>) {
this.extension = BuildSrcVersionsExtensionImpl()
action.execute(this.extension!!)
}

@Input @Optional
var extension: BuildSrcVersionsExtension? = null

@TaskAction
fun taskAction() {
val extension : BuildSrcVersionsExtension = extension ?: project.extensions.getByType()
if (extension.indent == PluginConfig.DEFAULT_INDENT) {
extension.indent = EditorConfig.findIndentForKotlin(project.file("buildSrc/src/main/kotlin")) ?: " "
}
println("""
|Plugin configuration: $extension
|See documentation at ${PluginConfig.issue53PluginConfiguration}
Expand Down Expand Up @@ -49,20 +57,25 @@ open class BuildSrcVersionsTask : DefaultTask() {
checkIfFilesExistInitiallyAndCreateThem(project)
}

val kotlinPoetry: KotlinPoetry = kotlinpoet(dependencies, dependencyGraph.gradle, extension)
val sortedDependencies = when {
OutputFile.VERSIONS.existed -> dependencies
else -> dependencies.sortedByDescending { it.versionName.length }
}

val kotlinPoetry: KotlinPoetry = kotlinpoet(sortedDependencies, dependencyGraph.gradle, extension)

if (generatesAll) {
kotlinPoetry.Libs.writeTo(outputDir)
OutputFile.LIBS.logFileWasModified()
OutputFile.logFileWasModified(OutputFile.LIBS.path, OutputFile.LIBS.existed)
}

kotlinPoetry.Versions.writeTo(outputDir)
OutputFile.VERSIONS.logFileWasModified()
OutputFile.logFileWasModified(OutputFile.VERSIONS.path, OutputFile.VERSIONS.existed)

val file = extension.versionsOnlyFile?.let { project.file(it) }
if (file != null && generatesAll.not()) {
project.file(OutputFile.VERSIONS.path).renameTo(file)
println("File $file updated")
OutputFile.logFileWasModified(file.relativeTo(project.projectDir).path, existed = true)
}
}

Expand All @@ -71,6 +84,8 @@ open class BuildSrcVersionsTask : DefaultTask() {
val file = extension.versionsOnlyFile?.let { project.file(it) }
val projectUseKotlin = project.file("build.gradle.kts").exists()
regenerateBuildFile(file, extension, dependencies, projectUseKotlin)
if (file != null) OutputFile.logFileWasModified(file.relativeTo(project.projectDir).path, existed = true)

}

fun checkIfFilesExistInitiallyAndCreateThem(project: Project) {
Expand All @@ -90,7 +105,7 @@ open class BuildSrcVersionsTask : DefaultTask() {
for ((outputFile, initialContent) in initializationMap) {
if (outputFile.existed.not()) {
project.file(outputFile.path).writeText(initialContent)
outputFile.logFileWasModified()
OutputFile.logFileWasModified(outputFile.path, outputFile.existed)
}
}
}
Expand Down
100 changes: 100 additions & 0 deletions plugin/src/main/kotlin/de/fayard/EditorConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package de.fayard

import java.io.File

data class Section(val name: String, val lines: MutableList<Pair<String, String>>) {
operator fun get(key: String): String? {
return lines.firstOrNull { it.first == key }?.second
}
}

object EditorConfig {
const val NAME = ".editorconfig"
const val INDENT_STYLE = "indent_style"
const val INDENT_SIZE = "indent_size"
const val SPACE = "space"
const val TAB = "tab"

fun findIndentForKotlin(fromDir: File) : String? {
return findEditorConfig(fromDir)
.flatMap { file -> file.parseSections() }
.findIndentForKotlinFiles()
}

fun List<Section>.findIndentForKotlinFiles() : String? {
val section = this.sortedByDescending { it.priority() }
.filter { s ->
s[INDENT_STYLE] != null && s.priority() > 0
}.firstOrNull()
return section?.findIndent()
}

fun Section.findIndent() : String? {
val size = this[INDENT_SIZE]?.toIntOrNull()
val style = this[INDENT_STYLE]
return when {
style == TAB -> "\t"
style == SPACE && size != null -> List(size) { " " }.joinToString(separator = "")
else -> null
}
}


fun File.isRootEditorConfig() : Boolean = when {
name != NAME -> false
this.exists().not() -> false
else -> readLines().any { it.replace(" ", "").contains("root=true") }
}

fun Section.priority() = when {
name.contains("kt") -> 4
name.contains("gradle") -> 3
name.contains("java") -> 2
name == "*" -> 1
else -> -1
}

fun File.parseSections(): List<Section> {
assert(name == NAME)
assert(canRead())
val result = mutableListOf<Section>()
var currentSection: Section? = null
readLines().map { line ->
line.substringBefore("#").substringBefore(";")
}.forEach { line ->
val section = line.parseSection()
val split = line.split("=").map { it.trim() }
when {
section != null -> {
currentSection = Section(section, mutableListOf())
result.add(currentSection!!)
}
currentSection == null || line.isBlank() || split.size != 2 -> { }
else -> currentSection!!.lines.add(split.first() to split.last())
}
}
return result
}

fun String.parseSection() : String? {
val section = this.substringAfter("[", "").substringBefore("]", "").trim()
return if (section.isBlank()) null else section
}

fun findEditorConfig(fromDir: File) : List<File> {
val result = mutableListOf<File>()
var current: File? = fromDir
while (current != null) {
val ec = current.resolve(NAME)
if (ec.exists()) {
assert(ec.name == NAME)
result += ec
}
if (ec.isRootEditorConfig()) {
break
}
current = current.parentFile
}
return result
}
}
Loading

0 comments on commit ccfabd4

Please sign in to comment.