From 7006f587625962f46faa1e7f7232bcc601bcf7d4 Mon Sep 17 00:00:00 2001 From: Russell Banks <74878137+russellbanks@users.noreply.github.com> Date: Thu, 17 Aug 2023 16:22:20 +0100 Subject: [PATCH] Fix values being at root and local level Resolves #278 --- src/main/kotlin/data/InstallerManifestData.kt | 54 ++++++++-------- src/main/kotlin/data/shared/PackageName.kt | 10 ++- src/main/kotlin/github/GitHubImpl.kt | 1 - src/main/kotlin/utils/IterableExtensions.kt | 35 +++++----- .../extensions/IterableExtensionsTest.kt | 64 ++++++++++++------- 5 files changed, 92 insertions(+), 72 deletions(-) diff --git a/src/main/kotlin/data/InstallerManifestData.kt b/src/main/kotlin/data/InstallerManifestData.kt index b2cdbd88..6c84e7cc 100644 --- a/src/main/kotlin/data/InstallerManifestData.kt +++ b/src/main/kotlin/data/InstallerManifestData.kt @@ -10,11 +10,11 @@ import schemas.manifest.DefaultLocaleManifest import schemas.manifest.InstallerManifest import utils.ManifestUtils.updateVersionInString import utils.Zip -import utils.getDistinctOrNull +import utils.filterSingleDistinctOrElse +import utils.mapDistinctSingleOrNull import utils.msi.Msi import utils.msix.Msix import utils.msix.MsixBundle -import utils.takeIfNotDistinct object InstallerManifestData { suspend fun addInstaller( @@ -163,40 +163,40 @@ object InstallerManifestData { return InstallerManifest.getBase(previousInstallerManifest, packageIdentifier, packageVersion).copy( packageIdentifier = packageIdentifier, packageVersion = packageVersion, - installerLocale = installers.getDistinctOrNull(InstallerManifest.Installer::installerLocale) + installerLocale = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::installerLocale) ?.ifBlank { null } ?: previousInstallerManifest?.installerLocale, - platform = installers.getDistinctOrNull(InstallerManifest.Installer::platform) + platform = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::platform) ?: previousInstallerManifest?.platform, - minimumOSVersion = installers.getDistinctOrNull(InstallerManifest.Installer::minimumOSVersion) + minimumOSVersion = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::minimumOSVersion) ?.ifBlank { null }, - installerType = installers.getDistinctOrNull(InstallerManifest.Installer::installerType) + installerType = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::installerType) ?: previousInstallerManifest?.installerType, - nestedInstallerType = installers.getDistinctOrNull(InstallerManifest.Installer::nestedInstallerType) + nestedInstallerType = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::nestedInstallerType) ?: previousInstallerManifest?.nestedInstallerType, nestedInstallerFiles = ( - installers.getDistinctOrNull(InstallerManifest.Installer::nestedInstallerFiles) + installers.mapDistinctSingleOrNull(InstallerManifest.Installer::nestedInstallerFiles) ?: previousInstallerManifest?.nestedInstallerFiles )?.map { it.copy(relativeFilePath = it.relativeFilePath.updateVersionInString(allVersions, packageVersion)) }, - scope = installers.getDistinctOrNull(InstallerManifest.Installer::scope) + scope = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::scope) ?: previousInstallerManifest?.scope, - packageFamilyName = installers.getDistinctOrNull(InstallerManifest.Installer::packageFamilyName) + packageFamilyName = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::packageFamilyName) ?: previousInstallerManifest?.packageFamilyName, - productCode = installers.getDistinctOrNull(InstallerManifest.Installer::productCode), + productCode = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::productCode), installModes = installModes?.ifEmpty { null } ?: previousInstallerManifest?.installModes, - installerSwitches = installers.getDistinctOrNull(InstallerManifest.Installer::installerSwitches) + installerSwitches = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::installerSwitches) ?: previousInstallerManifest?.installerSwitches, installerSuccessCodes = installerSuccessCodes?.ifEmpty { null } ?: previousInstallerManifest?.installerSuccessCodes, - upgradeBehavior = installers.getDistinctOrNull(InstallerManifest.Installer::upgradeBehavior) + upgradeBehavior = installers.mapDistinctSingleOrNull(InstallerManifest.Installer::upgradeBehavior) ?: previousInstallerManifest?.upgradeBehavior, commands = commands?.ifEmpty { null } ?: previousInstallerManifest?.commands, protocols = protocols?.ifEmpty { null } ?: previousInstallerManifest?.protocols, fileExtensions = fileExtensions?.ifEmpty { null } ?: previousInstallerManifest?.fileExtensions, - releaseDate = installers.getDistinctOrNull { it.releaseDate }, + releaseDate = installers.mapDistinctSingleOrNull { it.releaseDate }, appsAndFeaturesEntries = when (installers.distinctBy { it.appsAndFeaturesEntries }.size) { 0 -> previousInstallerManifest?.appsAndFeaturesEntries 1 -> installers.first().appsAndFeaturesEntries @@ -212,22 +212,22 @@ object InstallerManifestData { List { return map { installer -> installer.copy( - installerLocale = installers.takeIfNotDistinct(installer.installerLocale) { it.installerLocale }, - platform = installers.takeIfNotDistinct(installer.platform) { it.platform }, - minimumOSVersion = installers.takeIfNotDistinct(installer.minimumOSVersion) { it.minimumOSVersion }, - installerType = installers.takeIfNotDistinct(installer.installerType) { it.installerType }, + installerLocale = installers.filterSingleDistinctOrElse(installer.installerLocale) { it.installerLocale }, + platform = installers.filterSingleDistinctOrElse(installer.platform) { it.platform }, + minimumOSVersion = installers.filterSingleDistinctOrElse(installer.minimumOSVersion) { it.minimumOSVersion }, + installerType = installers.filterSingleDistinctOrElse(installer.installerType) { it.installerType }, nestedInstallerType = installers - .takeIfNotDistinct(installer.nestedInstallerType) { it.nestedInstallerType }, + .filterSingleDistinctOrElse(installer.nestedInstallerType) { it.nestedInstallerType }, nestedInstallerFiles = installers - .takeIfNotDistinct(installer.nestedInstallerFiles) { it.nestedInstallerFiles }, - scope = installers.takeIfNotDistinct(installer.scope) { it.scope }, - packageFamilyName = installers.takeIfNotDistinct(installer.packageFamilyName) { it.packageFamilyName }, - productCode = installers.takeIfNotDistinct(installer.productCode) { it.productCode }, - releaseDate = installers.takeIfNotDistinct(installer.releaseDate) { it.releaseDate }, - upgradeBehavior = installers.takeIfNotDistinct(installer.upgradeBehavior) { it.upgradeBehavior }, - installerSwitches = installers.takeIfNotDistinct(installer.installerSwitches) { it.installerSwitches }, + .filterSingleDistinctOrElse(installer.nestedInstallerFiles) { it.nestedInstallerFiles }, + scope = installers.filterSingleDistinctOrElse(installer.scope) { it.scope }, + packageFamilyName = installers.filterSingleDistinctOrElse(installer.packageFamilyName) { it.packageFamilyName }, + productCode = installers.filterSingleDistinctOrElse(installer.productCode) { it.productCode }, + releaseDate = installers.filterSingleDistinctOrElse(installer.releaseDate) { it.releaseDate }, + upgradeBehavior = installers.filterSingleDistinctOrElse(installer.upgradeBehavior) { it.upgradeBehavior }, + installerSwitches = installers.filterSingleDistinctOrElse(installer.installerSwitches) { it.installerSwitches }, appsAndFeaturesEntries = installers - .takeIfNotDistinct(installer.appsAndFeaturesEntries) { it.appsAndFeaturesEntries } + .filterSingleDistinctOrElse(installer.appsAndFeaturesEntries) { it.appsAndFeaturesEntries } ) } } diff --git a/src/main/kotlin/data/shared/PackageName.kt b/src/main/kotlin/data/shared/PackageName.kt index 17fe5eb1..8d818122 100644 --- a/src/main/kotlin/data/shared/PackageName.kt +++ b/src/main/kotlin/data/shared/PackageName.kt @@ -15,9 +15,15 @@ class PackageName(private val msi: Msi?, private val defaultLocaleManifest: Defa ) override val extraText: String = buildString { - append("Example: Microsoft Teams") - msi?.productName?.let { appendLine("Detected from MSI: $it") } + msi?.productName?.let { + appendLine(EXAMPLE) + append("Detected from MSI: $it") + } ?: append(EXAMPLE) } override val default: String? get() = defaultLocaleManifest?.packageName + + companion object { + private const val EXAMPLE = "Example: Microsoft Teams" + } } diff --git a/src/main/kotlin/github/GitHubImpl.kt b/src/main/kotlin/github/GitHubImpl.kt index 51979f06..31801cbf 100644 --- a/src/main/kotlin/github/GitHubImpl.kt +++ b/src/main/kotlin/github/GitHubImpl.kt @@ -138,7 +138,6 @@ object GitHubImpl { info("Would you like to proceed?") if (!yesNoMenu(default = false).prompt()) throw ProgramResult(0) } - println() } fun createBranchFromUpstreamDefaultBranch( diff --git a/src/main/kotlin/utils/IterableExtensions.kt b/src/main/kotlin/utils/IterableExtensions.kt index 76ba5702..a9ca5699 100644 --- a/src/main/kotlin/utils/IterableExtensions.kt +++ b/src/main/kotlin/utils/IterableExtensions.kt @@ -1,30 +1,27 @@ package utils /** - * Returns the default value if the values returned by the [selector] function on each element - * in this iterable are all the same. Otherwise, returns `null`. + * Transforms each element of the iterable using the provided [selector] function, collects the transformed elements + * into a set, and then evaluates whether there is a single distinct element in the set. If there's only one distinct + * element, returns `null`; otherwise, returns the specified [default] value. * - * @param default the value to return if the elements are not distinct - * @param selector a function that maps elements to a value to be compared for distinctness - * @return the default value if the elements are not distinct, `null` otherwise + * @param default the default value to return if there is more than one distinct element. + * @param selector the function to transform elements. + * @return `null` if there is a single distinct element; otherwise, the [default] value. */ -inline fun Iterable.takeIfNotDistinct(default: R, selector: (T) -> R): R? { - return if (any()) { - if (distinctBy(selector).size == 1) null else default - } else { - null - } +inline fun Iterable.filterSingleDistinctOrElse(default: R, selector: (T) -> R): R? { + return if (mapTo(HashSet(), selector).size == 1) null else default } /** - * Returns a distinct value of type [R] obtained by applying the given [selector] function to each element of the - * iterable, or null if there are multiple distinct values or if there are no values after applying the [selector]. + * Maps each element of the iterable using the provided [selector] function, collects the transformed elements into a + * set, and then returns a single distinct element from the set, or null if the set is empty or contains more than one + * element. * - * @param selector a function that maps an element of the iterable to a value of type [R] or returns null if the - * element should be skipped. - * @return a distinct value of type [R] or null if there are multiple distinct values or if there are no values - * after applying the [selector]. + * @param selector the function to transform elements. + * @return a single distinct element from the transformed set, or null if the set is empty or contains more than one + * element. */ -inline fun Iterable.getDistinctOrNull(selector: (T) -> R?): R? { - return mapNotNull(selector).toSet().singleOrNull() +inline fun Iterable.mapDistinctSingleOrNull(selector: (T) -> R): R? { + return mapTo(HashSet(), selector).singleOrNull() } diff --git a/src/test/kotlin/extensions/IterableExtensionsTest.kt b/src/test/kotlin/extensions/IterableExtensionsTest.kt index 1ba41cad..3b08abdb 100644 --- a/src/test/kotlin/extensions/IterableExtensionsTest.kt +++ b/src/test/kotlin/extensions/IterableExtensionsTest.kt @@ -2,34 +2,52 @@ package extensions import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe -import io.ktor.http.URLBuilder import io.ktor.http.Url import schemas.manifest.InstallerManifest -import utils.takeIfNotDistinct +import utils.filterSingleDistinctOrElse +import utils.mapDistinctSingleOrNull class IterableExtensionsTest : FunSpec({ - context("takeIfNotDistinct") { - val baseInstaller = InstallerManifest.Installer( - architecture = InstallerManifest.Installer.Architecture.NEUTRAL, - installerUrl = Url(URLBuilder()), - installerSha256 = "" - ) - val userScopeInstaller = baseInstaller.copy(scope = InstallerManifest.Scope.User) - val machineScopeInstaller = baseInstaller.copy(scope = InstallerManifest.Scope.Machine) + val baseInstaller = InstallerManifest.Installer( + architecture = InstallerManifest.Installer.Architecture.NEUTRAL, + installerUrl = Url(""), + installerSha256 = "" + ) + val userScopeInstaller = baseInstaller.copy(scope = InstallerManifest.Scope.User) + val machineScopeInstaller = baseInstaller.copy(scope = InstallerManifest.Scope.Machine) - test("returns default value if iterable is not distinct") { - listOf( - userScopeInstaller, - machineScopeInstaller - ).takeIfNotDistinct(default = machineScopeInstaller.scope) { it.scope } shouldBe machineScopeInstaller.scope - } + test("filterSingleDistinctOrElse returns the default value if the iterable is not distinct by the mapper") { + listOf( + userScopeInstaller, + machineScopeInstaller + ).filterSingleDistinctOrElse( + default = machineScopeInstaller.scope, + selector = InstallerManifest.Installer::scope + ) shouldBe machineScopeInstaller.scope + } + + test("filterSingleDistinctOrElse returns null if the iterable is distinct by the mapper") { + listOf( + userScopeInstaller, + userScopeInstaller, + userScopeInstaller + ).filterSingleDistinctOrElse( + default = userScopeInstaller.scope, + selector = InstallerManifest.Installer::scope + ) shouldBe null + } + + test("mapDistinctSingleOrNull returns null if the iterable is not distinct by the mapper") { + listOf( + userScopeInstaller, + baseInstaller + ).mapDistinctSingleOrNull(InstallerManifest.Installer::scope) shouldBe null + } - test("returns null if iterable is distinct") { - listOf( - userScopeInstaller, - userScopeInstaller, - userScopeInstaller - ).takeIfNotDistinct(default = userScopeInstaller.scope) { it.scope } shouldBe null - } + test("mapDistinctSingleOrNull returns the value if the iterable is distinct by the mapper") { + listOf( + userScopeInstaller, + userScopeInstaller + ).mapDistinctSingleOrNull(InstallerManifest.Installer::scope) shouldBe userScopeInstaller.scope } })