From ba8b8af5bfeda75ace3ff3359083afc57486aec2 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 07:50:25 +0200 Subject: [PATCH 01/30] simplify: focus on refreshVersions #104 --- composite/build.gradle.kts | 10 +- composite/settings.gradle.kts | 2 +- plugin/build.gradle.kts | 10 +- plugin/gradle.properties | 2 +- .../de/fayard/BuildSrcVersionsPlugin.kt | 2 - .../kotlin/de/fayard/BuildSrcVersionsTask.kt | 77 +------ .../kotlin/de/fayard/internal/KotlinPoetry.kt | 138 +------------ .../kotlin/de/fayard/internal/PluginConfig.kt | 32 +-- sample-groovy/buildSrc/.gitignore | 3 - sample-groovy/buildSrc/build.gradle | 4 - .../buildSrc/src/main/kotlin/Libs.kt | 27 --- .../buildSrc/src/main/kotlin/Versions.kt | 29 --- sample-groovy/gradle.properties | 4 +- sample-kotlin/build.gradle.kts | 1 + sample-kotlin/buildSrc/.gitignore | 3 - sample-kotlin/buildSrc/build.gradle.kts | 11 - .../buildSrc/src/main/kotlin/Libs.kt | 53 ----- .../buildSrc/src/main/kotlin/Versions.kt | 31 --- sample-kotlin/gradle.properties | 4 +- sample-versionsOnlyMode/GROOVY_DEF.gradle | 16 -- sample-versionsOnlyMode/GROOVY_EXT.gradle | 18 -- sample-versionsOnlyMode/KOTLIN_OBJECT.kt | 27 --- sample-versionsOnlyMode/KOTLIN_VAL.gradle.kts | 16 -- sample-versionsOnlyMode/build.gradle.kts | 91 --------- sample-versionsOnlyMode/gradle.properties | 25 --- sample-versionsOnlyMode/gradle/myversions.kt | 29 --- .../gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - sample-versionsOnlyMode/gradlew | 188 ------------------ sample-versionsOnlyMode/gradlew.bat | 100 ---------- sample-versionsOnlyMode/report.json | 87 -------- sample-versionsOnlyMode/settings.gradle.kts | 26 --- 32 files changed, 16 insertions(+), 1055 deletions(-) delete mode 100644 sample-groovy/buildSrc/.gitignore delete mode 100644 sample-groovy/buildSrc/build.gradle delete mode 100644 sample-groovy/buildSrc/src/main/kotlin/Libs.kt delete mode 100644 sample-groovy/buildSrc/src/main/kotlin/Versions.kt delete mode 100644 sample-kotlin/buildSrc/.gitignore delete mode 100644 sample-kotlin/buildSrc/build.gradle.kts delete mode 100644 sample-kotlin/buildSrc/src/main/kotlin/Libs.kt delete mode 100644 sample-kotlin/buildSrc/src/main/kotlin/Versions.kt delete mode 100644 sample-versionsOnlyMode/GROOVY_DEF.gradle delete mode 100644 sample-versionsOnlyMode/GROOVY_EXT.gradle delete mode 100644 sample-versionsOnlyMode/KOTLIN_OBJECT.kt delete mode 100644 sample-versionsOnlyMode/KOTLIN_VAL.gradle.kts delete mode 100644 sample-versionsOnlyMode/build.gradle.kts delete mode 100644 sample-versionsOnlyMode/gradle.properties delete mode 100644 sample-versionsOnlyMode/gradle/myversions.kt delete mode 100644 sample-versionsOnlyMode/gradle/wrapper/gradle-wrapper.jar delete mode 100644 sample-versionsOnlyMode/gradle/wrapper/gradle-wrapper.properties delete mode 100755 sample-versionsOnlyMode/gradlew delete mode 100644 sample-versionsOnlyMode/gradlew.bat delete mode 100644 sample-versionsOnlyMode/report.json delete mode 100644 sample-versionsOnlyMode/settings.gradle.kts diff --git a/composite/build.gradle.kts b/composite/build.gradle.kts index 01f159b92..3b5e3706c 100644 --- a/composite/build.gradle.kts +++ b/composite/build.gradle.kts @@ -10,9 +10,8 @@ defaultTasks("run") val PLUGIN: IncludedBuild = gradle.includedBuild("plugin") val SAMPLE_KOTLIN: IncludedBuild = gradle.includedBuild("sample-kotlin") val SAMPLE_GROOVY: IncludedBuild = gradle.includedBuild("sample-groovy") -val SAMPLE_VERSIONS_ONLY: IncludedBuild = gradle.includedBuild("sample-versionsOnlyMode") +val SAMPLE_ANDROID: IncludedBuild = gradle.includedBuild("sample-android") val REFRESH_VERSIONS = ":refreshVersions" -val BUILD_SRC_VERSIONS = ":buildSrcVersions" val CUSTOM = "custom" tasks.register("publishLocally") { @@ -44,14 +43,11 @@ tasks.register("pluginTests") { tasks.register("checkAll") { group = CUSTOM description = "Run all checks" - dependsOn(SAMPLE_VERSIONS_ONLY.task(REFRESH_VERSIONS)) + dependsOn(SAMPLE_ANDROID.task(REFRESH_VERSIONS)) dependsOn(SAMPLE_KOTLIN.task(REFRESH_VERSIONS)) dependsOn(SAMPLE_GROOVY.task(REFRESH_VERSIONS)) - dependsOn(SAMPLE_KOTLIN.task(BUILD_SRC_VERSIONS)) - dependsOn(SAMPLE_GROOVY.task(BUILD_SRC_VERSIONS)) dependsOn(PLUGIN.task(":validateTaskProperties")) dependsOn(PLUGIN.task(":check")) - dependsOn(SAMPLE_VERSIONS_ONLY.task(":checkAll")) } @@ -62,7 +58,7 @@ tasks.register("updateGradle") { dependsOn(PLUGIN.task(":wrapper")) dependsOn(SAMPLE_KOTLIN.task(":wrapper")) dependsOn(SAMPLE_GROOVY.task(":wrapper")) - dependsOn(SAMPLE_VERSIONS_ONLY.task(":wrapper")) + dependsOn(SAMPLE_ANDROID.task(":wrapper")) } tasks.withType { diff --git a/composite/settings.gradle.kts b/composite/settings.gradle.kts index be148fe6f..92826cfb5 100644 --- a/composite/settings.gradle.kts +++ b/composite/settings.gradle.kts @@ -2,4 +2,4 @@ rootProject.name = "buildSrcVersions-composite" includeBuild("../plugin") includeBuild("../sample-kotlin") includeBuild("../sample-groovy") -includeBuild("../sample-versionsOnlyMode") +includeBuild("../sample-android") diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 6cab9647a..29c6a1273 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -11,18 +11,12 @@ plugins { } -version = "0.7.1" // plugin.de.fayard.refreshversions +version = "0.8.0" // plugin.de.fayard.refreshversions group = "de.fayard" gradlePlugin { plugins { - create("buildSrcVersions") { - id = "de.fayard.buildSrcVersions" - displayName = "./gradlew buildSrcVersions" - description = "Painless dependencies management" - implementationClass = "de.fayard.BuildSrcVersionsPlugin" - } create("refreshVersions") { id = "de.fayard.refreshVersions" displayName = "./gradlew refreshVersions" @@ -63,8 +57,6 @@ dependencies { implementation("com.squareup.okio:okio:2.1.0") implementation( "com.squareup.moshi:moshi:1.7.0") - implementation("com.squareup:kotlinpoet:1.3.0") - } diff --git a/plugin/gradle.properties b/plugin/gradle.properties index 79136c599..12a3f8324 100644 --- a/plugin/gradle.properties +++ b/plugin/gradle.properties @@ -3,7 +3,7 @@ # See https://github.com/jmfayard/buildSrcVersions/issues/77 plugin.org.gradle.kotlin.kotlin.dsl=1.2.9 # available=1.3.1 -plugin.de.fayard.refreshVersions=0.7.0 +plugin.de.fayard.refreshVersions=0.8.0 plugin.com.gradle.plugin-publish=0.10.0 # available=0.10.1 plugin.com.gradle.build-scan=2.4.1 diff --git a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt index 97ca6d062..e8356c538 100644 --- a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt +++ b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt @@ -34,7 +34,6 @@ open class BuildSrcVersionsPlugin : Plugin { configureGradleVersions = { operation -> provider.configure(operation) } configureGradleVersions(DependencyUpdatesTask::configureBenManesVersions) - tasks.register(BUILD_SRC_VERSIONS, BuildSrcVersionsTask::class.java, BuildSrcVersionsTask::configureBuildSrcVersions) tasks.register(REFRESH_VERSIONS, BuildSrcVersionsTask::class.java, BuildSrcVersionsTask::configureRefreshVersions) } else { @@ -42,7 +41,6 @@ open class BuildSrcVersionsPlugin : Plugin { configureGradleVersions = { operation -> dependencyUpdatesTask.operation() } configureGradleVersions(DependencyUpdatesTask::configureBenManesVersions) - tasks.create(BUILD_SRC_VERSIONS, BuildSrcVersionsTask::class, BuildSrcVersionsTask::configureBuildSrcVersions) tasks.create(REFRESH_VERSIONS, BuildSrcVersionsTask::class, BuildSrcVersionsTask::configureRefreshVersions) } } diff --git a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt index 9007ee587..80d51d5e1 100644 --- a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt +++ b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt @@ -5,13 +5,10 @@ import de.fayard.VersionsOnlyMode.KOTLIN_OBJECT import de.fayard.internal.BuildSrcVersionsExtensionImpl import de.fayard.internal.Dependency import de.fayard.internal.DependencyGraph -import de.fayard.internal.EditorConfig -import de.fayard.internal.KotlinPoetry import de.fayard.internal.OutputFile import de.fayard.internal.PluginConfig import de.fayard.internal.UpdateGradleProperties import de.fayard.internal.UpdateVersionsOnly.regenerateBuildFile -import de.fayard.internal.kotlinpoet import de.fayard.internal.parseGraph import de.fayard.internal.sortedBeautifullyBy import org.gradle.api.Action @@ -21,7 +18,6 @@ import org.gradle.api.tasks.Optional import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.options.Option import org.gradle.kotlin.dsl.getByType -import java.io.File @Suppress("UnstableApiUsage") open class BuildSrcVersionsTask : DefaultTask() { @@ -35,73 +31,13 @@ open class BuildSrcVersionsTask : DefaultTask() { @Option(description = "Tabs or Spaces?") var indent: String? = null - @TaskAction - fun taskActionInitializeBuildSrc() { - val extension: BuildSrcVersionsExtensionImpl = extension() - if (extension.shouldInitializeBuildSrc().not()) return - - project.file(OutputFile.OUTPUTDIR.path).also { - if (it.isDirectory.not()) it.mkdirs() - } - for (output in OutputFile.values()) { - output.existed = output.fileExists(project) - } - val initializationMap = mapOf( - OutputFile.BUILD to PluginConfig.INITIAL_BUILD_GRADLE_KTS, - OutputFile.GIT_IGNORE to PluginConfig.INITIAL_GITIGNORE - ) - for ((outputFile, initialContent) in initializationMap) { - if (outputFile.existed.not()) { - project.file(outputFile.path).writeText(initialContent) - OutputFile.logFileWasModified(outputFile.path, outputFile.existed) - } - } - } - - - @TaskAction - fun taskActionUpdateBuildSrc() { - val extension: BuildSrcVersionsExtensionImpl = extension() - val outputDir = project.file(OutputFile.OUTPUTDIR.path) - val shouldGenerateLibsKt = when(extension.versionsOnlyMode) { - null -> true - KOTLIN_OBJECT -> false - else -> return - } - val versions = unsortedParsedDependencies.sortedBeautifullyBy(extension.orderBy) { it.versionName } - - val kotlinPoetry: KotlinPoetry = kotlinpoet(versions, dependencyGraph.gradle, extension, computeIndent()) - - if (shouldGenerateLibsKt) { - kotlinPoetry.Libs.writeTo(outputDir) - OutputFile.logFileWasModified(OutputFile.LIBS.path, OutputFile.LIBS.existed) - } - - if (PluginConfig.useRefreshVersions.not()) { - kotlinPoetry.Versions.writeTo(outputDir) - OutputFile.logFileWasModified(OutputFile.VERSIONS.path, OutputFile.VERSIONS.existed) - } - - val renamedVersionsKt: File? = when(extension.versionsOnlyMode to extension.versionsOnlyFile) { - null to null -> null - KOTLIN_OBJECT to null -> null - else -> project.file(extension.versionsOnlyFile!!) - } - - if (renamedVersionsKt != null) { - project.file(OutputFile.VERSIONS.path).renameTo(renamedVersionsKt) - OutputFile.logFileWasModified(renamedVersionsKt.relativeTo(project.projectDir).path, existed = true) - } - } - - @TaskAction fun taskActionGradleProperties() { val extension: BuildSrcVersionsExtensionImpl = extension() val updateGradleProperties = UpdateGradleProperties(extension) val specialDependencies = - listOf(PluginConfig.gradleVersionsPlugin, PluginConfig.buildSrcVersionsPlugin, PluginConfig.gradleLatestVersion(dependencyGraph)) + listOf(PluginConfig.gradleVersionsPlugin, PluginConfig.gradleRefreshVersions, PluginConfig.gradleLatestVersion(dependencyGraph)) val versionsOnlyMode = when(val mode = extension.versionsOnlyMode) { null, KOTLIN_OBJECT -> return @@ -158,18 +94,7 @@ open class BuildSrcVersionsTask : DefaultTask() { PluginConfig.useRefreshVersions = project.hasProperty("plugin.de.fayard.buildSrcVersions") || project.hasProperty("plugin.de.refreshVersions") } - private fun computeIndent(): String { - val fromEditorConfig = EditorConfig.findIndentForKotlin(project.file("buildSrc/src/main/kotlin")) - val computedIndent = indent ?: extension().indent ?: fromEditorConfig ?: PluginConfig.DEFAULT_INDENT - return if (computedIndent.isBlank()) computedIndent else PluginConfig.DEFAULT_INDENT - } private fun extension(): BuildSrcVersionsExtensionImpl = _extension - fun BuildSrcVersionsExtension.shouldInitializeBuildSrc() = when(versionsOnlyMode) { - null -> true - KOTLIN_OBJECT -> false - else -> false - } - } diff --git a/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt b/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt index 81bb550b2..a60a49226 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt @@ -1,68 +1,10 @@ package de.fayard.internal -import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.FileSpec -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.PropertySpec -import com.squareup.kotlinpoet.TypeSpec -import com.squareup.kotlinpoet.asClassName -import de.fayard.BuildSrcVersionsExtension import de.fayard.OrderBy -import de.fayard.OrderBy.* -import org.gradle.plugin.use.PluginDependenciesSpec -import org.gradle.plugin.use.PluginDependencySpec +import de.fayard.OrderBy.GROUP_AND_ALPHABETICAL +import de.fayard.OrderBy.GROUP_AND_LENGTH -fun kotlinpoet( - versions: List, - gradleConfig: GradleConfig, - extension: BuildSrcVersionsExtension, - indent: String -): KotlinPoetry { - - - val gradleVersion = constStringProperty( - PluginConfig.GRADLE_LATEST_VERSION, - gradleConfig.current.version, - CodeBlock.of(PluginConfig.gradleKdoc(gradleConfig.running.version)) - ) - - val versionsProperties: List = versions - .distinctBy { it.versionName } - .map(Dependency::generateVersionProperty) + gradleVersion - - val libsProperties: List = versions - .distinctBy { it.escapedName } - .map { it.generateLibsProperty(extension) } - - val Versions: TypeSpec = TypeSpec.objectBuilder(extension.renameVersions) - .addKdoc(PluginConfig.KDOC_VERSIONS) - .addProperties(versionsProperties) - .build() - - - val Libs = TypeSpec.objectBuilder(extension.renameLibs) - .addKdoc(PluginConfig.KDOC_LIBS) - .addProperties(libsProperties) - .build() - - - val LibsFile = FileSpec.builder("", extension.renameLibs) - .indent(indent) - .addType(Libs) - .build() - - val VersionsFile = FileSpec.builder("", extension.renameVersions) - .indent(indent) - .addType(Versions) - .apply { addMaybeBuildSrcVersions(versions, extension) } - .build() - - return KotlinPoetry(Libs = LibsFile, Versions = VersionsFile) - -} - // https://github.com/jmfayard/buildSrcVersions/issues/65 fun List.sortedBeautifullyBy(orderBy: OrderBy, selection: (Dependency) -> String?) : List { val unsorted = this.filterNot { selection(it) == null } @@ -73,28 +15,6 @@ fun List.sortedBeautifullyBy(orderBy: OrderBy, selection: (Dependenc } } -fun FileSpec.Builder.addMaybeBuildSrcVersions(versions: List, extension: BuildSrcVersionsExtension) { - versions.firstOrNull { - it.name in listOf("de.fayard.buildSrcVersions.gradle.plugin", "buildSrcVersions-plugin") - }?.let { buildSrcVersionsDependency -> - val pluginAccessorForBuildSrcVersions = pluginProperty( - id = "de.fayard.buildSrcVersions", - property = "buildSrcVersions", - dependency = buildSrcVersionsDependency, - kdoc = CodeBlock.of(PluginConfig.issue47UpdatePlugin), - extension = extension - ) - addProperty(pluginAccessorForBuildSrcVersions) - } -} - -fun Dependency.generateVersionProperty(): PropertySpec { - return constStringProperty( - name = versionName, - initializer = CodeBlock.of("%S%L", version, versionInformation()) - ) -} - fun Dependency.versionInformation(): String { val newerVersion = newerVersion() val comment = when { @@ -116,27 +36,6 @@ fun Dependency.newerVersion(): String? = else -> null }?.trim() -fun Dependency.generateLibsProperty(extension: BuildSrcVersionsExtension): PropertySpec { - val libValue = when { - version == "none" -> CodeBlock.of("%S", "$group:$name") - PluginConfig.useRefreshVersions -> CodeBlock.of("%S", "$group:$name:$version") - else -> CodeBlock.of("%S + ${extension.renameVersions}.%L", "$group:$name:", versionName) - } - - val libComment = when { - projectUrl == null -> null - PluginConfig.useRefreshVersions -> null - else -> CodeBlock.of("%L", this.projectUrl) - } - - return constStringProperty( - name = escapedName, - initializer = libValue, - kdoc = libComment - ) - -} - fun parseGraph( graph: DependencyGraph, @@ -182,36 +81,3 @@ fun List.findCommonVersions(): List { } return this } - -fun constStringProperty(name: String, initializer: CodeBlock, kdoc: CodeBlock? = null) = - PropertySpec.builder(name, String::class) - .addModifiers(KModifier.CONST) - .initializer(initializer) - .apply { - if (kdoc != null) addKdoc(kdoc) - }.build() - -fun pluginProperty( - id: String, - property: String, - dependency: Dependency, - kdoc: CodeBlock? = null, - extension: BuildSrcVersionsExtension -): PropertySpec { - val type = PluginDependencySpec::class.asClassName() - return PropertySpec.builder(property, type) - .apply { if (kdoc!= null) addKdoc(kdoc) } - .receiver(PluginDependenciesSpec::class.asClassName()) - .getter( - FunSpec.getterBuilder() - .addModifiers(KModifier.INLINE) - .addStatement("return id(%S).version(${extension.renameVersions}.%L)", id, dependency.versionName) - .build() - ) - .build() -} - -fun constStringProperty(name: String, initializer: String, kdoc: CodeBlock? = null) = - constStringProperty(name, CodeBlock.of("%S", initializer), kdoc) - - diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt index 534e36501..6595916ac 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt @@ -16,14 +16,13 @@ object PluginConfig { const val PLUGIN_ID = "de.fayard.refreshVersions" - const val PLUGIN_VERSION = "0.7.0" // plugin.de.fayard.refreshVersions + const val PLUGIN_VERSION = "0.8.0" // plugin.de.fayard.refreshVersions const val GRADLE_VERSIONS_PLUGIN_ID = "com.github.ben-manes.versions" const val GRADLE_VERSIONS_PLUGIN_VERSION = "0.25.0" // Sync with plugin/build.gradle.kts const val EXTENSION_NAME = "buildSrcVersions" const val DEPENDENCY_UPDATES = "dependencyUpdates" const val DEPENDENCY_UPDATES_PATH = ":$DEPENDENCY_UPDATES" const val REFRESH_VERSIONS = "refreshVersions" - const val BUILD_SRC_VERSIONS = EXTENSION_NAME /** There is no standard on how to name stable and unstable versions * This version is a good starting point but you can define you rown @@ -133,33 +132,6 @@ object PluginConfig { |$issue19UpdateGradle """.trimMargin() - val KDOC_LIBS = """ - |Generated by $buildSrcVersionsUrl - | - |Update this file with - | `$ ./gradlew buildSrcVersions` - """.trimMargin() - - val KDOC_VERSIONS = """ - |Generated by $buildSrcVersionsUrl - | - |Find which updates are available by running - | `$ ./gradlew buildSrcVersions` - |This will only update the comments. - | - |YOU are responsible for updating manually the dependency version. - """.trimMargin() - - - val INITIAL_BUILD_GRADLE_KTS = """ - |plugins { - | `kotlin-dsl` - |} - |repositories { - | mavenCentral() - |} - """.trimMargin() - val moshi: Moshi = Moshi.Builder().build() @@ -218,7 +190,7 @@ object PluginConfig { available = null ) - val buildSrcVersionsPlugin: Dependency = Dependency( + val gradleRefreshVersions: Dependency = Dependency( group = "de.fayard", name = "$PLUGIN_ID.gradle.plugin", version = PLUGIN_VERSION, diff --git a/sample-groovy/buildSrc/.gitignore b/sample-groovy/buildSrc/.gitignore deleted file mode 100644 index ea958e573..000000000 --- a/sample-groovy/buildSrc/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ - -.gradle/ -build/ diff --git a/sample-groovy/buildSrc/build.gradle b/sample-groovy/buildSrc/build.gradle deleted file mode 100644 index acf913e6a..000000000 --- a/sample-groovy/buildSrc/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ - -repositories { - mavenCentral() -} diff --git a/sample-groovy/buildSrc/src/main/kotlin/Libs.kt b/sample-groovy/buildSrc/src/main/kotlin/Libs.kt deleted file mode 100644 index 6f9178399..000000000 --- a/sample-groovy/buildSrc/src/main/kotlin/Libs.kt +++ /dev/null @@ -1,27 +0,0 @@ -import kotlin.String - -/** - * Generated by https://github.com/jmfayard/buildSrcVersions - * - * Update this file with - * `$ ./gradlew buildSrcVersions` - */ -object Libs { - const val androidx_annotation_annotation: String = "androidx.annotation:annotation:" + - Versions.androidx_annotation_annotation - - const val org_jetbrains_annotation: String = "org.jetbrains:annotation:" + - Versions.org_jetbrains_annotation - - /** - * http://code.google.com/p/google-guice/ - */ - const val com_google_inject_guice: String = "com.google.inject:guice:" + - Versions.com_google_inject_guice - - const val com_gradle_build_scan_gradle_plugin: String = - "com.gradle.build-scan:com.gradle.build-scan.gradle.plugin:" + - Versions.com_gradle_build_scan_gradle_plugin - - const val guava: String = "com.google.guava:guava:" + Versions.guava -} diff --git a/sample-groovy/buildSrc/src/main/kotlin/Versions.kt b/sample-groovy/buildSrc/src/main/kotlin/Versions.kt deleted file mode 100644 index 12b6b38e4..000000000 --- a/sample-groovy/buildSrc/src/main/kotlin/Versions.kt +++ /dev/null @@ -1,29 +0,0 @@ -import kotlin.String - -/** - * Generated by https://github.com/jmfayard/buildSrcVersions - * - * Find which updates are available by running - * `$ ./gradlew buildSrcVersions` - * This will only update the comments. - * - * YOU are responsible for updating manually the dependency version. - */ -object Versions { - const val androidx_annotation_annotation: String = "1.1.0" - - const val org_jetbrains_annotation: String = "17.0.0" - - const val com_google_inject_guice: String = "2.0" - - const val com_gradle_build_scan_gradle_plugin: String = "2.4.2" - - const val guava: String = "15.0" - - /** - * Current version: "5.6.2" - * See issue 19: How to update Gradle itself? - * https://github.com/jmfayard/buildSrcVersions/issues/19 - */ - const val gradleLatestVersion: String = "5.6.2" -} diff --git a/sample-groovy/gradle.properties b/sample-groovy/gradle.properties index 7fafd20a7..e376e3751 100644 --- a/sample-groovy/gradle.properties +++ b/sample-groovy/gradle.properties @@ -8,10 +8,10 @@ resolutionStrategyConfig=verbose # You can edit the rest of the file, it will be kept intact # See https://github.com/jmfayard/buildSrcVersions/issues/77 plugin.com.github.ben-manes.versions=0.25.0 -plugin.de.fayard.refreshVersions=0.7.0 +plugin.de.fayard.refreshVersions=0.8.0 plugin.com.gradle.build-scan=2.4.2 version.androidx.annotation..annotation=1.1.0 version.org.jetbrains..annotation=17.0.0 version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 -version.guava=15.0 \ No newline at end of file +version.guava=15.0 diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts index 37c2473e6..85d1c112b 100644 --- a/sample-kotlin/build.gradle.kts +++ b/sample-kotlin/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { implementation("com.squareup.okhttp3:okhttp-urlconnection:3.10.0") implementation(kotlin("stdlib-jdk8")) implementation("org.mongodb:mongo-java-driver:3.11.0") + } tasks.register("run", JavaExec::class.java) { diff --git a/sample-kotlin/buildSrc/.gitignore b/sample-kotlin/buildSrc/.gitignore deleted file mode 100644 index ea958e573..000000000 --- a/sample-kotlin/buildSrc/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ - -.gradle/ -build/ diff --git a/sample-kotlin/buildSrc/build.gradle.kts b/sample-kotlin/buildSrc/build.gradle.kts deleted file mode 100644 index 19b9a9a45..000000000 --- a/sample-kotlin/buildSrc/build.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ - -plugins { - `kotlin-dsl` -} -repositories { - jcenter() -} - -kotlinDslPluginOptions { - experimentalWarning.set(false) -} diff --git a/sample-kotlin/buildSrc/src/main/kotlin/Libs.kt b/sample-kotlin/buildSrc/src/main/kotlin/Libs.kt deleted file mode 100644 index b0ce77de2..000000000 --- a/sample-kotlin/buildSrc/src/main/kotlin/Libs.kt +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Generated by https://github.com/jmfayard/buildSrcVersions - * - * Update this file with - * `$ ./gradlew buildSrcVersions` - */ -object Libs { - /** - * https://github.com/square/okhttp - */ - const val okhttp: String = "com.squareup.okhttp3:okhttp:" + Versions.com_squareup_okhttp3 - - /** - * https://github.com/square/okhttp - */ - const val okhttp_urlconnection: String = "com.squareup.okhttp3:okhttp-urlconnection:" + - Versions.com_squareup_okhttp3 - - /** - * https://kotlinlang.org/ - */ - const val kotlin_scripting_compiler_embeddable: String = - "org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_stdlib_jdk8: String = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:" + - Versions.org_jetbrains_kotlin - - /** - * http://www.mongodb.org - */ - const val org_mongodb_mongo_java_driver: String = "org.mongodb:mongo-java-driver:" + - Versions.org_mongodb_mongo_java_driver - - /** - * http://code.google.com/p/google-guice/ - */ - const val com_google_inject_guice: String = "com.google.inject:guice:" + - Versions.com_google_inject_guice - - const val org_jetbrains_kotlin_jvm_gradle_plugin: String = - "org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:" + - Versions.org_jetbrains_kotlin_jvm_gradle_plugin - - const val com_gradle_build_scan_gradle_plugin: String = - "com.gradle.build-scan:com.gradle.build-scan.gradle.plugin:" + - Versions.com_gradle_build_scan_gradle_plugin - - const val guava: String = "com.google.guava:guava:" + Versions.guava -} diff --git a/sample-kotlin/buildSrc/src/main/kotlin/Versions.kt b/sample-kotlin/buildSrc/src/main/kotlin/Versions.kt deleted file mode 100644 index 5c0ed34df..000000000 --- a/sample-kotlin/buildSrc/src/main/kotlin/Versions.kt +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Generated by https://github.com/jmfayard/buildSrcVersions - * - * Find which updates are available by running - * `$ ./gradlew buildSrcVersions` - * This will only update the comments. - * - * YOU are responsible for updating manually the dependency version. - */ -object Versions { - const val com_squareup_okhttp3: String = "4.2.0" - - const val org_jetbrains_kotlin: String = "1.3.50" - - const val org_mongodb_mongo_java_driver: String = "3.11.0" - - const val com_google_inject_guice: String = "2.0" - - const val org_jetbrains_kotlin_jvm_gradle_plugin: String = "1.3.50" - - const val com_gradle_build_scan_gradle_plugin: String = "2.4.2" - - const val guava: String = "15.0" - - /** - * Current version: "5.6.2" - * See issue 19: How to update Gradle itself? - * https://github.com/jmfayard/buildSrcVersions/issues/19 - */ - const val gradleLatestVersion: String = "5.6.2" -} diff --git a/sample-kotlin/gradle.properties b/sample-kotlin/gradle.properties index 6c5111c35..bd22c3d69 100644 --- a/sample-kotlin/gradle.properties +++ b/sample-kotlin/gradle.properties @@ -8,7 +8,7 @@ resolutionStrategyConfig=verbose # You can edit the rest of the file, it will be kept intact # See https://github.com/jmfayard/buildSrcVersions/issues/77 plugin.com.github.ben-manes.versions=0.25.0 -plugin.de.fayard.refreshVersions=0.7.0 +plugin.de.fayard.refreshVersions=0.8.0 plugin.org.jetbrains.kotlin.jvm=1.3.50 plugin.com.gradle.build-scan=2.4.2 version.com.squareup.okhttp3=4.2.0 @@ -16,4 +16,4 @@ version.org.jetbrains.kotlin=1.3.50 version.org.mongodb..mongo-java-driver=3.11.0 version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 -version.guava=15.0 \ No newline at end of file +version.guava=15.0 diff --git a/sample-versionsOnlyMode/GROOVY_DEF.gradle b/sample-versionsOnlyMode/GROOVY_DEF.gradle deleted file mode 100644 index 19f717406..000000000 --- a/sample-versionsOnlyMode/GROOVY_DEF.gradle +++ /dev/null @@ -1,16 +0,0 @@ -// versionOnlyMode = GROOVY_DEF - -// -// Generated by ./gradle buildSrcVersions -// See https://github.com/jmfayard/buildSrcVersions/issues/54 -def org_jetbrains_kotlin = '1.3.50' -def com_github_ben_manes_versions_gradle_plugin = '0.25.0' -def de_fayard_refreshversions_gradle_plugin = '0.7.0' -def gradlelatestversion = '5.5.1' // available: '5.6.1' -def okhttp = '4.1.0' // available: '4.1.1' -def okio = '2.0.0' -def org_jetbrains_kotlin_jvm_gradle_plugin = '1.3.50' -// - - -// versionOnlyMode = GROOVY_DEF diff --git a/sample-versionsOnlyMode/GROOVY_EXT.gradle b/sample-versionsOnlyMode/GROOVY_EXT.gradle deleted file mode 100644 index b7ff82421..000000000 --- a/sample-versionsOnlyMode/GROOVY_EXT.gradle +++ /dev/null @@ -1,18 +0,0 @@ -// versionOnlyMode = GROOVY_EXT - -// -// Generated by ./gradle buildSrcVersions -// See https://github.com/jmfayard/buildSrcVersions/issues/54 -ext { - org_jetbrains_kotlin = '1.3.50' - com_github_ben_manes_versions_gradle_plugin = '0.25.0' - de_fayard_refreshversions_gradle_plugin = '0.7.0' - gradlelatestversion = '5.5.1' // available: '5.6.1' - okhttp = '4.1.0' // available: '4.1.1' - okio = '2.0.0' - org_jetbrains_kotlin_jvm_gradle_plugin = '1.3.50' -} -// - - -// versionOnlyMode = GROOVY_EXT diff --git a/sample-versionsOnlyMode/KOTLIN_OBJECT.kt b/sample-versionsOnlyMode/KOTLIN_OBJECT.kt deleted file mode 100644 index 8966a1838..000000000 --- a/sample-versionsOnlyMode/KOTLIN_OBJECT.kt +++ /dev/null @@ -1,27 +0,0 @@ -import kotlin.String - -/** - * Generated by https://github.com/jmfayard/buildSrcVersions - * - * Find which updates are available by running - * `$ ./gradlew buildSrcVersions` - * This will only update the comments. - * - * YOU are responsible for updating manually the dependency version. - */ -object Versions { - const val org_jetbrains_kotlin: String = "1.3.50" - - const val okhttp: String = "4.1.0" // available: "4.1.1" - - const val okio: String = "2.0.0" - - const val org_jetbrains_kotlin_jvm_gradle_plugin: String = "1.3.50" - - /** - * Current version: "5.5.1" - * See issue 19: How to update Gradle itself? - * https://github.com/jmfayard/buildSrcVersions/issues/19 - */ - const val gradleLatestVersion: String = "5.6.1" -} diff --git a/sample-versionsOnlyMode/KOTLIN_VAL.gradle.kts b/sample-versionsOnlyMode/KOTLIN_VAL.gradle.kts deleted file mode 100644 index c02f8665c..000000000 --- a/sample-versionsOnlyMode/KOTLIN_VAL.gradle.kts +++ /dev/null @@ -1,16 +0,0 @@ -// versionOnlyMode = KOTLIN_VAL - -// -// Generated by ./gradle buildSrcVersions -// See https://github.com/jmfayard/buildSrcVersions/issues/54 -val org_jetbrains_kotlin = "1.3.50" -val com_github_ben_manes_versions_gradle_plugin = "0.25.0" -val de_fayard_refreshversions_gradle_plugin = "0.7.0" -val gradlelatestversion = "5.5.1" // available: "5.6.1" -val okhttp = "4.1.0" // available: "4.1.1" -val okio = "2.0.0" -val org_jetbrains_kotlin_jvm_gradle_plugin = "1.3.50" -// - - -// versionOnlyMode = KOTLIN_VAL diff --git a/sample-versionsOnlyMode/build.gradle.kts b/sample-versionsOnlyMode/build.gradle.kts deleted file mode 100644 index d3661294c..000000000 --- a/sample-versionsOnlyMode/build.gradle.kts +++ /dev/null @@ -1,91 +0,0 @@ -import de.fayard.BuildSrcVersionsTask -import de.fayard.OrderBy -import de.fayard.VersionsOnlyMode -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - id("org.lovedev.greeting.kotlin") - id("de.fayard.buildSrcVersions") - id("ch.tutteli.kotlin.utils") - id("nebula.kotlin") - kotlin("jvm") - `build-scan` -} -group = "de.fayard" - -buildSrcVersions { - // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 - indent = " " - orderBy = OrderBy.GROUP_AND_ALPHABETICAL -} - -repositories { - maven { - setUrl("../plugin/src/test/resources/maven") - } - mavenCentral() -} - -dependencies { - implementation("com.google.guava:guava:15.0") - implementation("com.google.inject:guice:2.0") - implementation("com.wealthfront:magellan:+") - implementation("com.wealthfront:magellan-rx:+") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.0.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.13.0") - implementation("com.jakewharton.timber:timber:4.7.0") -} - -tasks.withType { - kotlinOptions.jvmTarget = "1.8" -} -tasks.withType { - gradleVersion = System.getenv("GRADLE_VERSION") ?: "5.6.1" - distributionType = Wrapper.DistributionType.ALL -} - -tasks.register("copyReport") { - from(".") - include("report.json") - into("build/dependencyUpdates") -} - -tasks.register("hello") { - group = "Custom" -} - -VersionsOnlyMode.values().forEach { mode -> - if (mode == VersionsOnlyMode.GRADLE_PROPERTIES) { - tasks.register(mode.name) - return@forEach - } - - tasks.register(mode.name) { - description = "buildSrcVersion - $mode" - group = "Custom" - dependsOn(":copyReport") - val filename = mode.name + "." + mode.suggestedFilename().substringAfter(".") - configure { - versionsOnlyFile = filename - versionsOnlyMode = mode - } - } -} - -tasks.register("checkAll") { - description = "versionsOnlyMode - check all modes" - group = "Custom" - dependsOn(VersionsOnlyMode.values().map { it.name }) -} - -buildScan { - setTermsOfServiceUrl("https://gradle.com/terms-of-service") - setTermsOfServiceAgree("yes") -} - -// How to update Gradle itself? https://github.com/jmfayard/buildSrcVersions/issues/19 -tasks.withType { - gradleVersion = findProperty("gradleLatestVersion") as? String ?: gradle.gradleVersion - distributionType = Wrapper.DistributionType.ALL -} diff --git a/sample-versionsOnlyMode/gradle.properties b/sample-versionsOnlyMode/gradle.properties deleted file mode 100644 index 1d35fcb2f..000000000 --- a/sample-versionsOnlyMode/gradle.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The plugin https://github.com/jmfayard/buildSrcVersions -# allows to overwrite plugin and dependencies versions from the values inside 'gradle.properties' -# Set to 'verbose' to understand how dependency and plugin versions are overwritten -# Set to 'false' to disable this feature -resolutionStrategyConfig=verbose -# Dependencies and Plugin versions with their available updates -# Generated by $ ./gradlew refreshVersions -# You can edit the rest of the file, it will be kept intact -# See https://github.com/jmfayard/buildSrcVersions/issues/77 -plugin.ch.tutteli.kotlin.utils=0.29.0 -plugin.com.github.ben-manes.versions=0.25.0 -plugin.com.gradle.build-scan=2.4.2 -plugin.de.fayard.refreshVersions=0.7.0 -plugin.nebula.kotlin=1.3.50 -plugin.org.jetbrains.kotlin.jvm=1.3.50 -plugin.org.lovedev.greeting.kotlin=1.1 -version.com.wealthfront=1.1.0 -version.org.jetbrains.kotlin=1.3.50 -version.org.jetbrains.kotlinx.kotlinx-coroutines=1.0.0 -# # available=1.3.2 -version.org.jetbrains.kotlinx.kotlinx-serialization=0.13.0 -version.gradleLatestVersion=5.6.2 -version.guava=15.0 -version.guice=2.0 -version.timber=4.7.0 \ No newline at end of file diff --git a/sample-versionsOnlyMode/gradle/myversions.kt b/sample-versionsOnlyMode/gradle/myversions.kt deleted file mode 100644 index 2a8ce4739..000000000 --- a/sample-versionsOnlyMode/gradle/myversions.kt +++ /dev/null @@ -1,29 +0,0 @@ -import kotlin.String - -/** - * Generated by https://github.com/jmfayard/buildSrcVersions - * - * Find which updates are available by running - * `$ ./gradlew buildSrcVersions` - * This will only update the comments. - * - * YOU are responsible for updating manually the dependency version. - */ -object Versions { - const val okhttp: String = "4.1.0" - - const val okio: String = "2.0.0" - - const val org_jetbrains_kotlin_jvm_gradle_plugin: String = "1.3.50" - - const val org_jetbrains_kotlin: String = "1.3.50" - - /** - * - * See issue 19: How to update Gradle itself? - * https://github.com/jmfayard/buildSrcVersions/issues/19 - */ - const val gradleLatestVersion: String = "5.6.1" - - const val gradleCurrentVersion: String = "5.5.1" -} diff --git a/sample-versionsOnlyMode/gradle/wrapper/gradle-wrapper.jar b/sample-versionsOnlyMode/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55616 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/sample-versionsOnlyMode/gradlew.bat b/sample-versionsOnlyMode/gradlew.bat deleted file mode 100644 index 24467a141..000000000 --- a/sample-versionsOnlyMode/gradlew.bat +++ /dev/null @@ -1,100 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/sample-versionsOnlyMode/report.json b/sample-versionsOnlyMode/report.json deleted file mode 100644 index 02bed4ab5..000000000 --- a/sample-versionsOnlyMode/report.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "current": { - "dependencies": [ - { - "group": "org.jetbrains.kotlin", - "version": "1.3.50", - "projectUrl": "https://kotlinlang.org/", - "name": "kotlin-scripting-compiler-embeddable" - }, - { - "group": "org.jetbrains.kotlin", - "version": "1.3.50", - "projectUrl": "https://kotlinlang.org/", - "name": "kotlin-stdlib-jdk8" - }, - { - "group": "org.jetbrains.kotlin.jvm", - "version": "1.3.50", - "projectUrl": null, - "name": "org.jetbrains.kotlin.jvm.gradle.plugin" - } - ], - "count": 3 - }, - "gradle": { - "current": { - "version": "5.6.1", - "reason": "", - "isUpdateAvailable": true, - "isFailure": false - }, - "nightly": { - "version": "", - "reason": "update check disabled", - "isUpdateAvailable": false, - "isFailure": false - }, - "enabled": true, - "releaseCandidate": { - "version": "", - "reason": "update check succeeded: no release available", - "isUpdateAvailable": false, - "isFailure": false - }, - "running": { - "version": "5.5.1", - "reason": "", - "isUpdateAvailable": false, - "isFailure": false - } - }, - "exceeded": { - "dependencies": [ - - ], - "count": 0 - }, - "outdated": { - "dependencies": [ - { - "group": "com.squareup.okhttp3", - "available": { - "release": null, - "milestone": "4.1.1", - "integration": null - }, - "version": "4.1.0", - "projectUrl": "https://github.com/square/okhttp", - "name": "okhttp" - } - ], - "count": 1 - }, - "unresolved": { - "dependencies": [ - { - "group": "com.squareup.okio", - "version": "2.0.0", - "reason": "Could not resolve com.squareup.okio:okio:+.", - "projectUrl": "2.4.0", - "name": "okio" - } - ], - "count": 1 - }, - "count": 5 -} diff --git a/sample-versionsOnlyMode/settings.gradle.kts b/sample-versionsOnlyMode/settings.gradle.kts deleted file mode 100644 index 86624e75f..000000000 --- a/sample-versionsOnlyMode/settings.gradle.kts +++ /dev/null @@ -1,26 +0,0 @@ -pluginManagement { - repositories { - mavenLocal() - gradlePluginPortal() - } - - /** - * This `resolutionStrategy` allows plugin versions to be configured from `gradle.properties - * The convention is simply - * plugin.$PLUGINID=$PLUGIN_VERSION - * To check what happen, you can set in gradle.properties the line: - * resolutionStrategyConfig=verbose - */ - val resolutionStrategyConfig: String? by extra - resolutionStrategy.eachPlugin { - val property = "plugin.${requested.id.id}" - if (extra.has(property) && resolutionStrategyConfig != "false") { - val version = extra.get(property) as String - if (resolutionStrategyConfig == "verbose") println("ResolutionStrategy selected version=$version from property=$property") - useVersion(version) - } - } -} -rootProject.name = "sample-versionsOnlyMode" -includeBuild("../plugin") - From 0731102df638111b06fef322a69beaa11807a8c0 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 08:05:23 +0200 Subject: [PATCH 02/30] simplify: remove buildSrcVersions code #104 --- .../de/fayard/BuildSrcVersionsExtension.kt | 25 +-- .../de/fayard/BuildSrcVersionsPlugin.kt | 14 +- .../kotlin/de/fayard/BuildSrcVersionsTask.kt | 20 +- .../internal/BuildSrcVersionsExtensionImpl.kt | 9 +- .../de/fayard/internal/DependencyGraph.kt | 8 - .../kotlin/de/fayard/internal/OutputFile.kt | 4 - .../de/fayard/internal/UpdateVersionsOnly.kt | 126 ------------ .../test/kotlin/de/fayard/NonRegression.kt | 35 +--- .../kotlin/de/fayard/VersionsOnlyModeTest.kt | 81 -------- plugin/src/test/resources/libs/Catchup.txt | 133 ------------- plugin/src/test/resources/libs/FastHub.txt | 77 ------- plugin/src/test/resources/libs/Kodein-DI.txt | 19 -- .../test/resources/libs/KotlinAcademyApp.txt | 79 -------- .../test/resources/libs/KotlinUnitTesting.txt | 12 -- plugin/src/test/resources/libs/SdkSearch.txt | 64 ------ .../test/resources/libs/android-sunflower.txt | 35 ---- plugin/src/test/resources/libs/http4k.txt | 50 ----- plugin/src/test/resources/libs/koin.txt | 56 ------ .../test/resources/libs/material-dialogs.txt | 16 -- .../test/resources/libs/sample-synclibs.txt | 7 - .../src/test/resources/libs/simple-stack.txt | 82 -------- plugin/src/test/resources/libs/tachiyomi.txt | 84 -------- .../versionOnly/GROOVY_DEF_validated.txt | 22 -- .../versionOnly/GROOVY_EXT_validated.txt | 24 --- .../versionOnly/KOTLIN_VAL_validated.txt | 22 -- .../resources/versionOnly/singleBuildFile.txt | 22 -- .../src/test/resources/versions/Catchup.txt | 76 ------- .../src/test/resources/versions/FastHub.txt | 48 ----- .../src/test/resources/versions/Kodein-DI.txt | 9 - .../resources/versions/KotlinAcademyApp.txt | 66 ------ .../resources/versions/KotlinUnitTesting.txt | 9 - .../src/test/resources/versions/SdkSearch.txt | 45 ----- .../resources/versions/android-sunflower.txt | 23 --- plugin/src/test/resources/versions/http4k.txt | 38 ---- plugin/src/test/resources/versions/koin.txt | 36 ---- .../resources/versions/material-dialogs.txt | 13 -- .../resources/versions/sample-synclibs.txt | 7 - .../test/resources/versions/simple-stack.txt | 64 ------ .../src/test/resources/versions/tachiyomi.txt | 68 ------- sample-android/build.gradle.kts | 71 +++++++ sample-android/gradle.properties | 25 +++ sample-android/gradle/myversions.kt | 29 +++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 55616 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + sample-android/gradlew | 188 ++++++++++++++++++ sample-android/gradlew.bat | 100 ++++++++++ sample-android/report.json | 86 ++++++++ sample-android/settings.gradle.kts | 26 +++ sample-groovy/build.gradle | 10 +- sample-kotlin/build.gradle.kts | 3 - 50 files changed, 540 insertions(+), 1631 deletions(-) delete mode 100644 plugin/src/test/kotlin/de/fayard/VersionsOnlyModeTest.kt delete mode 100644 plugin/src/test/resources/libs/Catchup.txt delete mode 100644 plugin/src/test/resources/libs/FastHub.txt delete mode 100644 plugin/src/test/resources/libs/Kodein-DI.txt delete mode 100644 plugin/src/test/resources/libs/KotlinAcademyApp.txt delete mode 100644 plugin/src/test/resources/libs/KotlinUnitTesting.txt delete mode 100644 plugin/src/test/resources/libs/SdkSearch.txt delete mode 100644 plugin/src/test/resources/libs/android-sunflower.txt delete mode 100644 plugin/src/test/resources/libs/http4k.txt delete mode 100644 plugin/src/test/resources/libs/koin.txt delete mode 100644 plugin/src/test/resources/libs/material-dialogs.txt delete mode 100644 plugin/src/test/resources/libs/sample-synclibs.txt delete mode 100644 plugin/src/test/resources/libs/simple-stack.txt delete mode 100644 plugin/src/test/resources/libs/tachiyomi.txt delete mode 100644 plugin/src/test/resources/versionOnly/GROOVY_DEF_validated.txt delete mode 100644 plugin/src/test/resources/versionOnly/GROOVY_EXT_validated.txt delete mode 100644 plugin/src/test/resources/versionOnly/KOTLIN_VAL_validated.txt delete mode 100644 plugin/src/test/resources/versionOnly/singleBuildFile.txt delete mode 100644 plugin/src/test/resources/versions/Catchup.txt delete mode 100644 plugin/src/test/resources/versions/FastHub.txt delete mode 100644 plugin/src/test/resources/versions/Kodein-DI.txt delete mode 100644 plugin/src/test/resources/versions/KotlinAcademyApp.txt delete mode 100644 plugin/src/test/resources/versions/KotlinUnitTesting.txt delete mode 100644 plugin/src/test/resources/versions/SdkSearch.txt delete mode 100644 plugin/src/test/resources/versions/android-sunflower.txt delete mode 100644 plugin/src/test/resources/versions/http4k.txt delete mode 100644 plugin/src/test/resources/versions/koin.txt delete mode 100644 plugin/src/test/resources/versions/material-dialogs.txt delete mode 100644 plugin/src/test/resources/versions/sample-synclibs.txt delete mode 100644 plugin/src/test/resources/versions/simple-stack.txt delete mode 100644 plugin/src/test/resources/versions/tachiyomi.txt create mode 100644 sample-android/build.gradle.kts create mode 100644 sample-android/gradle.properties create mode 100644 sample-android/gradle/myversions.kt create mode 100644 sample-android/gradle/wrapper/gradle-wrapper.jar create mode 100644 sample-android/gradle/wrapper/gradle-wrapper.properties create mode 100755 sample-android/gradlew create mode 100644 sample-android/gradlew.bat create mode 100644 sample-android/report.json create mode 100644 sample-android/settings.gradle.kts diff --git a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsExtension.kt b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsExtension.kt index e5a597c0f..5bdba58bb 100644 --- a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsExtension.kt +++ b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsExtension.kt @@ -47,34 +47,11 @@ interface BuildSrcVersionsExtension { ***/ fun useFqdnFor(vararg dependencyName: String) - /** - * `renameLibs = Deps` if you think that Deps.kt is much better than Libs.kt - ***/ - var renameLibs: String - - /** - * `renameVersions = "V"` if you think that V.kt is much better than Versionskt - ***/ - var renameVersions: String - - /** - * Tabs or Spaces? You choose. - * Even better, define an https://editorconfig.org file. - * It will be used if detected. - */ - var indent: String? - - /** - * Possible values: KOTLIN_VAL, KOTLIN_OBJECT, GROOVY_DEF, GROOVY_EXT, GRADLE_PROPERTIES - * See https://github.com/jmfayard/buildSrcVersions/tree/master/sample-versionsOnlyMode - **/ - var versionsOnlyMode: VersionsOnlyMode? - /** * See [versionsOnlyMode] * Probably "gradle.properties" for GRADLE_PROPERTIES, "build.gradle" for GROOVY_DEF, ... */ - var versionsOnlyFile: String? + var propertiesFile: String? /** * orderBy = OrderBy.GROUP_AND_ALPHABETICAL to override the default behavior diff --git a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt index e8356c538..a9a9168e5 100644 --- a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt +++ b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt @@ -85,18 +85,6 @@ fun BuildSrcVersionsTask.configureRefreshVersions() { dependsOn(PluginConfig.DEPENDENCY_UPDATES_PATH) outputs.upToDateWhen { false } configure { - versionsOnlyMode = VersionsOnlyMode.GRADLE_PROPERTIES - versionsOnlyFile = "gradle.properties" - } -} - -fun BuildSrcVersionsTask.configureBuildSrcVersions() { - group = "Help" - description = "Update buildSrc/src/main/kotlin/{Versions.kt,Libs.kt}" - dependsOn(PluginConfig.DEPENDENCY_UPDATES_PATH) - outputs.upToDateWhen { false } - configure { - versionsOnlyMode = null - versionsOnlyFile = null + propertiesFile = "gradle.properties" } } diff --git a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt index 80d51d5e1..923ac3aed 100644 --- a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt +++ b/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt @@ -1,14 +1,11 @@ package de.fayard -import de.fayard.VersionsOnlyMode.GRADLE_PROPERTIES -import de.fayard.VersionsOnlyMode.KOTLIN_OBJECT import de.fayard.internal.BuildSrcVersionsExtensionImpl import de.fayard.internal.Dependency import de.fayard.internal.DependencyGraph import de.fayard.internal.OutputFile import de.fayard.internal.PluginConfig import de.fayard.internal.UpdateGradleProperties -import de.fayard.internal.UpdateVersionsOnly.regenerateBuildFile import de.fayard.internal.parseGraph import de.fayard.internal.sortedBeautifullyBy import org.gradle.api.Action @@ -39,25 +36,13 @@ open class BuildSrcVersionsTask : DefaultTask() { val specialDependencies = listOf(PluginConfig.gradleVersionsPlugin, PluginConfig.gradleRefreshVersions, PluginConfig.gradleLatestVersion(dependencyGraph)) - val versionsOnlyMode = when(val mode = extension.versionsOnlyMode) { - null, KOTLIN_OBJECT -> return - else -> mode - } - val dependencies = (unsortedParsedDependencies + specialDependencies) .sortedBeautifullyBy(extension.orderBy) { it.versionProperty } .distinctBy { it.versionProperty } - if (versionsOnlyMode == GRADLE_PROPERTIES) { - updateGradleProperties.generateVersionProperties(project.file("gradle.properties"), dependencies) - OutputFile.GRADLE_PROPERTIES.logFileWasModified() + updateGradleProperties.generateVersionProperties(project.file("gradle.properties"), dependencies) + OutputFile.GRADLE_PROPERTIES.logFileWasModified() - } else { - val file = extension.versionsOnlyFile?.let { project.file(it) } - val projectUseKotlin = project.file("build.gradle.kts").exists() - regenerateBuildFile(file, versionsOnlyMode, dependencies, projectUseKotlin) - if (file != null) OutputFile.logFileWasModified(file.relativeTo(project.projectDir).path, existed = true) - } } private val dependencyGraph: DependencyGraph by lazy { @@ -72,7 +57,6 @@ open class BuildSrcVersionsTask : DefaultTask() { } println(message) - OutputFile.configure(extension) val jsonInput = project.file(PluginConfig.BENMANES_REPORT_PATH) diff --git a/plugin/src/main/kotlin/de/fayard/internal/BuildSrcVersionsExtensionImpl.kt b/plugin/src/main/kotlin/de/fayard/internal/BuildSrcVersionsExtensionImpl.kt index 1cda448c5..d744fac25 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/BuildSrcVersionsExtensionImpl.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/BuildSrcVersionsExtensionImpl.kt @@ -3,14 +3,9 @@ package de.fayard.internal import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentFilter import de.fayard.BuildSrcVersionsExtension import de.fayard.OrderBy -import de.fayard.VersionsOnlyMode internal open class BuildSrcVersionsExtensionImpl( - override var renameLibs: String = PluginConfig.DEFAULT_LIBS, - override var renameVersions: String = PluginConfig.DEFAULT_VERSIONS, - override var indent: String? = null, - override var versionsOnlyMode: VersionsOnlyMode? = null, - override var versionsOnlyFile: String? = null, + override var propertiesFile: String? = null, var useFqqnFor: List = emptyList(), var alwaysUpdateVersions: Boolean = false, override var orderBy: OrderBy = OrderBy.GROUP_AND_LENGTH @@ -18,7 +13,7 @@ internal open class BuildSrcVersionsExtensionImpl( // Necessary because of https://github.com/jmfayard/buildSrcVersions/issues/92 fun defensiveCopy(): BuildSrcVersionsExtensionImpl = BuildSrcVersionsExtensionImpl( - renameLibs, renameVersions, indent, versionsOnlyMode, versionsOnlyFile, useFqqnFor, alwaysUpdateVersions, orderBy + propertiesFile, useFqqnFor, alwaysUpdateVersions, orderBy ) override fun alwaysUpdateVersions() { diff --git a/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt b/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt index d6615005a..86a74be9c 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt @@ -1,15 +1,7 @@ package de.fayard.internal -import com.squareup.kotlinpoet.FileSpec import de.fayard.VersionsOnlyMode -data class KotlinPoetry( - val Libs: FileSpec, - val Versions: FileSpec -) - - - data class DependencyGraph( val gradle: GradleConfig, val current: Dependencies, diff --git a/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt b/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt index 292108d6d..8d54a0de2 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt @@ -22,10 +22,6 @@ internal enum class OutputFile(var path: String, var existed: Boolean = false, v } companion object { - fun configure(extension: BuildSrcVersionsExtension) { - LIBS.path = "buildSrc/src/main/kotlin/${extension.renameLibs}.kt" - VERSIONS.path = "buildSrc/src/main/kotlin/${extension.renameVersions}.kt" - } fun logFileWasModified(path: String, existed: Boolean) { val ANSI_RESET = "\u001B[0m" diff --git a/plugin/src/main/kotlin/de/fayard/internal/UpdateVersionsOnly.kt b/plugin/src/main/kotlin/de/fayard/internal/UpdateVersionsOnly.kt index 58927fd63..fcc8d1269 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/UpdateVersionsOnly.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/UpdateVersionsOnly.kt @@ -1,14 +1,10 @@ package de.fayard.internal -import de.fayard.VersionsOnlyMode -import java.io.File - object UpdateVersionsOnly { const val singleQuote = "'" const val doubleQuote = "\"" const val slashslash = "//" - const val newline = "\n" fun Dependency.asGradleProperty(): String { val pluginName = versionProperty.substringBeforeLast(".gradle.plugin", "") @@ -31,126 +27,4 @@ object UpdateVersionsOnly { return "$key=$validatedVersion$available" } - fun parseBuildFileOrNew(versionsOnlyFile: File?, versionsOnlyMode: VersionsOnlyMode, fromDir: File): Pair = when { - versionsOnlyMode == VersionsOnlyMode.GRADLE_PROPERTIES -> { - val file = versionsOnlyFile ?: fromDir.resolve("gradle.properties") - if (file.canRead().not()) file.createNewFile() - Pair(file, SingleModeResult.newFile(versionsOnlyMode)) - } - versionsOnlyFile == null || versionsOnlyFile.canRead().not() -> Pair( - fromDir.resolve(versionsOnlyMode.suggestedFilename()), - SingleModeResult.newFile(versionsOnlyMode) - ) - else -> Pair( - versionsOnlyFile, - parseBuildFile(versionsOnlyFile, versionsOnlyMode) ?: SingleModeResult.blockNotFound(versionsOnlyMode) - ) - } - - fun parseBuildFile(versionsOnlyFile: File?, versionsOnlyMode: VersionsOnlyMode): SingleModeResult? { - if (versionsOnlyFile == null || versionsOnlyFile.canRead().not()) { - return null - } - - val lines = versionsOnlyFile.readLines() - val startOfBlock = lines.indexOfFirst { - it.trim().endsWith(PluginConfig.VERSIONS_ONLY_START) - } - val endOfBlock = lines.indexOfFirst { - it.trim().endsWith(PluginConfig.VERSIONS_ONLY_END) - } - val noBlockFound = startOfBlock == -1 || endOfBlock == -1 - return when { - noBlockFound -> null - else -> { - var indent = lines[endOfBlock].substringBefore(versionsOnlyMode.comment, missingDelimiterValue = PluginConfig.SPACES4) - if (versionsOnlyMode == VersionsOnlyMode.GRADLE_PROPERTIES) indent = "" - SingleModeResult(startOfBlock, endOfBlock, indent) - } - } - } - - fun regenerateBuildFile( - versionsOnlyFile: File?, - versionsOnlyMode: VersionsOnlyMode, - sortedDependencies: List, - projectUseKotlin: Boolean = true - ) { - val (file, parseResult) = parseBuildFileOrNew(versionsOnlyFile, versionsOnlyMode, File(".")) - val (startOfBlock, endOfBlock, indent) = parseResult - - val newBlock = regenerateBlock(versionsOnlyMode, sortedDependencies, indent) - - if (parseResult.isBlockNotFound().not()) { - val lines = file.readLines() - val newLines = lines.subList(0, startOfBlock) + newBlock + lines.subList(endOfBlock + 1, lines.size) - file.writeText(newLines.joinWithNewlines() + "\n") - - } else { - val groovyOrKotlin = if (projectUseKotlin) "VersionsOnlyMode.${versionsOnlyMode}" else "\"${versionsOnlyMode}\"" - println( - """ - | - |== 📋 copy-paste needed! 📋 == - | - |Copy-paste the snippet below: - | - |${newBlock.joinWithNewlines()} - | - |in the file you configure with something like: - | - |// build.gradle(.kts) - |buildSrcVersions { - | versionsOnlyMode = $groovyOrKotlin - | versionsOnlyFile = "${versionsOnlyMode.suggestedFilename()}" - |} - | - |See ${PluginConfig.issue54VersionOnlyMode} - | """.trimMargin() - ) - println() - } - } - - fun regenerateBlock(mode: VersionsOnlyMode, dependencies: List, indent: String): List { - val comment = mode.comment - val result = mutableListOf() - val (before, after) = mode.beforeAfter() - - result += PluginConfig.VERSIONS_ONLY_INTRO.map { "$indent$comment $it" } - - before?.run { - result += "$indent$before" - } - - result += dependencies.map { versionOnly(it, mode, indent) } - - after?.run { - result += "$indent$after" - } - - result += "$indent$comment ${PluginConfig.VERSIONS_ONLY_END}" - - return result - } - - fun versionOnly(d: Dependency, mode: VersionsOnlyMode, indent: String): String { - val available = d.versionInformation() - .replace(doubleQuote, mode.quote) - .replace(slashslash, mode.comment) - .replace(newline, "") - val postIndent = if (indent.isNotBlank()) indent else PluginConfig.SPACES4 - - return when (mode) { - VersionsOnlyMode.KOTLIN_OBJECT -> throw IllegalStateException("$mode should not be handled here") - VersionsOnlyMode.GRADLE_PROPERTIES -> d.asGradleProperty() - VersionsOnlyMode.KOTLIN_VAL -> """${indent}val ${d.versionName} = "${d.version}"$available""" - VersionsOnlyMode.GROOVY_DEF -> """${indent}def ${d.versionName} = '${d.version}'$available""" - VersionsOnlyMode.GROOVY_EXT -> """${indent}${postIndent}${d.versionName} = '${d.version}'$available""" - }.trimEnd() - } - - - fun List.joinWithNewlines(): String = - this.joinToString(separator = "\n") } diff --git a/plugin/src/test/kotlin/de/fayard/NonRegression.kt b/plugin/src/test/kotlin/de/fayard/NonRegression.kt index 2be7eb7e0..986826c19 100644 --- a/plugin/src/test/kotlin/de/fayard/NonRegression.kt +++ b/plugin/src/test/kotlin/de/fayard/NonRegression.kt @@ -15,8 +15,6 @@ import java.io.File class NonRegression : FreeSpec({ val reportsFolder = testResourceFile("reports") - val libsFolder = testResourceFile("libs") - val versionsFolder = testResourceFile("versions") val propertiesFolder = testResourceFile("properties") val jsonReports = reportsFolder.walk().filter { it.extension == "json" }.toList() @@ -42,43 +40,12 @@ class NonRegression : FreeSpec({ PluginConfig.MEANING_LESS_NAMES ) - "Identifiers in Libs for file=$name" { - val libsFile = libsFolder.resolve(name) - val libsIdentifiers: List = dependencyGraph.map { it.escapedName }.sorted().distinct() - val (received, message) = receivedMessage(libsFile) - received.writeText(libsIdentifiers.joinToStringWithNewLines()) - if (libsFile.exists()) { - withClue(message) { - (libsFile.readLines() - libsIdentifiers).shouldBeEmpty() - received.delete() - } - } else { - println("Added to non-regression file ${libsFile.absolutePath}") - } - } - - "Identifiers in Versions for file=$name" { - val versionsFile = versionsFolder.resolve(name) - val versionsIdentifiers = dependencyGraph.map { it.versionName }.sorted().distinct() - val (received, message) = receivedMessage(versionsFile) - received.writeText(versionsIdentifiers.joinToStringWithNewLines()) - if (versionsFile.exists()) { - withClue(message) { - (versionsFile.readLines() - versionsIdentifiers).shouldBeEmpty() - received.delete() - } - } else { - println("Added to non-regression file ${versionsFile.absolutePath}") - } - } - "Identifiers in Properties for file=$name" { val propertiesFile = propertiesFolder.resolve(name) val (received, message) = receivedMessage(propertiesFile) val extension = BuildSrcVersionsExtensionImpl( - versionsOnlyMode = VersionsOnlyMode.GRADLE_PROPERTIES, - versionsOnlyFile = propertiesFile.relativeTo(buildSrcVersionsDir).path + propertiesFile = propertiesFile.relativeTo(buildSrcVersionsDir).path ) val dependencies = (dependencyGraph.map { it.copy(available = null) }) .sortedBeautifullyBy(OrderBy.GROUP_AND_LENGTH) { it.versionProperty } diff --git a/plugin/src/test/kotlin/de/fayard/VersionsOnlyModeTest.kt b/plugin/src/test/kotlin/de/fayard/VersionsOnlyModeTest.kt deleted file mode 100644 index 34218dc5d..000000000 --- a/plugin/src/test/kotlin/de/fayard/VersionsOnlyModeTest.kt +++ /dev/null @@ -1,81 +0,0 @@ -package de.fayard - -import de.fayard.VersionsOnlyMode.GRADLE_PROPERTIES -import de.fayard.VersionsOnlyMode.GROOVY_DEF -import de.fayard.VersionsOnlyMode.GROOVY_EXT -import de.fayard.VersionsOnlyMode.KOTLIN_VAL -import de.fayard.internal.SingleModeResult -import de.fayard.internal.UpdateVersionsOnly.parseBuildFile -import de.fayard.internal.UpdateVersionsOnly.parseBuildFileOrNew -import de.fayard.internal.UpdateVersionsOnly.regenerateBuildFile -import io.kotlintest.matchers.withClue -import io.kotlintest.shouldBe -import io.kotlintest.specs.FreeSpec -import java.io.File -import java.nio.file.Files - -class VersionsOnlyModeTest: FreeSpec({ - - val versionOnlyFolder = testResourceFile("versionOnly").absoluteFile - val kotlinValInput = versionOnlyFolder.resolve("singleBuildFile.txt") - - "check repos" { - buildSrcVersionsDir.name shouldBe "buildSrcVersions" - } - - - "Parse file" { - val singleModeResult = parseBuildFile(kotlinValInput, KOTLIN_VAL) - singleModeResult shouldBe SingleModeResult(6, 11, " ") - - parseBuildFileOrNew(kotlinValInput, KOTLIN_VAL, File(".")) shouldBe Pair(kotlinValInput, singleModeResult) - } - - val tempDir = Files.createTempDirectory("versions-only").toFile() - - "always modify gradle.properties" { - val (file1, result1) = parseBuildFileOrNew(null, GRADLE_PROPERTIES, File(".")) - file1.name shouldBe "gradle.properties" - result1 shouldBe SingleModeResult.newFile(GRADLE_PROPERTIES) - - val (file2, result2) = parseBuildFileOrNew(File("gradle.properties"), GRADLE_PROPERTIES, File(".")) - file2.name shouldBe "gradle.properties" - result2 shouldBe SingleModeResult.newFile(GRADLE_PROPERTIES) - } - - "Create new file if needed" { - val (file, result) = parseBuildFileOrNew(null, KOTLIN_VAL, tempDir) - file shouldBe tempDir.resolve("build.gradle.kts") - result shouldBe SingleModeResult.newFile(KOTLIN_VAL) - } - - - val testCases = listOf( - KOTLIN_VAL, - GROOVY_DEF, - GROOVY_EXT - ) - for (mode in testCases) { - "VersionsOnlyMode for mode = $mode" { - val received = versionOnlyFolder.resolve("${mode}_received.txt") - val validated = versionOnlyFolder.resolve("${mode}_validated.txt") - kotlinValInput.copyTo(received, overwrite = true) - - val deps = listOf( - "com.squareup.okhttp3:okhttp:2.1.0 // 2.2.0", - "com.squareup.okio:okio:2.0.0" - ).map { it.asDependency() } - - regenerateBuildFile(received, mode, deps) - withClue( - """Files differ. Run: - | diff -u ${validated.relativeTo(buildSrcVersionsDir)} ${received.relativeTo(buildSrcVersionsDir)} - |""".trimMargin() - ) { - (received.readText() == validated.readText()).shouldBe(true) - received.delete() - } - } - } - -}) diff --git a/plugin/src/test/resources/libs/Catchup.txt b/plugin/src/test/resources/libs/Catchup.txt deleted file mode 100644 index 4d1c81f8d..000000000 --- a/plugin/src/test/resources/libs/Catchup.txt +++ /dev/null @@ -1,133 +0,0 @@ -aapt2 -adapter_rxjava2 -androidx_annotation_annotation -androidx_core_core -annotations -apollo_android_support -apollo_gradle_plugin -apollo_http_cache -apollo_runtime -apollo_rx2_support -appcompat -auto_common -auto_service -autodispose -autodispose_android -autodispose_android_archcomponents -autodispose_android_archcomponents_ktx -autodispose_android_ktx -autodispose_ktx -autodispose_lifecycle -autodispose_lifecycle_ktx -browser -bugsnag_android -bugsnag_android_gradle_plugin -com_android_tools_build_gradle -com_github_bumptech_glide_compiler -com_gradle_build_scan_gradle_plugin -com_tickaroo_tikxml_annotation -com_tickaroo_tikxml_core -constraintlayout -converter_htmlescape -converter_moshi -core_ktx -crumb_annotations -crumb_compiler -crumb_compiler_api -dagger -dagger_android -dagger_android_processor -dagger_android_support -dagger_compiler -dagger_spi -drawerlayout -emoji -emoji_appcompat -error_prone_annotations -firebase_config -firebase_core -firebase_database -firebase_perf -firebase_plugins -flick -flipper -fragment -fragment_ktx -gesture_views -glide -inboxrecyclerview -inspector -inspector_android_compiler_extension -inspector_autovalue_compiler_extension -inspector_compiler -inspector_factory_compiler -inspector_factory_compiler_annotations -inspector_nullability_compiler_extension -javapoet -javax_annotation -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -jsoup -jsr305 -junit -kotlin_annotation_processing_gradle -kotlin_gradle_plugin -kotlin_metadata -kotlin_noarg -kotlin_scripting_compiler_embeddable -kotlin_stdlib -kotlin_stdlib_jdk7 -kotlin_stdlib_jdk8 -kotlinpoet -lazythreetenbp -leakcanary_android -leakcanary_android_no_op -library -library_no_op -lifecycle_compiler -lifecycle_extensions -lint_gradle -logging_interceptor -lottie -madge -material -moshi -moshi_kotlin_codegen -moshi_lazy_adapters -okhttp -okhttp3_integration -okio -palette -palette_ktx -play_publisher -preference -preference_ktx -process_phoenix -processor -psync -recyclerview_animators -recyclerview_integration -retrofit -retrofit_converter -retrofit_mock -room_compiler -room_runtime -room_rxjava2 -rx_preferences -rxandroid -rxbinding_design_kotlin -rxbinding_kotlin -rxbinding_support_v4_kotlin -rxjava -rxrelay -scalpel -stetho -stetho_okhttp3 -stetho_timber -support_annotations -swiperefreshlayout -taptargetview -telescope -timber -truth -unbescape -viewpager \ No newline at end of file diff --git a/plugin/src/test/resources/libs/FastHub.txt b/plugin/src/test/resources/libs/FastHub.txt deleted file mode 100644 index 92a3dd386..000000000 --- a/plugin/src/test/resources/libs/FastHub.txt +++ /dev/null @@ -1,77 +0,0 @@ -aapt2 -aboutlibraries -adapter_rxjava2 -android_device_names -android_state -android_state_processor -apollo_runtime -apollo_rx2_support -appcompat_v7 -assertj_core -bottom_navigation -butterknife -butterknife_compiler -cardview_v7 -colorpicker_library -com_android_support_test_rules -com_android_support_test_runner -com_android_tools_build_gradle -com_github_b3er_rxfirebase_firebase_database -com_google_firebase_firebase_database -commonmark -commonmark_ext_autolink -commonmark_ext_gfm_strikethrough -commonmark_ext_gfm_tables -commonmark_ext_ins -commonmark_ext_yaml_front_matter -converter_gson -crashlytics -customtabs -design -espresso_core -espresso_intents -firebase_core -firebase_database_kotlin -firebase_jobdispatcher -firebase_messaging -glide -google_services -gradle_build_properties_plugin -gradle_plugin -htmlcleaner -htmlspanner -io_fabric_tools_gradle -jacoco_android -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -jsoup -junit -keyboardvisibilityevent -kotlin_annotation_processing_gradle -kotlin_gradle_plugin -kotlin_stdlib_jre7 -lint_gradle -logging_interceptor -lombok -lottie -material_about_library -mockito_core -palette_v7 -play_services_base -preference_v14 -recyclerview_v7 -requery -requery_android -requery_processor -retaineddatetimepickers -retrofit -rxandroid -rxbillingservice -rxjava -shapedimageview -shortbread -shortbread_compiler -stream -support_annotations -thirtyinch -thirtyinch_rx2 -toasty \ No newline at end of file diff --git a/plugin/src/test/resources/libs/Kodein-DI.txt b/plugin/src/test/resources/libs/Kodein-DI.txt deleted file mode 100644 index 3819d6459..000000000 --- a/plugin/src/test/resources/libs/Kodein-DI.txt +++ /dev/null @@ -1,19 +0,0 @@ -appcompat -appcompat_v7 -guice -javax_inject -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -kodein_internal_gradle_plugin -kotlin_reflect -kotlin_scripting_compiler_embeddable -kotlin_stdlib -kotlin_stdlib_common -kotlin_stdlib_jdk7 -kotlin_stdlib_js -kotlin_test -kotlin_test_annotations_common -kotlin_test_common -kotlin_test_js -kotlin_test_junit -lint_gradle \ No newline at end of file diff --git a/plugin/src/test/resources/libs/KotlinAcademyApp.txt b/plugin/src/test/resources/libs/KotlinAcademyApp.txt deleted file mode 100644 index 6871c19f8..000000000 --- a/plugin/src/test/resources/libs/KotlinAcademyApp.txt +++ /dev/null @@ -1,79 +0,0 @@ -activitystarter -activitystarter_compiler -activitystarter_kotlin -anko_coroutines -appcompat_v7 -codeview -com_android_tools_build_gradle -com_google_android_support_wearable -com_google_android_wearable_wearable -controlsfx -converter_gson -converter_scalars -crashlytics -design -espresso_contrib -espresso_core -espresso_intents -firebase_core -firebase_messaging -glide -google_services -gradle_node_plugin -gson -hikaricp -io_fabric_tools_gradle -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -joda_time -junit -kotlin_android_extensions -kotlin_android_extensions_runtime -kotlin_annotation_processing_gradle -kotlin_frontend_plugin -kotlin_gradle_plugin -kotlin_native_gradle_plugin -kotlin_react -kotlin_react_dom -kotlin_react_router_dom -kotlin_scripting_compiler_embeddable -kotlin_stdlib_common -kotlin_stdlib_jdk7 -kotlin_stdlib_jdk8 -kotlin_stdlib_js -kotlin_test -kotlin_test_annotations_common -kotlin_test_common -kotlin_test_js -kotlin_test_junit -kotlinandroidviewbindings -kotlinx_coroutines_core -kotlinx_coroutines_core_js -kotlinx_coroutines_core_native -kotlinx_coroutines_javafx -kotlinx_gradle_serialization_plugin -kotlinx_html_js -kotlinx_serialization_runtime -kotlinx_serialization_runtime_js -ktor_gson -ktor_server_netty -lint_gradle -logback_classic -logging_interceptor -mockk -multidex -multidex_instrumentation -okhttp -preferenceholder -preferenceholder_gson_serializer -recyclerview_v7 -retrofit -retrofit2_kotlin_coroutines_experimental_adapter -rome -sendgrid_java -shadow -squash -squash_h2 -squash_postgres -tornadofx -traynotification -wear \ No newline at end of file diff --git a/plugin/src/test/resources/libs/KotlinUnitTesting.txt b/plugin/src/test/resources/libs/KotlinUnitTesting.txt deleted file mode 100644 index edb10b0c6..000000000 --- a/plugin/src/test/resources/libs/KotlinUnitTesting.txt +++ /dev/null @@ -1,12 +0,0 @@ -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -junit_jupiter_api -junit_jupiter_engine -junit_jupiter_params -kotlin_reflect -kotlin_scripting_compiler_embeddable -kotlintest_runner_junit5 -org_jetbrains_kotlin_kotlin_gradle_plugin -org_jetbrains_kotlin_kotlin_stdlib_jdk8 -spek_dsl_jvm -spek_runner_junit5 \ No newline at end of file diff --git a/plugin/src/test/resources/libs/SdkSearch.txt b/plugin/src/test/resources/libs/SdkSearch.txt deleted file mode 100644 index 18cd704d8..000000000 --- a/plugin/src/test/resources/libs/SdkSearch.txt +++ /dev/null @@ -1,64 +0,0 @@ -android_driver -androidx_test_runner -api -appcompat -browser -bugsnag_android -byteunits -com_android_tools_build_gradle -com_squareup_sqldelight_runtime -constraintlayout -converter_moshi -core_ktx -dagger -dagger_android -dagger_android_processor -dagger_compiler -gradle_node_plugin -gradle_plugin -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -kotlin_android_extensions -kotlin_android_extensions_runtime -kotlin_annotation_processing_gradle -kotlin_argparser -kotlin_frontend_plugin -kotlin_gradle_plugin -kotlin_scripting_compiler_embeddable -kotlin_serialization -kotlin_serialization_unshaded -kotlin_stdlib -kotlin_stdlib_common -kotlin_stdlib_js -kotlin_test_annotations_common -kotlin_test_common -kotlin_test_js -kotlin_test_junit -kotlinx_coroutines_android -kotlinx_coroutines_core -kotlinx_coroutines_core_common -kotlinx_coroutines_core_js -kotlinx_serialization_runtime -kotlinx_serialization_runtime_common -kotlinx_serialization_runtime_js -ktlint -ktlint_gradle -lint_gradle -logging_interceptor -material -moshi -okhttp -okio -recyclerview -retrofit -retrofit2_kotlin_coroutines_adapter -retrofit2_kotlinx_serialization_converter -runtime_js -runtime_jvm -runtime_metadata -se_ansman_kotshi_compiler -sqlite_framework -timber_android -timber_common -timber_jdk -timber_js -truth \ No newline at end of file diff --git a/plugin/src/test/resources/libs/android-sunflower.txt b/plugin/src/test/resources/libs/android-sunflower.txt deleted file mode 100644 index 467a3f8a8..000000000 --- a/plugin/src/test/resources/libs/android-sunflower.txt +++ /dev/null @@ -1,35 +0,0 @@ -aapt2 -appcompat -com_android_tools_build_gradle -com_diffplug_gradle_spotless_gradle_plugin -com_github_bumptech_glide_compiler -constraintlayout -core_ktx -core_testing -databinding_adapters -databinding_common -databinding_compiler -databinding_runtime -espresso_contrib -espresso_core -espresso_intents -glide -gson -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -kotlin_android_extensions -kotlin_annotation_processing_gradle -kotlin_gradle_plugin -kotlin_stdlib_jdk8 -legacy_support_v4 -lifecycle_extensions -lint_gradle -material -navigation_fragment_ktx -navigation_safe_args_gradle_plugin -navigation_ui_ktx -recyclerview -room_compiler -room_runtime -uiautomator -work_runtime_ktx \ No newline at end of file diff --git a/plugin/src/test/resources/libs/http4k.txt b/plugin/src/test/resources/libs/http4k.txt deleted file mode 100644 index 3b29dc234..000000000 --- a/plugin/src/test/resources/libs/http4k.txt +++ /dev/null @@ -1,50 +0,0 @@ -alpn_boot -argo -cobertura -com_github_kt3k_coveralls_gradle_plugin -com_jfrog_bintray_gradle_plugin -commons_pool2 -coveralls_gradle_plugin -dokka_gradle_plugin -gradle_cobertura_plugin -gradle_extra_configurations_plugin -gson -hamkrest -handlebars -http2_server -httpasyncclient -httpclient -httpcore -jackson_module_kotlin -java_websocket -javax_servlet_api -javax_websocket_server_impl -jetty_alpn_conscrypt_server -jetty_client -jetty_server -jetty_servlet -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -json -jsoup -junit_jupiter_api -junit_jupiter_engine -kotlin_gradle_plugin -kotlin_reflect -kotlin_scripting_compiler_embeddable -kotlin_stdlib_jdk8 -micrometer_core -moshi -moshi_kotlin -net_saliman_cobertura_gradle_plugin -netty_codec_http2 -okhttp -pebble -rerunner_jupiter -resilience4j_bulkhead -resilience4j_circuitbreaker -resilience4j_ratelimiter -resilience4j_retry -selenium_api -thymeleaf -undertow_core -undertow_servlet \ No newline at end of file diff --git a/plugin/src/test/resources/libs/koin.txt b/plugin/src/test/resources/libs/koin.txt deleted file mode 100644 index 23c3d591a..000000000 --- a/plugin/src/test/resources/libs/koin.txt +++ /dev/null @@ -1,56 +0,0 @@ -aapt2 -adapter_rxjava2 -android_arch_lifecycle_common -android_arch_lifecycle_extensions -android_arch_persistence_room_compiler -android_arch_persistence_room_runtime -android_arch_persistence_room_testing -android_iconify_weathericons -android_maven_publish -anko_commons -appcompat_v7 -asciidoctor_gradle_plugin -asciidoctorj_pdf -com_android_support_test_runner -com_android_tools_build_gradle -constraint_layout -converter_gson -core_testing -design -dokka_android_gradle_plugin -gradle_bintray_plugin -gson -httpclient -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -kotlin_android_extensions -kotlin_annotation_processing_gradle -kotlin_gradle_plugin -kotlin_scripting_compiler_embeddable -kotlin_stdlib -kotlin_stdlib_jdk8 -kotlinx_coroutines_android -kotlinx_coroutines_core -ktor_server_core -ktor_server_netty -ktor_server_test_host -leakcanary_android -leakcanary_android_no_op -lifecycle_common -lifecycle_extensions -lint_gradle -logback_classic -logging_interceptor -mockito_inline -navigation_fragment -navigation_ui_ktx -okhttp -orchestrator -retrofit -retrofit2_kotlin_coroutines_experimental_adapter -rxandroid -rxjava -rxjava2 -slf4j_api -slf4j_log4j12 -spark_kotlin \ No newline at end of file diff --git a/plugin/src/test/resources/libs/material-dialogs.txt b/plugin/src/test/resources/libs/material-dialogs.txt deleted file mode 100644 index e8274af6e..000000000 --- a/plugin/src/test/resources/libs/material-dialogs.txt +++ /dev/null @@ -1,16 +0,0 @@ -annotation -appcompat -assent -bintray_release -com_android_tools_build_gradle -gradle_versions_plugin -gridlayout -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -kotlin_android_extensions -kotlin_compiler_embeddable -kotlin_gradle_plugin -kotlin_stdlib_jdk7 -lint_gradle -material -recyclerview -spotless_plugin_gradle \ No newline at end of file diff --git a/plugin/src/test/resources/libs/sample-synclibs.txt b/plugin/src/test/resources/libs/sample-synclibs.txt deleted file mode 100644 index bbc0181a5..000000000 --- a/plugin/src/test/resources/libs/sample-synclibs.txt +++ /dev/null @@ -1,7 +0,0 @@ -com_github_bumptech_glide_compiler -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -kotlin_scripting_compiler_embeddable -krangl -okio -org_jetbrains_kotlin_jvm_gradle_plugin -rxjava \ No newline at end of file diff --git a/plugin/src/test/resources/libs/simple-stack.txt b/plugin/src/test/resources/libs/simple-stack.txt deleted file mode 100644 index d2f39bb85..000000000 --- a/plugin/src/test/resources/libs/simple-stack.txt +++ /dev/null @@ -1,82 +0,0 @@ -adapters -android_adapters -android_arch_lifecycle_compiler -android_arch_lifecycle_extensions -android_arch_lifecycle_runtime -android_maven_gradle_plugin -anko_commons -anko_sdk15_listeners -appcompat_v7 -assertj_android -assertj_android_appcompat_v7 -assertj_android_design -assertj_android_recyclerview_v7 -assertj_android_support_v4 -assertj_core -auto_parcel -auto_value -auto_value_ignore_hash_equals -baselibrary -bottom_navigation -butterknife -butterknife_compiler -cardview_v7 -com_android_databinding_compiler -com_android_support_test_rules -com_android_support_test_runner -com_android_tools_build_gradle -command_queue -conductor -converter_gson -dagger -dagger_compiler -design -dexmaker -dexmaker_mockito -espresso_contrib -espresso_core -espresso_idling_resource -espresso_intents -gradle_retrolambda -hamcrest_all -javatuples -javax_annotation -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -kotlin_android_extensions_runtime -kotlin_annotation_processing_gradle -kotlin_gradle_plugin -kotlin_stdlib_jdk7 -kotlin_stdlib_jdk8 -kotlin_stdlib_jre7 -library -lint_gradle -logging_interceptor -maven_ant_tasks -mockito_all -mockito_core -multidex -okhttp -paperparcel -paperparcel_compiler -powermock_module_junit4 -realm_android_kotlin_extensions -realm_android_library -realm_annotations -realm_annotations_processor -realm_gradle_plugin -realmfieldnameshelper -recyclerview_v7 -retrofit -retrofit2_rxjava2_adapter -robolectric -rxandroid -rxbinding -rxjava -rxkotlin -rxrelay -state_bundle -support_annotations -support_v4 -support_vector_drawable -transitionseverywhere \ No newline at end of file diff --git a/plugin/src/test/resources/libs/tachiyomi.txt b/plugin/src/test/resources/libs/tachiyomi.txt deleted file mode 100644 index ae3d11b88..000000000 --- a/plugin/src/test/resources/libs/tachiyomi.txt +++ /dev/null @@ -1,84 +0,0 @@ -aapt2 -acra -adapter_rxjava -android_job -android_shortcut_gradle_plugin -appcompat_v7 -assertj_core -cardview_v7 -changelog -com_afollestad_material_dialogs_core -com_android_tools_build_gradle -com_github_bumptech_glide_compiler -com_github_dmytrodanylyk_android_process_button_library -conductor -conductor_support -conductor_support_preference -constraint_layout -converter_gson -customtabs -design -directionalviewpager -disklrucache -duktape_android -filepicker -firebase_core -flexible_adapter -flexible_adapter_ui -glide -glide_transformations -google_services -gradle_versions_plugin -gson -injekt_core -java_nat_sort -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -jsoup -junit -junrar_android -kotlin_android_extensions -kotlin_android_extensions_runtime -kotlin_annotation_processing_gradle -kotlin_gradle_plugin -kotlin_stdlib -kotlinx_coroutines_android -kotlinx_coroutines_core -kotson -lint_gradle -material_design_dimens -me_gujun_android_taggroup_library -me_zhanghai_android_systemuihelper_library -mockito_core -multidex -multidex_instrumentation -nucleus -nucleus_support_v7 -okhttp -okhttp3_integration -okio -photoview -play_services_gcm -preference_v7 -reactivenetwork -recyclerview_v7 -retrofit -robolectric -rx_preferences -rxandroid -rxbinding_appcompat_v7_kotlin -rxbinding_kotlin -rxbinding_recyclerview_v7_kotlin -rxbinding_support_v4_kotlin -rxjava -rxrelay -shadows_multidex -shadows_play_services -slice -sqlite -subsampling_scale_image_view -support_annotations -support_v4 -textdrawable -timber -unifile -viewstatepageradapter \ No newline at end of file diff --git a/plugin/src/test/resources/versionOnly/GROOVY_DEF_validated.txt b/plugin/src/test/resources/versionOnly/GROOVY_DEF_validated.txt deleted file mode 100644 index 721dc90d1..000000000 --- a/plugin/src/test/resources/versionOnly/GROOVY_DEF_validated.txt +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - kotlin("jvm") version "1.3.50" -} - -dependencies { - - // - // Generated by ./gradle buildSrcVersions - // See https://github.com/jmfayard/buildSrcVersions/issues/54 - def okhttp = '2.1.0' // available: '2.2.0' - def okio = '2.0.0' - // - - implementation(kotlin("stdlib-jdk8", kotlin_stdlib_jdk8)) - - implementation("com.squareup.okhttp3:okhttp:$okhttp") - implementation("com.squareup.okio:okio:$okio") -} - -tasks.withType { - kotlinOptions.jvmTarget = "1.8" -} diff --git a/plugin/src/test/resources/versionOnly/GROOVY_EXT_validated.txt b/plugin/src/test/resources/versionOnly/GROOVY_EXT_validated.txt deleted file mode 100644 index aaf990563..000000000 --- a/plugin/src/test/resources/versionOnly/GROOVY_EXT_validated.txt +++ /dev/null @@ -1,24 +0,0 @@ -plugins { - kotlin("jvm") version "1.3.50" -} - -dependencies { - - // - // Generated by ./gradle buildSrcVersions - // See https://github.com/jmfayard/buildSrcVersions/issues/54 - ext { - okhttp = '2.1.0' // available: '2.2.0' - okio = '2.0.0' - } - // - - implementation(kotlin("stdlib-jdk8", kotlin_stdlib_jdk8)) - - implementation("com.squareup.okhttp3:okhttp:$okhttp") - implementation("com.squareup.okio:okio:$okio") -} - -tasks.withType { - kotlinOptions.jvmTarget = "1.8" -} diff --git a/plugin/src/test/resources/versionOnly/KOTLIN_VAL_validated.txt b/plugin/src/test/resources/versionOnly/KOTLIN_VAL_validated.txt deleted file mode 100644 index 1fb96c1d7..000000000 --- a/plugin/src/test/resources/versionOnly/KOTLIN_VAL_validated.txt +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - kotlin("jvm") version "1.3.50" -} - -dependencies { - - // - // Generated by ./gradle buildSrcVersions - // See https://github.com/jmfayard/buildSrcVersions/issues/54 - val okhttp = "2.1.0" // available: "2.2.0" - val okio = "2.0.0" - // - - implementation(kotlin("stdlib-jdk8", kotlin_stdlib_jdk8)) - - implementation("com.squareup.okhttp3:okhttp:$okhttp") - implementation("com.squareup.okio:okio:$okio") -} - -tasks.withType { - kotlinOptions.jvmTarget = "1.8" -} diff --git a/plugin/src/test/resources/versionOnly/singleBuildFile.txt b/plugin/src/test/resources/versionOnly/singleBuildFile.txt deleted file mode 100644 index a5372cee7..000000000 --- a/plugin/src/test/resources/versionOnly/singleBuildFile.txt +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - kotlin("jvm") version "1.3.50" -} - -dependencies { - - // - // Generated by ./gradle buildSrcVersions - // See https://github.com/jmfayard/buildSrcVersions/issues/54 - val okhttp = "2.1.0" - val okio = "2.0.0" - // - - implementation(kotlin("stdlib-jdk8", kotlin_stdlib_jdk8)) - - implementation("com.squareup.okhttp3:okhttp:$okhttp") - implementation("com.squareup.okio:okio:$okio") -} - -tasks.withType { - kotlinOptions.jvmTarget = "1.8" -} diff --git a/plugin/src/test/resources/versions/Catchup.txt b/plugin/src/test/resources/versions/Catchup.txt deleted file mode 100644 index 43411bb38..000000000 --- a/plugin/src/test/resources/versions/Catchup.txt +++ /dev/null @@ -1,76 +0,0 @@ -aapt2 -androidx_annotation_annotation -androidx_core -androidx_emoji -androidx_fragment -androidx_lifecycle -androidx_palette -androidx_preference -androidx_room -appcompat -auto_common -auto_service -browser -bugsnag_android -bugsnag_android_gradle_plugin -com_android_tools_build_gradle -com_apollographql_apollo -com_facebook_stetho -com_github_bumptech_glide -com_google_dagger -com_gradle_build_scan_gradle_plugin -com_jakewharton_rxbinding2 -com_readystatesoftware_chuck -com_squareup_leakcanary -com_squareup_moshi -com_squareup_okhttp3 -com_squareup_retrofit2 -com_tickaroo_tikxml -com_uber_autodispose -com_uber_crumb -constraintlayout -drawerlayout -error_prone_annotations -firebase_config -firebase_core -firebase_database -firebase_perf -firebase_plugins -flick -flipper -gesture_views -inboxrecyclerview -io_sweers_inspector -javapoet -javax_annotation -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -jsoup -jsr305 -junit -kotlin_metadata -kotlinpoet -lazythreetenbp -lint_gradle -lottie -madge -material -moshi_lazy_adapters -okio -org_jetbrains_kotlin -play_publisher -process_phoenix -psync -recyclerview_animators -rx_preferences -rxandroid -rxjava -rxrelay -scalpel -support_annotations -swiperefreshlayout -taptargetview -telescope -timber -truth -unbescape -viewpager \ No newline at end of file diff --git a/plugin/src/test/resources/versions/FastHub.txt b/plugin/src/test/resources/versions/FastHub.txt deleted file mode 100644 index ef939208e..000000000 --- a/plugin/src/test/resources/versions/FastHub.txt +++ /dev/null @@ -1,48 +0,0 @@ -aapt2 -aboutlibraries -android_device_names -assertj_core -bottom_navigation -colorpicker_library -com_android_support -com_android_support_test -com_android_support_test_espresso -com_android_tools_build_gradle -com_apollographql_apollo -com_atlassian_commonmark -com_evernote -com_github_b3er_rxfirebase -com_github_matthiasrobbers -com_google_firebase -com_jakewharton -com_squareup_retrofit2 -crashlytics -firebase_jobdispatcher -glide -google_services -gradle_build_properties_plugin -htmlcleaner -htmlspanner -io_fabric_tools_gradle -io_requery -jacoco_android -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -jsoup -junit -keyboardvisibilityevent -lint_gradle -logging_interceptor -lombok -lottie -material_about_library -mockito_core -net_grandcentrix_thirtyinch -org_jetbrains_kotlin -play_services_base -retaineddatetimepickers -rxandroid -rxbillingservice -rxjava -shapedimageview -stream -toasty \ No newline at end of file diff --git a/plugin/src/test/resources/versions/Kodein-DI.txt b/plugin/src/test/resources/versions/Kodein-DI.txt deleted file mode 100644 index 402a8e3b0..000000000 --- a/plugin/src/test/resources/versions/Kodein-DI.txt +++ /dev/null @@ -1,9 +0,0 @@ -appcompat -appcompat_v7 -guice -javax_inject -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -kodein_internal_gradle_plugin -lint_gradle -org_jetbrains_kotlin \ No newline at end of file diff --git a/plugin/src/test/resources/versions/KotlinAcademyApp.txt b/plugin/src/test/resources/versions/KotlinAcademyApp.txt deleted file mode 100644 index 9bc0186c1..000000000 --- a/plugin/src/test/resources/versions/KotlinAcademyApp.txt +++ /dev/null @@ -1,66 +0,0 @@ -anko_coroutines -appcompat_v7 -codeview -com_android_support_test_espresso -com_android_tools_build_gradle -com_github_marcinmoskala_activitystarter -com_google_android_support_wearable -com_google_android_wearable_wearable -com_google_firebase -com_marcinmoskala_preferenceholder -com_squareup_okhttp3 -com_squareup_retrofit2 -controlsfx -crashlytics -design -glide -google_services -gradle_node_plugin -gson -hikaricp -io_fabric_tools_gradle -io_ktor -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -joda_time -junit -kotlin_android_extensions -kotlin_android_extensions_runtime -kotlin_annotation_processing_gradle -kotlin_frontend_plugin -kotlin_gradle_plugin -kotlin_native_gradle_plugin -kotlin_react -kotlin_react_dom -kotlin_react_router_dom -kotlin_scripting_compiler_embeddable -kotlin_stdlib_common -kotlin_stdlib_jdk7 -kotlin_stdlib_jdk8 -kotlin_stdlib_js -kotlin_test -kotlin_test_annotations_common -kotlin_test_common -kotlin_test_js -kotlin_test_junit -kotlinandroidviewbindings -kotlinx_coroutines_core -kotlinx_coroutines_core_js -kotlinx_coroutines_core_native -kotlinx_coroutines_javafx -kotlinx_gradle_serialization_plugin -kotlinx_html_js -lint_gradle -logback_classic -mockk -multidex -multidex_instrumentation -org_jetbrains_kotlinx_kotlinx_serialization -org_jetbrains_squash -recyclerview_v7 -retrofit2_kotlin_coroutines_experimental_adapter -rome -sendgrid_java -shadow -tornadofx -traynotification -wear \ No newline at end of file diff --git a/plugin/src/test/resources/versions/KotlinUnitTesting.txt b/plugin/src/test/resources/versions/KotlinUnitTesting.txt deleted file mode 100644 index 3b9cd63ce..000000000 --- a/plugin/src/test/resources/versions/KotlinUnitTesting.txt +++ /dev/null @@ -1,9 +0,0 @@ -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -kotlin_reflect -kotlin_scripting_compiler_embeddable -kotlintest_runner_junit5 -org_jetbrains_kotlin_kotlin_gradle_plugin -org_jetbrains_kotlin_kotlin_stdlib_jdk8 -org_junit_jupiter -org_spekframework_spek2 \ No newline at end of file diff --git a/plugin/src/test/resources/versions/SdkSearch.txt b/plugin/src/test/resources/versions/SdkSearch.txt deleted file mode 100644 index 30d6303b8..000000000 --- a/plugin/src/test/resources/versions/SdkSearch.txt +++ /dev/null @@ -1,45 +0,0 @@ -androidx_test_runner -appcompat -browser -bugsnag_android -byteunits -com_android_tools_build_gradle -com_google_dagger -com_jakewharton_timber -com_squareup_okhttp3 -com_squareup_retrofit2 -com_squareup_sqldelight -constraintlayout -core_ktx -gradle_node_plugin -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -kotlin_android_extensions -kotlin_android_extensions_runtime -kotlin_annotation_processing_gradle -kotlin_argparser -kotlin_frontend_plugin -kotlin_gradle_plugin -kotlin_scripting_compiler_embeddable -kotlin_serialization -kotlin_serialization_unshaded -kotlin_stdlib -kotlin_stdlib_common -kotlin_stdlib_js -kotlin_test_annotations_common -kotlin_test_common -kotlin_test_js -kotlin_test_junit -ktlint -ktlint_gradle -lint_gradle -material -moshi -okio -org_jetbrains_kotlinx_kotlinx_coroutines -org_jetbrains_kotlinx_kotlinx_serialization -recyclerview -retrofit2_kotlin_coroutines_adapter -retrofit2_kotlinx_serialization_converter -se_ansman_kotshi -sqlite_framework -truth \ No newline at end of file diff --git a/plugin/src/test/resources/versions/android-sunflower.txt b/plugin/src/test/resources/versions/android-sunflower.txt deleted file mode 100644 index 47a8b9f3b..000000000 --- a/plugin/src/test/resources/versions/android-sunflower.txt +++ /dev/null @@ -1,23 +0,0 @@ -aapt2 -android_arch_navigation -androidx_databinding -androidx_room -androidx_test_espresso -appcompat -com_android_tools_build_gradle -com_diffplug_gradle_spotless_gradle_plugin -com_github_bumptech_glide -constraintlayout -core_ktx -core_testing -gson -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -legacy_support_v4 -lifecycle_extensions -lint_gradle -material -org_jetbrains_kotlin -recyclerview -uiautomator -work_runtime_ktx \ No newline at end of file diff --git a/plugin/src/test/resources/versions/http4k.txt b/plugin/src/test/resources/versions/http4k.txt deleted file mode 100644 index 61f85dad6..000000000 --- a/plugin/src/test/resources/versions/http4k.txt +++ /dev/null @@ -1,38 +0,0 @@ -alpn_boot -argo -cobertura -com_github_kt3k_coveralls_gradle_plugin -com_jfrog_bintray_gradle_plugin -com_squareup_moshi -commons_pool2 -coveralls_gradle_plugin -dokka_gradle_plugin -gradle_cobertura_plugin -gradle_extra_configurations_plugin -gson -hamkrest -handlebars -http2_server -httpasyncclient -httpclient -httpcore -io_github_resilience4j -io_undertow -jackson_module_kotlin -java_websocket -javax_servlet_api -javax_websocket_server_impl -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -json -jsoup -micrometer_core -net_saliman_cobertura_gradle_plugin -netty_codec_http2 -okhttp -org_eclipse_jetty -org_jetbrains_kotlin -org_junit_jupiter -pebble -rerunner_jupiter -selenium_api -thymeleaf \ No newline at end of file diff --git a/plugin/src/test/resources/versions/koin.txt b/plugin/src/test/resources/versions/koin.txt deleted file mode 100644 index da855542c..000000000 --- a/plugin/src/test/resources/versions/koin.txt +++ /dev/null @@ -1,36 +0,0 @@ -aapt2 -android_arch_lifecycle -android_arch_navigation -android_arch_persistence_room -android_iconify_weathericons -android_maven_publish -androidx_lifecycle -anko_commons -asciidoctor_gradle_plugin -asciidoctorj_pdf -com_android_support -com_android_support_test -com_android_tools_build_gradle -com_squareup_leakcanary -com_squareup_okhttp3 -com_squareup_retrofit2 -constraint_layout -core_testing -dokka_android_gradle_plugin -gradle_bintray_plugin -gson -httpclient -io_ktor -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -lint_gradle -logback_classic -mockito_inline -org_jetbrains_kotlin -org_jetbrains_kotlinx_kotlinx_coroutines -retrofit2_kotlin_coroutines_experimental_adapter -rxandroid -rxjava -slf4j_api -slf4j_log4j12 -spark_kotlin \ No newline at end of file diff --git a/plugin/src/test/resources/versions/material-dialogs.txt b/plugin/src/test/resources/versions/material-dialogs.txt deleted file mode 100644 index 63ed4327e..000000000 --- a/plugin/src/test/resources/versions/material-dialogs.txt +++ /dev/null @@ -1,13 +0,0 @@ -annotation -appcompat -assent -bintray_release -com_android_tools_build_gradle -gradle_versions_plugin -gridlayout -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -lint_gradle -material -org_jetbrains_kotlin -recyclerview -spotless_plugin_gradle \ No newline at end of file diff --git a/plugin/src/test/resources/versions/sample-synclibs.txt b/plugin/src/test/resources/versions/sample-synclibs.txt deleted file mode 100644 index bbc0181a5..000000000 --- a/plugin/src/test/resources/versions/sample-synclibs.txt +++ /dev/null @@ -1,7 +0,0 @@ -com_github_bumptech_glide_compiler -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -kotlin_scripting_compiler_embeddable -krangl -okio -org_jetbrains_kotlin_jvm_gradle_plugin -rxjava \ No newline at end of file diff --git a/plugin/src/test/resources/versions/simple-stack.txt b/plugin/src/test/resources/versions/simple-stack.txt deleted file mode 100644 index f4547af96..000000000 --- a/plugin/src/test/resources/versions/simple-stack.txt +++ /dev/null @@ -1,64 +0,0 @@ -android_adapters -android_arch_lifecycle_compiler -android_arch_lifecycle_extensions -android_arch_lifecycle_runtime -android_maven_gradle_plugin -appcompat_v7 -assertj_core -auto_parcel -auto_value -auto_value_ignore_hash_equals -bottom_navigation -cardview_v7 -com_android_databinding -com_android_support_test -com_android_support_test_espresso -com_android_tools_build_gradle -com_google_dagger -com_google_dexmaker -com_jakewharton -com_squareup_assertj -com_squareup_okhttp3 -com_squareup_retrofit2 -command_queue -conductor -design -gradle_retrolambda -hamcrest_all -javatuples -javax_annotation -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -junit -kotlin_android_extensions_runtime -kotlin_annotation_processing_gradle -kotlin_gradle_plugin -kotlin_stdlib_jdk7 -kotlin_stdlib_jdk8 -kotlin_stdlib_jre7 -lint_gradle -maven_ant_tasks -mockito_all -mockito_core -multidex -nz_bradcampbell -org_jetbrains_anko -powermock_module_junit4 -realm_android_kotlin_extensions -realm_android_library -realm_annotations -realm_annotations_processor -realm_gradle_plugin -realmfieldnameshelper -recyclerview_v7 -retrofit2_rxjava2_adapter -robolectric -rxandroid -rxbinding -rxjava -rxkotlin -rxrelay -state_bundle -support_annotations -support_v4 -support_vector_drawable -transitionseverywhere \ No newline at end of file diff --git a/plugin/src/test/resources/versions/tachiyomi.txt b/plugin/src/test/resources/versions/tachiyomi.txt deleted file mode 100644 index e84280435..000000000 --- a/plugin/src/test/resources/versions/tachiyomi.txt +++ /dev/null @@ -1,68 +0,0 @@ -aapt2 -acra -android_job -android_shortcut_gradle_plugin -appcompat_v7 -assertj_core -cardview_v7 -changelog -com_afollestad_material_dialogs_core -com_android_tools_build_gradle -com_bluelinelabs -com_github_bumptech_glide -com_github_dmytrodanylyk_android_process_button_library -com_jakewharton_rxbinding -com_squareup_retrofit2 -conductor_support_preference -constraint_layout -customtabs -design -directionalviewpager -disklrucache -duktape_android -filepicker -firebase_core -flexible_adapter -flexible_adapter_ui -glide_transformations -google_services -gradle_versions_plugin -gson -info_android15_nucleus -injekt_core -java_nat_sort -jmfayard_github_io_gradle_kotlin_dsl_libs_gradle_plugin -jsoup -junit -junrar_android -kotson -lint_gradle -material_design_dimens -me_gujun_android_taggroup_library -me_zhanghai_android_systemuihelper_library -mockito_core -multidex -multidex_instrumentation -okhttp -okio -org_jetbrains_kotlin -org_jetbrains_kotlinx_kotlinx_coroutines -org_robolectric -photoview -play_services_gcm -preference_v7 -reactivenetwork -recyclerview_v7 -rx_preferences -rxandroid -rxjava -rxrelay -slice -sqlite -subsampling_scale_image_view -support_annotations -support_v4 -textdrawable -timber -unifile -viewstatepageradapter \ No newline at end of file diff --git a/sample-android/build.gradle.kts b/sample-android/build.gradle.kts new file mode 100644 index 000000000..6b23493c6 --- /dev/null +++ b/sample-android/build.gradle.kts @@ -0,0 +1,71 @@ +import de.fayard.OrderBy +import de.fayard.VersionsOnlyMode +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id("org.lovedev.greeting.kotlin") + id("de.fayard.refreshVersions") + id("ch.tutteli.kotlin.utils") + id("nebula.kotlin") + kotlin("jvm") + `build-scan` +} +group = "de.fayard" + +buildSrcVersions { + // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 + orderBy = OrderBy.GROUP_AND_ALPHABETICAL +} + +repositories { + maven { + setUrl("../plugin/src/test/resources/maven") + } + mavenCentral() +} + +dependencies { + implementation("com.google.guava:guava:15.0") + implementation("com.google.inject:guice:2.0") + implementation("com.wealthfront:magellan:+") + implementation("com.wealthfront:magellan-rx:+") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.0.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.13.0") + implementation("com.jakewharton.timber:timber:4.7.0") +} + +tasks.withType { + kotlinOptions.jvmTarget = "1.8" +} +tasks.withType { + gradleVersion = System.getenv("GRADLE_VERSION") ?: "5.6.1" + distributionType = Wrapper.DistributionType.ALL +} + +tasks.register("copyReport") { + from(".") + include("report.json") + into("build/dependencyUpdates") +} + +tasks.register("hello") { + group = "Custom" +} + +tasks.register("checkAll") { + description = "versionsOnlyMode - check all modes" + group = "Custom" + dependsOn(VersionsOnlyMode.values().map { it.name }) +} + +buildScan { + setTermsOfServiceUrl("https://gradle.com/terms-of-service") + setTermsOfServiceAgree("yes") +} + +// How to update Gradle itself? https://github.com/jmfayard/buildSrcVersions/issues/19 +tasks.withType { + gradleVersion = findProperty("gradleLatestVersion") as? String ?: gradle.gradleVersion + distributionType = Wrapper.DistributionType.ALL +} diff --git a/sample-android/gradle.properties b/sample-android/gradle.properties new file mode 100644 index 000000000..b63716bd5 --- /dev/null +++ b/sample-android/gradle.properties @@ -0,0 +1,25 @@ +# The plugin https://github.com/jmfayard/buildSrcVersions +# allows to overwrite plugin and dependencies versions from the values inside 'gradle.properties' +# Set to 'verbose' to understand how dependency and plugin versions are overwritten +# Set to 'false' to disable this feature +resolutionStrategyConfig=verbose +# Dependencies and Plugin versions with their available updates +# Generated by $ ./gradlew refreshVersions +# You can edit the rest of the file, it will be kept intact +# See https://github.com/jmfayard/buildSrcVersions/issues/77 +plugin.ch.tutteli.kotlin.utils=0.29.0 +plugin.com.github.ben-manes.versions=0.25.0 +plugin.com.gradle.build-scan=2.4.2 +plugin.de.fayard.refreshVersions=0.8.0 +plugin.nebula.kotlin=1.3.50 +plugin.org.jetbrains.kotlin.jvm=1.3.50 +plugin.org.lovedev.greeting.kotlin=1.1 +version.com.wealthfront=1.1.0 +version.org.jetbrains.kotlin=1.3.50 +version.org.jetbrains.kotlinx.kotlinx-coroutines=1.0.0 +# # available=1.3.2 +version.org.jetbrains.kotlinx.kotlinx-serialization=0.13.0 +version.gradleLatestVersion=5.6.2 +version.guava=15.0 +version.guice=2.0 +version.timber=4.7.0 diff --git a/sample-android/gradle/myversions.kt b/sample-android/gradle/myversions.kt new file mode 100644 index 000000000..a80ba015d --- /dev/null +++ b/sample-android/gradle/myversions.kt @@ -0,0 +1,29 @@ +import kotlin.String + +/** + * Generated by https://github.com/jmfayard/buildSrcVersions + * + * Find which updates are available by running + * `$ ./gradlew buildSrcVersions` + * This will only update the comments. + * + * YOU are responsible for updating manually the dependency version. + */ +object Versions { + const val okhttp: String = "4.1.0" + + const val okio: String = "2.0.0" + + const val org_jetbrains_kotlin_jvm_gradle_plugin: String = "1.3.50" + + const val org_jetbrains_kotlin: String = "1.3.50" + + /** + * + * See issue 19: How to update Gradle itself? + * https://github.com/jmfayard/buildSrcVersions/issues/19 + */ + const val gradleLatestVersion: String = "5.6.1" + + const val gradleCurrentVersion: String = "5.5.1" +} diff --git a/sample-android/gradle/wrapper/gradle-wrapper.jar b/sample-android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..5c2d1cf016b3885f6930543d57b744ea8c220a1a GIT binary patch literal 55616 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/sample-android/gradlew.bat b/sample-android/gradlew.bat new file mode 100644 index 000000000..9618d8d96 --- /dev/null +++ b/sample-android/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/sample-android/report.json b/sample-android/report.json new file mode 100644 index 000000000..506731b9b --- /dev/null +++ b/sample-android/report.json @@ -0,0 +1,86 @@ +{ + "current": { + "dependencies": [ + { + "group": "org.jetbrains.kotlin", + "version": "1.3.50", + "projectUrl": "https://kotlinlang.org/", + "name": "kotlin-scripting-compiler-embeddable" + }, + { + "group": "org.jetbrains.kotlin", + "version": "1.3.50", + "projectUrl": "https://kotlinlang.org/", + "name": "kotlin-stdlib-jdk8" + }, + { + "group": "org.jetbrains.kotlin.jvm", + "version": "1.3.50", + "projectUrl": null, + "name": "org.jetbrains.kotlin.jvm.gradle.plugin" + } + ], + "count": 3 + }, + "gradle": { + "current": { + "version": "5.6.1", + "reason": "", + "isUpdateAvailable": true, + "isFailure": false + }, + "nightly": { + "version": "", + "reason": "update check disabled", + "isUpdateAvailable": false, + "isFailure": false + }, + "enabled": true, + "releaseCandidate": { + "version": "", + "reason": "update check succeeded: no release available", + "isUpdateAvailable": false, + "isFailure": false + }, + "running": { + "version": "5.5.1", + "reason": "", + "isUpdateAvailable": false, + "isFailure": false + } + }, + "exceeded": { + "dependencies": [ + ], + "count": 0 + }, + "outdated": { + "dependencies": [ + { + "group": "com.squareup.okhttp3", + "available": { + "release": null, + "milestone": "4.1.1", + "integration": null + }, + "version": "4.1.0", + "projectUrl": "https://github.com/square/okhttp", + "name": "okhttp" + } + ], + "count": 1 + }, + "unresolved": { + "dependencies": [ + { + "group": "com.squareup.okio", + "version": "2.0.0", + "reason": "Could not resolve com.squareup.okio:okio:+.", + "projectUrl": "2.4.0", + "name": "okio" + } + ], + "count": 1 + }, + "count": 5 +} diff --git a/sample-android/settings.gradle.kts b/sample-android/settings.gradle.kts new file mode 100644 index 000000000..532cd531d --- /dev/null +++ b/sample-android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + } + + /** + * This `resolutionStrategy` allows plugin versions to be configured from `gradle.properties + * The convention is simply + * plugin.$PLUGINID=$PLUGIN_VERSION + * To check what happen, you can set in gradle.properties the line: + * resolutionStrategyConfig=verbose + */ + val resolutionStrategyConfig: String? by extra + resolutionStrategy.eachPlugin { + val property = "plugin.${requested.id.id}" + if (extra.has(property) && resolutionStrategyConfig != "false") { + val version = extra.get(property) as String + if (resolutionStrategyConfig == "verbose") println("ResolutionStrategy selected version=$version from property=$property") + useVersion(version) + } + } +} +rootProject.name = "sample-android" +includeBuild("../plugin") + diff --git a/sample-groovy/build.gradle b/sample-groovy/build.gradle index 9dc5d2954..198657e29 100644 --- a/sample-groovy/build.gradle +++ b/sample-groovy/build.gradle @@ -10,7 +10,6 @@ group = "de.fayard" buildSrcVersions { // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 - indent = " " } repositories { @@ -35,12 +34,9 @@ def isNonStable = { String version -> buildSrcVersions { useFqdnFor('module', 'com.google.inject') - renameLibs = "Libs" - renameVersions = "Versions" - indent = " " -// rejectVersionIf { -// isNonStable(candidate.version) && !isNonStable(currentVersion) -// } + rejectVersionIf { + isNonStable(candidate.version) && !isNonStable(currentVersion) + } } wrapper { distributionType = Wrapper.DistributionType.ALL diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts index 85d1c112b..6b17daba4 100644 --- a/sample-kotlin/build.gradle.kts +++ b/sample-kotlin/build.gradle.kts @@ -48,9 +48,6 @@ buildSrcVersions { // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 alwaysUpdateVersions() useFqdnFor("guice", "mongo-java-driver") - renameLibs = "Libs" - renameVersions = "Versions" - indent = " " rejectVersionIf { isNonStable(candidate.version) && isNonStable(currentVersion).not() } From 8a17d6ea87e87611b4ec368f5e6807dec36c9581 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 08:08:43 +0200 Subject: [PATCH 03/30] simplify: remove VersionsOnlyMode #104 --- .../main/kotlin/de/fayard/VersionsOnlyMode.kt | 55 ------------------- .../de/fayard/internal/DependencyGraph.kt | 36 +++--------- sample-android/build.gradle.kts | 7 --- sample-android/gradle.properties | 4 +- sample-groovy/gradle.properties | 5 +- sample-kotlin/gradle.properties | 3 +- 6 files changed, 14 insertions(+), 96 deletions(-) delete mode 100644 plugin/src/main/kotlin/de/fayard/VersionsOnlyMode.kt diff --git a/plugin/src/main/kotlin/de/fayard/VersionsOnlyMode.kt b/plugin/src/main/kotlin/de/fayard/VersionsOnlyMode.kt deleted file mode 100644 index d6c919d6d..000000000 --- a/plugin/src/main/kotlin/de/fayard/VersionsOnlyMode.kt +++ /dev/null @@ -1,55 +0,0 @@ -package de.fayard - -import de.fayard.internal.PluginConfig -import de.fayard.internal.UpdateVersionsOnly.doubleQuote -import de.fayard.internal.UpdateVersionsOnly.singleQuote -import de.fayard.internal.UpdateVersionsOnly.slashslash - -enum class VersionsOnlyMode { - KOTLIN_VAL, - KOTLIN_OBJECT, - GROOVY_DEF, - GROOVY_EXT, - GRADLE_PROPERTIES; - - val quote: String get() = when(this) { - KOTLIN_VAL, - KOTLIN_OBJECT -> doubleQuote - GROOVY_DEF, - GROOVY_EXT -> singleQuote - GRADLE_PROPERTIES -> "" - } - - fun suggestedFilename(): String = when(this) { - KOTLIN_VAL -> "build.gradle.kts" - KOTLIN_OBJECT -> "Versions.kt" - GROOVY_DEF -> "build.gradle" - GROOVY_EXT -> "build.gradle" - GRADLE_PROPERTIES -> "gradle.properties" - } - - val comment: String get() = when(this) { - GRADLE_PROPERTIES -> "#" - KOTLIN_VAL, - GROOVY_DEF, - KOTLIN_OBJECT, - GROOVY_EXT -> slashslash - } - - val defaultIndent: String get() = when(this) { - GRADLE_PROPERTIES -> PluginConfig.SPACES0 - GROOVY_EXT, - KOTLIN_VAL, - KOTLIN_OBJECT, - GROOVY_DEF -> PluginConfig.SPACES4 - } - - fun beforeAfter(): Pair = when(this) { - GROOVY_EXT -> Pair("ext {", "}") - KOTLIN_VAL, - KOTLIN_OBJECT, - GROOVY_DEF, - GRADLE_PROPERTIES -> Pair(null, null) - } -} - diff --git a/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt b/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt index 86a74be9c..5059c7c87 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt @@ -1,7 +1,5 @@ package de.fayard.internal -import de.fayard.VersionsOnlyMode - data class DependencyGraph( val gradle: GradleConfig, val current: Dependencies, @@ -29,7 +27,7 @@ data class Dependency( var mode: VersionMode = VersionMode.MODULE, val available: AvailableDependency? = null ) { - fun groupOrVirtualGroup() : String = virtualGroup(this) ?: group + fun groupOrVirtualGroup(): String = virtualGroup(this) ?: group val module: String get() = name val versionName: String @@ -72,33 +70,15 @@ data class GradleConfig( ) data class GradleVersion( - val version: String = "", - val reason: String = "", - val isUpdateAvailable: Boolean = false, - val isFailure: Boolean = false + val version: String = "", + val reason: String = "", + val isUpdateAvailable: Boolean = false, + val isFailure: Boolean = false ) data class AvailableDependency( - val release: String? = "", - val milestone: String? = "", - val integration: String? = "" + val release: String? = "", + val milestone: String? = "", + val integration: String? = "" ) - -data class SingleModeResult( - val startOfBlock: Int, - val endOfBlock: Int, - val indentation: String -) { - fun isBlockNotFound(): Boolean { - return startOfBlock == -1 && endOfBlock == -1 - } - - fun isNewFile() = startOfBlock == 0 && endOfBlock == 0 - - companion object { - fun blockNotFound(versionMode: VersionsOnlyMode) = SingleModeResult(-1, -1, versionMode.defaultIndent) - fun newFile(versionMode: VersionsOnlyMode) = SingleModeResult(0, 0, versionMode.defaultIndent) - } -} - diff --git a/sample-android/build.gradle.kts b/sample-android/build.gradle.kts index 6b23493c6..00b63da62 100644 --- a/sample-android/build.gradle.kts +++ b/sample-android/build.gradle.kts @@ -1,5 +1,4 @@ import de.fayard.OrderBy -import de.fayard.VersionsOnlyMode import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { @@ -53,12 +52,6 @@ tasks.register("hello") { group = "Custom" } -tasks.register("checkAll") { - description = "versionsOnlyMode - check all modes" - group = "Custom" - dependsOn(VersionsOnlyMode.values().map { it.name }) -} - buildScan { setTermsOfServiceUrl("https://gradle.com/terms-of-service") setTermsOfServiceAgree("yes") diff --git a/sample-android/gradle.properties b/sample-android/gradle.properties index b63716bd5..805a90814 100644 --- a/sample-android/gradle.properties +++ b/sample-android/gradle.properties @@ -8,6 +8,7 @@ resolutionStrategyConfig=verbose # You can edit the rest of the file, it will be kept intact # See https://github.com/jmfayard/buildSrcVersions/issues/77 plugin.ch.tutteli.kotlin.utils=0.29.0 +# # available=0.30.0 plugin.com.github.ben-manes.versions=0.25.0 plugin.com.gradle.build-scan=2.4.2 plugin.de.fayard.refreshVersions=0.8.0 @@ -20,6 +21,7 @@ version.org.jetbrains.kotlinx.kotlinx-coroutines=1.0.0 # # available=1.3.2 version.org.jetbrains.kotlinx.kotlinx-serialization=0.13.0 version.gradleLatestVersion=5.6.2 +# # available=5.6.3 version.guava=15.0 version.guice=2.0 -version.timber=4.7.0 +version.timber=4.7.0 \ No newline at end of file diff --git a/sample-groovy/gradle.properties b/sample-groovy/gradle.properties index e376e3751..a50018503 100644 --- a/sample-groovy/gradle.properties +++ b/sample-groovy/gradle.properties @@ -10,8 +10,5 @@ resolutionStrategyConfig=verbose plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.com.gradle.build-scan=2.4.2 -version.androidx.annotation..annotation=1.1.0 -version.org.jetbrains..annotation=17.0.0 -version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 -version.guava=15.0 +# # available=5.6.3 \ No newline at end of file diff --git a/sample-kotlin/gradle.properties b/sample-kotlin/gradle.properties index bd22c3d69..39f91e53f 100644 --- a/sample-kotlin/gradle.properties +++ b/sample-kotlin/gradle.properties @@ -16,4 +16,5 @@ version.org.jetbrains.kotlin=1.3.50 version.org.mongodb..mongo-java-driver=3.11.0 version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 -version.guava=15.0 +# # available=5.6.3 +version.guava=15.0 \ No newline at end of file From c66740c7a1ba89ef4c3c1146f5304131f78f7cd1 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 08:12:07 +0200 Subject: [PATCH 04/30] simplify: #112 Rename extension to refreshVersions --- plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt | 2 +- sample-android/build.gradle.kts | 2 +- sample-groovy/build.gradle | 4 ++-- sample-kotlin/build.gradle.kts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt index 6595916ac..9a014f55e 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt @@ -19,10 +19,10 @@ object PluginConfig { const val PLUGIN_VERSION = "0.8.0" // plugin.de.fayard.refreshVersions const val GRADLE_VERSIONS_PLUGIN_ID = "com.github.ben-manes.versions" const val GRADLE_VERSIONS_PLUGIN_VERSION = "0.25.0" // Sync with plugin/build.gradle.kts - const val EXTENSION_NAME = "buildSrcVersions" const val DEPENDENCY_UPDATES = "dependencyUpdates" const val DEPENDENCY_UPDATES_PATH = ":$DEPENDENCY_UPDATES" const val REFRESH_VERSIONS = "refreshVersions" + const val EXTENSION_NAME = REFRESH_VERSIONS /** There is no standard on how to name stable and unstable versions * This version is a good starting point but you can define you rown diff --git a/sample-android/build.gradle.kts b/sample-android/build.gradle.kts index 00b63da62..ec74f3650 100644 --- a/sample-android/build.gradle.kts +++ b/sample-android/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } group = "de.fayard" -buildSrcVersions { +refreshVersions { // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 orderBy = OrderBy.GROUP_AND_ALPHABETICAL } diff --git a/sample-groovy/build.gradle b/sample-groovy/build.gradle index 198657e29..820ffec7a 100644 --- a/sample-groovy/build.gradle +++ b/sample-groovy/build.gradle @@ -8,7 +8,7 @@ plugins { group = "de.fayard" -buildSrcVersions { +refreshVersions { // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 } @@ -32,7 +32,7 @@ def isNonStable = { String version -> return !stableKeyword && !(version ==~ regex) } -buildSrcVersions { +refreshVersions { useFqdnFor('module', 'com.google.inject') rejectVersionIf { isNonStable(candidate.version) && !isNonStable(currentVersion) diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts index 6b17daba4..4a7d98226 100644 --- a/sample-kotlin/build.gradle.kts +++ b/sample-kotlin/build.gradle.kts @@ -44,7 +44,7 @@ tasks.withType { distributionType = Wrapper.DistributionType.ALL } -buildSrcVersions { +refreshVersions { // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 alwaysUpdateVersions() useFqdnFor("guice", "mongo-java-driver") From fdeb4f0a2ba4aa097f3b3db18f6763841f7cfef9 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 08:27:23 +0200 Subject: [PATCH 05/30] simplify: #112 Rename project to "refreshVersions" --- plugin/build.gradle.kts | 2 +- ...tension.kt => RefreshVersionsExtension.kt} | 2 +- ...ionsPlugin.kt => RefreshVersionsPlugin.kt} | 12 +++---- ...VersionsTask.kt => RefreshVersionsTask.kt} | 20 +++++------ .../de/fayard/internal/DependencyGraph.kt | 2 -- .../kotlin/de/fayard/internal/KotlinPoetry.kt | 34 +------------------ .../kotlin/de/fayard/internal/OutputFile.kt | 1 - .../kotlin/de/fayard/internal/PluginConfig.kt | 2 +- ...mpl.kt => RefreshVersionsExtensionImpl.kt} | 8 ++--- ...radleProperties.kt => UpdateProperties.kt} | 6 ++-- .../kotlin/de/fayard/internal/extensions.kt | 31 +++++++++++++++++ plugin/src/test/kotlin/de/fayard/Utils.kt | 2 +- .../fayard/{ => internal}/DependenciesTest.kt | 13 +++---- .../de/fayard/{ => internal}/NonRegression.kt | 18 ++++------ sample-groovy/gradle.properties | 6 +++- 15 files changed, 75 insertions(+), 84 deletions(-) rename plugin/src/main/kotlin/de/fayard/{BuildSrcVersionsExtension.kt => RefreshVersionsExtension.kt} (98%) rename plugin/src/main/kotlin/de/fayard/{BuildSrcVersionsPlugin.kt => RefreshVersionsPlugin.kt} (86%) rename plugin/src/main/kotlin/de/fayard/{BuildSrcVersionsTask.kt => RefreshVersionsTask.kt} (78%) rename plugin/src/main/kotlin/de/fayard/internal/{BuildSrcVersionsExtensionImpl.kt => RefreshVersionsExtensionImpl.kt} (84%) rename plugin/src/main/kotlin/de/fayard/internal/{UpdateGradleProperties.kt => UpdateProperties.kt} (91%) create mode 100644 plugin/src/main/kotlin/de/fayard/internal/extensions.kt rename plugin/src/test/kotlin/de/fayard/{ => internal}/DependenciesTest.kt (93%) rename plugin/src/test/kotlin/de/fayard/{ => internal}/NonRegression.kt (79%) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 29c6a1273..25e4540da 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -21,7 +21,7 @@ gradlePlugin { id = "de.fayard.refreshVersions" displayName = "./gradlew refreshVersions" description = "Painless dependencies management" - implementationClass = "de.fayard.BuildSrcVersionsPlugin" + implementationClass = "de.fayard.RefreshVersionsPlugin" } } } diff --git a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsExtension.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsExtension.kt similarity index 98% rename from plugin/src/main/kotlin/de/fayard/BuildSrcVersionsExtension.kt rename to plugin/src/main/kotlin/de/fayard/RefreshVersionsExtension.kt index 5bdba58bb..d6df2c8dc 100644 --- a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsExtension.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsExtension.kt @@ -3,7 +3,7 @@ package de.fayard import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentFilter import de.fayard.internal.PluginConfig -interface BuildSrcVersionsExtension { +interface RefreshVersionsExtension { /** If you prefer the plugin to update the versions and check afterwards the git diff **/ fun alwaysUpdateVersions() diff --git a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt similarity index 86% rename from plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt rename to plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt index a9a9168e5..879873ee5 100644 --- a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsPlugin.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt @@ -1,7 +1,7 @@ package de.fayard import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask -import de.fayard.internal.BuildSrcVersionsExtensionImpl +import de.fayard.internal.RefreshVersionsExtensionImpl import de.fayard.internal.PluginConfig import de.fayard.internal.PluginConfig.isNonStable import org.gradle.api.Plugin @@ -13,7 +13,7 @@ import org.gradle.kotlin.dsl.create import org.gradle.kotlin.dsl.extra -open class BuildSrcVersionsPlugin : Plugin { +open class RefreshVersionsPlugin : Plugin { override fun apply(project: Project) { check(project == project.rootProject) { "ERROR: plugins de.fayard.refreshVersions must be applied to the root build.gradle(.kts)" } @@ -23,7 +23,7 @@ open class BuildSrcVersionsPlugin : Plugin { } fun Project.configure() = with(PluginConfig) { - extensions.create(BuildSrcVersionsExtension::class, EXTENSION_NAME, BuildSrcVersionsExtensionImpl::class) + extensions.create(RefreshVersionsExtension::class, EXTENSION_NAME, RefreshVersionsExtensionImpl::class) if (supportsTaskAvoidance()) { val provider: TaskProvider = when { @@ -34,14 +34,14 @@ open class BuildSrcVersionsPlugin : Plugin { configureGradleVersions = { operation -> provider.configure(operation) } configureGradleVersions(DependencyUpdatesTask::configureBenManesVersions) - tasks.register(REFRESH_VERSIONS, BuildSrcVersionsTask::class.java, BuildSrcVersionsTask::configureRefreshVersions) + tasks.register(REFRESH_VERSIONS, RefreshVersionsTask::class.java, RefreshVersionsTask::configureRefreshVersions) } else { val dependencyUpdatesTask = tasks.maybeCreate(DEPENDENCY_UPDATES, DependencyUpdatesTask::class.java) configureGradleVersions = { operation -> dependencyUpdatesTask.operation() } configureGradleVersions(DependencyUpdatesTask::configureBenManesVersions) - tasks.create(REFRESH_VERSIONS, BuildSrcVersionsTask::class, BuildSrcVersionsTask::configureRefreshVersions) + tasks.create(REFRESH_VERSIONS, RefreshVersionsTask::class, RefreshVersionsTask::configureRefreshVersions) } } } @@ -79,7 +79,7 @@ fun DependencyUpdatesTask.configureBenManesVersions() { outputFormatter = "json" } -fun BuildSrcVersionsTask.configureRefreshVersions() { +fun RefreshVersionsTask.configureRefreshVersions() { group = "Help" description = "Search for available dependencies updates and update gradle.properties" dependsOn(PluginConfig.DEPENDENCY_UPDATES_PATH) diff --git a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt similarity index 78% rename from plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt rename to plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt index 923ac3aed..2d4b496ae 100644 --- a/plugin/src/main/kotlin/de/fayard/BuildSrcVersionsTask.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt @@ -1,11 +1,11 @@ package de.fayard -import de.fayard.internal.BuildSrcVersionsExtensionImpl +import de.fayard.internal.RefreshVersionsExtensionImpl import de.fayard.internal.Dependency import de.fayard.internal.DependencyGraph import de.fayard.internal.OutputFile import de.fayard.internal.PluginConfig -import de.fayard.internal.UpdateGradleProperties +import de.fayard.internal.UpdateProperties import de.fayard.internal.parseGraph import de.fayard.internal.sortedBeautifullyBy import org.gradle.api.Action @@ -17,7 +17,7 @@ import org.gradle.api.tasks.options.Option import org.gradle.kotlin.dsl.getByType @Suppress("UnstableApiUsage") -open class BuildSrcVersionsTask : DefaultTask() { +open class RefreshVersionsTask : DefaultTask() { @Input @Option(description = "Update all versions, I will check git diff afterwards") @@ -30,8 +30,8 @@ open class BuildSrcVersionsTask : DefaultTask() { @TaskAction fun taskActionGradleProperties() { - val extension: BuildSrcVersionsExtensionImpl = extension() - val updateGradleProperties = UpdateGradleProperties(extension) + val extension: RefreshVersionsExtensionImpl = extension() + val updateGradleProperties = UpdateProperties(extension) val specialDependencies = listOf(PluginConfig.gradleVersionsPlugin, PluginConfig.gradleRefreshVersions, PluginConfig.gradleLatestVersion(dependencyGraph)) @@ -46,7 +46,7 @@ open class BuildSrcVersionsTask : DefaultTask() { } private val dependencyGraph: DependencyGraph by lazy { - val extension: BuildSrcVersionsExtensionImpl = extension() + val extension: RefreshVersionsExtensionImpl = extension() val message = with(PluginConfig) { """ @@ -69,16 +69,16 @@ open class BuildSrcVersionsTask : DefaultTask() { } @Input @Optional @Transient - private lateinit var _extension: BuildSrcVersionsExtensionImpl + private lateinit var _extension: RefreshVersionsExtensionImpl - fun configure(action: Action) { - val projectExtension = project.extensions.getByType() as BuildSrcVersionsExtensionImpl + fun configure(action: Action) { + val projectExtension = project.extensions.getByType() as RefreshVersionsExtensionImpl this._extension = projectExtension.defensiveCopy() action.execute(this._extension) PluginConfig.useRefreshVersions = project.hasProperty("plugin.de.fayard.buildSrcVersions") || project.hasProperty("plugin.de.refreshVersions") } - private fun extension(): BuildSrcVersionsExtensionImpl = _extension + private fun extension(): RefreshVersionsExtensionImpl = _extension } diff --git a/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt b/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt index 5059c7c87..7a53fb203 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt @@ -9,8 +9,6 @@ data class DependencyGraph( val count: Int = 0 ) -fun Dependency.gradleNotation() = "$group:$name:$version" - data class Dependencies( val dependencies: List = emptyList(), val count: Int = 0 diff --git a/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt b/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt index a60a49226..4dce4abb3 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt @@ -1,19 +1,5 @@ package de.fayard.internal -import de.fayard.OrderBy -import de.fayard.OrderBy.GROUP_AND_ALPHABETICAL -import de.fayard.OrderBy.GROUP_AND_LENGTH - - -// https://github.com/jmfayard/buildSrcVersions/issues/65 -fun List.sortedBeautifullyBy(orderBy: OrderBy, selection: (Dependency) -> String?) : List { - val unsorted = this.filterNot { selection(it) == null } - .sortedBy { selection(it)!! } - return when(orderBy) { - GROUP_AND_LENGTH -> unsorted.sortedByDescending { selection(it)!!.length }.sortedBy { it.mode } - GROUP_AND_ALPHABETICAL -> unsorted.sortedBy { it.mode } - } -} fun Dependency.versionInformation(): String { val newerVersion = newerVersion() @@ -27,7 +13,7 @@ fun Dependency.versionInformation(): String { return if (addNewLine) "\n$comment" else comment } -fun Dependency.newerVersion(): String? = +fun Dependency.newerVersion(): String? = when { available == null -> null available.release.isNullOrBlank().not() -> available.release @@ -63,21 +49,3 @@ fun List.checkModeAndNames(useFdqnByDefault: List): List.orderDependencies(): List { - return this.sortedBy { it.gradleNotation() } -} - - -fun List.findCommonVersions(): List { - val map = groupBy { d: Dependency -> d.groupOrVirtualGroup() } - for (deps in map.values) { - val sameVersions = deps.map { it.version }.distinct().size == 1 - val hasVirtualGroup = deps.any { it.groupOrVirtualGroup() != it.group } - if (sameVersions && (hasVirtualGroup || deps.size > 1)) { - deps.forEach { d -> d.mode = VersionMode.GROUP } - } - } - return this -} diff --git a/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt b/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt index 8d54a0de2..6239a3106 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt @@ -1,6 +1,5 @@ package de.fayard.internal -import de.fayard.BuildSrcVersionsExtension import org.gradle.api.Project internal enum class OutputFile(var path: String, var existed: Boolean = false, val alternativePath: String? = null) { diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt index 9a014f55e..a3640e194 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt @@ -139,7 +139,7 @@ object PluginConfig { val dependencyGraphAdapter: JsonAdapter by moshiAdapter() - internal val extensionAdapter: JsonAdapter by moshiAdapter() + internal val extensionAdapter: JsonAdapter by moshiAdapter() fun readGraphFromJsonFile(jsonInput: File): DependencyGraph { return dependencyGraphAdapter.fromJson(jsonInput.source().buffer())!! diff --git a/plugin/src/main/kotlin/de/fayard/internal/BuildSrcVersionsExtensionImpl.kt b/plugin/src/main/kotlin/de/fayard/internal/RefreshVersionsExtensionImpl.kt similarity index 84% rename from plugin/src/main/kotlin/de/fayard/internal/BuildSrcVersionsExtensionImpl.kt rename to plugin/src/main/kotlin/de/fayard/internal/RefreshVersionsExtensionImpl.kt index d744fac25..94168a8b1 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/BuildSrcVersionsExtensionImpl.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/RefreshVersionsExtensionImpl.kt @@ -1,18 +1,18 @@ package de.fayard.internal import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentFilter -import de.fayard.BuildSrcVersionsExtension +import de.fayard.RefreshVersionsExtension import de.fayard.OrderBy -internal open class BuildSrcVersionsExtensionImpl( +internal open class RefreshVersionsExtensionImpl( override var propertiesFile: String? = null, var useFqqnFor: List = emptyList(), var alwaysUpdateVersions: Boolean = false, override var orderBy: OrderBy = OrderBy.GROUP_AND_LENGTH -) : BuildSrcVersionsExtension, java.io.Serializable { +) : RefreshVersionsExtension, java.io.Serializable { // Necessary because of https://github.com/jmfayard/buildSrcVersions/issues/92 - fun defensiveCopy(): BuildSrcVersionsExtensionImpl = BuildSrcVersionsExtensionImpl( + fun defensiveCopy(): RefreshVersionsExtensionImpl = RefreshVersionsExtensionImpl( propertiesFile, useFqqnFor, alwaysUpdateVersions, orderBy ) diff --git a/plugin/src/main/kotlin/de/fayard/internal/UpdateGradleProperties.kt b/plugin/src/main/kotlin/de/fayard/internal/UpdateProperties.kt similarity index 91% rename from plugin/src/main/kotlin/de/fayard/internal/UpdateGradleProperties.kt rename to plugin/src/main/kotlin/de/fayard/internal/UpdateProperties.kt index 382d8a236..be1e32427 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/UpdateGradleProperties.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/UpdateProperties.kt @@ -1,10 +1,10 @@ package de.fayard.internal -import de.fayard.BuildSrcVersionsExtension +import de.fayard.RefreshVersionsExtension import java.io.File -data class UpdateGradleProperties( - val extension: BuildSrcVersionsExtension +data class UpdateProperties( + val extension: RefreshVersionsExtension ) { fun generateVersionProperties(file: File, dependencies: List) = with(UpdateVersionsOnly) { diff --git a/plugin/src/main/kotlin/de/fayard/internal/extensions.kt b/plugin/src/main/kotlin/de/fayard/internal/extensions.kt new file mode 100644 index 000000000..02dcc8960 --- /dev/null +++ b/plugin/src/main/kotlin/de/fayard/internal/extensions.kt @@ -0,0 +1,31 @@ +package de.fayard.internal + +import de.fayard.OrderBy + +fun Dependency.gradleNotation() = "$group:$name:$version" + +fun List.orderDependencies(): List { + return this.sortedBy { it.gradleNotation() } +} + +fun List.findCommonVersions(): List { + val map = groupBy { d: Dependency -> d.groupOrVirtualGroup() } + for (deps in map.values) { + val sameVersions = deps.map { it.version }.distinct().size == 1 + val hasVirtualGroup = deps.any { it.groupOrVirtualGroup() != it.group } + if (sameVersions && (hasVirtualGroup || deps.size > 1)) { + deps.forEach { d -> d.mode = VersionMode.GROUP } + } + } + return this +} + +// https://github.com/jmfayard/buildSrcVersions/issues/65 +fun List.sortedBeautifullyBy(orderBy: OrderBy, selection: (Dependency) -> String?) : List { + val unsorted = this.filterNot { selection(it) == null } + .sortedBy { selection(it)!! } + return when(orderBy) { + OrderBy.GROUP_AND_LENGTH -> unsorted.sortedByDescending { selection(it)!!.length }.sortedBy { it.mode } + OrderBy.GROUP_AND_ALPHABETICAL -> unsorted.sortedBy { it.mode } + } +} diff --git a/plugin/src/test/kotlin/de/fayard/Utils.kt b/plugin/src/test/kotlin/de/fayard/Utils.kt index d5980070d..ffa35649b 100644 --- a/plugin/src/test/kotlin/de/fayard/Utils.kt +++ b/plugin/src/test/kotlin/de/fayard/Utils.kt @@ -19,7 +19,7 @@ fun List.joinToStringWithNewLines(): String = val testResourcesDir: File get() = File("src/test/resources").absoluteFile -val buildSrcVersionsDir: File +val refreshVersionsDir: File get() = File(".").absoluteFile.parentFile.parentFile /** diff --git a/plugin/src/test/kotlin/de/fayard/DependenciesTest.kt b/plugin/src/test/kotlin/de/fayard/internal/DependenciesTest.kt similarity index 93% rename from plugin/src/test/kotlin/de/fayard/DependenciesTest.kt rename to plugin/src/test/kotlin/de/fayard/internal/DependenciesTest.kt index 07e76039b..272cd4268 100644 --- a/plugin/src/test/kotlin/de/fayard/DependenciesTest.kt +++ b/plugin/src/test/kotlin/de/fayard/internal/DependenciesTest.kt @@ -1,12 +1,7 @@ -package de.fayard - -import de.fayard.internal.Dependency -import de.fayard.internal.PluginConfig -import de.fayard.internal.VersionMode -import de.fayard.internal.findCommonVersions -import de.fayard.internal.sortedBeautifullyBy -import io.kotlintest.matchers.collections.containExactlyInAnyOrder -import io.kotlintest.should +package de.fayard.internal + +import de.fayard.OrderBy +import de.fayard.asDependency import io.kotlintest.shouldBe import io.kotlintest.specs.FreeSpec diff --git a/plugin/src/test/kotlin/de/fayard/NonRegression.kt b/plugin/src/test/kotlin/de/fayard/internal/NonRegression.kt similarity index 79% rename from plugin/src/test/kotlin/de/fayard/NonRegression.kt rename to plugin/src/test/kotlin/de/fayard/internal/NonRegression.kt index 986826c19..aa00605ee 100644 --- a/plugin/src/test/kotlin/de/fayard/NonRegression.kt +++ b/plugin/src/test/kotlin/de/fayard/internal/NonRegression.kt @@ -1,12 +1,8 @@ -package de.fayard +package de.fayard.internal -import de.fayard.internal.BuildSrcVersionsExtensionImpl -import de.fayard.internal.Dependency -import de.fayard.internal.PluginConfig -import de.fayard.internal.UpdateGradleProperties -import de.fayard.internal.parseGraph -import de.fayard.internal.sortedBeautifullyBy -import io.kotlintest.matchers.collections.shouldBeEmpty +import de.fayard.OrderBy +import de.fayard.refreshVersionsDir +import de.fayard.testResourceFile import io.kotlintest.matchers.withClue import io.kotlintest.shouldBe import io.kotlintest.specs.FreeSpec @@ -22,7 +18,7 @@ class NonRegression : FreeSpec({ val received = approved.resolveSibling(approved.nameWithoutExtension + "-received." + approved.extension) val message = """ |Files differ. Run: - | diff -u ${approved.relativeTo(buildSrcVersionsDir)} ${received.relativeTo(buildSrcVersionsDir)} + | diff -u ${approved.relativeTo(refreshVersionsDir)} ${received.relativeTo(refreshVersionsDir)} |""".trimMargin() return Pair(received, message) } @@ -44,8 +40,8 @@ class NonRegression : FreeSpec({ val propertiesFile = propertiesFolder.resolve(name) val (received, message) = receivedMessage(propertiesFile) - val extension = BuildSrcVersionsExtensionImpl( - propertiesFile = propertiesFile.relativeTo(buildSrcVersionsDir).path + val extension = RefreshVersionsExtensionImpl( + propertiesFile = propertiesFile.relativeTo(refreshVersionsDir).path ) val dependencies = (dependencyGraph.map { it.copy(available = null) }) .sortedBeautifullyBy(OrderBy.GROUP_AND_LENGTH) { it.versionProperty } diff --git a/sample-groovy/gradle.properties b/sample-groovy/gradle.properties index a50018503..c04c23039 100644 --- a/sample-groovy/gradle.properties +++ b/sample-groovy/gradle.properties @@ -10,5 +10,9 @@ resolutionStrategyConfig=verbose plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.com.gradle.build-scan=2.4.2 +version.androidx.annotation..annotation=1.1.0 +version.org.jetbrains..annotation=17.0.0 +version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 -# # available=5.6.3 \ No newline at end of file +# # available=5.6.3 +version.guava=15.0 \ No newline at end of file From 4cb282186283c2d34bead44ccd80c06809b8ca98 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 08:33:18 +0200 Subject: [PATCH 06/30] simplify: remove Outputfile --- .../kotlin/de/fayard/RefreshVersionsPlugin.kt | 4 +- .../kotlin/de/fayard/RefreshVersionsTask.kt | 11 +++--- .../kotlin/de/fayard/internal/OutputFile.kt | 38 ------------------- .../kotlin/de/fayard/internal/PluginConfig.kt | 1 + .../kotlin/de/fayard/internal/extensions.kt | 12 ++++++ .../de/fayard/internal/NonRegression.kt | 2 +- sample-groovy/gradle.properties | 6 +-- 7 files changed, 23 insertions(+), 51 deletions(-) delete mode 100644 plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt diff --git a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt index 879873ee5..2b5b9d0e8 100644 --- a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt @@ -1,9 +1,9 @@ package de.fayard import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask -import de.fayard.internal.RefreshVersionsExtensionImpl import de.fayard.internal.PluginConfig import de.fayard.internal.PluginConfig.isNonStable +import de.fayard.internal.RefreshVersionsExtensionImpl import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.ModuleVersionSelector @@ -85,6 +85,6 @@ fun RefreshVersionsTask.configureRefreshVersions() { dependsOn(PluginConfig.DEPENDENCY_UPDATES_PATH) outputs.upToDateWhen { false } configure { - propertiesFile = "gradle.properties" + propertiesFile = PluginConfig.DEFAULT_PROPERTIES_FILE } } diff --git a/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt index 2d4b496ae..4edaeb662 100644 --- a/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt @@ -1,11 +1,11 @@ package de.fayard -import de.fayard.internal.RefreshVersionsExtensionImpl import de.fayard.internal.Dependency import de.fayard.internal.DependencyGraph -import de.fayard.internal.OutputFile import de.fayard.internal.PluginConfig +import de.fayard.internal.RefreshVersionsExtensionImpl import de.fayard.internal.UpdateProperties +import de.fayard.internal.logFileWasModified import de.fayard.internal.parseGraph import de.fayard.internal.sortedBeautifullyBy import org.gradle.api.Action @@ -40,9 +40,10 @@ open class RefreshVersionsTask : DefaultTask() { .sortedBeautifullyBy(extension.orderBy) { it.versionProperty } .distinctBy { it.versionProperty } - updateGradleProperties.generateVersionProperties(project.file("gradle.properties"), dependencies) - OutputFile.GRADLE_PROPERTIES.logFileWasModified() - + val propertiesFile = project.file(extension.propertiesFile!!) + val existed = propertiesFile.canRead() + updateGradleProperties.generateVersionProperties(propertiesFile, dependencies) + logFileWasModified(propertiesFile.name, existed) } private val dependencyGraph: DependencyGraph by lazy { diff --git a/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt b/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt deleted file mode 100644 index 6239a3106..000000000 --- a/plugin/src/main/kotlin/de/fayard/internal/OutputFile.kt +++ /dev/null @@ -1,38 +0,0 @@ -package de.fayard.internal - -import org.gradle.api.Project - -internal enum class OutputFile(var path: String, var existed: Boolean = false, val alternativePath: String? = null) { - OUTPUTDIR("buildSrc/src/main/kotlin"), - BUILD("buildSrc/build.gradle.kts", alternativePath = "buildSrc/build.gradle"), - GIT_IGNORE("buildSrc/.gitignore"), - LIBS("buildSrc/src/main/kotlin/Libs.kt"), - VERSIONS("buildSrc/src/main/kotlin/Versions.kt"), - GRADLE_PROPERTIES("gradle.properties"); - - fun fileExists(project: Project) = when { - project.file(path).exists() -> true - alternativePath != null -> project.file(alternativePath).exists() - else -> false - } - - fun logFileWasModified() { - logFileWasModified(path, existed) - } - - companion object { - - fun logFileWasModified(path: String, existed: Boolean) { - val ANSI_RESET = "\u001B[0m" - val ANSI_GREEN = "\u001B[32m" - - val status = if (existed) { - " modified: " - } else { - " new file: " - } - println("$ANSI_GREEN$status$path$ANSI_RESET") - } - - } -} diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt index a3640e194..a59effa38 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt @@ -23,6 +23,7 @@ object PluginConfig { const val DEPENDENCY_UPDATES_PATH = ":$DEPENDENCY_UPDATES" const val REFRESH_VERSIONS = "refreshVersions" const val EXTENSION_NAME = REFRESH_VERSIONS + const val DEFAULT_PROPERTIES_FILE = "gradle.properties" /** There is no standard on how to name stable and unstable versions * This version is a good starting point but you can define you rown diff --git a/plugin/src/main/kotlin/de/fayard/internal/extensions.kt b/plugin/src/main/kotlin/de/fayard/internal/extensions.kt index 02dcc8960..9fcbc72c3 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/extensions.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/extensions.kt @@ -29,3 +29,15 @@ fun List.sortedBeautifullyBy(orderBy: OrderBy, selection: (Dependenc OrderBy.GROUP_AND_ALPHABETICAL -> unsorted.sortedBy { it.mode } } } + +fun logFileWasModified(path: String, existed: Boolean) { + val ANSI_RESET = "\u001B[0m" + val ANSI_GREEN = "\u001B[32m" + + val status = if (existed) { + " modified: " + } else { + " new file: " + } + println("$ANSI_GREEN$status$path$ANSI_RESET") +} diff --git a/plugin/src/test/kotlin/de/fayard/internal/NonRegression.kt b/plugin/src/test/kotlin/de/fayard/internal/NonRegression.kt index aa00605ee..d855ba288 100644 --- a/plugin/src/test/kotlin/de/fayard/internal/NonRegression.kt +++ b/plugin/src/test/kotlin/de/fayard/internal/NonRegression.kt @@ -46,7 +46,7 @@ class NonRegression : FreeSpec({ val dependencies = (dependencyGraph.map { it.copy(available = null) }) .sortedBeautifullyBy(OrderBy.GROUP_AND_LENGTH) { it.versionProperty } .distinctBy { it.versionProperty } - UpdateGradleProperties(extension).generateVersionProperties(received, dependencies) + UpdateProperties(extension).generateVersionProperties(received, dependencies) if (propertiesFile.exists()) { val receivedIdentifiers = received.readLines().map { it.substringBefore("=", "") }.filter { it.startsWith("#") || it.isBlank() } diff --git a/sample-groovy/gradle.properties b/sample-groovy/gradle.properties index c04c23039..a50018503 100644 --- a/sample-groovy/gradle.properties +++ b/sample-groovy/gradle.properties @@ -10,9 +10,5 @@ resolutionStrategyConfig=verbose plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.com.gradle.build-scan=2.4.2 -version.androidx.annotation..annotation=1.1.0 -version.org.jetbrains..annotation=17.0.0 -version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 -# # available=5.6.3 -version.guava=15.0 \ No newline at end of file +# # available=5.6.3 \ No newline at end of file From 6be3c797727f72850679765684f6138de81a831b Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 08:47:45 +0200 Subject: [PATCH 07/30] feature(#102): alignVersionsForGroups --- .../src/main/kotlin/de/fayard/RefreshVersionsExtension.kt | 2 ++ plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt | 5 +++-- plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt | 2 ++ .../src/main/kotlin/de/fayard/internal/DependencyGraph.kt | 2 +- plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt | 6 ++++-- .../de/fayard/internal/RefreshVersionsExtensionImpl.kt | 7 ++++--- sample-android/build.gradle.kts | 1 + sample-android/gradle.properties | 8 +++++--- 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/plugin/src/main/kotlin/de/fayard/RefreshVersionsExtension.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsExtension.kt index d6df2c8dc..447bd4817 100644 --- a/plugin/src/main/kotlin/de/fayard/RefreshVersionsExtension.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsExtension.kt @@ -47,6 +47,8 @@ interface RefreshVersionsExtension { ***/ fun useFqdnFor(vararg dependencyName: String) + var alignVersionsForGroups: MutableList + /** * See [versionsOnlyMode] * Probably "gradle.properties" for GRADLE_PROPERTIES, "build.gradle" for GROOVY_DEF, ... diff --git a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt index 2b5b9d0e8..0e30b7d51 100644 --- a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt @@ -19,7 +19,7 @@ open class RefreshVersionsPlugin : Plugin { check(project == project.rootProject) { "ERROR: plugins de.fayard.refreshVersions must be applied to the root build.gradle(.kts)" } project.apply(plugin = PluginConfig.GRADLE_VERSIONS_PLUGIN_ID) project.configure() - project.useVersionsFromGradleProperties() + project.useVersionsFromProperties() } fun Project.configure() = with(PluginConfig) { @@ -46,7 +46,7 @@ open class RefreshVersionsPlugin : Plugin { } } -fun Project.useVersionsFromGradleProperties() { +fun Project.useVersionsFromProperties() { val resolutionStrategyConfig = project.findProperty("resolutionStrategyConfig") as? String if (resolutionStrategyConfig == "false") return allprojects { @@ -86,5 +86,6 @@ fun RefreshVersionsTask.configureRefreshVersions() { outputs.upToDateWhen { false } configure { propertiesFile = PluginConfig.DEFAULT_PROPERTIES_FILE + alignVersionsForGroups = mutableListOf() } } diff --git a/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt index 4edaeb662..3ed4b6eb1 100644 --- a/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsTask.kt @@ -77,6 +77,8 @@ open class RefreshVersionsTask : DefaultTask() { this._extension = projectExtension.defensiveCopy() action.execute(this._extension) PluginConfig.useRefreshVersions = project.hasProperty("plugin.de.fayard.buildSrcVersions") || project.hasProperty("plugin.de.refreshVersions") + PluginConfig.ALIGN_VERSION_GROUPS.clear() + PluginConfig.ALIGN_VERSION_GROUPS.addAll(_extension.alignVersionsForGroups) } diff --git a/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt b/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt index 7a53fb203..f321456e0 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/DependencyGraph.kt @@ -45,7 +45,7 @@ data class Dependency( companion object { fun virtualGroup(dependency: Dependency, withVersion: Boolean = false): String? { - val virtualGroup = PluginConfig.virtualGroups.firstOrNull { "${dependency.group}.${dependency.module}".startsWith(it) } + val virtualGroup = PluginConfig.ALIGN_VERSION_GROUPS.firstOrNull { "${dependency.group}.${dependency.module}".startsWith(it) } return when { virtualGroup == null -> null withVersion -> "version.$virtualGroup" diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt index a59effa38..0788e9119 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt @@ -60,9 +60,11 @@ object PluginConfig { * For now this list is not part of the public API but feel free to add feedback that you need it. * Add your use case here https://github.com/jmfayard/buildSrcVersions/issues/102 ***/ - val virtualGroups : MutableList = mutableListOf( + val ALIGN_VERSION_GROUPS: MutableList = mutableListOf( "org.jetbrains.kotlinx.kotlinx-coroutines", - "org.jetbrains.kotlinx.kotlinx-serialization" + "org.jetbrains.kotlinx.kotlinx-serialization", + "com.louiscad.splitties:splitties", + "com.squareup.retrofit2" ) diff --git a/plugin/src/main/kotlin/de/fayard/internal/RefreshVersionsExtensionImpl.kt b/plugin/src/main/kotlin/de/fayard/internal/RefreshVersionsExtensionImpl.kt index 94168a8b1..f897f3fb5 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/RefreshVersionsExtensionImpl.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/RefreshVersionsExtensionImpl.kt @@ -1,19 +1,20 @@ package de.fayard.internal import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentFilter -import de.fayard.RefreshVersionsExtension import de.fayard.OrderBy +import de.fayard.RefreshVersionsExtension internal open class RefreshVersionsExtensionImpl( override var propertiesFile: String? = null, var useFqqnFor: List = emptyList(), var alwaysUpdateVersions: Boolean = false, - override var orderBy: OrderBy = OrderBy.GROUP_AND_LENGTH + override var orderBy: OrderBy = OrderBy.GROUP_AND_LENGTH, + override var alignVersionsForGroups: MutableList = PluginConfig.ALIGN_VERSION_GROUPS ) : RefreshVersionsExtension, java.io.Serializable { // Necessary because of https://github.com/jmfayard/buildSrcVersions/issues/92 fun defensiveCopy(): RefreshVersionsExtensionImpl = RefreshVersionsExtensionImpl( - propertiesFile, useFqqnFor, alwaysUpdateVersions, orderBy + propertiesFile, useFqqnFor, alwaysUpdateVersions, orderBy, alignVersionsForGroups ) override fun alwaysUpdateVersions() { diff --git a/sample-android/build.gradle.kts b/sample-android/build.gradle.kts index ec74f3650..86067a681 100644 --- a/sample-android/build.gradle.kts +++ b/sample-android/build.gradle.kts @@ -14,6 +14,7 @@ group = "de.fayard" refreshVersions { // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 orderBy = OrderBy.GROUP_AND_ALPHABETICAL + //alignVersionsForGroups = listOf() } repositories { diff --git a/sample-android/gradle.properties b/sample-android/gradle.properties index 805a90814..995236442 100644 --- a/sample-android/gradle.properties +++ b/sample-android/gradle.properties @@ -17,11 +17,13 @@ plugin.org.jetbrains.kotlin.jvm=1.3.50 plugin.org.lovedev.greeting.kotlin=1.1 version.com.wealthfront=1.1.0 version.org.jetbrains.kotlin=1.3.50 -version.org.jetbrains.kotlinx.kotlinx-coroutines=1.0.0 -# # available=1.3.2 -version.org.jetbrains.kotlinx.kotlinx-serialization=0.13.0 version.gradleLatestVersion=5.6.2 # # available=5.6.3 version.guava=15.0 version.guice=2.0 +version.kotlinx-coroutines-core=1.0.0 +# # available=1.3.2 +version.kotlinx-coroutines-core-common=1.0.0 +# # available=1.3.2 +version.kotlinx-serialization-runtime=0.13.0 version.timber=4.7.0 \ No newline at end of file From e9ed893b956242944caf95db9bc9fa9ac6f9d3df Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 09:00:48 +0200 Subject: [PATCH 08/30] sample-android: add com.louiscad.splitties --- sample-android/gradle.properties | 2 -- sample-kotlin/build.gradle.kts | 13 +++++++++++++ sample-kotlin/gradle.properties | 5 +++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/sample-android/gradle.properties b/sample-android/gradle.properties index 995236442..87cd8ede5 100644 --- a/sample-android/gradle.properties +++ b/sample-android/gradle.properties @@ -22,8 +22,6 @@ version.gradleLatestVersion=5.6.2 version.guava=15.0 version.guice=2.0 version.kotlinx-coroutines-core=1.0.0 -# # available=1.3.2 version.kotlinx-coroutines-core-common=1.0.0 -# # available=1.3.2 version.kotlinx-serialization-runtime=0.13.0 version.timber=4.7.0 \ No newline at end of file diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts index 4a7d98226..a19dbeb14 100644 --- a/sample-kotlin/build.gradle.kts +++ b/sample-kotlin/build.gradle.kts @@ -1,8 +1,12 @@ +import com.louiscad.splitties.AndroidX +import com.louiscad.splitties.KotlinX +import com.louiscad.splitties.Testing import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("de.fayard.refreshVersions") kotlin("jvm") + id("com.louiscad.splitties") `build-scan` } @@ -16,7 +20,16 @@ repositories { mavenCentral() } +fun DependencyHandler.implementations(deps: List) = + deps.forEach { implementation(it) } + +fun DependencyHandler.testImplementations(deps: List) = + deps.forEach { testImplementation(it) } + dependencies { + implementations(listOf(AndroidX.browser, AndroidX.cardView)) + testImplementations(listOf(KotlinX.coroutines.core, KotlinX.coroutines.coreCommon)) + testImplementations(listOf(Testing.kotestRunner, Testing.kotestExtensions)) implementation("com.google.guava:guava:15.0") implementation("com.google.inject:guice:2.0") implementation("com.squareup.okhttp3:okhttp:3.10.0") diff --git a/sample-kotlin/gradle.properties b/sample-kotlin/gradle.properties index 39f91e53f..8dce5ab47 100644 --- a/sample-kotlin/gradle.properties +++ b/sample-kotlin/gradle.properties @@ -10,11 +10,16 @@ resolutionStrategyConfig=verbose plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.org.jetbrains.kotlin.jvm=1.3.50 +plugin.com.louiscad.splitties=0.1.2 plugin.com.gradle.build-scan=2.4.2 +version.org.jetbrains.kotlinx=1.3.2 version.com.squareup.okhttp3=4.2.0 version.org.jetbrains.kotlin=1.3.50 +version.io.kotestArtifact=+ version.org.mongodb..mongo-java-driver=3.11.0 version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 # # available=5.6.3 +version.cardview=+ +version.browser=+ version.guava=15.0 \ No newline at end of file From 0ed9f0be8eef219cf2a88d50096c1b8c73ab8178 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 09:47:15 +0200 Subject: [PATCH 09/30] pr: solve conflicts --- sample-groovy/gradle.properties | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sample-groovy/gradle.properties b/sample-groovy/gradle.properties index d1bdaa99c..c04c23039 100644 --- a/sample-groovy/gradle.properties +++ b/sample-groovy/gradle.properties @@ -10,5 +10,9 @@ resolutionStrategyConfig=verbose plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.com.gradle.build-scan=2.4.2 +version.androidx.annotation..annotation=1.1.0 +version.org.jetbrains..annotation=17.0.0 +version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 # # available=5.6.3 +version.guava=15.0 \ No newline at end of file From be2d71d1211b2deede41d6100a10d92d021529e4 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 16:51:08 +0200 Subject: [PATCH 10/30] sample-kotlin: use versions.properties --- .../kotlin/de/fayard/RefreshVersionsPlugin.kt | 12 +++++++---- sample-android/gradle.properties | 1 + sample-kotlin/build.gradle.kts | 19 ++++++++++------- sample-kotlin/gradle.properties | 2 +- sample-kotlin/settings.gradle.kts | 20 ++++++++++++------ sample-kotlin/versions.properties | 21 +++++++++++++++++++ 6 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 sample-kotlin/versions.properties diff --git a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt index 0e30b7d51..d0caeb603 100644 --- a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt @@ -10,7 +10,7 @@ import org.gradle.api.artifacts.ModuleVersionSelector import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.create -import org.gradle.kotlin.dsl.extra +import java.util.Properties open class RefreshVersionsPlugin : Plugin { @@ -47,13 +47,17 @@ open class RefreshVersionsPlugin : Plugin { } fun Project.useVersionsFromProperties() { + @Suppress("UNCHECKED_CAST") + val properties: Map = Properties().apply { + val propertiesFile = listOf("versions.properties", "gradle.properties").first { project.file(it).canRead() } + load(project.file(propertiesFile).reader()) + } as Map + + val resolutionStrategyConfig = project.findProperty("resolutionStrategyConfig") as? String if (resolutionStrategyConfig == "false") return allprojects { val project: Project = this - @Suppress("UNCHECKED_CAST") - val properties = project.extra.properties - .filterKeys { it.startsWith("version.") } as Map project.configurations.all { val configurationName = this.name if (configurationName.contains("copy")) return@all diff --git a/sample-android/gradle.properties b/sample-android/gradle.properties index 87cd8ede5..a8350c7b3 100644 --- a/sample-android/gradle.properties +++ b/sample-android/gradle.properties @@ -11,6 +11,7 @@ plugin.ch.tutteli.kotlin.utils=0.29.0 # # available=0.30.0 plugin.com.github.ben-manes.versions=0.25.0 plugin.com.gradle.build-scan=2.4.2 +# # available=3.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.nebula.kotlin=1.3.50 plugin.org.jetbrains.kotlin.jvm=1.3.50 diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts index fced689db..3cf7f12dd 100644 --- a/sample-kotlin/build.gradle.kts +++ b/sample-kotlin/build.gradle.kts @@ -13,6 +13,16 @@ plugins { group = "de.fayard" +refreshVersions { + // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 + propertiesFile = "versions.properties" + alwaysUpdateVersions() + useFqdnFor("guice", "mongo-java-driver") + rejectVersionIf { + isNonStable(candidate.version) && isNonStable(currentVersion).not() + } +} + repositories { maven { setUrl("../plugin/src/test/resources/maven") @@ -57,14 +67,7 @@ tasks.withType { distributionType = Wrapper.DistributionType.ALL } -refreshVersions { - // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 - alwaysUpdateVersions() - useFqdnFor("guice", "mongo-java-driver") - rejectVersionIf { - isNonStable(candidate.version) && isNonStable(currentVersion).not() - } -} + buildScan { diff --git a/sample-kotlin/gradle.properties b/sample-kotlin/gradle.properties index 2e050f3bf..a798210a9 100644 --- a/sample-kotlin/gradle.properties +++ b/sample-kotlin/gradle.properties @@ -12,7 +12,7 @@ plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.org.jetbrains.kotlin.jvm=1.3.50 plugin.com.louiscad.splitties=0.1.2 -plugin.com.gradle.build-scan=2.4.2 +plugin.com.gradle.build-scan=3.0 version.org.jetbrains.kotlinx=1.3.2 version.com.squareup.okhttp3=4.2.0 version.org.jetbrains.kotlin=1.3.50 diff --git a/sample-kotlin/settings.gradle.kts b/sample-kotlin/settings.gradle.kts index a25b2c2d4..ee9874210 100644 --- a/sample-kotlin/settings.gradle.kts +++ b/sample-kotlin/settings.gradle.kts @@ -1,3 +1,5 @@ +import java.util.Properties + pluginManagement { repositories { mavenLocal() @@ -5,20 +7,26 @@ pluginManagement { } /** - * This `resolutionStrategy` allows plugin versions to be configured from `gradle.properties + * This `resolutionStrategy` allows plugin versions to be configured from + * `versions.properties * The convention is simply * plugin.$PLUGINID=$PLUGIN_VERSION * To check what happen, you can set the property * resolutionStrategyConfig=verbose **/ val resolutionStrategyConfig: String? by extra + if (resolutionStrategyConfig == "false") return@pluginManagement + + @Suppress("UNCHECKED_CAST") + val properties: Map = Properties().apply { + load(file("versions.properties").reader()) + } as Map + resolutionStrategy.eachPlugin { val property = "plugin.${requested.id.id}" - if (extra.has(property) && resolutionStrategyConfig != "false") { - val version = extra.get(property) as String - if (resolutionStrategyConfig == "verbose") println("ResolutionStrategy used version=$version from property=$property") - useVersion(version) - } + val version = properties[property] ?: return@eachPlugin + if (resolutionStrategyConfig == "verbose") println("ResolutionStrategy used version=$version from property=$property") + useVersion(version) } } rootProject.name = "sample-kotlin" diff --git a/sample-kotlin/versions.properties b/sample-kotlin/versions.properties new file mode 100644 index 000000000..5829509d6 --- /dev/null +++ b/sample-kotlin/versions.properties @@ -0,0 +1,21 @@ +# Dependencies and Plugin versions with their available updates +# Generated by $ ./gradlew refreshVersions +# You can edit the rest of the file, it will be kept intact +# See https://github.com/jmfayard/buildSrcVersions/issues/77 +plugin.org.nosphere.gradle.github.actions=1.0.0 +plugin.com.github.ben-manes.versions=0.25.0 +plugin.de.fayard.refreshVersions=0.8.0 +plugin.org.jetbrains.kotlin.jvm=1.3.50 +plugin.com.louiscad.splitties=0.1.2 +plugin.com.gradle.build-scan=3.0 +version.org.jetbrains.kotlinx=1.3.2 +version.com.squareup.okhttp3=4.2.0 +version.org.jetbrains.kotlin=1.3.50 +version.io.kotestArtifact=+ +version.org.mongodb..mongo-java-driver=3.11.0 +version.com.google.inject..guice=2.0 +version.gradleLatestVersion=5.6.2 +# # available=5.6.3 +version.cardview=+ +version.browser=+ +version.guava=15.0 From d9271e28ba3cbe166d451093e4ef1807dbb3e386 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 17:53:03 +0200 Subject: [PATCH 11/30] sample-android: add lots of things --- sample-android/app/android.gradle | 16 ++ sample-android/app/build.gradle.kts | 38 ++++ .../smallvictories/MainActivityTest.kt | 117 ++++++++++++ .../smallvictories/VictoryViewModelTest.kt | 137 ++++++++++++++ .../app/src/main/AndroidManifest.xml | 28 +++ .../app/src/main/ic_launcher-web.png | Bin 0 -> 18814 bytes .../android/smallvictories/MainActivity.kt | 115 ++++++++++++ .../android/smallvictories/Repository.kt | 68 +++++++ .../android/smallvictories/SplashActivity.kt | 45 +++++ .../smallvictories/VictoryRepository.kt | 40 +++++ .../android/smallvictories/VictoryUiModel.kt | 38 ++++ .../smallvictories/VictoryViewModel.kt | 64 +++++++ .../drawable-v24/ic_launcher_foreground.xml | 34 ++++ .../main/res/drawable/ic_add_black_24dp.xml | 5 + .../res/drawable/ic_launcher_background.xml | 170 ++++++++++++++++++ .../main/res/drawable/ic_star_black_240dp.xml | 5 + .../src/main/res/drawable/splash_image.xml | 10 ++ .../app/src/main/res/layout/activity_main.xml | 33 ++++ .../app/src/main/res/layout/content_main.xml | 57 ++++++ .../app/src/main/res/menu/menu_main.xml | 10 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 1862 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 1866 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 3694 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1338 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 1166 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2365 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 2601 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 2585 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 5302 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 3924 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 4183 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 8307 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 5638 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 5930 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 12057 bytes .../app/src/main/res/values/colors.xml | 6 + .../app/src/main/res/values/dimens.xml | 3 + .../res/values/ic_launcher_background.xml | 4 + .../app/src/main/res/values/strings.xml | 8 + .../app/src/main/res/values/styles.xml | 24 +++ sample-android/build.gradle.kts | 53 ++---- sample-android/gradle.properties | 38 ++-- sample-android/settings.gradle.kts | 43 ++++- sample-android/versions.properties | 21 +++ 46 files changed, 1166 insertions(+), 74 deletions(-) create mode 100644 sample-android/app/android.gradle create mode 100755 sample-android/app/build.gradle.kts create mode 100755 sample-android/app/src/androidTest/java/com/raywenderlich/android/smallvictories/MainActivityTest.kt create mode 100755 sample-android/app/src/androidTest/java/com/raywenderlich/android/smallvictories/VictoryViewModelTest.kt create mode 100755 sample-android/app/src/main/AndroidManifest.xml create mode 100755 sample-android/app/src/main/ic_launcher-web.png create mode 100755 sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/MainActivity.kt create mode 100755 sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/Repository.kt create mode 100755 sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/SplashActivity.kt create mode 100755 sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryRepository.kt create mode 100755 sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryUiModel.kt create mode 100755 sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryViewModel.kt create mode 100755 sample-android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100755 sample-android/app/src/main/res/drawable/ic_add_black_24dp.xml create mode 100755 sample-android/app/src/main/res/drawable/ic_launcher_background.xml create mode 100755 sample-android/app/src/main/res/drawable/ic_star_black_240dp.xml create mode 100755 sample-android/app/src/main/res/drawable/splash_image.xml create mode 100755 sample-android/app/src/main/res/layout/activity_main.xml create mode 100755 sample-android/app/src/main/res/layout/content_main.xml create mode 100755 sample-android/app/src/main/res/menu/menu_main.xml create mode 100755 sample-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100755 sample-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100755 sample-android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100755 sample-android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100755 sample-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100755 sample-android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100755 sample-android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100755 sample-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100755 sample-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100755 sample-android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100755 sample-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100755 sample-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100755 sample-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100755 sample-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100755 sample-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100755 sample-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100755 sample-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100755 sample-android/app/src/main/res/values/colors.xml create mode 100755 sample-android/app/src/main/res/values/dimens.xml create mode 100755 sample-android/app/src/main/res/values/ic_launcher_background.xml create mode 100755 sample-android/app/src/main/res/values/strings.xml create mode 100755 sample-android/app/src/main/res/values/styles.xml create mode 100644 sample-android/versions.properties diff --git a/sample-android/app/android.gradle b/sample-android/app/android.gradle new file mode 100644 index 000000000..8661cea2c --- /dev/null +++ b/sample-android/app/android.gradle @@ -0,0 +1,16 @@ +android { + compileSdkVersion findProperty("compileSdkVersion") as Integer + defaultConfig { + applicationId findProperty("applicationId") + minSdkVersion findProperty("minSdkVersion") as Integer + targetSdkVersion findProperty("targetSdkVersion") + versionCode findProperty("versionCode") as Integer + versionName findProperty("versionName") + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables.useSupportLibrary = true + } + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } +} diff --git a/sample-android/app/build.gradle.kts b/sample-android/app/build.gradle.kts new file mode 100755 index 000000000..db2de6545 --- /dev/null +++ b/sample-android/app/build.gradle.kts @@ -0,0 +1,38 @@ +import com.louiscad.splitties.AndroidX +import com.louiscad.splitties.Google +import com.louiscad.splitties.Kotlin +import com.louiscad.splitties.Testing +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id("com.android.application") + id("com.louiscad.splitties") + id("org.jetbrains.kotlin.android") + id("org.jetbrains.kotlin.kapt") + //id("kotlin-android-extensions") +} + +apply(from = "android.gradle") + +tasks.withType { + kotlinOptions.jvmTarget = "1.8" +} + +dependencies { + implementation(Kotlin.stdlibJdk7) + implementation(AndroidX.appCompat) + implementation(AndroidX.constraintLayout) + implementation(Google.material) + implementation(AndroidX.lifecycle.runtime) + implementation(AndroidX.lifecycle.extensions) + kapt(AndroidX.lifecycle.compiler) + testImplementation(Testing.junit4) + androidTestImplementation(AndroidX.test.core) + androidTestImplementation(AndroidX.archCore.testing) + androidTestImplementation(Testing.mockitoCore) + androidTestImplementation(Testing.mockitoAndroid) + androidTestImplementation(Testing.mockitoKotlin) + androidTestImplementation(AndroidX.test.runner) + androidTestImplementation(AndroidX.test.rules) + androidTestImplementation(AndroidX.test.espresso.core) +} diff --git a/sample-android/app/src/androidTest/java/com/raywenderlich/android/smallvictories/MainActivityTest.kt b/sample-android/app/src/androidTest/java/com/raywenderlich/android/smallvictories/MainActivityTest.kt new file mode 100755 index 000000000..7d8a5105e --- /dev/null +++ b/sample-android/app/src/androidTest/java/com/raywenderlich/android/smallvictories/MainActivityTest.kt @@ -0,0 +1,117 @@ +/* + * + * Copyright (c) 2018 Razeware LLC + * + * 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. + * + * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, + * distribute, sublicense, create a derivative work, and/or sell copies of the + * Software in any work that is designed, intended, or marketed for pedagogical or + * instructional purposes related to programming, coding, application development, + * or information technology. Permission for such use, copying, modification, + * merger, publication, distribution, sublicensing, creation of derivative works, + * or sale is expressly withheld. + * + * 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 com.raywenderlich.android.smallvictories + + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import androidx.test.runner.AndroidJUnit4 +import android.widget.EditText +import android.widget.TextView +import org.hamcrest.CoreMatchers.allOf +import org.hamcrest.CoreMatchers.instanceOf +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@LargeTest +class MainActivityTest { + + @Rule + @JvmField + var rule = ActivityTestRule(MainActivity::class.java) + + @Test + fun tappingOnTitleOpensEditDialog() { + onView(withId(R.id.textVictoryTitle)) + .perform(click()) + + onView(withId(R.id.alertTitle)) + .check(matches(isDisplayed())) + + onView(withId(android.R.id.button2)) + .perform(click()) + } + + @Test + fun editingDialogUpdatesTitle() { + onView(withId(R.id.textVictoryTitle)) + .perform(click()) + + val newTitle = "Made the bed" + onView(instanceOf(EditText::class.java)) + .perform(clearText()) + .perform(typeText(newTitle)) + + onView(withText(R.string.dialog_ok)) + .perform(click()) + + onView(allOf(withId(R.id.textVictoryTitle), withText(newTitle))) + .check(matches(isDisplayed())) + } + + @Test + fun editingTitleDoesntChangeCount() { + // 1 + onView(withId(R.id.fab)) + .perform(click()) + // 2 + onView(withId(R.id.textVictoryTitle)) + .perform(click()) + val newTitle = "Made the bed" + onView(instanceOf(EditText::class.java)) + .perform(clearText()) + .perform(typeText(newTitle)) + onView(withText(R.string.dialog_ok)) + .perform(click()) + + // 3 + onView(allOf(withId(R.id.textVictoryCount), withText("0"))) + .check(doesNotExist()) + } + + @Test + fun incrementingVictoryCountUpdatesCountView() { + val previousCountString = rule.activity.findViewById(R.id.textVictoryCount).text.toString() + val previousCount = if (previousCountString.isBlank()) 0 else previousCountString.toInt() + + onView(withId(R.id.fab)) + .perform(click()) + + onView(allOf(withId(R.id.textVictoryCount), withText((previousCount + 1).toString()))) + .check(matches(isDisplayed())) + } +} diff --git a/sample-android/app/src/androidTest/java/com/raywenderlich/android/smallvictories/VictoryViewModelTest.kt b/sample-android/app/src/androidTest/java/com/raywenderlich/android/smallvictories/VictoryViewModelTest.kt new file mode 100755 index 000000000..5cd83c1e5 --- /dev/null +++ b/sample-android/app/src/androidTest/java/com/raywenderlich/android/smallvictories/VictoryViewModelTest.kt @@ -0,0 +1,137 @@ +package com.raywenderlich.android.smallvictories + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.Observer +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +/* + * + * Copyright (c) 2018 Razeware LLC + * + * 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. + * + * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, + * distribute, sublicense, create a derivative work, and/or sell copies of the + * Software in any work that is designed, intended, or marketed for pedagogical or + * instructional purposes related to programming, coding, application development, + * or information technology. Permission for such use, copying, modification, + * merger, publication, distribution, sublicensing, creation of derivative works, + * or sale is expressly withheld. + * + * 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. + */ + +class VictoryViewModelTest { + + @Rule + @JvmField + var instantTaskExecutorRule = InstantTaskExecutorRule() + + private val viewStateObserver: Observer = mock() + private val mockVictoryRepository: VictoryRepository = mock() + private val viewModel = VictoryViewModel() + + @Before + fun setUpTaskDetailViewModel() { + viewModel.viewState.observeForever(viewStateObserver) + viewModel.repository = mockVictoryRepository + } + + @Test + fun initializeReturnsTitle() { + val title = "New title" + val count = 5 + stubVictoryRepositoryGetVictoryTitleAndCount(Pair(title, count)) + viewModel.initialize() + + verify(viewStateObserver).onChanged(VictoryUiModel.TitleUpdated(title)) + } + + @Test + fun initializeReturnsCount() { + val title = "New title" + val count = 5 + stubVictoryRepositoryGetVictoryTitleAndCount(Pair(title, count)) + viewModel.initialize() + + verify(viewStateObserver).onChanged(VictoryUiModel.CountUpdated(count)) + } + + @Test + fun setVictoryTitleSavesTitle() { + val title = "New title" + viewModel.setVictoryTitle(title) + + verify(mockVictoryRepository).setVictoryTitle(title) + } + + @Test + fun setVictoryTitleReturnsTitle() { + val title = "New title" + viewModel.setVictoryTitle(title) + + verify(viewStateObserver).onChanged(VictoryUiModel.TitleUpdated(title)) + } + + @Test + fun incrementVictoryCountCallsRepository() { + stubVictoryRepositoryGetVictoryCount(5) + viewModel.incrementVictoryCount() + + verify(mockVictoryRepository).getVictoryCount() + } + + @Test + fun incrementVictoryCountUpdatesCount() { + val previousCount = 5 + stubVictoryRepositoryGetVictoryCount(previousCount) + viewModel.incrementVictoryCount() + + verify(mockVictoryRepository).setVictoryCount(previousCount + 1) + } + + @Test + fun incrementVictoryCountReturnsUpdatedCount() { + val previousCount = 5 + stubVictoryRepositoryGetVictoryCount(previousCount) + viewModel.incrementVictoryCount() + + verify(viewStateObserver).onChanged(VictoryUiModel.CountUpdated(previousCount + 1)) + } + + private fun stubVictoryRepositoryGetVictoryTitleAndCount(titleAndCount: Pair) { + stubVictoryRepositoryGetVictoryTitle(titleAndCount.first) + stubVictoryRepositoryGetVictoryCount(titleAndCount.second) + whenever(mockVictoryRepository.getVictoryTitleAndCount()) + .thenReturn(titleAndCount) + } + + private fun stubVictoryRepositoryGetVictoryTitle(title: String) { + whenever(mockVictoryRepository.getVictoryTitle()) + .thenReturn(title) + } + + private fun stubVictoryRepositoryGetVictoryCount(count: Int) { + whenever(mockVictoryRepository.getVictoryCount()) + .thenReturn(count) + } +} diff --git a/sample-android/app/src/main/AndroidManifest.xml b/sample-android/app/src/main/AndroidManifest.xml new file mode 100755 index 000000000..d5dd49fff --- /dev/null +++ b/sample-android/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + diff --git a/sample-android/app/src/main/ic_launcher-web.png b/sample-android/app/src/main/ic_launcher-web.png new file mode 100755 index 0000000000000000000000000000000000000000..e665711d08266fdbe76ca162a84b0f6c8ea5facb GIT binary patch literal 18814 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 z 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 literal 0 HcmV?d00001 diff --git a/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/MainActivity.kt b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/MainActivity.kt new file mode 100755 index 000000000..6d763817d --- /dev/null +++ b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/MainActivity.kt @@ -0,0 +1,115 @@ +/* + * + * Copyright (c) 2018 Razeware LLC + * + * 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. + * + * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, + * distribute, sublicense, create a derivative work, and/or sell copies of the + * Software in any work that is designed, intended, or marketed for pedagogical or + * instructional purposes related to programming, coding, application development, + * or information technology. Permission for such use, copying, modification, + * merger, publication, distribution, sublicensing, creation of derivative works, + * or sale is expressly withheld. + * + * 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 com.raywenderlich.android.smallvictories + +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import android.content.res.Resources +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import android.view.Menu +import android.view.MenuItem +import android.widget.EditText +import android.widget.FrameLayout +import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.android.synthetic.main.content_main.* + +class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + setSupportActionBar(toolbar) + + val viewModel = ViewModelProviders.of(this).get(VictoryViewModel::class.java) + viewModel.viewState.observe(this, Observer { it -> + it?.let { render(it) } + }) + viewModel.repository = Repository(this) + viewModel.initialize() + + fab.setOnClickListener { + viewModel.incrementVictoryCount() + } + textVictoryTitle.setOnClickListener { showVictoryTitleDialog(viewModel) } + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.menu_main, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.action_reset -> { + // TODO reset existing victory title and count + true + } + else -> super.onOptionsItemSelected(item) + } + } + + private fun render(uiModel: VictoryUiModel) { + when (uiModel) { + is VictoryUiModel.TitleUpdated -> { + textVictoryTitle.text = uiModel.title + } + is VictoryUiModel.CountUpdated -> { + textVictoryCount.text = uiModel.count.toString() + } + } + } + + private fun showVictoryTitleDialog(viewModel: VictoryViewModel) { + AlertDialog.Builder(this).apply { + setTitle(getString(R.string.dialog_title)) + + val input = EditText(this@MainActivity) + input.setText(textVictoryTitle.text) + val density = Resources.getSystem().displayMetrics.density + val padding = Math.round(16 * density) + + val layout = FrameLayout(context) + layout.setPadding(padding, 0, padding, 0) + layout.addView(input) + + setView(layout) + + setPositiveButton(getString(R.string.dialog_ok)) { _, _ -> + viewModel.setVictoryTitle(input.text.toString()) + } + setNegativeButton(getString(R.string.dialog_cancel), null) + create().show() + } + } +} diff --git a/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/Repository.kt b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/Repository.kt new file mode 100755 index 000000000..099535eea --- /dev/null +++ b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/Repository.kt @@ -0,0 +1,68 @@ +/* + * + * Copyright (c) 2018 Razeware LLC + * + * 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. + * + * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, + * distribute, sublicense, create a derivative work, and/or sell copies of the + * Software in any work that is designed, intended, or marketed for pedagogical or + * instructional purposes related to programming, coding, application development, + * or information technology. Permission for such use, copying, modification, + * merger, publication, distribution, sublicensing, creation of derivative works, + * or sale is expressly withheld. + * + * 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 com.raywenderlich.android.smallvictories + +import android.content.Context + +open class Repository(context: Context) : VictoryRepository { + companion object { + + private const val PACKAGE_NAME = "com.raywenderlich.android.smallvictories" + private const val KEY_VICTORY_TITLE = "victory_title" + private const val KEY_VICTORY_COUNT = "victory_count" + } + + private val sharedPreferences = context.getSharedPreferences(PACKAGE_NAME, Context.MODE_PRIVATE) + + override fun getVictoryTitleAndCount(): Pair { + return Pair(getVictoryTitle(), getVictoryCount()) + } + + override fun setVictoryTitle(title: String) { + sharedPreferences.edit().putString(KEY_VICTORY_TITLE, title).apply() + } + + override fun getVictoryTitle(): String { + return sharedPreferences.getString(KEY_VICTORY_TITLE, "Victory title")!! + } + + override fun setVictoryCount(count: Int) { + sharedPreferences.edit().putInt(KEY_VICTORY_COUNT, count).apply() + } + + override fun getVictoryCount(): Int { + return sharedPreferences.getInt(KEY_VICTORY_COUNT, 0) + } + + override fun clear() { + sharedPreferences.edit().clear().apply() + } +} diff --git a/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/SplashActivity.kt b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/SplashActivity.kt new file mode 100755 index 000000000..09540f451 --- /dev/null +++ b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/SplashActivity.kt @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2018 Razeware LLC + * + * 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. + * + * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, + * distribute, sublicense, create a derivative work, and/or sell copies of the + * Software in any work that is designed, intended, or marketed for pedagogical or + * instructional purposes related to programming, coding, application development, + * or information technology. Permission for such use, copying, modification, + * merger, publication, distribution, sublicensing, creation of derivative works, + * or sale is expressly withheld. + * + * 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 com.raywenderlich.android.smallvictories + +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity + +class SplashActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) + finish() + } +} diff --git a/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryRepository.kt b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryRepository.kt new file mode 100755 index 000000000..3d4ac8ff9 --- /dev/null +++ b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryRepository.kt @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2018 Razeware LLC + * + * 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. + * + * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, + * distribute, sublicense, create a derivative work, and/or sell copies of the + * Software in any work that is designed, intended, or marketed for pedagogical or + * instructional purposes related to programming, coding, application development, + * or information technology. Permission for such use, copying, modification, + * merger, publication, distribution, sublicensing, creation of derivative works, + * or sale is expressly withheld. + * + * 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 com.raywenderlich.android.smallvictories + +interface VictoryRepository { + fun getVictoryTitleAndCount(): Pair + fun setVictoryTitle(title: String) + fun getVictoryTitle(): String + fun setVictoryCount(count: Int) + fun getVictoryCount(): Int + fun clear() +} diff --git a/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryUiModel.kt b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryUiModel.kt new file mode 100755 index 000000000..d3658a929 --- /dev/null +++ b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryUiModel.kt @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2018 Razeware LLC + * + * 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. + * + * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, + * distribute, sublicense, create a derivative work, and/or sell copies of the + * Software in any work that is designed, intended, or marketed for pedagogical or + * instructional purposes related to programming, coding, application development, + * or information technology. Permission for such use, copying, modification, + * merger, publication, distribution, sublicensing, creation of derivative works, + * or sale is expressly withheld. + * + * 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 com.raywenderlich.android.smallvictories + +sealed class VictoryUiModel { + + data class TitleUpdated(val title: String) : VictoryUiModel() + + data class CountUpdated(val count: Int) : VictoryUiModel() +} diff --git a/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryViewModel.kt b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryViewModel.kt new file mode 100755 index 000000000..432027523 --- /dev/null +++ b/sample-android/app/src/main/java/com/raywenderlich/android/smallvictories/VictoryViewModel.kt @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2018 Razeware LLC + * + * 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. + * + * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, + * distribute, sublicense, create a derivative work, and/or sell copies of the + * Software in any work that is designed, intended, or marketed for pedagogical or + * instructional purposes related to programming, coding, application development, + * or information technology. Permission for such use, copying, modification, + * merger, publication, distribution, sublicensing, creation of derivative works, + * or sale is expressly withheld. + * + * 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 com.raywenderlich.android.smallvictories + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + + +class VictoryViewModel : ViewModel() { + + val viewState: MutableLiveData = MutableLiveData() + lateinit var repository: VictoryRepository + + fun initialize() { + val (title, count) = repository.getVictoryTitleAndCount() + viewState.value = VictoryUiModel.TitleUpdated(title) + viewState.value = VictoryUiModel.CountUpdated(count) + } + + fun setVictoryTitle(title: String) { + repository.setVictoryTitle(title) + viewState.value = VictoryUiModel.TitleUpdated(title) + } + + fun incrementVictoryCount() { + val newCount = repository.getVictoryCount() + 1 + repository.setVictoryCount(newCount) + viewState.value = VictoryUiModel.CountUpdated(newCount) + } + + fun reset() { + // TODO reset existing victory title and count + } +} + diff --git a/sample-android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/sample-android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100755 index 000000000..c3903edf4 --- /dev/null +++ b/sample-android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/sample-android/app/src/main/res/drawable/ic_add_black_24dp.xml b/sample-android/app/src/main/res/drawable/ic_add_black_24dp.xml new file mode 100755 index 000000000..4a3faa8fa --- /dev/null +++ b/sample-android/app/src/main/res/drawable/ic_add_black_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/sample-android/app/src/main/res/drawable/ic_launcher_background.xml b/sample-android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100755 index 000000000..310fdaadb --- /dev/null +++ b/sample-android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample-android/app/src/main/res/drawable/ic_star_black_240dp.xml b/sample-android/app/src/main/res/drawable/ic_star_black_240dp.xml new file mode 100755 index 000000000..05560721b --- /dev/null +++ b/sample-android/app/src/main/res/drawable/ic_star_black_240dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/sample-android/app/src/main/res/drawable/splash_image.xml b/sample-android/app/src/main/res/drawable/splash_image.xml new file mode 100755 index 000000000..378ef77e6 --- /dev/null +++ b/sample-android/app/src/main/res/drawable/splash_image.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/sample-android/app/src/main/res/layout/activity_main.xml b/sample-android/app/src/main/res/layout/activity_main.xml new file mode 100755 index 000000000..9f6256486 --- /dev/null +++ b/sample-android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/sample-android/app/src/main/res/layout/content_main.xml b/sample-android/app/src/main/res/layout/content_main.xml new file mode 100755 index 000000000..93cb980e7 --- /dev/null +++ b/sample-android/app/src/main/res/layout/content_main.xml @@ -0,0 +1,57 @@ + + + + + + + + + + diff --git a/sample-android/app/src/main/res/menu/menu_main.xml b/sample-android/app/src/main/res/menu/menu_main.xml new file mode 100755 index 000000000..edc894d7d --- /dev/null +++ b/sample-android/app/src/main/res/menu/menu_main.xml @@ -0,0 +1,10 @@ +

