Skip to content
Merged
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 @@ -11,13 +11,6 @@ import ca.cgagnier.wlednativeandroid.model.Version
import ca.cgagnier.wlednativeandroid.model.VersionWithAssets
import kotlinx.coroutines.flow.Flow

/**
* nightly tag is not supported at the moment. Exclude it from results.
* TODO: Add support for nightly tags. This will need special handling since the tag itself never
* changes. Probably need a new Branch option for it too.
*/
private const val IGNORED_TAG = "nightly"

@Dao
interface VersionDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
Expand All @@ -38,31 +31,6 @@ interface VersionDao {
@Query("SELECT * FROM version WHERE repositoryId = :repositoryId")
suspend fun getVersionsByRepository(repositoryId: Long): List<Version>

@Transaction
@Query(
"""
SELECT * FROM version
WHERE repositoryId = :repositoryId
AND isPrerelease = 0
AND tagName != '$IGNORED_TAG'
ORDER BY publishedDate DESC
LIMIT 1
""",
)
suspend fun getLatestStableVersionWithAssets(repositoryId: Long): VersionWithAssets?

@Transaction
@Query(
"""
SELECT * FROM version
WHERE repositoryId = :repositoryId
AND tagName != '$IGNORED_TAG'
ORDER BY publishedDate DESC
LIMIT 1
""",
)
suspend fun getLatestBetaVersionWithAssets(repositoryId: Long): VersionWithAssets?

@Transaction
@Query("SELECT * FROM version WHERE repositoryId = :repositoryId AND tagName = :tagName LIMIT 1")
suspend fun getVersionByTagName(repositoryId: Long, tagName: String): VersionWithAssets?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,16 @@ import ca.cgagnier.wlednativeandroid.model.Asset
import ca.cgagnier.wlednativeandroid.model.Repository
import ca.cgagnier.wlednativeandroid.model.Version
import ca.cgagnier.wlednativeandroid.model.VersionWithAssets
import com.vdurmont.semver4j.Semver
import javax.inject.Inject
Comment thread
Moustachauve marked this conversation as resolved.

/**
* nightly tag is not supported at the moment. Exclude it from results.
* TODO: Add support for nightly tags. This will need special handling since the tag itself never
* changes. Probably need a new Branch option for it too.
*/
private const val IGNORED_TAG = "nightly"

class VersionWithAssetsRepository @Inject constructor(
private val database: DevicesDatabase,
private val repositoryDao: RepositoryDao,
Expand Down Expand Up @@ -76,12 +84,41 @@ class VersionWithAssetsRepository @Inject constructor(
}
}

suspend fun getLatestStableVersionWithAssets(repositoryId: Long): VersionWithAssets? =
versionDao.getLatestStableVersionWithAssets(repositoryId)
suspend fun getLatestStableVersionWithAssets(repositoryId: Long): VersionWithAssets? {
val latestVersion = getLatestVersion(
versionDao.getVersionsByRepository(repositoryId).filter { !it.isPrerelease && it.tagName != IGNORED_TAG },
)
return latestVersion?.let { versionDao.getVersionByTagName(repositoryId, it.tagName) }
}

suspend fun getLatestBetaVersionWithAssets(repositoryId: Long): VersionWithAssets? =
versionDao.getLatestBetaVersionWithAssets(repositoryId)
suspend fun getLatestBetaVersionWithAssets(repositoryId: Long): VersionWithAssets? {
val latestVersion = getLatestVersion(
versionDao.getVersionsByRepository(repositoryId).filter { it.tagName != IGNORED_TAG },
)
return latestVersion?.let { versionDao.getVersionByTagName(repositoryId, it.tagName) }
}

suspend fun getVersionByTag(repositoryId: Long, tagName: String): VersionWithAssets? =
versionDao.getVersionByTagName(repositoryId, tagName)

companion object {
val semVerComparator =
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The semVerComparator is currently public. Since it is an implementation detail used for sorting versions within this repository and its associated tests, consider changing its visibility to internal to maintain a cleaner public API.

Suggested change
val semVerComparator =
internal val semVerComparator =

Comparator<Pair<Version, Semver?>> { v1, v2 ->
val semver1 = v1.second
val semver2 = v2.second

when {
semver1 != null && semver2 != null -> semver1.compareTo(semver2)
semver1 != null -> 1
semver2 != null -> -1
else -> v1.first.publishedDate.compareTo(v2.first.publishedDate)
}
}

fun getLatestVersion(versions: List<Version>): Version? = versions.map {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The getLatestVersion function is currently public. Consider making it internal to restrict its scope to the module, as it is primarily a helper for the repository's public methods and for unit testing.

Suggested change
fun getLatestVersion(versions: List<Version>): Version? = versions.map {
internal fun getLatestVersion(versions: List<Version>): Version? = versions.map {

it to runCatching {
Semver(it.tagName, Semver.SemverType.LOOSE)
}.getOrNull()
}.maxWithOrNull(semVerComparator)?.first
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package ca.cgagnier.wlednativeandroid.repository

import ca.cgagnier.wlednativeandroid.model.Version
import ca.cgagnier.wlednativeandroid.model.VersionWithAssets
Comment thread
Moustachauve marked this conversation as resolved.
import com.vdurmont.semver4j.Semver
import org.junit.Assert.assertEquals
import org.junit.Test

class VersionWithAssetsRepositoryTest {

@Test
fun semVerComparator_sortsCorrectly() {
val versions = listOf(
createVersion("0.14.0", "2023-01-01T00:00:00Z"),
createVersion("0.15.0", "2023-06-01T00:00:00Z"),
createVersion("0.15.5", "2023-07-01T00:00:00Z"),
createVersion("16.0.0", "2022-01-01T00:00:00Z"), // Older date, newer semver
createVersion("invalid-tag", "2024-01-01T00:00:00Z"), // Fallback to date
createVersion("invalid-old", "2023-12-01T00:00:00Z"), // Fallback to date
).shuffled()

val parsedVersions = versions.map {
it to runCatching {
Semver(it.tagName, Semver.SemverType.LOOSE)
}.getOrNull()
}
val sorted = parsedVersions.sortedWith(VersionWithAssetsRepository.semVerComparator).map { it.first }

// Invalid semver tags are sorted by date and placed before valid semver tags
assertEquals("invalid-old", sorted[0].tagName)
assertEquals("invalid-tag", sorted[1].tagName)
// Valid semver tags are sorted by semver
assertEquals("0.14.0", sorted[2].tagName)
assertEquals("0.15.0", sorted[3].tagName)
assertEquals("0.15.5", sorted[4].tagName)
assertEquals("16.0.0", sorted[5].tagName)

val latest = VersionWithAssetsRepository.getLatestVersion(versions)
assertEquals("16.0.0", latest?.tagName)
}

private fun createVersion(tagName: String, publishedDate: String): Version = Version(
id = 0,
repositoryId = 0,
tagName = tagName,
name = tagName,
description = "",
isPrerelease = false,
publishedDate = publishedDate,
htmlUrl = "",
)
}