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
@@ -0,0 +1,10 @@
/*
* Copyright (c) 2024-2025 Joachim Ansorg.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package dev.ja.marketplace.client

object PluginVendors {
val JetBrains = setOf("JetBrains s.r.o.", "JetBrains")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2024-2025 Joachim Ansorg.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package dev.ja.marketplace.client.model

import dev.ja.marketplace.client.JetBrainsProductId

object JetBrainsProductFamilies {
val IntelliJPlatform = setOf<JetBrainsProductId>(
"ANDROID_STUDIO",
"APPCODE",
"AQUA",
"CLION",
"CWMGUEST",
"DATASPELL",
"DBE",
"GOLAND",
"IDEA",
"IDEA_COMMUNITY",
"JBCLIENT",
"MPS",
"PHPSTORM",
"PYCHARM",
"PYCHARM_COMMUNITY",
"RUBYMINE",
"RUST",
"WEBSTORM",
"WRITERSIDE",
)

val IntelliJPlatformWithRider = IntelliJPlatform + "RIDER"

val Fleet = setOf<JetBrainsProductId>("FLEET")

val Resharper = setOf<JetBrainsProductId>("RESHARPER")
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package dev.ja.marketplace.client.model

import dev.ja.marketplace.client.*
import dev.ja.marketplace.services.BuildNumberRef
import io.ktor.http.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -34,17 +35,17 @@ data class PluginReleaseInfo(
val recalculateCompatibilityAllowed: Boolean? = null,
@SerialName("cdate")
@Serializable(CDateSerializer::class)
val createdTimestamp: Instant? = null,
val createdTimestamp: Instant,
@SerialName("file")
val fileUrlPath: String,
@SerialName("size")
val fileSizeBytes: Long,
@SerialName("notes")
val notes: String? = null,
@SerialName("since")
val since: String? = null,
val since: BuildNumberRef? = null,
@SerialName("until")
val until: String? = null,
val until: BuildNumberRef? = null,
@SerialName("sinceUntil")
val sinceUntil: String? = null,
@SerialName("channel")
Expand All @@ -61,6 +62,10 @@ data class PluginReleaseInfo(
@SerialName("releaseVersion")
val releaseVersion: String? = null,
) {
override fun toString(): String {
return "PluginReleaseInfo(id=$id, pluginId=$pluginId)"
}

val isPaidOrFreemiumUpdate: Boolean
get() {
return releaseVersion != null
Expand All @@ -80,6 +85,11 @@ data class PluginReleaseInfo(
}.build()
}

val channelNameOrStable: String
get() {
return channel.ifBlank { "stable" }
}

/**
* The base filename of the uploaded file.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 Joachim Ansorg.
* Copyright (c) 2024-2025 Joachim Ansorg.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

Expand All @@ -16,6 +16,9 @@ enum class ProductFamily(@Transient val jsonId: String) {
@SerialName("teamcity")
TeamCity("teamcity"),

@SerialName("teamcity_recipes")
TeamCityRecipes("teamcity"),

@SerialName("hub")
Hub("hub"),

Expand All @@ -33,4 +36,7 @@ enum class ProductFamily(@Transient val jsonId: String) {

@SerialName("edu")
Edu("edu"),

@SerialName("youtrack")
YouTrack("youtrack"),
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 Joachim Ansorg.
* Copyright (c) 2024-2025 Joachim Ansorg.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

Expand All @@ -8,7 +8,7 @@ package dev.ja.marketplace.services
import kotlinx.serialization.Serializable

@Serializable(BuildNumberSerializer::class)
data class BuildNumber(private val segments: IntArray) : Comparable<BuildNumber> {
data class BuildNumber(internal val segments: IntArray) : Comparable<BuildNumber> {
val baseVersion: Int
get() {
return segments[0]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2024-2025 Joachim Ansorg.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package dev.ja.marketplace.services

import kotlinx.serialization.Serializable

/**
* A reference to a product [BuildNumber], e.g. a 'since' or 'until' attribute value.
* This supports the wildcard qualifier
*/
@Serializable(BuildNumberRefSerializer::class)
data class BuildNumberRef(private val segments: IntArray, val hasWildcard: Boolean) : Comparable<BuildNumber> {
fun toBuilderNumberString(): String {
val base = segments.joinToString(".")
return when {
hasWildcard -> "$base.*"
else -> base
}
}

override fun compareTo(other: BuildNumber): Int {
val buildSegments = other.segments
segments.forEachIndexed { index, a ->
if (index >= buildSegments.size) {
return 1
}

val b = buildSegments[index]
if (a > b) {
return 1
}

if (a < b) {
return -1
}
}

if (hasWildcard) {
return 1
}

return 0
}

infix fun equalsBuild(other: BuildNumber): Boolean {
return compareTo(other) == 0
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as BuildNumberRef

return segments.contentEquals(other.segments) && hasWildcard == other.hasWildcard
}

override fun hashCode(): Int {
return segments.contentHashCode()
}

override fun toString(): String {
return toBuilderNumberString()
}

companion object {
fun of(value: String): BuildNumberRef {
val segments = value
.let {
// some older plugins use a value like "IC-193.0", we're parsing this to 193.*
when (val index = value.indexOf('-')) {
-1 -> it
else -> it.substring(index + 1)
}
}
.removeSuffix(".*")
.split('.')
.mapNotNull(String::toIntOrNull)

require(segments.isNotEmpty()) {
"Unable to parse build number $value"
}

return BuildNumberRef(segments.toIntArray(), value.endsWith(".*"))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2024-2025 Joachim Ansorg.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package dev.ja.marketplace.services

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

object BuildNumberRefSerializer : KSerializer<BuildNumberRef?> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("buildNumberRef", PrimitiveKind.STRING)

override fun deserialize(decoder: Decoder): BuildNumberRef? {
val value = decoder.decodeString()
if (value.isEmpty()) {
return null
}
return BuildNumberRef.of(value)
}

@OptIn(ExperimentalSerializationApi::class)
override fun serialize(encoder: Encoder, value: BuildNumberRef?) {
if (value == null) {
encoder.encodeNull()
} else {
encoder.encodeString(value.toBuilderNumberString())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2025 Joachim Ansorg.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package dev.ja.marketplace.services

import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test

class BuildNumberRefTest {
@Test
fun parse() {
assertEquals(BuildNumberRef(intArrayOf(1, 2, 3), false), BuildNumberRef.of("1.2.3"))
assertEquals(BuildNumberRef(intArrayOf(1, 2), true), BuildNumberRef.of("1.2.*"))
assertEquals(BuildNumberRef(intArrayOf(221, 123), false), BuildNumberRef.of("221.123"))
assertEquals(BuildNumberRef(intArrayOf(162, 1236), true), BuildNumberRef.of("162.1236.*"))

assertEquals(BuildNumberRef(intArrayOf(193, 0), false), BuildNumberRef.of("IC-193.0"))
}

@Test
fun compare() {
assertTrue(BuildNumberRef.of("242.0") <= BuildNumber.of("242.10241.18"))
assertTrue(BuildNumberRef.of("242.*") > BuildNumber.of("242.10241.18"))
assertTrue(BuildNumberRef.of("242.*") >= BuildNumber.of("242.10241.18"))
assertTrue(BuildNumberRef.of("243.0") > BuildNumber.of("242.10241.18"))
assertTrue(BuildNumberRef.of("243.0") >= BuildNumber.of("242.10241.18"))
assertTrue(BuildNumberRef.of("242.0") equalsBuild BuildNumber.of("242.0"))

assertFalse(BuildNumberRef.of("242.*") < BuildNumber.of("242.20224.300"))
assertTrue(BuildNumberRef.of("242.*") > BuildNumber.of("242.20224.300"))
}
}