Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotations @FunctionalCore and @NeedsRefactoring #644

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,26 @@ fun addMissingEntriesInVersionsProperties(project: Project) {

val versionsMap = RefreshVersionsConfigHolder.readVersionsMap()
val versionKeyReader = RefreshVersionsConfigHolder.versionKeyReader

val newEntries: Map<String, ExternalDependency> = findMissingEntries(
configurations = configurationsWithHardcodedDependencies,
versionsMap = versionsMap,
versionKeyReader = versionKeyReader
) + UsedPluginsTracker.usedPluginsWithoutEntryInVersionsFile
.associateBy { d -> pluginDependencyNotationToVersionKey(d.name) }
.filterKeys { key -> key != null && key !in versionsMap }
.mapKeys { (k, _) -> k!! }
) + externalDependencyMap(UsedPluginsTracker.usedPluginsWithoutEntryInVersionsFile, versionsMap)


VersionsPropertiesModel.writeWithNewEntries(newEntries)
OutputFile.VERSIONS_PROPERTIES.logFileWasModified()
}

@InternalRefreshVersionsApi
@FunctionalCore(testName = "TODO")
private fun externalDependencyMap(usedPluginsWithoutEntryInVersionsFile: List<ExternalDependency>, versionsMap: Map<String, String>) =
usedPluginsWithoutEntryInVersionsFile
.associateBy { d -> pluginDependencyNotationToVersionKey(d.name) }
.filterKeys { key -> key != null && key !in versionsMap }
.mapKeys { (k, _) -> k!! }