+ + diff --git a/sample-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/sample-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100755 index 000000000..036d09bc5 --- /dev/null +++ b/sample-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/sample-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/sample-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100755 index 000000000..036d09bc5 --- /dev/null +++ b/sample-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/sample-android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/sample-android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100755 index 0000000000000000000000000000000000000000..c90ef63753d85b68f4b04149c732469993f17143 GIT binary patch literal 1862 zcmV-M2f6r(P)6ey*<`@j}U3z!IK z(8w#kV*JA+njlfYv}lZis6SLJ8WB;cr5@+&bY-*bcJJJ~yZ7$RPI9uFy?4&c`R>el z&ACeyX^|Fbkrrv;-I&S2#pJXV37G-|PBBH<_Q4yK&7A>nqijKIcsp(8S}GUcE5eE} zXUrWk2w4n+`Qf=o>{0-)9O3S`v-kn=(rZELpi3Iag&%V{TM)dx^HZ4VVdjbgd~ zxkVC|e#ihSqFuTH`nimD1OuQys))ZXA%15O@#-AnC(?b+Y$g_GCyn*{^sKnfbN}$ghYfdPGGHb4#H z3FnR=c18sr92dnz6X$0T|56cV0G$;|^?spjqa48l$3+<9!GXl*)`bZ`0B2aTRIaMR zCd3hUi_-_vh}#uGG6NuNE36zn;Goaa(Zo-W($^m#JupCFyM-DcD9haY^lz(99f&_$ zL40aCaa?=-+bw^jM#UXUfM9N6t&AvS_&M-zK;u%4DeeOcG`Ikv1gN3Rm?`fNBZSJk z#&3U~{7o;vzTKstWC?&U2%JD8mT1r|Ey=6@d0wg{PVHfg=lX}_+)M`u;e!zm8G55) z^7VYnCmC}SdUqxMagzlALTqIybm%Hw18?pEt{LHt*v(Xc5MgJf8WUn+hWFqTzu}q@ z-cbBLvjCw02q_ChNsh>KM|S_}KHlpYq2A#P=otuzH7Q2xd(KNb44Jr&wX8tELcNsa6N)Z_%ghQSa8ul3NTkeW<$g1_582 zqYlu{S?b`Js-)X8^Zp2DU8(@VpV2dxsb=1nqv$U&_Pq|%k3Oo2G}9eLc*6;bp+QSTY&DHlrA@PL4GH&y{7Y6`2;@Zi=YxkosQXg8zT4$A%YjbOHLb8U5PrFCz z5vmb7hh~TH%NY z_YM|)UY|$2@sYL<7M;=ZgygE#4h|7|%p2i5^#Gx8QW0z5I48E9`=scT^aC3;+knP z6PXaFu?(2x;Ur385L>~?Y^t$gowR2b;HwhixAKWsjhC6pF#~0e8w3Dnq{~%@VsoTb zY+p$3S6@}jg8)!t2wz1o22g3}-qkScWtO_-2Hw@UP!YNnWY+6Yr&k$RLFY@U((W(R z9WS6Ax&b;?Kr>y;0`dZhRaQ@pd?gd5etU9hA!I#~M=`1|^+pT2`P;R0s;QMBfU*NY z7RYq6km`htJt3>|9}Vn%tOcMhId@S;eG%3Dwpm&lFb-$Jwz~Kt@u$nEeq0KTf{ewP z3fs%QW!^>|#77T7cUDe`Dt!M*+H>?-I&f$S?K|=e?RTfc9^Vgpxu)fwVDN1DTuS>e zcgO%)AQNO8){|n5{P}_-tq0v8K5r7#S5S(e)G()%R#_4UCsIeqX!t)a($XkKtfnpk zta!n+dpHwhXptpNK`E=OD4S5EMOvgqT3EFI0O2FD#kzabW&i*H07*qoM6N<$f=`NU AZ2$lO literal 0 HcmV?d00001 diff --git a/sample-android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/sample-android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100755 index 0000000000000000000000000000000000000000..0c8b56785c7fba3f90bd3a2012e2892e029d1293 GIT binary patch literal 1866 zcma)7`#Tc~7#^LIN|Z}3BdZK4IW98{Nl}~2LWOdjA=?a#B9|1&A#*7$rN%U)WOAEP zYR6>@xkP3-IHBAcma#Qf$N3M=_dMVCKF{~O@AE$IFW;Bxjy$8V3%Cma04N~fj-Fds z`d{zZzBOCFt7!oMa!LqChx75H{Bcahg$t@IL77+BNO;+UGD9!59#GdoiMxZNs_J3I z%yYjxY|~dx-qH5qpt6dgiO0^alE1Qy@DR?-#eAwme}?B^z@^g|5~*s)dJj2wgDfJy z&WP!i{tCJUdLtrB*Qa(TR=4Et*fRbfb<@D#qPKtU8G*vSDV!|FX>*F@=vN0dN(Haj zhlp2!HW0;dZTj9{*v;oPZs-QKEKv?Zce}4%aVe090D{85MHzgqZ3h9DX_+HM_U1?C z>81|o_cv0sZ_*SP zBWt&FBdL{4|CqjHM7s|msawg6u@`{`{Z$>orw(el6x=>mb9!2}xzP$C4rR^o3_9xr zDkjI^W@^({v?Z?MRPbs)r7zo$7PA?oEFt&nq|!ez^;<(F3OYgGG058?KI03bVJES) zd~Q8SQw{THSbQZ~L+P`qswb{r`Xk6(-*kIrV|TvOE3YW#sj1xw#V)}1(AAn68egY6 z+V-68{_ZQNNZ1QPK5XJheIGsA7HYZaO+^C{uyzz0Q}ZG`VBsGo=`@VSpI_N0TXawm zX0<&o+V9jMonaNKlaHNVfX5>3$da#pZfwLmL~Zk4g=na@cZYyD`_kuzmoo@Q%v5-A zzK+-Vvv287&U;}XK;;k_AI6P-Vy>$*t1;02ZY>`sDgoojl|zkD2q_v!j?UI$NoS)%RcB%<4=lk;K)2He;QHDa%3&hYWot5kG=L$erlHudch z3g0vA0e2DyL72t8c0@DSAqc2P*8-Nfq4y}`26DPVsI#O+v;(FjV(&N1#t*PtD4rWh zD@bBBc*K1^l-LB!#kdwwldyTGQxG(Hn={yldUty~0x5(#_F=>|P~D}rbYK)Ni6(do z*0LV@ZpqB4Cq#J?pT6?!vJhbt|DaDDH+|coX?!*iZjD`&U?O_@f2LE3iCSh8N2PfI z>sejK)fX$Xxp~kfet{%QCekpdXxSMATQF2eo7R#f$Rqjl!im&z70^A2eEi7Z7^SX# zJouTWQgL1-sylerMw^Y==FYKPH0JO~&c`{t=JGZRncf6SUHx^}}{w{;1EC z{vN*e3CWC&(y_Nah%^5BoiBS)%BGW&yOSpeC`w~tb%u#{j9ix(MUdC1d}49e$`1bH z13$k$zV6dGzv5<*z9-kYFnwYD(@(0nx++A>PIJc})L(zUkln;Le@HMwq zvoX(4xERUv$c?s*>1DDy$umu>`f?H7s(tv2h-R_*NX%@y-?VArM%z^F5$(V<7Q^H@ zj>X`G#=H}2J+Uv2HT)VM%*DeZn&vKO+P`L>^YuBjmt{wWMI{h9gvVfWu-sswL8p8t z?lbNgt%jPJ!f^b=VZ=6i{n&UqkVA)j317sr;cKfyjhV&RLyR){_O(Yd?g@8nfW8V$ zM%Hqjx{QB7hiDDHJnP2@1T#pbxGAQLf&cpQP4~o|tM%$ukp!Ni zZ&kehyb{+aW4|~_?&0T;KzpuWd|kODf4?7HJsN5RwQ-ToRBStQL44!rWZ)MQ#BnaO zzI8d9Ae53;4DPEDn4@fFRONDgZ_??_^GIL9^5B&jvMrtDkgdOeYW@isvoO!XR~fhI zf+-H6vGr(wX&pa%@nVuNi>)`6qVw95ckMdkq+kg4wr$<#n;UQ@ z?P+H%Qi^{Nzubqr=v`|ueR=CX3`l=`k7y6c+E+KXzG)3@@x~T_>l?LWDPyahgoe=zvn`J`4>Fq=w^h#VyWA+uI8c>35bjY6A9fEN*e!DQn~ z!A-AEFt@{Buy97y+PC+j+}DG@QEP#}hUF&8YfSr97**$L^or5x>B#VmeJ_v*P=unD z>v3P#UvI%tI-vp^Z1A@Cmhjr4&b#;C(77ao*z+xTy-=^Y=74){_QwPfiAqq%)R=Kd q0_}3&EsW4*c@=K;KiXo}YW literal 0 HcmV?d00001 diff --git a/sample-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/sample-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100755 index 0000000000000000000000000000000000000000..ed36c3690656fef260311e0f367791ed3354b81d GIT binary patch literal 3694 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 literal 0 HcmV?d00001 diff --git a/sample-android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/sample-android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100755 index 0000000000000000000000000000000000000000..4e762544303f11adef70e93b5120e34c2651688d GIT binary patch literal 1166 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 NpufWGDs684@qchq*nI#1 literal 0 HcmV?d00001 diff --git a/sample-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/sample-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100755 index 0000000000000000000000000000000000000000..dfca9e9c2daf248ccce93a25afdcbb50f44f5798 GIT binary patch literal 5302 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 literal 0 HcmV?d00001 diff --git a/sample-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/sample-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100755 index 0000000000000000000000000000000000000000..a5d6f3d293ab462fa59ae36a1d24c4056e308f62 GIT binary patch literal 8307 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 literal 0 HcmV?d00001 diff --git a/sample-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/sample-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100755 index 0000000000000000000000000000000000000000..ab9fd753c19737b0f818e16428d3ea47f1fdcb57 GIT binary patch literal 5638 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 literal 0 HcmV?d00001 diff --git a/sample-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/sample-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100755 index 0000000000000000000000000000000000000000..481a9e8b6fbaa55099556c35aab7bdda4897b5e7 GIT binary patch literal 12057 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 DKd>eY literal 0 HcmV?d00001 diff --git a/sample-android/app/src/main/res/values/colors.xml b/sample-android/app/src/main/res/values/colors.xml new file mode 100755 index 000000000..ebd739bfb --- /dev/null +++ b/sample-android/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #FF9800 + #AE5F00 + #000 + diff --git a/sample-android/app/src/main/res/values/dimens.xml b/sample-android/app/src/main/res/values/dimens.xml new file mode 100755 index 000000000..59a0b0c4f --- /dev/null +++ b/sample-android/app/src/main/res/values/dimens.xml @@ -0,0 +1,3 @@ + + 16dp + diff --git a/sample-android/app/src/main/res/values/ic_launcher_background.xml b/sample-android/app/src/main/res/values/ic_launcher_background.xml new file mode 100755 index 000000000..5dc7c0f5b --- /dev/null +++ b/sample-android/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FF9800 + \ No newline at end of file diff --git a/sample-android/app/src/main/res/values/strings.xml b/sample-android/app/src/main/res/values/strings.xml new file mode 100755 index 000000000..ba5a3b4d2 --- /dev/null +++ b/sample-android/app/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ + + Small Victories + Reset + Your Victory + Set Victory title + OK + Cancel + diff --git a/sample-android/app/src/main/res/values/styles.xml b/sample-android/app/src/main/res/values/styles.xml new file mode 100755 index 000000000..3afe4d0dc --- /dev/null +++ b/sample-android/app/src/main/res/values/styles.xml @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/sample-android/build.gradle.kts b/sample-android/build.gradle.kts index 86067a681..2deaeff12 100644 --- a/sample-android/build.gradle.kts +++ b/sample-android/build.gradle.kts @@ -1,54 +1,26 @@ import de.fayard.OrderBy -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("org.lovedev.greeting.kotlin") id("de.fayard.refreshVersions") - id("ch.tutteli.kotlin.utils") - id("nebula.kotlin") - kotlin("jvm") `build-scan` } group = "de.fayard" +subprojects { + repositories { + google() + jcenter() + mavenCentral() + } +} + refreshVersions { // See configuration options at https://github.com/jmfayard/buildSrcVersions/issues/53 orderBy = OrderBy.GROUP_AND_ALPHABETICAL + propertiesFile = "versions.properties" //alignVersionsForGroups = listOf() } -repositories { - maven { - setUrl("../plugin/src/test/resources/maven") - } - mavenCentral() -} - -dependencies { - implementation("com.google.guava:guava:15.0") - implementation("com.google.inject:guice:2.0") - implementation("com.wealthfront:magellan:+") - implementation("com.wealthfront:magellan-rx:+") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.0.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.13.0") - implementation("com.jakewharton.timber:timber:4.7.0") -} - -tasks.withType { - kotlinOptions.jvmTarget = "1.8" -} -tasks.withType { - gradleVersion = System.getenv("GRADLE_VERSION") ?: "5.6.1" - distributionType = Wrapper.DistributionType.ALL -} - -tasks.register("copyReport") { - from(".") - include("report.json") - into("build/dependencyUpdates") -} - tasks.register("hello") { group = "Custom" } @@ -56,10 +28,5 @@ tasks.register("hello") { buildScan { setTermsOfServiceUrl("https://gradle.com/terms-of-service") setTermsOfServiceAgree("yes") -} - -// How to update Gradle itself? https://github.com/jmfayard/buildSrcVersions/issues/19 -tasks.withType { - gradleVersion = findProperty("gradleLatestVersion") as? String ?: gradle.gradleVersion - distributionType = Wrapper.DistributionType.ALL + publishAlways() } diff --git a/sample-android/gradle.properties b/sample-android/gradle.properties index a8350c7b3..7a8403ca9 100644 --- a/sample-android/gradle.properties +++ b/sample-android/gradle.properties @@ -1,28 +1,20 @@ +# See https://dev.to/jmfayard/configuring-gradle-with-gradle-properties-211k +org.gradle.jvmargs=-Xmx1536m +org.gradle.caching=true +org.gradle.parallel=true +kotlin.code.style=official +studio.projectview=true +android.useAndroidX=true +android.enableJetifier=false +# Allows to have ./app/android.gradle as generic as possible +compileSdkVersion=28 +applicationId=com.raywenderlich.android.smallvictories +targetSdkVersion=28 +minSdkVersion=19 +versionCode=2 +versionName=2.0 # The plugin https://github.com/jmfayard/buildSrcVersions # allows to overwrite plugin and dependencies versions from the values inside 'gradle.properties' # Set to 'verbose' to understand how dependency and plugin versions are overwritten # Set to 'false' to disable this feature resolutionStrategyConfig=verbose -# Dependencies and Plugin versions with their available updates -# Generated by $ ./gradlew refreshVersions -# You can edit the rest of the file, it will be kept intact -# See https://github.com/jmfayard/buildSrcVersions/issues/77 -plugin.ch.tutteli.kotlin.utils=0.29.0 -# # available=0.30.0 -plugin.com.github.ben-manes.versions=0.25.0 -plugin.com.gradle.build-scan=2.4.2 -# # available=3.0 -plugin.de.fayard.refreshVersions=0.8.0 -plugin.nebula.kotlin=1.3.50 -plugin.org.jetbrains.kotlin.jvm=1.3.50 -plugin.org.lovedev.greeting.kotlin=1.1 -version.com.wealthfront=1.1.0 -version.org.jetbrains.kotlin=1.3.50 -version.gradleLatestVersion=5.6.2 -# # available=5.6.3 -version.guava=15.0 -version.guice=2.0 -version.kotlinx-coroutines-core=1.0.0 -version.kotlinx-coroutines-core-common=1.0.0 -version.kotlinx-serialization-runtime=0.13.0 -version.timber=4.7.0 \ No newline at end of file diff --git a/sample-android/settings.gradle.kts b/sample-android/settings.gradle.kts index 532cd531d..fa9491467 100644 --- a/sample-android/settings.gradle.kts +++ b/sample-android/settings.gradle.kts @@ -1,26 +1,53 @@ +import java.util.Properties + pluginManagement { repositories { + google() mavenLocal() gradlePluginPortal() } /** - * This `resolutionStrategy` allows plugin versions to be configured from `gradle.properties + * This `resolutionStrategy` allows plugin versions to be configured from + * `versions.properties * The convention is simply * plugin.$PLUGINID=$PLUGIN_VERSION - * To check what happen, you can set in gradle.properties the line: + * To check what happen, you can set the property * resolutionStrategyConfig=verbose - */ + **/ val resolutionStrategyConfig: String? by extra + if (resolutionStrategyConfig == "false") return@pluginManagement + val androidPluginIds = listOf("com.android.application", "com.android.library") + val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") + @Suppress("UNCHECKED_CAST") + val properties: Map = Properties().apply { + load(file("versions.properties").reader()) + } as Map + require("module.kotlin" in properties && "module.android" in properties) { "version.properties MUST contain module.android=... and module.kotlin=...." } resolutionStrategy.eachPlugin { - val property = "plugin.${requested.id.id}" - if (extra.has(property) && resolutionStrategyConfig != "false") { - val version = extra.get(property) as String - if (resolutionStrategyConfig == "verbose") println("ResolutionStrategy selected version=$version from property=$property") - useVersion(version) + val pluginId = requested.id.id + val version = properties["plugin.$pluginId"] + val message = when { + pluginId in kotlinPluginIds -> { + val module = "org.jetbrains.kotlin:kotlin-gradle-plugin:${properties["module.kotlin"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + pluginId in androidPluginIds -> { + val module = "com.android.tools.build:gradle:${properties["module.android"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + version != null -> { + useVersion(version) + "ResolutionStrategy used version=$version for plugin=$pluginId" + } + else -> "ResolutionStrategy did not find a version for $pluginId" } + if (resolutionStrategyConfig == "verbose") println(message) } } rootProject.name = "sample-android" includeBuild("../plugin") +include(":app") diff --git a/sample-android/versions.properties b/sample-android/versions.properties new file mode 100644 index 000000000..f91a6c518 --- /dev/null +++ b/sample-android/versions.properties @@ -0,0 +1,21 @@ +# Dependencies and Plugin versions with their available updates +# Generated by $ ./gradlew refreshVersions +# You can edit the rest of the file, it will be kept intact +# See https://github.com/jmfayard/buildSrcVersions/issues/77 +module.android=3.5.0 +module.kotlin=1.3.50 +plugin.com.github.ben-manes.versions=0.25.0 +plugin.com.gradle.build-scan=2.4.2 +plugin.com.louiscad.splitties=0.1.2 +# # available=3.0 +plugin.de.fayard.refreshVersions=0.8.0 +version.com.wealthfront=1.1.0 +version.org.jetbrains.kotlin=1.3.50 +version.gradleLatestVersion=5.6.2 +# # available=5.6.3 +version.guava=15.0 +version.guice=2.0 +version.kotlinx-coroutines-core=1.0.0 +version.kotlinx-coroutines-core-common=1.0.0 +version.kotlinx-serialization-runtime=0.13.0 +version.timber=4.7.0 From effeea0c8f63995734d8a8e1ba29403af5b93531 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 19:37:14 +0200 Subject: [PATCH 12/30] sample-android: plugins.gradle.kts <3 --- .gitignore | 4 ++ sample-android/app/build.gradle.kts | 2 +- sample-android/build.gradle.kts | 10 ++++- sample-android/gradle.properties | 4 +- sample-android/plugins.gradle.kts | 57 +++++++++++++++++++++++++++++ sample-android/settings.gradle.kts | 51 +------------------------- 6 files changed, 75 insertions(+), 53 deletions(-) create mode 100644 sample-android/plugins.gradle.kts diff --git a/.gitignore b/.gitignore index f23d935ca..6abd434ca 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ build/ .idea/ !gradle-wrapper.jar _DS_Store +*.iml +local.properties +.gradle + diff --git a/sample-android/app/build.gradle.kts b/sample-android/app/build.gradle.kts index db2de6545..d26b34980 100755 --- a/sample-android/app/build.gradle.kts +++ b/sample-android/app/build.gradle.kts @@ -9,7 +9,7 @@ plugins { id("com.louiscad.splitties") id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.kapt") - //id("kotlin-android-extensions") + id("kotlin-android-extensions") } apply(from = "android.gradle") diff --git a/sample-android/build.gradle.kts b/sample-android/build.gradle.kts index 2deaeff12..dea5872d0 100644 --- a/sample-android/build.gradle.kts +++ b/sample-android/build.gradle.kts @@ -1,5 +1,13 @@ import de.fayard.OrderBy - +//TODO: find another solution to this problem https://gradle.com/s/7rm5h3bk6fzzq +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath("com.sun.istack:istack-commons-runtime:3.0.8") + } +} plugins { id("de.fayard.refreshVersions") `build-scan` diff --git a/sample-android/gradle.properties b/sample-android/gradle.properties index 7a8403ca9..1d8d6dba4 100644 --- a/sample-android/gradle.properties +++ b/sample-android/gradle.properties @@ -1,11 +1,12 @@ # See https://dev.to/jmfayard/configuring-gradle-with-gradle-properties-211k org.gradle.jvmargs=-Xmx1536m -org.gradle.caching=true +org.gradle.caching=false org.gradle.parallel=true kotlin.code.style=official studio.projectview=true android.useAndroidX=true android.enableJetifier=false + # Allows to have ./app/android.gradle as generic as possible compileSdkVersion=28 applicationId=com.raywenderlich.android.smallvictories @@ -13,6 +14,7 @@ targetSdkVersion=28 minSdkVersion=19 versionCode=2 versionName=2.0 + # The plugin https://github.com/jmfayard/buildSrcVersions # allows to overwrite plugin and dependencies versions from the values inside 'gradle.properties' # Set to 'verbose' to understand how dependency and plugin versions are overwritten diff --git a/sample-android/plugins.gradle.kts b/sample-android/plugins.gradle.kts new file mode 100644 index 000000000..ec966f355 --- /dev/null +++ b/sample-android/plugins.gradle.kts @@ -0,0 +1,57 @@ +import java.util.Properties + +/** + * Included in "settings.gradle.kts" via + * apply(from = "plugins.gradle.kts") + * + * See the Gradle guide on plugin management + * https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_management + ***/ + +pluginManagement { + repositories { + google() + mavenLocal() + gradlePluginPortal() + } + + /** + * This `resolutionStrategy` allows plugin versions to be configured from + * `versions.properties + * The convention is simply + * plugin.$PLUGINID=$PLUGIN_VERSION + * To check what happen, you can set the property + * resolutionStrategyConfig=verbose + **/ + val resolutionStrategyConfig: String? by extra + if (resolutionStrategyConfig == "false") return@pluginManagement + val androidPluginIds = listOf("com.android.application", "com.android.library") + val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") + @Suppress("UNCHECKED_CAST") + val properties: Map = Properties().apply { + load(file("versions.properties").reader()) + } as Map + require("module.kotlin" in properties && "module.android" in properties) { "version.properties MUST contain module.android=... and module.kotlin=...." } + resolutionStrategy.eachPlugin { + val pluginId = requested.id.id + val version = properties["plugin.$pluginId"] + val message = when { + pluginId in kotlinPluginIds -> { + val module = "org.jetbrains.kotlin:kotlin-gradle-plugin:${properties["module.kotlin"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + pluginId in androidPluginIds -> { + val module = "com.android.tools.build:gradle:${properties["module.android"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + version != null -> { + useVersion(version) + "ResolutionStrategy used version=$version for plugin=$pluginId" + } + else -> "ResolutionStrategy did not find a version for $pluginId" + } + if (resolutionStrategyConfig == "verbose") println(message) + } +} diff --git a/sample-android/settings.gradle.kts b/sample-android/settings.gradle.kts index fa9491467..8846d61b7 100644 --- a/sample-android/settings.gradle.kts +++ b/sample-android/settings.gradle.kts @@ -1,53 +1,4 @@ -import java.util.Properties - -pluginManagement { - repositories { - google() - mavenLocal() - gradlePluginPortal() - } - - /** - * This `resolutionStrategy` allows plugin versions to be configured from - * `versions.properties - * The convention is simply - * plugin.$PLUGINID=$PLUGIN_VERSION - * To check what happen, you can set the property - * resolutionStrategyConfig=verbose - **/ - val resolutionStrategyConfig: String? by extra - if (resolutionStrategyConfig == "false") return@pluginManagement - val androidPluginIds = listOf("com.android.application", "com.android.library") - val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") - @Suppress("UNCHECKED_CAST") - val properties: Map = Properties().apply { - load(file("versions.properties").reader()) - } as Map - require("module.kotlin" in properties && "module.android" in properties) { "version.properties MUST contain module.android=... and module.kotlin=...." } - resolutionStrategy.eachPlugin { - val pluginId = requested.id.id - val version = properties["plugin.$pluginId"] - val message = when { - pluginId in kotlinPluginIds -> { - val module = "org.jetbrains.kotlin:kotlin-gradle-plugin:${properties["module.kotlin"]}" - useModule(module) - "ResolutionStrategy used module=$module for plugin=$pluginId" - } - pluginId in androidPluginIds -> { - val module = "com.android.tools.build:gradle:${properties["module.android"]}" - useModule(module) - "ResolutionStrategy used module=$module for plugin=$pluginId" - } - version != null -> { - useVersion(version) - "ResolutionStrategy used version=$version for plugin=$pluginId" - } - else -> "ResolutionStrategy did not find a version for $pluginId" - } - if (resolutionStrategyConfig == "verbose") println(message) - } -} +apply(from = "plugins.gradle.kts") rootProject.name = "sample-android" includeBuild("../plugin") include(":app") - From c1486428300ffa0be4e8bf91f14e71c75334e094 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 20:26:17 +0200 Subject: [PATCH 13/30] sample-android: plugins.gradle.kts <3 --- sample-android/plugins.gradle.kts | 7 +------ sample-android/settings.gradle.kts | 7 +++++++ sample-android/versions.properties | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/sample-android/plugins.gradle.kts b/sample-android/plugins.gradle.kts index ec966f355..d584c4055 100644 --- a/sample-android/plugins.gradle.kts +++ b/sample-android/plugins.gradle.kts @@ -9,11 +9,6 @@ import java.util.Properties ***/ pluginManagement { - repositories { - google() - mavenLocal() - gradlePluginPortal() - } /** * This `resolutionStrategy` allows plugin versions to be configured from @@ -24,7 +19,7 @@ pluginManagement { * resolutionStrategyConfig=verbose **/ val resolutionStrategyConfig: String? by extra - if (resolutionStrategyConfig == "false") return@pluginManagement + if (resolutionStrategyConfig == "false" || file("versions.properties").canRead().not()) return@pluginManagement val androidPluginIds = listOf("com.android.application", "com.android.library") val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") @Suppress("UNCHECKED_CAST") diff --git a/sample-android/settings.gradle.kts b/sample-android/settings.gradle.kts index 8846d61b7..7a2759950 100644 --- a/sample-android/settings.gradle.kts +++ b/sample-android/settings.gradle.kts @@ -1,3 +1,10 @@ +pluginManagement { + repositories { + google() + mavenLocal() + gradlePluginPortal() + } +} apply(from = "plugins.gradle.kts") rootProject.name = "sample-android" includeBuild("../plugin") diff --git a/sample-android/versions.properties b/sample-android/versions.properties index f91a6c518..450070a21 100644 --- a/sample-android/versions.properties +++ b/sample-android/versions.properties @@ -6,7 +6,7 @@ module.android=3.5.0 module.kotlin=1.3.50 plugin.com.github.ben-manes.versions=0.25.0 plugin.com.gradle.build-scan=2.4.2 -plugin.com.louiscad.splitties=0.1.2 +plugin.com.louiscad.splitties=0.1.3 # # available=3.0 plugin.de.fayard.refreshVersions=0.8.0 version.com.wealthfront=1.1.0 From ef06d76899f14d71ec5341e28f8aa0d6b272c679 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 20:35:54 +0200 Subject: [PATCH 14/30] simplify: remove wrapper configurations --- plugin/build.gradle.kts | 5 ----- sample-groovy/build.gradle | 4 ---- sample-groovy/gradle.properties | 6 +----- sample-kotlin/build.gradle.kts | 31 ++++++------------------------- sample-kotlin/gradle.properties | 2 +- 5 files changed, 8 insertions(+), 40 deletions(-) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 25e4540da..de3a26dff 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -68,11 +68,6 @@ tasks.withType { useJUnitPlatform() } -tasks.withType { - gradleVersion = System.getenv("GRADLE_VERSION") ?: "5.6.1" - distributionType = Wrapper.DistributionType.ALL -} - java { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 diff --git a/sample-groovy/build.gradle b/sample-groovy/build.gradle index 820ffec7a..59aafd9df 100644 --- a/sample-groovy/build.gradle +++ b/sample-groovy/build.gradle @@ -38,10 +38,6 @@ refreshVersions { isNonStable(candidate.version) && !isNonStable(currentVersion) } } -wrapper { - distributionType = Wrapper.DistributionType.ALL - gradleVersion = findProperty("gradleLatestVersion") ?: gradle.gradleVersion -} buildScan { setTermsOfServiceUrl("https://gradle.com/terms-of-service") diff --git a/sample-groovy/gradle.properties b/sample-groovy/gradle.properties index c04c23039..a50018503 100644 --- a/sample-groovy/gradle.properties +++ b/sample-groovy/gradle.properties @@ -10,9 +10,5 @@ resolutionStrategyConfig=verbose plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.com.gradle.build-scan=2.4.2 -version.androidx.annotation..annotation=1.1.0 -version.org.jetbrains..annotation=17.0.0 -version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 -# # available=5.6.3 -version.guava=15.0 \ No newline at end of file +# # available=5.6.3 \ No newline at end of file diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts index 3cf7f12dd..b9f04f521 100644 --- a/sample-kotlin/build.gradle.kts +++ b/sample-kotlin/build.gradle.kts @@ -23,10 +23,13 @@ refreshVersions { } } +buildScan { + setTermsOfServiceUrl("https://gradle.com/terms-of-service") + setTermsOfServiceAgree("yes") +} + repositories { - maven { - setUrl("../plugin/src/test/resources/maven") - } + maven("../plugin/src/test/resources/maven") mavenCentral() } @@ -61,29 +64,7 @@ tasks.withType(JavaExec::class.java) { classpath = sourceSets["main"].runtimeClasspath } -// How to update Gradle itself? https://github.com/jmfayard/buildSrcVersions/issues/19 -tasks.withType { - gradleVersion = findProperty("gradleLatestVersion") as? String ?: gradle.gradleVersion - distributionType = Wrapper.DistributionType.ALL -} - - - - -buildScan { - setTermsOfServiceUrl("https://gradle.com/terms-of-service") - setTermsOfServiceAgree("yes") -} - tasks.register("hello") { group = "Custom" description = "Minimal task that do nothing. Useful to debug a failing build" } -val compileKotlin: KotlinCompile by tasks -compileKotlin.kotlinOptions { - jvmTarget = "1.8" -} -val compileTestKotlin: KotlinCompile by tasks -compileTestKotlin.kotlinOptions { - jvmTarget = "1.8" -} diff --git a/sample-kotlin/gradle.properties b/sample-kotlin/gradle.properties index a798210a9..cc2b60c7b 100644 --- a/sample-kotlin/gradle.properties +++ b/sample-kotlin/gradle.properties @@ -11,7 +11,7 @@ plugin.org.nosphere.gradle.github.actions=1.0.0 plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.org.jetbrains.kotlin.jvm=1.3.50 -plugin.com.louiscad.splitties=0.1.2 +plugin.com.louiscad.splitties=0.1.3 plugin.com.gradle.build-scan=3.0 version.org.jetbrains.kotlinx=1.3.2 version.com.squareup.okhttp3=4.2.0 From c905d153eb3dcfce9213871c57cc2f946475e49d Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Wed, 23 Oct 2019 20:36:33 +0200 Subject: [PATCH 15/30] fix: sample-android should be opened in Android Studio, not IntelliJ IDEA --- composite/build.gradle.kts | 22 ++-------------------- composite/settings.gradle.kts | 7 ++++++- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/composite/build.gradle.kts b/composite/build.gradle.kts index 3b5e3706c..09371bca8 100644 --- a/composite/build.gradle.kts +++ b/composite/build.gradle.kts @@ -10,7 +10,7 @@ defaultTasks("run") val PLUGIN: IncludedBuild = gradle.includedBuild("plugin") val SAMPLE_KOTLIN: IncludedBuild = gradle.includedBuild("sample-kotlin") val SAMPLE_GROOVY: IncludedBuild = gradle.includedBuild("sample-groovy") -val SAMPLE_ANDROID: IncludedBuild = gradle.includedBuild("sample-android") +// val SAMPLE_ANDROID: IncludedBuild = gradle.includedBuild("sample-android") val REFRESH_VERSIONS = ":refreshVersions" val CUSTOM = "custom" @@ -43,31 +43,13 @@ tasks.register("pluginTests") { tasks.register("checkAll") { group = CUSTOM description = "Run all checks" - dependsOn(SAMPLE_ANDROID.task(REFRESH_VERSIONS)) + //dependsOn(SAMPLE_ANDROID.task(REFRESH_VERSIONS)) dependsOn(SAMPLE_KOTLIN.task(REFRESH_VERSIONS)) dependsOn(SAMPLE_GROOVY.task(REFRESH_VERSIONS)) dependsOn(PLUGIN.task(":validateTaskProperties")) dependsOn(PLUGIN.task(":check")) } - -tasks.register("updateGradle") { - group = CUSTOM - description = "Update Gradle in all modules" - dependsOn(":wrapper") - dependsOn(PLUGIN.task(":wrapper")) - dependsOn(SAMPLE_KOTLIN.task(":wrapper")) - dependsOn(SAMPLE_GROOVY.task(":wrapper")) - dependsOn(SAMPLE_ANDROID.task(":wrapper")) -} - -tasks.withType { - group = CUSTOM - description = "Update Gradle with ./gradlew wrapper" - gradleVersion = System.getenv("GRADLE_VERSION") ?: "5.6.1" - distributionType = Wrapper.DistributionType.ALL -} - buildScan { termsOfServiceUrl = "https://gradle.com/terms-of-service" termsOfServiceAgree = "yes" diff --git a/composite/settings.gradle.kts b/composite/settings.gradle.kts index 92826cfb5..87b3d151c 100644 --- a/composite/settings.gradle.kts +++ b/composite/settings.gradle.kts @@ -2,4 +2,9 @@ rootProject.name = "buildSrcVersions-composite" includeBuild("../plugin") includeBuild("../sample-kotlin") includeBuild("../sample-groovy") -includeBuild("../sample-android") + +// ../sample-android should be opened in Android Studio +//Adding +// includeBuild("../sample-android") +// would fail with the error: +// New Gradle Sync is not supported due to containing Kotlin modules From e7bb971f6969fe2edf51698116ecc6b9cf96c4bb Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 00:21:53 +0200 Subject: [PATCH 16/30] sample-android: buildscript not necessary --- sample-android/build.gradle.kts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sample-android/build.gradle.kts b/sample-android/build.gradle.kts index dea5872d0..377ac625f 100644 --- a/sample-android/build.gradle.kts +++ b/sample-android/build.gradle.kts @@ -1,13 +1,6 @@ import de.fayard.OrderBy //TODO: find another solution to this problem https://gradle.com/s/7rm5h3bk6fzzq -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath("com.sun.istack:istack-commons-runtime:3.0.8") - } -} + plugins { id("de.fayard.refreshVersions") `build-scan` From 597e8e8f9d93bb0f24b91f6390450ea40bed15d3 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 00:27:16 +0200 Subject: [PATCH 17/30] ci: improve Gradle GitHub Actions - test on push - test only on ubuntu - test daily with Gradle 6 RC https://github.com/marketplace/actions/gradle-command --- .github/workflows/gradle4-build.yml | 4 ++-- .github/workflows/gradle5-build.yml | 4 ++-- .github/workflows/gradlerc-cron.yml | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/gradle4-build.yml b/.github/workflows/gradle4-build.yml index 22caaccd9..592925bed 100644 --- a/.github/workflows/gradle4-build.yml +++ b/.github/workflows/gradle4-build.yml @@ -1,12 +1,12 @@ # .github/workflows/gradle-build-pr.yml # https://github.com/marketplace/actions/gradle-command -name: Run gradle checkAll +name: Gradle 4.8 on: [push, pull_request] jobs: gradle: strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/gradle5-build.yml b/.github/workflows/gradle5-build.yml index b5f309128..80737179c 100644 --- a/.github/workflows/gradle5-build.yml +++ b/.github/workflows/gradle5-build.yml @@ -1,12 +1,12 @@ # .github/workflows/gradle-build-pr.yml # https://github.com/marketplace/actions/gradle-command -name: Run gradle checkAll +name: Gradle 5.6.3 on: [push, pull_request] jobs: gradle: strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/gradlerc-cron.yml b/.github/workflows/gradlerc-cron.yml index b5f309128..dc567a2d1 100644 --- a/.github/workflows/gradlerc-cron.yml +++ b/.github/workflows/gradlerc-cron.yml @@ -1,12 +1,14 @@ # .github/workflows/gradle-build-pr.yml # https://github.com/marketplace/actions/gradle-command -name: Run gradle checkAll -on: [push, pull_request] +name: Gradle RC +on: + schedule: + - cron: 0 0 * * * # daily jobs: gradle: strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 @@ -15,6 +17,6 @@ jobs: java-version: 11 - uses: eskatos/gradle-command-action@v1 with: - gradle-version: 5.6.3 + gradle-version: rc arguments: checkAll build-root-directory: composite From 11d3f69c9b5129cfad295eec5cb9219eb55c4ef8 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 01:01:18 +0200 Subject: [PATCH 18/30] ci: only on pull request --- .github/workflows/gradle4-build.yml | 2 +- .github/workflows/gradle5-build.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle4-build.yml b/.github/workflows/gradle4-build.yml index 592925bed..2c8526490 100644 --- a/.github/workflows/gradle4-build.yml +++ b/.github/workflows/gradle4-build.yml @@ -1,7 +1,7 @@ # .github/workflows/gradle-build-pr.yml # https://github.com/marketplace/actions/gradle-command name: Gradle 4.8 -on: [push, pull_request] +on: [pull_request] jobs: gradle: strategy: diff --git a/.github/workflows/gradle5-build.yml b/.github/workflows/gradle5-build.yml index 80737179c..477b7f2a3 100644 --- a/.github/workflows/gradle5-build.yml +++ b/.github/workflows/gradle5-build.yml @@ -1,7 +1,7 @@ # .github/workflows/gradle-build-pr.yml # https://github.com/marketplace/actions/gradle-command name: Gradle 5.6.3 -on: [push, pull_request] +on: [pull_request] jobs: gradle: strategy: From da8b735973af5842779a57162c12c0d3976e3f4b Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 01:02:08 +0200 Subject: [PATCH 19/30] feature: initialize build with plugins.gradle.kts --- .../kotlin/de/fayard/RefreshVersionsPlugin.kt | 5 +- .../kotlin/de/fayard/internal/PluginConfig.kt | 2 +- .../kotlin/de/fayard/internal/PluginsSetup.kt | 45 ++++++++++ plugin/src/main/resources/plugins.gradle.kts | 83 +++++++++++++++++++ sample-groovy/versions.properties | 9 ++ sample-kotlin/gradle.properties | 2 +- sample-kotlin/settings.gradle.kts | 1 - sample-kotlin/versions.properties | 2 +- 8 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt create mode 100644 plugin/src/main/resources/plugins.gradle.kts create mode 100644 sample-groovy/versions.properties diff --git a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt index d0caeb603..025a220e9 100644 --- a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt @@ -3,6 +3,7 @@ package de.fayard import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask import de.fayard.internal.PluginConfig import de.fayard.internal.PluginConfig.isNonStable +import de.fayard.internal.PluginsSetup import de.fayard.internal.RefreshVersionsExtensionImpl import org.gradle.api.Plugin import org.gradle.api.Project @@ -23,6 +24,8 @@ open class RefreshVersionsPlugin : Plugin { } fun Project.configure() = with(PluginConfig) { + PluginsSetup.copyPluginsGradleKtsIfNeeded(project) + extensions.create(RefreshVersionsExtension::class, EXTENSION_NAME, RefreshVersionsExtensionImpl::class) if (supportsTaskAvoidance()) { @@ -49,7 +52,7 @@ open class RefreshVersionsPlugin : Plugin { fun Project.useVersionsFromProperties() { @Suppress("UNCHECKED_CAST") val properties: Map = Properties().apply { - val propertiesFile = listOf("versions.properties", "gradle.properties").first { project.file(it).canRead() } + val propertiesFile = listOf("versions.properties", "gradle.properties").firstOrNull { project.file(it).canRead() } ?: return load(project.file(propertiesFile).reader()) } as Map diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt index 0788e9119..09bb8713e 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt @@ -23,7 +23,7 @@ object PluginConfig { const val DEPENDENCY_UPDATES_PATH = ":$DEPENDENCY_UPDATES" const val REFRESH_VERSIONS = "refreshVersions" const val EXTENSION_NAME = REFRESH_VERSIONS - const val DEFAULT_PROPERTIES_FILE = "gradle.properties" + const val DEFAULT_PROPERTIES_FILE = "versions.properties" /** There is no standard on how to name stable and unstable versions * This version is a good starting point but you can define you rown diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt new file mode 100644 index 000000000..2c477066e --- /dev/null +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt @@ -0,0 +1,45 @@ +package de.fayard.internal + +import org.gradle.api.GradleException +import org.gradle.api.Project + +object PluginsSetup { + const val PLUGIN_GRADLE_KTS = "plugins.gradle.kts" + const val SETTINGS_GRADLE_KTS = "settings.gradle.kts" + const val OK = "✔ \uD83C\uDD97" + + const val INCLUDE_PLUGINS_GRADLE_KTS = """ +pluginManagement { + repositories { + google() // for Android projects only + jcenter() // if you use plugins not published on the gradlePluginPortal() + gradlePluginPortal() + } +} +apply(from = "plugins.gradle.kts") +// rootProject.name = xxx +// include(":app") +""" + + fun pluginFileContent(): String { + return this::class.java.getResourceAsStream("/$PLUGIN_GRADLE_KTS").reader().readText() + } + + fun copyPluginsGradleKtsIfNeeded(project: Project) { + println("copyPluginsGradleKtsIfNeeded") + val file = project.rootProject.file(PLUGIN_GRADLE_KTS) + val settingsFile = project.rootProject.file(SETTINGS_GRADLE_KTS) + if (settingsFile.canRead() && file.canRead().not()) { + file.writeText(pluginFileContent()) + println("$OK Created file ./$PLUGIN_GRADLE_KTS") + throw GradleException( + """ + |Action required: Please include $PLUGIN_GRADLE_KTS file in $SETTINGS_GRADLE_KTS + | // ./$SETTINGS_GRADLE_KTS + | $INCLUDE_PLUGINS_GRADLE_KTS + | """.trimMargin() + ) + } + + } +} diff --git a/plugin/src/main/resources/plugins.gradle.kts b/plugin/src/main/resources/plugins.gradle.kts new file mode 100644 index 000000000..25c9cc36e --- /dev/null +++ b/plugin/src/main/resources/plugins.gradle.kts @@ -0,0 +1,83 @@ +/** + * File generated by $ ./gradlew refreshVersions + * + * Gradle has replaced the buildscript { ... } block by a better alternative that looks like this + * +``` +plugins { +id("com.android.application") +id("com.louiscad.splitties") +id("org.jetbrains.kotlin.android") +id("org.jetbrains.kotlin.kapt") +id("kotlin-android-extensions") +} +``` + * This boilerplate does two things: + * + * 1. it configures the plugin versions using the file `versions.properties` generated by + * $ ./gradlew refreshVersions + * + * 2. it fixes the bug of the Android Gradle Plugin that doesn't publish the required metadata + * Please see and upvote the issue: + * https://issuetracker.google.com/issues/64551265 + * + * Include this file like this: + * + +```kotlin +// settings.gradle.kts +pluginManagement { +repositories { +google() +gradlePluginPortal() +} +} +apply(from = "plugins.gradle.kts") +// rootProject.name = xxx +// include(":app") +``` + + ***/ +@Suppress("CAST_NEVER_SUCCEEDS") +(this as Settings).pluginManagement { + + /** + * This `resolutionStrategy` allows plugin versions to be configured from + * `versions.properties + * The convention is simply + * plugin.$PLUGINID=$PLUGIN_VERSION + * To check what happen, you can set the property + * resolutionStrategyConfig=verbose + **/ + val resolutionStrategyConfig: String? by extra + if (resolutionStrategyConfig == "false" || file("versions.properties").canRead().not()) return@pluginManagement + val androidPluginIds = listOf("com.android.application", "com.android.library") + val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") + @Suppress("UNCHECKED_CAST") + val properties: Map = Properties().apply { + load(file("versions.properties").reader()) + } as Map + require("module.kotlin" in properties && "module.android" in properties) { "version.properties MUST contain module.android=... and module.kotlin=...." } + resolutionStrategy.eachPlugin { + val pluginId = requested.id.id + val version = properties["plugin.$pluginId"] + val message = when { + pluginId in kotlinPluginIds -> { + val module = "org.jetbrains.kotlin:kotlin-gradle-plugin:${properties["module.kotlin"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + pluginId in androidPluginIds -> { + val module = "com.android.tools.build:gradle:${properties["module.android"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + version != null -> { + useVersion(version) + "ResolutionStrategy used version=$version for plugin=$pluginId" + } + else -> "ResolutionStrategy did not find a version for $pluginId" + } + if (resolutionStrategyConfig == "verbose") println(message) + } +} diff --git a/sample-groovy/versions.properties b/sample-groovy/versions.properties new file mode 100644 index 000000000..11418d600 --- /dev/null +++ b/sample-groovy/versions.properties @@ -0,0 +1,9 @@ +# Dependencies and Plugin versions with their available updates +# Generated by $ ./gradlew refreshVersions +# You can edit the rest of the file, it will be kept intact +# See https://github.com/jmfayard/buildSrcVersions/issues/77 +plugin.com.github.ben-manes.versions=0.25.0 +plugin.de.fayard.refreshVersions=0.8.0 +plugin.com.gradle.build-scan=2.4.2 +version.gradleLatestVersion=5.6.2 +# # available=5.6.3 \ No newline at end of file diff --git a/sample-kotlin/gradle.properties b/sample-kotlin/gradle.properties index cc2b60c7b..accc7b28f 100644 --- a/sample-kotlin/gradle.properties +++ b/sample-kotlin/gradle.properties @@ -23,4 +23,4 @@ version.gradleLatestVersion=5.6.2 # # available=5.6.3 version.cardview=+ version.browser=+ -version.guava=15.0 \ No newline at end of file +version.guava=15.0 diff --git a/sample-kotlin/settings.gradle.kts b/sample-kotlin/settings.gradle.kts index ee9874210..3972aca26 100644 --- a/sample-kotlin/settings.gradle.kts +++ b/sample-kotlin/settings.gradle.kts @@ -2,7 +2,6 @@ import java.util.Properties pluginManagement { repositories { - mavenLocal() gradlePluginPortal() } diff --git a/sample-kotlin/versions.properties b/sample-kotlin/versions.properties index 5829509d6..95dce8f48 100644 --- a/sample-kotlin/versions.properties +++ b/sample-kotlin/versions.properties @@ -18,4 +18,4 @@ version.gradleLatestVersion=5.6.2 # # available=5.6.3 version.cardview=+ version.browser=+ -version.guava=15.0 +version.guava=15.0 \ No newline at end of file From 9460b476378d591c25408f161d46ec24c9e311f6 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 01:17:19 +0200 Subject: [PATCH 20/30] fix: plugins.gradle.kts needs module.kotlin and/or module.android --- .../kotlin/de/fayard/internal/PluginConfig.kt | 6 ++ .../kotlin/de/fayard/internal/PluginsSetup.kt | 3 +- .../de/fayard/internal/UpdateProperties.kt | 5 +- .../src/main/resources/plugins.gradle.kts.txt | 82 +++++++++++++++++++ sample-groovy/versions.properties | 8 +- sample-kotlin/build.gradle.kts | 6 +- .../plugins.gradle.kts | 3 +- sample-kotlin/settings.gradle.kts | 27 +----- sample-kotlin/versions.properties | 5 +- 9 files changed, 109 insertions(+), 36 deletions(-) create mode 100644 plugin/src/main/resources/plugins.gradle.kts.txt rename {plugin/src/main/resources => sample-kotlin}/plugins.gradle.kts (92%) diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt index 09bb8713e..1f53d1637 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt @@ -162,6 +162,12 @@ object PluginConfig { "# You can edit the rest of the file, it will be kept intact", "# See $issue77RefreshVersionsGradleProperties" ) + var isAndroidProject: Boolean = false + val MODULES + get() = listOfNotNull( + "module.kotlin=1.3.50", + if (isAndroidProject) "module.android=3.5.0" else null + ) val REFRESH_VERSIONS_END: List = listOf() diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt index 2c477066e..95f86cf72 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt @@ -22,11 +22,10 @@ apply(from = "plugins.gradle.kts") """ fun pluginFileContent(): String { - return this::class.java.getResourceAsStream("/$PLUGIN_GRADLE_KTS").reader().readText() + return this::class.java.getResourceAsStream("/$PLUGIN_GRADLE_KTS.txt").reader().readText() } fun copyPluginsGradleKtsIfNeeded(project: Project) { - println("copyPluginsGradleKtsIfNeeded") val file = project.rootProject.file(PLUGIN_GRADLE_KTS) val settingsFile = project.rootProject.file(SETTINGS_GRADLE_KTS) if (settingsFile.canRead() && file.canRead().not()) { diff --git a/plugin/src/main/kotlin/de/fayard/internal/UpdateProperties.kt b/plugin/src/main/kotlin/de/fayard/internal/UpdateProperties.kt index be1e32427..3d2a983b1 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/UpdateProperties.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/UpdateProperties.kt @@ -8,12 +8,13 @@ data class UpdateProperties( ) { fun generateVersionProperties(file: File, dependencies: List) = with(UpdateVersionsOnly) { + PluginConfig.isAndroidProject = dependencies.any { it.group.contains("android") } val dependenciesLines = dependencies .sortedBy { d -> d.versionName.contains("gradle_plugin").not() } .map { d -> d.asGradleProperty() } val newLines = with(PluginConfig) { - REFRESH_VERSIONS_START + dependenciesLines + REFRESH_VERSIONS_END + REFRESH_VERSIONS_START + MODULES + dependenciesLines + REFRESH_VERSIONS_END } updateGradleProperties( @@ -24,6 +25,8 @@ data class UpdateProperties( } fun String.wasGeneratedByPlugin(): Boolean = when { + startsWith("module.kotlin") -> true + startsWith("module.android") -> true startsWith("version.") -> true startsWith("plugin.") -> true contains("# available=") -> true diff --git a/plugin/src/main/resources/plugins.gradle.kts.txt b/plugin/src/main/resources/plugins.gradle.kts.txt new file mode 100644 index 000000000..90a590b47 --- /dev/null +++ b/plugin/src/main/resources/plugins.gradle.kts.txt @@ -0,0 +1,82 @@ +/** + * File generated by $ ./gradlew refreshVersions + * + * Gradle has replaced the buildscript { ... } block by a better alternative that looks like this + * +``` +plugins { +id("com.android.application") +id("com.louiscad.splitties") +id("org.jetbrains.kotlin.android") +id("org.jetbrains.kotlin.kapt") +id("kotlin-android-extensions") +} +``` + * This boilerplate does two things: + * + * 1. it configures the plugin versions using the file `versions.properties` generated by + * $ ./gradlew refreshVersions + * + * 2. it fixes the bug of the Android Gradle Plugin that doesn't publish the required metadata + * Please see and upvote the issue: + * https://issuetracker.google.com/issues/64551265 + * + * Include this file like this: + * + +```kotlin +// settings.gradle.kts +pluginManagement { +repositories { +google() +gradlePluginPortal() +} +} +apply(from = "plugins.gradle.kts") +// rootProject.name = xxx +// include(":app") +``` + + ***/ +@Suppress("CAST_NEVER_SUCCEEDS") +(this as Settings).pluginManagement { + + /** + * This `resolutionStrategy` allows plugin versions to be configured from + * `versions.properties + * The convention is simply + * plugin.$PLUGINID=$PLUGIN_VERSION + * To check what happen, you can set the property + * resolutionStrategyConfig=verbose + **/ + val resolutionStrategyConfig: String? by extra + if (resolutionStrategyConfig == "false" || file("versions.properties").canRead().not()) return@pluginManagement + val androidPluginIds = listOf("com.android.application", "com.android.library") + val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") + @Suppress("UNCHECKED_CAST") + val properties: Map = java.util.Properties().apply { + load(file("versions.properties").reader()) + } as Map + resolutionStrategy.eachPlugin { + val pluginId = requested.id.id + val version = properties["plugin.$pluginId"] + val message = when { + pluginId in kotlinPluginIds -> { + val module = "org.jetbrains.kotlin:kotlin-gradle-plugin:${properties["module.kotlin"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + pluginId in androidPluginIds -> { + val module = "com.android.tools.build:gradle:${properties["module.android"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + version != null -> { + useVersion(version) + "ResolutionStrategy used version=$version for plugin=$pluginId" + } + else -> "ResolutionStrategy did not find a version for $pluginId" + } + if (resolutionStrategyConfig == "verbose") println(message) + } +} diff --git a/sample-groovy/versions.properties b/sample-groovy/versions.properties index 11418d600..8dcb71140 100644 --- a/sample-groovy/versions.properties +++ b/sample-groovy/versions.properties @@ -2,8 +2,14 @@ # Generated by $ ./gradlew refreshVersions # You can edit the rest of the file, it will be kept intact # See https://github.com/jmfayard/buildSrcVersions/issues/77 +module.kotlin=1.3.50 +module.android=3.5.0 plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.com.gradle.build-scan=2.4.2 +version.androidx.annotation..annotation=1.1.0 +version.org.jetbrains..annotation=17.0.0 +version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 -# # available=5.6.3 \ No newline at end of file +# # available=5.6.3 +version.guava=15.0 diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts index b9f04f521..b953808b5 100644 --- a/sample-kotlin/build.gradle.kts +++ b/sample-kotlin/build.gradle.kts @@ -5,10 +5,10 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("de.fayard.refreshVersions") - kotlin("jvm") - id("com.louiscad.splitties") + kotlin("jvm").version("1.3.50") + id("com.louiscad.splitties").version("0.1.2") `build-scan` - id("org.nosphere.gradle.github.actions") + //id("org.nosphere.gradle.github.actions") } group = "de.fayard" diff --git a/plugin/src/main/resources/plugins.gradle.kts b/sample-kotlin/plugins.gradle.kts similarity index 92% rename from plugin/src/main/resources/plugins.gradle.kts rename to sample-kotlin/plugins.gradle.kts index 25c9cc36e..90a590b47 100644 --- a/plugin/src/main/resources/plugins.gradle.kts +++ b/sample-kotlin/plugins.gradle.kts @@ -54,10 +54,9 @@ apply(from = "plugins.gradle.kts") val androidPluginIds = listOf("com.android.application", "com.android.library") val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") @Suppress("UNCHECKED_CAST") - val properties: Map = Properties().apply { + val properties: Map = java.util.Properties().apply { load(file("versions.properties").reader()) } as Map - require("module.kotlin" in properties && "module.android" in properties) { "version.properties MUST contain module.android=... and module.kotlin=...." } resolutionStrategy.eachPlugin { val pluginId = requested.id.id val version = properties["plugin.$pluginId"] diff --git a/sample-kotlin/settings.gradle.kts b/sample-kotlin/settings.gradle.kts index 3972aca26..18b1ae246 100644 --- a/sample-kotlin/settings.gradle.kts +++ b/sample-kotlin/settings.gradle.kts @@ -1,33 +1,10 @@ -import java.util.Properties - pluginManagement { repositories { gradlePluginPortal() - } - - /** - * This `resolutionStrategy` allows plugin versions to be configured from - * `versions.properties - * The convention is simply - * plugin.$PLUGINID=$PLUGIN_VERSION - * To check what happen, you can set the property - * resolutionStrategyConfig=verbose - **/ - val resolutionStrategyConfig: String? by extra - if (resolutionStrategyConfig == "false") return@pluginManagement - - @Suppress("UNCHECKED_CAST") - val properties: Map = Properties().apply { - load(file("versions.properties").reader()) - } as Map - - resolutionStrategy.eachPlugin { - val property = "plugin.${requested.id.id}" - val version = properties[property] ?: return@eachPlugin - if (resolutionStrategyConfig == "verbose") println("ResolutionStrategy used version=$version from property=$property") - useVersion(version) + mavenCentral() } } +//apply(from = "plugins.gradle.kts") rootProject.name = "sample-kotlin" includeBuild("../plugin") diff --git a/sample-kotlin/versions.properties b/sample-kotlin/versions.properties index 95dce8f48..19fdc8f0b 100644 --- a/sample-kotlin/versions.properties +++ b/sample-kotlin/versions.properties @@ -2,7 +2,8 @@ # Generated by $ ./gradlew refreshVersions # You can edit the rest of the file, it will be kept intact # See https://github.com/jmfayard/buildSrcVersions/issues/77 -plugin.org.nosphere.gradle.github.actions=1.0.0 +module.kotlin=1.3.50 +module.android=3.5.0 plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.org.jetbrains.kotlin.jvm=1.3.50 @@ -18,4 +19,4 @@ version.gradleLatestVersion=5.6.2 # # available=5.6.3 version.cardview=+ version.browser=+ -version.guava=15.0 \ No newline at end of file +version.guava=15.0 From 2ba910ae4acc5d0c9cce9004ebbc79a0f7efca55 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 01:25:43 +0200 Subject: [PATCH 21/30] dogfooding: use refreshVersions inside plugin: --- plugin/build.gradle.kts | 2 +- plugin/gradle.properties | 21 +-------- plugin/plugins.gradle.kts | 83 +++++++++++++++++++++++++++++++++ plugin/settings.gradle.kts | 12 ++--- plugin/versions.properties | 22 +++++++++ sample-kotlin/gradle.properties | 21 --------- 6 files changed, 111 insertions(+), 50 deletions(-) create mode 100644 plugin/plugins.gradle.kts create mode 100644 plugin/versions.properties diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index de3a26dff..55ffa44c4 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("de.fayard.buildSrcVersions") version ("0.6.5") // plugin.de.fayard.buildSrcVersions + id("de.fayard.refreshVersions") version ("0.8.0") // plugin.de.fayard.buildSrcVersions id("com.gradle.plugin-publish") `java-gradle-plugin` diff --git a/plugin/gradle.properties b/plugin/gradle.properties index 12a3f8324..dda8af873 100644 --- a/plugin/gradle.properties +++ b/plugin/gradle.properties @@ -1,20 +1 @@ -# Dependencies and Plugin versions with their available updates -# Generated by $ ./gradlew refreshVersions -# See https://github.com/jmfayard/buildSrcVersions/issues/77 -plugin.org.gradle.kotlin.kotlin.dsl=1.2.9 -# available=1.3.1 -plugin.de.fayard.refreshVersions=0.8.0 -plugin.com.gradle.plugin-publish=0.10.0 -# available=0.10.1 -plugin.com.gradle.build-scan=2.4.1 -# available=2.4.2 -version.kotlintest.runner.junit5=3.1.9 -# available=3.4.1 -version.gradle.versions.plugin=0.25.0 -version.org.jetbrains.kotlin=1.3.41 -# available=1.3.50 -version.kotlinpoet=1.3.0 -version.moshi=1.7.0 -# available=1.8.0 -version.okio=2.1.0 -# You can edit the rest of the file, it will be kept intact +resolutionStrategyConfig=verbose diff --git a/plugin/plugins.gradle.kts b/plugin/plugins.gradle.kts new file mode 100644 index 000000000..cf0833bb0 --- /dev/null +++ b/plugin/plugins.gradle.kts @@ -0,0 +1,83 @@ +/** + * File generated by $ ./gradlew refreshVersions + * + * Gradle has replaced the buildscript { ... } block by a better alternative that looks like this + * +``` +plugins { +id("com.android.application") +id("com.louiscad.splitties") +id("org.jetbrains.kotlin.android") +id("org.jetbrains.kotlin.kapt") +id("kotlin-android-extensions") +} +``` + * This boilerplate does two things: + * + * 1. it configures the plugin versions using the file `versions.properties` generated by + * $ ./gradlew refreshVersions + * + * 2. it fixes the bug of the Android Gradle Plugin that doesn't publish the required metadata + * Please see and upvote the issue: + * https://issuetracker.google.com/issues/64551265 + * + * Include this file like this: + * + +```kotlin +// settings.gradle.kts +pluginManagement { +repositories { +google() +gradlePluginPortal() +} +} +apply(from = "plugins.gradle.kts") +// rootProject.name = xxx +// include(":app") +``` + + ***/ +@Suppress("CAST_NEVER_SUCCEEDS") +(this as Settings).pluginManagement { + + /** + * This `resolutionStrategy` allows plugin versions to be configured from + * `versions.properties + * The convention is simply + * plugin.$PLUGINID=$PLUGIN_VERSION + * To check what happen, you can set the property + * resolutionStrategyConfig=verbose + **/ + val resolutionStrategyConfig: String? by extra + if (resolutionStrategyConfig == "false" || file("versions.properties").canRead().not()) return@pluginManagement + val androidPluginIds = listOf("com.android.application", "com.android.library") + val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") + @Suppress("UNCHECKED_CAST") + val properties: Map = java.util.Properties().apply { + load(file("versions.properties").reader()) + } as Map + require("module.kotlin" in properties) { "version.properties MUST contain module.kotlin=.... and/or module.android=...." } + resolutionStrategy.eachPlugin { + val pluginId = requested.id.id + val version = properties["plugin.$pluginId"] + val message = when { + pluginId in kotlinPluginIds -> { + val module = "org.jetbrains.kotlin:kotlin-gradle-plugin:${properties["module.kotlin"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + pluginId in androidPluginIds -> { + val module = "com.android.tools.build:gradle:${properties["module.android"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + version != null -> { + useVersion(version) + "ResolutionStrategy used version=$version for plugin=$pluginId" + } + else -> "ResolutionStrategy did not find a version for $pluginId" + } + if (resolutionStrategyConfig == "verbose") println(message) + } +} diff --git a/plugin/settings.gradle.kts b/plugin/settings.gradle.kts index 3f3c70b25..e5bd391ec 100644 --- a/plugin/settings.gradle.kts +++ b/plugin/settings.gradle.kts @@ -1,12 +1,8 @@ pluginManagement { - val resolutionStrategyConfig: String? by extra - resolutionStrategy.eachPlugin { - val property = "plugin.${requested.id.id}" - if (extra.has(property) && resolutionStrategyConfig != "false") { - val version = extra.get(property) as String - useVersion(version) - if (resolutionStrategyConfig == "verbose") println("ResolutionStrategy selected version=$version from property=$property") - } + repositories { + mavenLocal() + gradlePluginPortal() } } +apply(from = "plugins.gradle.kts") rootProject.name = "plugin" diff --git a/plugin/versions.properties b/plugin/versions.properties new file mode 100644 index 000000000..0d04813d6 --- /dev/null +++ b/plugin/versions.properties @@ -0,0 +1,22 @@ +# Dependencies and Plugin versions with their available updates +# Generated by $ ./gradlew refreshVersions +# You can edit the rest of the file, it will be kept intact +# See https://github.com/jmfayard/buildSrcVersions/issues/77 +module.kotlin=1.3.50 +plugin.com.github.ben-manes.versions=0.25.0 +plugin.org.gradle.kotlin.kotlin-dsl=1.2.9 +# # available=1.3.1 +plugin.com.gradle.plugin-publish=0.10.0 +# # available=0.10.1 +plugin.de.fayard.refreshVersions=0.8.0 +plugin.com.gradle.build-scan=2.4.1 +# # available=3.0 +version.org.jetbrains.kotlin=1.3.41 +version.kotlintest-runner-junit5=3.1.9 +# # available=3.4.2 +version.gradle-versions-plugin=0.25.0 +# # available=0.27.0 +version.gradleLatestVersion=5.6.2 +# # available=5.6.3 +version.moshi=1.7.0 +version.okio=2.1.0 \ No newline at end of file diff --git a/sample-kotlin/gradle.properties b/sample-kotlin/gradle.properties index accc7b28f..f2f98cf39 100644 --- a/sample-kotlin/gradle.properties +++ b/sample-kotlin/gradle.properties @@ -3,24 +3,3 @@ # Set to 'verbose' to understand how dependency and plugin versions are overwritten # Set to 'false' to disable this feature resolutionStrategyConfig=verbose -# Dependencies and Plugin versions with their available updates -# Generated by $ ./gradlew refreshVersions -# You can edit the rest of the file, it will be kept intact -# See https://github.com/jmfayard/buildSrcVersions/issues/77 -plugin.org.nosphere.gradle.github.actions=1.0.0 -plugin.com.github.ben-manes.versions=0.25.0 -plugin.de.fayard.refreshVersions=0.8.0 -plugin.org.jetbrains.kotlin.jvm=1.3.50 -plugin.com.louiscad.splitties=0.1.3 -plugin.com.gradle.build-scan=3.0 -version.org.jetbrains.kotlinx=1.3.2 -version.com.squareup.okhttp3=4.2.0 -version.org.jetbrains.kotlin=1.3.50 -version.io.kotestArtifact=+ -version.org.mongodb..mongo-java-driver=3.11.0 -version.com.google.inject..guice=2.0 -version.gradleLatestVersion=5.6.2 -# # available=5.6.3 -version.cardview=+ -version.browser=+ -version.guava=15.0 From 3765c26204c156defbc0010c7d3eb710135b72b2 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 01:27:36 +0200 Subject: [PATCH 22/30] ci: try Gradle 4.8 in sample-android --- .github/workflows/gradle4-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle4-build.yml b/.github/workflows/gradle4-build.yml index 2c8526490..f0c77f59b 100644 --- a/.github/workflows/gradle4-build.yml +++ b/.github/workflows/gradle4-build.yml @@ -16,5 +16,5 @@ jobs: - uses: eskatos/gradle-command-action@v1 with: gradle-version: 4.8 - arguments: checkAll - build-root-directory: composite + arguments: refreshVersions + build-root-directory: sample-android From 7b667ac4800be0b02b1adf14e917d4c795a18cca Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 07:48:57 +0200 Subject: [PATCH 23/30] ci: fix maybe sample-android --- .../{gradle4-build.yml => sample-android.yml} | 5 ++-- sample-android/build.gradle.kts | 1 - sample-android/settings.gradle.kts | 4 +-- sample-android/versions.properties | 30 +++++++++++++------ 4 files changed, 25 insertions(+), 15 deletions(-) rename .github/workflows/{gradle4-build.yml => sample-android.yml} (86%) diff --git a/.github/workflows/gradle4-build.yml b/.github/workflows/sample-android.yml similarity index 86% rename from .github/workflows/gradle4-build.yml rename to .github/workflows/sample-android.yml index f0c77f59b..98af0286e 100644 --- a/.github/workflows/gradle4-build.yml +++ b/.github/workflows/sample-android.yml @@ -1,6 +1,6 @@ # .github/workflows/gradle-build-pr.yml # https://github.com/marketplace/actions/gradle-command -name: Gradle 4.8 +name: sample-android on: [pull_request] jobs: gradle: @@ -12,9 +12,8 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 8 - uses: eskatos/gradle-command-action@v1 with: - gradle-version: 4.8 arguments: refreshVersions build-root-directory: sample-android diff --git a/sample-android/build.gradle.kts b/sample-android/build.gradle.kts index 377ac625f..2deaeff12 100644 --- a/sample-android/build.gradle.kts +++ b/sample-android/build.gradle.kts @@ -1,5 +1,4 @@ import de.fayard.OrderBy -//TODO: find another solution to this problem https://gradle.com/s/7rm5h3bk6fzzq plugins { id("de.fayard.refreshVersions") diff --git a/sample-android/settings.gradle.kts b/sample-android/settings.gradle.kts index 7a2759950..767490265 100644 --- a/sample-android/settings.gradle.kts +++ b/sample-android/settings.gradle.kts @@ -1,11 +1,11 @@ pluginManagement { repositories { google() - mavenLocal() + //mavenLocal() gradlePluginPortal() } } apply(from = "plugins.gradle.kts") rootProject.name = "sample-android" -includeBuild("../plugin") +//includeBuild("../plugin") include(":app") diff --git a/sample-android/versions.properties b/sample-android/versions.properties index 450070a21..1815d4607 100644 --- a/sample-android/versions.properties +++ b/sample-android/versions.properties @@ -2,20 +2,32 @@ # Generated by $ ./gradlew refreshVersions # You can edit the rest of the file, it will be kept intact # See https://github.com/jmfayard/buildSrcVersions/issues/77 -module.android=3.5.0 module.kotlin=1.3.50 +module.android=3.5.0 plugin.com.github.ben-manes.versions=0.25.0 plugin.com.gradle.build-scan=2.4.2 -plugin.com.louiscad.splitties=0.1.3 # # available=3.0 +plugin.com.louiscad.splitties=0.1.2 plugin.de.fayard.refreshVersions=0.8.0 -version.com.wealthfront=1.1.0 +version.androidx.lifecycle=2.0.0 +# # available=2.1.0 version.org.jetbrains.kotlin=1.3.50 +version.org.mockito=3.1.0 +version.androidx.test..core=1.2.1-alpha02 +version.androidx.test..rules=1.3.0-alpha02 +version.androidx.test..runner=1.3.0-alpha02 +version.com.android.tools.build..gradle=3.5.0 +# # available=3.5.1 +version.aapt2=3.5.0-5435860 +# # available=3.5.1-5435860 +version.appcompat=1.1.0 +version.constraintlayout=2.0.0-beta3 +version.core-testing=2.1.0 +version.espresso-core=3.3.0-alpha02 version.gradleLatestVersion=5.6.2 # # available=5.6.3 -version.guava=15.0 -version.guice=2.0 -version.kotlinx-coroutines-core=1.0.0 -version.kotlinx-coroutines-core-common=1.0.0 -version.kotlinx-serialization-runtime=0.13.0 -version.timber=4.7.0 +version.junit=4.13-beta-3 +version.lint-gradle=26.5.0 +# # available=26.5.1 +version.material=1.0.0 +version.mockito-kotlin=2.2.0 \ No newline at end of file From 6d13915d454fa40c506325a62db0ea11b385eab1 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 08:13:25 +0200 Subject: [PATCH 24/30] refactor: put plugins.gradle.kts inside ./gradle --- plugin/build.gradle.kts | 3 +- plugin/{ => gradle}/plugins.gradle.kts | 7 +-- plugin/settings.gradle.kts | 2 +- .../kotlin/de/fayard/internal/PluginsSetup.kt | 15 ++---- .../src/main/resources/plugins.gradle.kts.txt | 7 +-- sample-android/build.gradle.kts | 2 +- sample-android/gradle/plugins.gradle.kts | 52 +++++++++++++++++++ sample-android/plugins.gradle.kts | 48 +++++++++++++---- sample-android/settings.gradle.kts | 5 +- sample-groovy/versions.properties | 2 +- sample-kotlin/build.gradle.kts | 5 +- sample-kotlin/{ => gradle}/plugins.gradle.kts | 5 +- sample-kotlin/settings.gradle.kts | 2 +- sample-kotlin/versions.properties | 2 +- 14 files changed, 115 insertions(+), 42 deletions(-) rename plugin/{ => gradle}/plugins.gradle.kts (91%) create mode 100644 sample-android/gradle/plugins.gradle.kts rename sample-kotlin/{ => gradle}/plugins.gradle.kts (92%) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 55ffa44c4..09448f432 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -1,8 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("de.fayard.refreshVersions") version ("0.8.0") // plugin.de.fayard.buildSrcVersions - + id("de.fayard.refreshVersions") id("com.gradle.plugin-publish") `java-gradle-plugin` `maven-publish` diff --git a/plugin/plugins.gradle.kts b/plugin/gradle/plugins.gradle.kts similarity index 91% rename from plugin/plugins.gradle.kts rename to plugin/gradle/plugins.gradle.kts index cf0833bb0..d14978871 100644 --- a/plugin/plugins.gradle.kts +++ b/plugin/gradle/plugins.gradle.kts @@ -49,13 +49,14 @@ apply(from = "plugins.gradle.kts") * To check what happen, you can set the property * resolutionStrategyConfig=verbose **/ - val resolutionStrategyConfig: String? by extra - if (resolutionStrategyConfig == "false" || file("versions.properties").canRead().not()) return@pluginManagement + val resolutionStrategyConfig = extra["resolutionStrategyConfig"] + val versionProperties = file("../versions.properties") + if (resolutionStrategyConfig == "false" || versionProperties.canRead().not()) return@pluginManagement val androidPluginIds = listOf("com.android.application", "com.android.library") val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") @Suppress("UNCHECKED_CAST") val properties: Map = java.util.Properties().apply { - load(file("versions.properties").reader()) + load(versionProperties.reader()) } as Map require("module.kotlin" in properties) { "version.properties MUST contain module.kotlin=.... and/or module.android=...." } resolutionStrategy.eachPlugin { diff --git a/plugin/settings.gradle.kts b/plugin/settings.gradle.kts index e5bd391ec..dbe44577d 100644 --- a/plugin/settings.gradle.kts +++ b/plugin/settings.gradle.kts @@ -4,5 +4,5 @@ pluginManagement { gradlePluginPortal() } } -apply(from = "plugins.gradle.kts") +apply(from = "gradle/plugins.gradle.kts") rootProject.name = "plugin" diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt index 95f86cf72..1babcbacb 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginsSetup.kt @@ -9,16 +9,7 @@ object PluginsSetup { const val OK = "✔ \uD83C\uDD97" const val INCLUDE_PLUGINS_GRADLE_KTS = """ -pluginManagement { - repositories { - google() // for Android projects only - jcenter() // if you use plugins not published on the gradlePluginPortal() - gradlePluginPortal() - } -} -apply(from = "plugins.gradle.kts") -// rootProject.name = xxx -// include(":app") +apply(from = "gradle/plugins.gradle.kts") """ fun pluginFileContent(): String { @@ -26,11 +17,11 @@ apply(from = "plugins.gradle.kts") } fun copyPluginsGradleKtsIfNeeded(project: Project) { - val file = project.rootProject.file(PLUGIN_GRADLE_KTS) + val file = project.rootProject.file("gradle/$PLUGIN_GRADLE_KTS") val settingsFile = project.rootProject.file(SETTINGS_GRADLE_KTS) if (settingsFile.canRead() && file.canRead().not()) { file.writeText(pluginFileContent()) - println("$OK Created file ./$PLUGIN_GRADLE_KTS") + println("$OK Created file ./gradle/$PLUGIN_GRADLE_KTS") throw GradleException( """ |Action required: Please include $PLUGIN_GRADLE_KTS file in $SETTINGS_GRADLE_KTS diff --git a/plugin/src/main/resources/plugins.gradle.kts.txt b/plugin/src/main/resources/plugins.gradle.kts.txt index 90a590b47..178047e07 100644 --- a/plugin/src/main/resources/plugins.gradle.kts.txt +++ b/plugin/src/main/resources/plugins.gradle.kts.txt @@ -49,13 +49,14 @@ apply(from = "plugins.gradle.kts") * To check what happen, you can set the property * resolutionStrategyConfig=verbose **/ - val resolutionStrategyConfig: String? by extra - if (resolutionStrategyConfig == "false" || file("versions.properties").canRead().not()) return@pluginManagement + val versionProperties = file("../versions.properties") + val resolutionStrategyConfig = extra["resolutionStrategyConfig"] + if (resolutionStrategyConfig == "false" || versionProperties.canRead().not()) return@pluginManagement val androidPluginIds = listOf("com.android.application", "com.android.library") val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") @Suppress("UNCHECKED_CAST") val properties: Map = java.util.Properties().apply { - load(file("versions.properties").reader()) + load(versionProperties.reader()) } as Map resolutionStrategy.eachPlugin { val pluginId = requested.id.id diff --git a/sample-android/build.gradle.kts b/sample-android/build.gradle.kts index 2deaeff12..8de7ddd3d 100644 --- a/sample-android/build.gradle.kts +++ b/sample-android/build.gradle.kts @@ -1,7 +1,7 @@ import de.fayard.OrderBy plugins { - id("de.fayard.refreshVersions") + id("de.fayard.refreshVersions").version("0.8.0") `build-scan` } group = "de.fayard" diff --git a/sample-android/gradle/plugins.gradle.kts b/sample-android/gradle/plugins.gradle.kts new file mode 100644 index 000000000..1f49feece --- /dev/null +++ b/sample-android/gradle/plugins.gradle.kts @@ -0,0 +1,52 @@ +import java.util.Properties + +/** + * Included in "settings.gradle.kts" via + * apply(from = "plugins.gradle.kts") + * + * See the Gradle guide on plugin management + * https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_management + ***/ + +pluginManagement { + + /** + * This `resolutionStrategy` allows plugin versions to be configured from + * `versions.properties + * The convention is simply + * plugin.$PLUGINID=$PLUGIN_VERSION + * To check what happen, you can set the property + * resolutionStrategyConfig=verbose + **/ + val resolutionStrategyConfig: String? by extra + if (resolutionStrategyConfig == "false" || file("../versions.properties").canRead().not()) return@pluginManagement + val androidPluginIds = listOf("com.android.application", "com.android.library") + val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") + @Suppress("UNCHECKED_CAST") + val properties: Map = Properties().apply { + load(file("../versions.properties").reader()) + } as Map + require("module.kotlin" in properties && "module.android" in properties) { "version.properties MUST contain module.android=... and module.kotlin=...." } + resolutionStrategy.eachPlugin { + val pluginId = requested.id.id + val version = properties["plugin.$pluginId"] + val message = when { + pluginId in kotlinPluginIds -> { + val module = "org.jetbrains.kotlin:kotlin-gradle-plugin:${properties["module.kotlin"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + pluginId in androidPluginIds -> { + val module = "com.android.tools.build:gradle:${properties["module.android"]}" + useModule(module) + "ResolutionStrategy used module=$module for plugin=$pluginId" + } + version != null -> { + useVersion(version) + "ResolutionStrategy used version=$version for plugin=$pluginId" + } + else -> "ResolutionStrategy did not find a version for $pluginId" + } + if (resolutionStrategyConfig == "verbose") println(message) + } +} diff --git a/sample-android/plugins.gradle.kts b/sample-android/plugins.gradle.kts index d584c4055..90a590b47 100644 --- a/sample-android/plugins.gradle.kts +++ b/sample-android/plugins.gradle.kts @@ -1,14 +1,45 @@ -import java.util.Properties - /** - * Included in "settings.gradle.kts" via - * apply(from = "plugins.gradle.kts") + * File generated by $ ./gradlew refreshVersions + * + * Gradle has replaced the buildscript { ... } block by a better alternative that looks like this + * +``` +plugins { +id("com.android.application") +id("com.louiscad.splitties") +id("org.jetbrains.kotlin.android") +id("org.jetbrains.kotlin.kapt") +id("kotlin-android-extensions") +} +``` + * This boilerplate does two things: + * + * 1. it configures the plugin versions using the file `versions.properties` generated by + * $ ./gradlew refreshVersions + * + * 2. it fixes the bug of the Android Gradle Plugin that doesn't publish the required metadata + * Please see and upvote the issue: + * https://issuetracker.google.com/issues/64551265 + * + * Include this file like this: * - * See the Gradle guide on plugin management - * https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_management - ***/ +```kotlin +// settings.gradle.kts pluginManagement { +repositories { +google() +gradlePluginPortal() +} +} +apply(from = "plugins.gradle.kts") +// rootProject.name = xxx +// include(":app") +``` + + ***/ +@Suppress("CAST_NEVER_SUCCEEDS") +(this as Settings).pluginManagement { /** * This `resolutionStrategy` allows plugin versions to be configured from @@ -23,10 +54,9 @@ pluginManagement { val androidPluginIds = listOf("com.android.application", "com.android.library") val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") @Suppress("UNCHECKED_CAST") - val properties: Map = Properties().apply { + val properties: Map = java.util.Properties().apply { load(file("versions.properties").reader()) } as Map - require("module.kotlin" in properties && "module.android" in properties) { "version.properties MUST contain module.android=... and module.kotlin=...." } resolutionStrategy.eachPlugin { val pluginId = requested.id.id val version = properties["plugin.$pluginId"] diff --git a/sample-android/settings.gradle.kts b/sample-android/settings.gradle.kts index 767490265..ff4ff7a73 100644 --- a/sample-android/settings.gradle.kts +++ b/sample-android/settings.gradle.kts @@ -1,11 +1,10 @@ pluginManagement { repositories { google() - //mavenLocal() gradlePluginPortal() + mavenLocal() } } -apply(from = "plugins.gradle.kts") +apply(from = "gradle/plugins.gradle.kts") rootProject.name = "sample-android" -//includeBuild("../plugin") include(":app") diff --git a/sample-groovy/versions.properties b/sample-groovy/versions.properties index 8dcb71140..a2c2140f6 100644 --- a/sample-groovy/versions.properties +++ b/sample-groovy/versions.properties @@ -12,4 +12,4 @@ version.org.jetbrains..annotation=17.0.0 version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 # # available=5.6.3 -version.guava=15.0 +version.guava=15.0 \ No newline at end of file diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts index b953808b5..62680be4d 100644 --- a/sample-kotlin/build.gradle.kts +++ b/sample-kotlin/build.gradle.kts @@ -5,10 +5,9 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("de.fayard.refreshVersions") - kotlin("jvm").version("1.3.50") - id("com.louiscad.splitties").version("0.1.2") + id("com.louiscad.splitties") + kotlin("jvm") `build-scan` - //id("org.nosphere.gradle.github.actions") } group = "de.fayard" diff --git a/sample-kotlin/plugins.gradle.kts b/sample-kotlin/gradle/plugins.gradle.kts similarity index 92% rename from sample-kotlin/plugins.gradle.kts rename to sample-kotlin/gradle/plugins.gradle.kts index 90a590b47..8a0255c67 100644 --- a/sample-kotlin/plugins.gradle.kts +++ b/sample-kotlin/gradle/plugins.gradle.kts @@ -50,12 +50,13 @@ apply(from = "plugins.gradle.kts") * resolutionStrategyConfig=verbose **/ val resolutionStrategyConfig: String? by extra - if (resolutionStrategyConfig == "false" || file("versions.properties").canRead().not()) return@pluginManagement + val versionProperties = file("../versions.properties") + if (resolutionStrategyConfig == "false" || versionProperties.canRead().not()) return@pluginManagement val androidPluginIds = listOf("com.android.application", "com.android.library") val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") @Suppress("UNCHECKED_CAST") val properties: Map = java.util.Properties().apply { - load(file("versions.properties").reader()) + load(versionProperties.reader()) } as Map resolutionStrategy.eachPlugin { val pluginId = requested.id.id diff --git a/sample-kotlin/settings.gradle.kts b/sample-kotlin/settings.gradle.kts index 18b1ae246..d811092fa 100644 --- a/sample-kotlin/settings.gradle.kts +++ b/sample-kotlin/settings.gradle.kts @@ -4,7 +4,7 @@ pluginManagement { mavenCentral() } } -//apply(from = "plugins.gradle.kts") +apply(from = "gradle/plugins.gradle.kts") rootProject.name = "sample-kotlin" includeBuild("../plugin") diff --git a/sample-kotlin/versions.properties b/sample-kotlin/versions.properties index 19fdc8f0b..26c96bdee 100644 --- a/sample-kotlin/versions.properties +++ b/sample-kotlin/versions.properties @@ -19,4 +19,4 @@ version.gradleLatestVersion=5.6.2 # # available=5.6.3 version.cardview=+ version.browser=+ -version.guava=15.0 +version.guava=15.0 \ No newline at end of file From b0ed8bf97ff42aa358924e8bb91398a60c133719 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 08:18:26 +0200 Subject: [PATCH 25/30] sample-android: use version released as 0.8.0 --- sample-android/gradle/plugins.gradle.kts | 5 +++-- sample-android/settings.gradle.kts | 2 +- sample-android/versions.properties | 5 +---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/sample-android/gradle/plugins.gradle.kts b/sample-android/gradle/plugins.gradle.kts index 1f49feece..c79ad12ea 100644 --- a/sample-android/gradle/plugins.gradle.kts +++ b/sample-android/gradle/plugins.gradle.kts @@ -18,13 +18,14 @@ pluginManagement { * To check what happen, you can set the property * resolutionStrategyConfig=verbose **/ + val versionProperties = file("../versions.properties") val resolutionStrategyConfig: String? by extra - if (resolutionStrategyConfig == "false" || file("../versions.properties").canRead().not()) return@pluginManagement + if (resolutionStrategyConfig == "false" || versionProperties.canRead().not()) return@pluginManagement val androidPluginIds = listOf("com.android.application", "com.android.library") val kotlinPluginIds = listOf("org.jetbrains.kotlin.android", "org.jetbrains.kotlin.kapt", "kotlin-android-extensions") @Suppress("UNCHECKED_CAST") val properties: Map = Properties().apply { - load(file("../versions.properties").reader()) + load(versionProperties.reader()) } as Map require("module.kotlin" in properties && "module.android" in properties) { "version.properties MUST contain module.android=... and module.kotlin=...." } resolutionStrategy.eachPlugin { diff --git a/sample-android/settings.gradle.kts b/sample-android/settings.gradle.kts index ff4ff7a73..80fb602af 100644 --- a/sample-android/settings.gradle.kts +++ b/sample-android/settings.gradle.kts @@ -2,7 +2,7 @@ pluginManagement { repositories { google() gradlePluginPortal() - mavenLocal() + //mavenLocal() } } apply(from = "gradle/plugins.gradle.kts") diff --git a/sample-android/versions.properties b/sample-android/versions.properties index 1815d4607..9275864fb 100644 --- a/sample-android/versions.properties +++ b/sample-android/versions.properties @@ -10,7 +10,6 @@ plugin.com.gradle.build-scan=2.4.2 plugin.com.louiscad.splitties=0.1.2 plugin.de.fayard.refreshVersions=0.8.0 version.androidx.lifecycle=2.0.0 -# # available=2.1.0 version.org.jetbrains.kotlin=1.3.50 version.org.mockito=3.1.0 version.androidx.test..core=1.2.1-alpha02 @@ -19,7 +18,6 @@ version.androidx.test..runner=1.3.0-alpha02 version.com.android.tools.build..gradle=3.5.0 # # available=3.5.1 version.aapt2=3.5.0-5435860 -# # available=3.5.1-5435860 version.appcompat=1.1.0 version.constraintlayout=2.0.0-beta3 version.core-testing=2.1.0 @@ -28,6 +26,5 @@ version.gradleLatestVersion=5.6.2 # # available=5.6.3 version.junit=4.13-beta-3 version.lint-gradle=26.5.0 -# # available=26.5.1 version.material=1.0.0 -version.mockito-kotlin=2.2.0 \ No newline at end of file +version.mockito-kotlin=2.2.0 From 7b2979ed53aa78731db88812cac8eb652b6df80f Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 08:24:53 +0200 Subject: [PATCH 26/30] ci(sample-android): gradle 5.6.3 --- .github/workflows/sample-android.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sample-android.yml b/.github/workflows/sample-android.yml index 98af0286e..13bea8688 100644 --- a/.github/workflows/sample-android.yml +++ b/.github/workflows/sample-android.yml @@ -16,4 +16,5 @@ jobs: - uses: eskatos/gradle-command-action@v1 with: arguments: refreshVersions + gradle-version: 5.6.3 build-root-directory: sample-android From 6b0782f998ec1862cfa13fbfcfd2396963555ad6 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 21:56:48 +0200 Subject: [PATCH 27/30] envOrProperty --- plugin/src/main/kotlin/de/fayard/Projects.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 plugin/src/main/kotlin/de/fayard/Projects.kt diff --git a/plugin/src/main/kotlin/de/fayard/Projects.kt b/plugin/src/main/kotlin/de/fayard/Projects.kt new file mode 100644 index 000000000..7715405e0 --- /dev/null +++ b/plugin/src/main/kotlin/de/fayard/Projects.kt @@ -0,0 +1,9 @@ +@file:JvmName("Projects") + +package de.fayard + +import org.gradle.api.Project + +fun Project.envOrProperty(environment: String, property: String): String = + System.getenv(environment) ?: findProperty(property) as String + From a83791df8faad45ce2d72434c82ffcd97b94e09b Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Thu, 24 Oct 2019 22:16:55 +0200 Subject: [PATCH 28/30] plugin: useFqdnFor(androidx.*) --- .../src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt | 2 +- .../src/main/kotlin/de/fayard/internal/KotlinPoetry.kt | 3 ++- sample-groovy/versions.properties | 7 +------ sample-kotlin/versions.properties | 10 +++++----- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt index 025a220e9..864c20f67 100644 --- a/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt +++ b/plugin/src/main/kotlin/de/fayard/RefreshVersionsPlugin.kt @@ -70,7 +70,7 @@ fun Project.useVersionsFromProperties() { val gradleProperty = PluginConfig.considerGradleProperties(candidate.group, candidate.name) .firstOrNull { it in properties } ?: return@eachDependency val message = - "ResolutionStrategy selected version=${properties[gradleProperty]} from property=$gradleProperty with for dependency=${candidate.group}:${candidate.name}" + "ResolutionStrategy selected version=${properties[gradleProperty]} from property=$gradleProperty with for dependency=${candidate.group}:${candidate.name} in $configurationName" if (resolutionStrategyConfig == "verbose") println(message) useVersion(properties[gradleProperty] ?: error(message)) } diff --git a/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt b/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt index 4dce4abb3..2fe991e9c 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/KotlinPoetry.kt @@ -28,7 +28,8 @@ fun parseGraph( useFdqn: List ): List { val dependencies: List = graph.current + graph.exceeded + graph.outdated + graph.unresolved - val resolvedUseFqdn = PluginConfig.computeUseFqdnFor(dependencies, useFdqn, PluginConfig.MEANING_LESS_NAMES) + val androidx = dependencies.map { it.group }.distinct().filter { it.startsWith("androidx.") } + val resolvedUseFqdn = PluginConfig.computeUseFqdnFor(dependencies, useFdqn + androidx, PluginConfig.MEANING_LESS_NAMES) return dependencies.checkModeAndNames(resolvedUseFqdn).findCommonVersions() } diff --git a/sample-groovy/versions.properties b/sample-groovy/versions.properties index a2c2140f6..0e52b2e82 100644 --- a/sample-groovy/versions.properties +++ b/sample-groovy/versions.properties @@ -3,13 +3,8 @@ # You can edit the rest of the file, it will be kept intact # See https://github.com/jmfayard/buildSrcVersions/issues/77 module.kotlin=1.3.50 -module.android=3.5.0 plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.com.gradle.build-scan=2.4.2 -version.androidx.annotation..annotation=1.1.0 -version.org.jetbrains..annotation=17.0.0 -version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 -# # available=5.6.3 -version.guava=15.0 \ No newline at end of file +# # available=5.6.3 \ No newline at end of file diff --git a/sample-kotlin/versions.properties b/sample-kotlin/versions.properties index 26c96bdee..ef73f48f6 100644 --- a/sample-kotlin/versions.properties +++ b/sample-kotlin/versions.properties @@ -7,16 +7,16 @@ module.android=3.5.0 plugin.com.github.ben-manes.versions=0.25.0 plugin.de.fayard.refreshVersions=0.8.0 plugin.org.jetbrains.kotlin.jvm=1.3.50 -plugin.com.louiscad.splitties=0.1.2 +plugin.com.louiscad.splitties=0.1.3 plugin.com.gradle.build-scan=3.0 version.org.jetbrains.kotlinx=1.3.2 version.com.squareup.okhttp3=4.2.0 version.org.jetbrains.kotlin=1.3.50 -version.io.kotestArtifact=+ +version.io.kotestArtifact=3.4.2 version.org.mongodb..mongo-java-driver=3.11.0 +version.androidx.cardview..cardview=1.0.0 +version.androidx.browser..browser=1.0.0 version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 # # available=5.6.3 -version.cardview=+ -version.browser=+ -version.guava=15.0 \ No newline at end of file +version.guava=15.0 From c6879b615e5b64eee1ea1ed5a97828711aa79c9e Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Fri, 25 Oct 2019 07:52:30 +0200 Subject: [PATCH 29/30] release: v0.8.1 --- plugin/build.gradle.kts | 2 +- .../src/main/kotlin/de/fayard/internal/PluginConfig.kt | 2 +- plugin/versions.properties | 4 ++-- sample-groovy/gradle.properties | 4 ++-- sample-groovy/versions.properties | 2 +- sample-kotlin/versions.properties | 10 +++++----- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 09448f432..b164adffc 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -10,7 +10,7 @@ plugins { } -version = "0.8.0" // plugin.de.fayard.refreshversions +version = "0.8.2" // plugin.de.fayard.refreshversions group = "de.fayard" diff --git a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt index 1f53d1637..346a08760 100644 --- a/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt +++ b/plugin/src/main/kotlin/de/fayard/internal/PluginConfig.kt @@ -16,7 +16,7 @@ object PluginConfig { const val PLUGIN_ID = "de.fayard.refreshVersions" - const val PLUGIN_VERSION = "0.8.0" // plugin.de.fayard.refreshVersions + const val PLUGIN_VERSION = "0.8.2" // plugin.de.fayard.refreshVersions const val GRADLE_VERSIONS_PLUGIN_ID = "com.github.ben-manes.versions" const val GRADLE_VERSIONS_PLUGIN_VERSION = "0.25.0" // Sync with plugin/build.gradle.kts const val DEPENDENCY_UPDATES = "dependencyUpdates" diff --git a/plugin/versions.properties b/plugin/versions.properties index 0d04813d6..0a63e6544 100644 --- a/plugin/versions.properties +++ b/plugin/versions.properties @@ -8,7 +8,7 @@ plugin.org.gradle.kotlin.kotlin-dsl=1.2.9 # # available=1.3.1 plugin.com.gradle.plugin-publish=0.10.0 # # available=0.10.1 -plugin.de.fayard.refreshVersions=0.8.0 +plugin.de.fayard.refreshVersions=0.8.1 plugin.com.gradle.build-scan=2.4.1 # # available=3.0 version.org.jetbrains.kotlin=1.3.41 @@ -19,4 +19,4 @@ version.gradle-versions-plugin=0.25.0 version.gradleLatestVersion=5.6.2 # # available=5.6.3 version.moshi=1.7.0 -version.okio=2.1.0 \ No newline at end of file +version.okio=2.1.0 diff --git a/sample-groovy/gradle.properties b/sample-groovy/gradle.properties index a50018503..1971218a8 100644 --- a/sample-groovy/gradle.properties +++ b/sample-groovy/gradle.properties @@ -8,7 +8,7 @@ resolutionStrategyConfig=verbose # You can edit the rest of the file, it will be kept intact # See https://github.com/jmfayard/buildSrcVersions/issues/77 plugin.com.github.ben-manes.versions=0.25.0 -plugin.de.fayard.refreshVersions=0.8.0 +plugin.de.fayard.refreshVersions=0.8.2 plugin.com.gradle.build-scan=2.4.2 version.gradleLatestVersion=5.6.2 -# # available=5.6.3 \ No newline at end of file +# # available=5.6.3 diff --git a/sample-groovy/versions.properties b/sample-groovy/versions.properties index 0e52b2e82..d9a4019a5 100644 --- a/sample-groovy/versions.properties +++ b/sample-groovy/versions.properties @@ -4,7 +4,7 @@ # See https://github.com/jmfayard/buildSrcVersions/issues/77 module.kotlin=1.3.50 plugin.com.github.ben-manes.versions=0.25.0 -plugin.de.fayard.refreshVersions=0.8.0 +plugin.de.fayard.refreshVersions=0.8.2 plugin.com.gradle.build-scan=2.4.2 version.gradleLatestVersion=5.6.2 # # available=5.6.3 \ No newline at end of file diff --git a/sample-kotlin/versions.properties b/sample-kotlin/versions.properties index ef73f48f6..2014858d9 100644 --- a/sample-kotlin/versions.properties +++ b/sample-kotlin/versions.properties @@ -5,18 +5,18 @@ module.kotlin=1.3.50 module.android=3.5.0 plugin.com.github.ben-manes.versions=0.25.0 -plugin.de.fayard.refreshVersions=0.8.0 +plugin.de.fayard.refreshVersions=0.8.2 plugin.org.jetbrains.kotlin.jvm=1.3.50 plugin.com.louiscad.splitties=0.1.3 plugin.com.gradle.build-scan=3.0 version.org.jetbrains.kotlinx=1.3.2 version.com.squareup.okhttp3=4.2.0 version.org.jetbrains.kotlin=1.3.50 -version.io.kotestArtifact=3.4.2 +version.io.kotestArtifact=+ version.org.mongodb..mongo-java-driver=3.11.0 -version.androidx.cardview..cardview=1.0.0 -version.androidx.browser..browser=1.0.0 +version.androidx.cardview..cardview=+ +version.androidx.browser..browser=+ version.com.google.inject..guice=2.0 version.gradleLatestVersion=5.6.2 # # available=5.6.3 -version.guava=15.0 +version.guava=15.0 \ No newline at end of file From 988bb69684bc5bbe2176d01d82c44f808e3d2b71 Mon Sep 17 00:00:00 2001 From: Jean-Michel Fayard Date: Fri, 25 Oct 2019 14:29:04 +0200 Subject: [PATCH 30/30] Remove travis --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 468672e48..000000000 --- a/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: java -cache: - directories: - - $HOME/.gradle -script: - - cd composite && ./gradlew checkAll