summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/renovate.json512
-rw-r--r--.github/workflows/pull_request.yml2
-rw-r--r--app/src/main/res/values-pl-rPL/strings.xml2
-rw-r--r--build-logic/build.gradle.kts10
-rw-r--r--build-logic/src/main/kotlin/app/passwordstore/gradle/KtfmtPlugin.kt37
-rw-r--r--build-logic/src/main/kotlin/app/passwordstore/gradle/SpotlessPlugin.kt44
-rw-r--r--build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtCheckTask.kt63
-rw-r--r--build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtDiffEntry.kt8
-rw-r--r--build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtDiffer.kt28
-rw-r--r--build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtFormatTask.kt46
-rw-r--r--build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtWorkerAction.kt38
-rw-r--r--build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtWorkerParameters.kt12
-rw-r--r--build.gradle.kts2
-rw-r--r--gradle/libs.versions.toml2
-rw-r--r--scripts/pre-push-hook.sh2
15 files changed, 65 insertions, 243 deletions
diff --git a/.github/renovate.json5 b/.github/renovate.json5
index 71995b37..ecbc5a60 100644
--- a/.github/renovate.json5
+++ b/.github/renovate.json5
@@ -68,6 +68,16 @@
"datasourceTemplate": "maven",
"depNameTemplate": "androidx.compose.compiler:compiler",
"registryUrlTemplate": "https://maven.google.com",
- }
+ },
+ {
+ "fileMatch": [
+ "build-logic/src/main/kotlin/app/passwordstore/gradle/SpotlessPlugin.kt"
+ ],
+ "matchStrings": [
+ "KTFMT_VERSION = \"(?<currentValue>.*)\""
+ ],
+ "datasourceTemplate": "maven",
+ "depNameTemplate": "com.facebook:ktfmt"
+ }
]
}
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index f5879ab7..242065f6 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -20,7 +20,7 @@ jobs:
- name: Check codestyle
shell: bash
- run: ./gradlew ktfmtCheck
+ run: ./gradlew spotlessCheck
- name: Upload Kotlin build report
if: "${{ always() }}"
diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml
index 0b3bee8f..e3d57b79 100644
--- a/app/src/main/res/values-pl-rPL/strings.xml
+++ b/app/src/main/res/values-pl-rPL/strings.xml
@@ -6,7 +6,7 @@
<resources>
<plurals name="delete_title">
<item quantity="one">Wybrano %d element</item>
- <item quantity="few">Wybrano %d elementy
+ <item quantity="few">Wybrano %d elementy
(If: 2,3,4)</item>
<item quantity="many">Wybrano %d elementów</item>
<item quantity="other">Liczba wybranych elementów: %d</item>
diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts
index 4917fc8c..1f98dde8 100644
--- a/build-logic/build.gradle.kts
+++ b/build-logic/build.gradle.kts
@@ -41,10 +41,6 @@ gradlePlugin {
id = "com.github.android-password-store.kotlin-jvm-library"
implementationClass = "app.passwordstore.gradle.KotlinJVMLibrary"
}
- register("ktfmt") {
- id = "com.github.android-password-store.ktfmt"
- implementationClass = "app.passwordstore.gradle.KtfmtPlugin"
- }
register("published-android-library") {
id = "com.github.android-password-store.published-android-library"
implementationClass = "app.passwordstore.gradle.PublishedAndroidLibraryPlugin"
@@ -61,6 +57,10 @@ gradlePlugin {
id = "com.github.android-password-store.sentry"
implementationClass = "app.passwordstore.gradle.SentryPlugin"
}
+ register("spotless") {
+ id = "com.github.android-password-store.spotless"
+ implementationClass = "app.passwordstore.gradle.SpotlessPlugin"
+ }
register("versioning") {
id = "com.github.android-password-store.versioning-plugin"
implementationClass = "app.passwordstore.gradle.versioning.VersioningPlugin"
@@ -79,7 +79,6 @@ dependencies {
implementation(libs.build.download)
implementation(libs.build.javapoet)
implementation(libs.build.kotlin)
- implementation(libs.build.ktfmt)
implementation(libs.build.mavenpublish)
implementation(libs.build.metalava)
implementation(libs.build.moshi)
@@ -88,6 +87,7 @@ dependencies {
implementation(libs.build.r8)
implementation(libs.build.semver)
implementation(libs.build.sentry)
+ implementation(libs.build.spotless)
implementation(libs.build.vcu)
implementation(libs.kotlinx.coroutines.core)
diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/KtfmtPlugin.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/KtfmtPlugin.kt
deleted file mode 100644
index 7aac48b5..00000000
--- a/build-logic/src/main/kotlin/app/passwordstore/gradle/KtfmtPlugin.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package app.passwordstore.gradle
-
-import app.passwordstore.gradle.ktfmt.KtfmtCheckTask
-import app.passwordstore.gradle.ktfmt.KtfmtFormatTask
-import com.facebook.ktfmt.format.FormattingOptions
-import java.util.concurrent.Callable
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.kotlin.dsl.register
-
-class KtfmtPlugin : Plugin<Project> {
-
- override fun apply(target: Project) {
- val input = Callable {
- target.layout.projectDirectory.asFileTree.filter { file ->
- file.extension == "kt" || file.extension == "kts" && !file.canonicalPath.contains("build/")
- }
- }
- target.tasks.register<KtfmtFormatTask>("ktfmtFormat") { source(input) }
- target.tasks.register<KtfmtCheckTask>("ktfmtCheck") {
- source(input)
- projectDirectory.set(target.layout.projectDirectory)
- }
- }
-
- companion object {
- val DEFAULT_FORMATTING_OPTIONS =
- FormattingOptions(
- maxWidth = FormattingOptions.DEFAULT_MAX_WIDTH,
- blockIndent = 2,
- continuationIndent = 2,
- removeUnusedImports = true,
- debuggingPrintOpsAfterFormatting = false,
- manageTrailingCommas = true,
- )
- }
-}
diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/SpotlessPlugin.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/SpotlessPlugin.kt
new file mode 100644
index 00000000..6f33f922
--- /dev/null
+++ b/build-logic/src/main/kotlin/app/passwordstore/gradle/SpotlessPlugin.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package app.passwordstore.gradle
+
+import com.diffplug.gradle.spotless.SpotlessExtension
+import com.diffplug.gradle.spotless.SpotlessPlugin
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.apply
+import org.gradle.kotlin.dsl.getByType
+
+@Suppress("Unused")
+class SpotlessPlugin : Plugin<Project> {
+
+ override fun apply(project: Project) {
+ project.pluginManager.apply(SpotlessPlugin::class)
+ project.extensions.getByType<SpotlessExtension>().run {
+ kotlin {
+ ktfmt(KTFMT_VERSION).googleStyle()
+ target("**/*.kt")
+ targetExclude("**/build/")
+ }
+ kotlinGradle {
+ ktfmt(KTFMT_VERSION).googleStyle()
+ target("**/*.kts")
+ targetExclude("**/build/")
+ }
+ format("xml") {
+ target("**/*.xml")
+ targetExclude("**/build/", ".idea/")
+ trimTrailingWhitespace()
+ indentWithSpaces()
+ endWithNewline()
+ }
+ }
+ }
+
+ private companion object {
+ private const val KTFMT_VERSION = "0.51"
+ }
+}
diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtCheckTask.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtCheckTask.kt
deleted file mode 100644
index 58ef432f..00000000
--- a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtCheckTask.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-package app.passwordstore.gradle.ktfmt
-
-import app.passwordstore.gradle.KtfmtPlugin
-import com.facebook.ktfmt.format.Formatter
-import java.io.File
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.runBlocking
-import org.gradle.api.GradleException
-import org.gradle.api.file.DirectoryProperty
-import org.gradle.api.file.FileCollection
-import org.gradle.api.tasks.IgnoreEmptyDirectories
-import org.gradle.api.tasks.InputFiles
-import org.gradle.api.tasks.Internal
-import org.gradle.api.tasks.PathSensitive
-import org.gradle.api.tasks.PathSensitivity
-import org.gradle.api.tasks.SourceTask
-import org.gradle.api.tasks.TaskAction
-
-@OptIn(ExperimentalCoroutinesApi::class)
-abstract class KtfmtCheckTask : SourceTask() {
-
- @get:PathSensitive(PathSensitivity.RELATIVE)
- @get:InputFiles
- @get:IgnoreEmptyDirectories
- protected val inputFiles: FileCollection
- get() = super.getSource()
-
- @get:Internal abstract val projectDirectory: DirectoryProperty
-
- @TaskAction
- fun execute() {
- runBlocking(Dispatchers.IO.limitedParallelism(PARALLEL_TASK_LIMIT)) {
- coroutineScope {
- val results = inputFiles.map { async { checkFile(it) } }.awaitAll()
- if (results.any { (notFormatted, _) -> notFormatted }) {
- val prettyDiff =
- results
- .map { (_, diffs) -> diffs }
- .flatten()
- .joinToString(separator = "\n") { diff -> diff.toString() }
- throw GradleException("[ktfmt] Found unformatted files\n${prettyDiff}")
- }
- }
- }
- }
-
- private fun checkFile(input: File): Pair<Boolean, List<KtfmtDiffEntry>> {
- val originCode = input.readText()
- val formattedCode = Formatter.format(KtfmtPlugin.DEFAULT_FORMATTING_OPTIONS, originCode)
- val pathNormalizer = { file: File -> file.toRelativeString(projectDirectory.asFile.get()) }
- return (originCode != formattedCode) to
- KtfmtDiffer.computeDiff(input, formattedCode, pathNormalizer)
- }
-
- companion object {
-
- private const val PARALLEL_TASK_LIMIT = 4
- }
-}
diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtDiffEntry.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtDiffEntry.kt
deleted file mode 100644
index ca01b5e9..00000000
--- a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtDiffEntry.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package app.passwordstore.gradle.ktfmt
-
-data class KtfmtDiffEntry(val input: String, val lineNumber: Int, val message: String) {
-
- override fun toString(): String {
- return "$input:$lineNumber - $message"
- }
-}
diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtDiffer.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtDiffer.kt
deleted file mode 100644
index f1332923..00000000
--- a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtDiffer.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package app.passwordstore.gradle.ktfmt
-
-import com.github.difflib.DiffUtils
-import com.github.difflib.patch.ChangeDelta
-import com.github.difflib.patch.DeleteDelta
-import com.github.difflib.patch.InsertDelta
-import java.io.File
-
-object KtfmtDiffer {
- fun computeDiff(
- inputFile: File,
- formattedCode: String,
- pathNormalizer: (File) -> String,
- ): List<KtfmtDiffEntry> {
- val originCode = inputFile.readText()
- return DiffUtils.diff(originCode, formattedCode, null).deltas.map {
- val line = it.source.position + 1
- val message: String =
- when (it) {
- is ChangeDelta -> "Line changed: ${it.source.lines.first()}"
- is DeleteDelta -> "Line deleted"
- is InsertDelta -> "Line added"
- else -> ""
- }
- KtfmtDiffEntry(pathNormalizer(inputFile), line, message)
- }
- }
-}
diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtFormatTask.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtFormatTask.kt
deleted file mode 100644
index c76b5c89..00000000
--- a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtFormatTask.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-package app.passwordstore.gradle.ktfmt
-
-import javax.inject.Inject
-import org.gradle.api.GradleException
-import org.gradle.api.file.ProjectLayout
-import org.gradle.api.tasks.SourceTask
-import org.gradle.api.tasks.TaskAction
-import org.gradle.internal.exceptions.MultiCauseException
-import org.gradle.workers.WorkerExecutor
-import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
-
-abstract class KtfmtFormatTask
-@Inject
-constructor(private val workerExecutor: WorkerExecutor, private val projectLayout: ProjectLayout) :
- SourceTask() {
-
- @TaskAction
- fun execute() {
- val result =
- with(workerExecutor.noIsolation()) {
- submit(KtfmtWorkerAction::class.java) {
- name.set("ktfmt-worker")
- files.from(source)
- projectDirectory.set(projectLayout.projectDirectory.asFile)
- }
- runCatching { await() }
- }
-
- result.exceptionOrNull()?.workErrorCauses<Exception>()?.ifNotEmpty {
- forEach { logger.error(it.message, it.cause) }
- throw GradleException("error formatting sources for $name")
- }
- }
-
- private inline fun <reified T : Throwable> Throwable.workErrorCauses(): List<Throwable> {
- return when (this) {
- is MultiCauseException -> this.causes.map { it.cause }
- else -> listOf(this.cause)
- }
- .filter {
- // class instance comparison doesn't work due to different classloaders
- it?.javaClass?.canonicalName == T::class.java.canonicalName
- }
- .filterNotNull()
- }
-}
diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtWorkerAction.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtWorkerAction.kt
deleted file mode 100644
index c955adbe..00000000
--- a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtWorkerAction.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package app.passwordstore.gradle.ktfmt
-
-import app.passwordstore.gradle.KtfmtPlugin
-import com.facebook.ktfmt.format.Formatter
-import java.io.File
-import org.gradle.api.logging.LogLevel
-import org.gradle.api.logging.Logger
-import org.gradle.api.logging.Logging
-import org.gradle.internal.logging.slf4j.DefaultContextAwareTaskLogger
-import org.gradle.workers.WorkAction
-
-abstract class KtfmtWorkerAction : WorkAction<KtfmtWorkerParameters> {
- private val logger: Logger =
- DefaultContextAwareTaskLogger(Logging.getLogger(KtfmtFormatTask::class.java))
- private val files: List<File> = parameters.files.toList()
- private val projectDirectory: File = parameters.projectDirectory.asFile.get()
- private val name: String = parameters.name.get()
-
- override fun execute() {
- try {
- files.forEach { file ->
- val sourceText = file.readText()
- val relativePath = file.toRelativeString(projectDirectory)
-
- logger.log(LogLevel.DEBUG, "$name checking format: $relativePath")
-
- val formattedText = Formatter.format(KtfmtPlugin.DEFAULT_FORMATTING_OPTIONS, sourceText)
-
- if (!formattedText.contentEquals(sourceText)) {
- logger.log(LogLevel.QUIET, "${file.toRelativeString(projectDirectory)}: Format fixed")
- file.writeText(formattedText)
- }
- }
- } catch (t: Throwable) {
- throw Exception("format worker execution error", t)
- }
- }
-}
diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtWorkerParameters.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtWorkerParameters.kt
deleted file mode 100644
index 1c550de8..00000000
--- a/build-logic/src/main/kotlin/app/passwordstore/gradle/ktfmt/KtfmtWorkerParameters.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package app.passwordstore.gradle.ktfmt
-
-import org.gradle.api.file.ConfigurableFileCollection
-import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.provider.Property
-import org.gradle.workers.WorkParameters
-
-interface KtfmtWorkerParameters : WorkParameters {
- val name: Property<String>
- val files: ConfigurableFileCollection
- val projectDirectory: RegularFileProperty
-}
diff --git a/build.gradle.kts b/build.gradle.kts
index aac6cf2b..8e6bedb4 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -5,6 +5,6 @@
plugins {
id("com.github.android-password-store.git-hooks")
id("com.github.android-password-store.kotlin-common")
- id("com.github.android-password-store.ktfmt")
+ id("com.github.android-password-store.spotless")
id("com.github.android-password-store.versions")
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 947c2983..45f63a68 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -39,7 +39,6 @@ build-diffutils = "io.github.java-diff-utils:java-diff-utils:4.12"
build-download = "de.undercouch:gradle-download-task:5.6.0"
build-javapoet = "com.squareup:javapoet:1.13.0"
build-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
-build-ktfmt = "com.facebook:ktfmt:0.51"
build-mavenpublish = "com.vanniktech:gradle-maven-publish-plugin:0.29.0"
build-metalava = "me.tylerbwong.gradle.metalava:plugin:0.3.5"
build-moshi = { module = "com.squareup.moshi:moshi", version.ref = "moshi" }
@@ -48,6 +47,7 @@ build-okhttp = "com.squareup.okhttp3:okhttp:5.0.0-alpha.14"
build-r8 = "com.android.tools:r8:8.4.6-dev"
build-semver = "com.github.zafarkhaja:java-semver:0.10.2"
build-sentry = "io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin:4.11.0"
+build-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0"
build-vcu = "nl.littlerobots.version-catalog-update:nl.littlerobots.version-catalog-update.gradle.plugin:0.8.4"
compose-bom = "androidx.compose:compose-bom:2024.06.00"
compose-foundation-core = { module = "androidx.compose.foundation:foundation" }
diff --git a/scripts/pre-push-hook.sh b/scripts/pre-push-hook.sh
index 65ea0682..e228815c 100644
--- a/scripts/pre-push-hook.sh
+++ b/scripts/pre-push-hook.sh
@@ -13,6 +13,6 @@ while read -r local_ref local_oid remote_ref remote_oid; do
_=$remote_ref
_=$remote_oid
if [ "${local_oid}" != "${ZERO}" ]; then
- CI=true "${GRADLE_EXEC}" metalavaCheckCompatibilityRelease lint ktfmtCheck test -PslimTests
+ CI=true "${GRADLE_EXEC}" metalavaCheckCompatibilityRelease lint spotlessCheck test -PslimTests
fi
done