@InternalRefreshVersionsApi
fun Configuration.countDependenciesWithHardcodedVersions(
Expand Down Expand Up @@ -77,6 +83,7 @@ fun Configuration.shouldBeIgnored(): Boolean {
// implementation, api, compileOnly, runtimeOnly, kapt, plus test, MPP and MPP test variants.
}

@FunctionalCore(testName = "TODO")
internal fun findMissingEntries(
configurations: List<Configuration>,
versionsMap: Map<String, String>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.fayard.refreshVersions.core.internal

import de.fayard.refreshVersions.core.ModuleId
import java.io.File

@InternalRefreshVersionsApi
abstract class ArtifactVersionKeyReader private constructor(
Expand All @@ -11,6 +12,7 @@ abstract class ArtifactVersionKeyReader private constructor(

companion object {

@FunctionalCore(testName = "TODO")
fun fromRules(
filesContent: List<String>,
getRemovedDependenciesVersionsKeys: () -> Map<ModuleId.Maven, String> = { emptyMap() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import de.fayard.refreshVersions.core.ModuleId
import org.gradle.api.artifacts.Dependency
import org.gradle.api.internal.artifacts.dependencies.AbstractDependency

@NeedsRefactoring("Simpler name and use it everywhere")
internal class ConfigurationLessDependency(
private val group: String,
private val name: String,
Expand All @@ -20,6 +21,7 @@ internal class ConfigurationLessDependency(
)

companion object {
@FunctionalCore(testName = "TODO")
operator fun invoke(dependencyNotation: String): ConfigurationLessDependency {
val beforeFirstColon = dependencyNotation.substringBefore(':')
val afterFirstColon = dependencyNotation.substringAfter(':')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ val MEANING_LESS_NAMES: MutableList<String> = mutableListOf(
)

@InternalRefreshVersionsApi
@NeedsRefactoring("Use Dependency instead of Library")
@FunctionalCore(testName = "TODO")
fun List<Library>.computeAliases(
configured: List<String>,
byDefault: List<String> = MEANING_LESS_NAMES
Expand Down Expand Up @@ -71,6 +73,7 @@ fun Project.findDependencies(): List<Library> {


@InternalRefreshVersionsApi
@NeedsRefactoring("Use Dependency instead")
data class Library(
val group: String = "",
val module: String = "",
Expand Down Expand Up @@ -102,6 +105,7 @@ data class Library(
}

@InternalRefreshVersionsApi
@NeedsRefactoring("Use Dependency instead")
class Deps(
val libraries: List<Library>,
val names: Map<Library, String>
Expand All @@ -114,6 +118,8 @@ enum class VersionMode {
}

@InternalRefreshVersionsApi
@NeedsRefactoring("Use Dependency instead of Library and Deps")
@FunctionalCore(testName = "TODO")
fun List<Library>.checkModeAndNames(useFdqnByDefault: List<String>, case: Case): Deps {
val dependencies = this

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package de.fayard.refreshVersions.core.internal

/**
* FunctionalCore/ImperativeShell is a simple but powerful testing strategy
* where you express your business logic as pure functions
* and you use the tested functions in a simple imperative shell that actually do things.
*
* In practical terms, a function annotated by @FunctionalCore must be tested
*
* See https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell
*/
@InternalRefreshVersionsApi
annotation class FunctionalCore(
val testName: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package de.fayard.refreshVersions.core.internal

/**
* For refactorings we don't want to do right now but want to keep track of
*/
@InternalRefreshVersionsApi
annotation class NeedsRefactoring(
val issueAndMessage: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import de.fayard.refreshVersions.core.internal.VersionsCatalogs.LIBS_VERSIONS_TO
import java.io.File

@InternalRefreshVersionsApi
@NeedsRefactoring("Design a better API")
enum class OutputFile(
val path: String,
var existed: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package de.fayard.refreshVersions.core.internal
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

@FunctionalCore(testName = "TODO")
internal class ResettableDelegates {

fun reset() {
Expand All @@ -26,7 +27,7 @@ internal class ResettableDelegates {

override fun getValue(thisRef: Any?, property: KProperty<*>): T = field ?: error(
"Property ${property.name} not initialized yet! " +
"Has it been used after reset or before init?"
"Has it been used after reset or before init?"
)

operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.fayard.refreshVersions.core.internal

@FunctionalCore(testName = "VersionsCatalogUpdaterTest")
internal data class Toml(
val sections: MutableMap<TomlSection, List<TomlLine>>
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.gradle.api.artifacts.Dependency
* Despite TOML supporting braces in its syntax, they must open and close on
* the same line, so having a per-line model is fine.
*/
@FunctionalCore(testName = "TomlLineTest")
internal data class TomlLine(
val section: TomlSection,
val text: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ internal sealed class VersionManagementKind {
object NoMatch : VersionManagementKind()
}

@FunctionalCore(testName = "TODO")
internal fun Dependency.versionManagementKind(
versionMap: Map<String, String>,
versionKeyReader: ArtifactVersionKeyReader,
Expand All @@ -55,6 +56,7 @@ internal fun Dependency.versionManagementKind(
this is ExternalDependency && versionPlaceholder in this.versionConstraint.rejectedVersions -> {
Match.VersionsFile.VersionPlaceholder
}

name.endsWith(".gradle.plugin") -> {
when (val moduleId = moduleId()) {
is ModuleId.Maven -> {
Expand All @@ -68,23 +70,29 @@ internal fun Dependency.versionManagementKind(
versionsCatalogLibraries = versionsCatalogLibraries,
versionsCatalogPlugins = versionsCatalogPlugins
) -> Match.VersionsCatalog.MatchingVersionConstraint

else -> NoMatch
}

version -> Match.VersionsFile.MatchingPluginVersion
else -> NoMatch
}
}

else -> NoMatch
}
}

else -> when {
hasVersionInVersionCatalog(
versionsCatalogLibraries = versionsCatalogLibraries
) -> Match.VersionsCatalog.MatchingVersionConstraint

else -> NoMatch
}
}

@FunctionalCore(testName = "TODO")
private fun Dependency.hasVersionInVersionCatalog(
versionsCatalogLibraries: Collection<MinimalExternalModuleDependency>,
versionsCatalogPlugins: Set<PluginDependencyCompat> = emptySet()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ object VersionsCatalogs {

fun isSupported(): Boolean = GradleVersion.current() >= minimumGradleVersion

@FunctionalCore(testName = "TODO")
fun defaultCatalogName(): String = try {
@Suppress("UnstableApiUsage")
RefreshVersionsConfigHolder.settings.dependencyResolutionManagement.defaultLibrariesExtensionName.get()
Expand All @@ -27,11 +28,13 @@ object VersionsCatalogs {
"libs"
}

@FunctionalCore(testName = "TODO")
fun getDefault(project: Project): VersionCatalog? {
val versionCatalogs = project.extensions.findByType<VersionCatalogsExtension>()
return versionCatalogs?.find(defaultCatalogName())?.orElse(null)
}

@FunctionalCore(testName = "TODO")
internal fun libraries(versionCatalog: VersionCatalog?): Set<MinimalExternalModuleDependency> {
if (versionCatalog == null) return emptySet()
val aliases = versionCatalog.libraryAliases
Expand All @@ -40,6 +43,7 @@ object VersionsCatalogs {
}
}

@FunctionalCore(testName = "TODO")
internal fun plugins(versionCatalog: VersionCatalog?): Set<PluginDependencyCompat> {
if (versionCatalog == null) return emptySet()
val aliases = versionCatalog.pluginAliases
Expand All @@ -48,6 +52,7 @@ object VersionsCatalogs {
}
}

@FunctionalCore(testName = "TODO")
fun dependencyAliases(versionCatalog: VersionCatalog?): Map<ModuleId.Maven, String> = when {
FeatureFlag.VERSIONS_CATALOG.isNotEnabled -> emptyMap()
versionCatalog == null -> emptyMap()
Expand All @@ -64,6 +69,7 @@ object VersionsCatalogs {
}.toMap()
}

@FunctionalCore("VersionsCatalogUpdaterTest")
internal fun parseToml(toml: String): Toml {
val map = parseTomlInSections(toml)
.map { (sectionName, paragraph) ->
Expand All @@ -76,6 +82,7 @@ object VersionsCatalogs {
/**
* Returns a map where the key is the section name, and the value, the section content.
*/
@FunctionalCore("TomlSectionTest")
internal fun parseTomlInSections(toml: String): Map<String, String> {
val result = mutableMapOf<String, StringBuilder>()
result["root"] = StringBuilder()
Expand All @@ -96,6 +103,7 @@ object VersionsCatalogs {
return result.mapValues { it.value.toString() }
}

@FunctionalCore("VersionsCatalogUpdaterTest")
fun generateVersionsCatalogText(
versionsMap: Map<String, String> = RefreshVersionsConfigHolder.readVersionsMap(),
versionKeyReader: ArtifactVersionKeyReader = RefreshVersionsConfigHolder.versionKeyReader,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package de.fayard.refreshVersions.core.internal.codeparsing

import de.fayard.refreshVersions.core.internal.FunctionalCore
import de.fayard.refreshVersions.core.internal.NeedsRefactoring
import de.fayard.refreshVersions.core.internal.codeparsing.SourceCodeSection.*

@NeedsRefactoring("parameterName and expressionWithCommentsIfAny properties are never used")
internal class FunctionArgument(
val parameterName: String?,
val expressionWithCommentsIfAny: String
Expand All @@ -13,6 +16,7 @@ internal class FunctionArgument(
* or if the passed [functionCallText] lacks the parentheses,
* it might fail in unexpected ways.
*/
@FunctionalCore(testName = "TODO")
internal fun extractArgumentsOfFunctionCall(
programmingLanguage: ProgrammingLanguage,
functionCallText: CharSequence
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package de.fayard.refreshVersions.core.internal.codeparsing

import de.fayard.refreshVersions.core.internal.FunctionalCore
import de.fayard.refreshVersions.core.internal.NeedsRefactoring
import de.fayard.refreshVersions.core.internal.TaggedRange

@FunctionalCore(testName = "TODO")
internal fun CharSequence.rangesOfCode(
code: String,
startIndex: Int = 0,
Expand Down Expand Up @@ -33,6 +36,7 @@ internal fun CharSequence.rangesOfCode(
return list
}

@FunctionalCore(testName = "TODO")
internal fun CharSequence.rangeOfCode(
code: String,
startIndex: Int = 0,
Expand All @@ -46,6 +50,8 @@ internal fun CharSequence.rangeOfCode(
sectionsRanges = sectionsRanges
)

@FunctionalCore(testName = "TODO")
@NeedsRefactoring("Dead code")
internal fun CharSequence.rangeOfStringLiteral(
stringLiteral: String,
startIndex: Int = 0,
Expand All @@ -59,6 +65,7 @@ internal fun CharSequence.rangeOfStringLiteral(
sectionsRanges = sectionsRanges
)

@FunctionalCore(testName = "TODO")
internal fun CharSequence.rangeOf(
text: String,
sectionKind: SourceCodeSection,
Expand All @@ -83,6 +90,7 @@ internal fun CharSequence.rangeOf(
/**
* Returns -1 if there's no import statement
*/
@FunctionalCore(testName = "TODO")
internal fun CharSequence.findFirstImportStatement(
sectionsRanges: List<TaggedRange<SourceCodeSection>>
): Int {
Expand All @@ -103,6 +111,7 @@ internal fun CharSequence.findFirstImportStatement(
/**
* Returns lastIndex + 1 (i.e. [CharSequence.length]) if no non-blank code chunk is found.
*/
@FunctionalCore(testName = "TODO")
internal fun CharSequence.indexOfFirstNonBlankCodeChunk(
sectionsRanges: List<TaggedRange<SourceCodeSection>>
): Int {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.fayard.refreshVersions.core.internal.codeparsing

import de.fayard.refreshVersions.core.extensions.text.forEachIndexedSkippable
import de.fayard.refreshVersions.core.internal.FunctionalCore
import de.fayard.refreshVersions.core.internal.TaggedRange

/**
Expand All @@ -9,6 +10,7 @@ string literals, and the rest, separately.

The returned list covers the entire passed CharSequence.
*/
@FunctionalCore(testName = "TODO")
internal fun CharSequence.findRanges(
programmingLanguage: ProgrammingLanguage
): List<TaggedRange<SourceCodeSection>> = mutableListOf<TaggedRange<SourceCodeSection>>().also {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package de.fayard.refreshVersions.core.internal.codeparsing.gradle

import de.fayard.refreshVersions.core.internal.FunctionalCore
import de.fayard.refreshVersions.core.internal.TaggedRange
import de.fayard.refreshVersions.core.internal.codeparsing.ProgrammingLanguage
import de.fayard.refreshVersions.core.internal.codeparsing.SourceCodeSection
import de.fayard.refreshVersions.core.internal.codeparsing.findRanges

@FunctionalCore(testName = "SettingsPluginUpdaterTest")
internal fun CharSequence.extractGradleScriptSections(
isKotlinDsl: Boolean
): List<TaggedRange<SourceCodeSection>> = findRanges(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package de.fayard.refreshVersions.core.internal.codeparsing.gradle

import de.fayard.refreshVersions.core.internal.FunctionalCore
import de.fayard.refreshVersions.core.internal.TaggedRange
import de.fayard.refreshVersions.core.internal.codeparsing.SourceCodeSection
import de.fayard.refreshVersions.core.internal.codeparsing.SymbolLocationFindingRule
import de.fayard.refreshVersions.core.internal.codeparsing.findSymbolsRanges

@FunctionalCore(testName = "TODO")
internal fun CharSequence.findPluginBlocksRanges(
ranges: List<TaggedRange<SourceCodeSection>>
): List<TaggedRange<*>> = findSymbolsRanges(
Expand Down
Loading