Skip to content

Commit 16b3263

Browse files
committed
Merge remote-tracking branch 'origin/master' into ECWID-150828
2 parents 13d6e1d + ced9558 commit 16b3263

15 files changed

Lines changed: 276 additions & 9 deletions

File tree

.github/workflows/pull-request.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ jobs:
2424
cache: 'gradle'
2525

2626
- name: Build, run tests and upload dev snapshot to Maven Central with Gradle
27-
run: ./gradlew devSnapshot printDevSnapshotReleaseNote
27+
run: |
28+
./gradlew devSnapshot printDevSnapshotReleaseNote printSanitizedVersion
29+
cat sanitized_version.md >> $GITHUB_STEP_SUMMARY
2830
env:
2931
STORE_ID: ${{ secrets.STORE_ID }}
3032
API_TOKEN: ${{ secrets.API_TOKEN }}
@@ -34,6 +36,7 @@ jobs:
3436
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
3537
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
3638
GITHUB_HEAD_REF: ${{ github.head_ref }}
39+
GITHUB_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
3740

3841
- name: Upload artifacts with checks results
3942
uses: actions/upload-artifact@v3

build.gradle.kts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ tasks.register(Tasks.PRINT_DEV_SNAPSHOT_RELEASE_NOTE_TASK_NAME) {
127127
dependsOn(tasks.getByName("devSnapshot"))
128128
}
129129

130+
tasks.register(Tasks.PRINT_SUMMARY_SANITIZED_TASK_NAME) {
131+
doLast {
132+
printSanitizedVersion(project.sanitizeVersion())
133+
}
134+
}
135+
130136
detekt {
131137
allRules = false
132138
basePath = "$projectDir"
@@ -210,15 +216,16 @@ nexusPublishing {
210216
// <major>.<minor>.<patch>-dev.#+<branchname>.<hash> (local branch)
211217
// <major>.<minor>.<patch>-dev.#+<hash> (github pull request)
212218
// to:
213-
// <major>.<minor>.<patch>-dev+<branchname>-SNAPSHOT
219+
// <major>.<minor>.<patch>-dev+<branchname>_<hash>-SNAPSHOT
214220
fun Project.sanitizeVersion(): String {
215221
val version = version.toString()
216222
return if (project.isSnapshotVersion()) {
217223
val githubHeadRef = settingsProvider.githubHeadRef
224+
val githubHeadSHA = settingsProvider.githubHeadSHA?.take(Consts.MAX_HEAD_SHA_LENGTH)
218225
if (githubHeadRef != null) {
219226
// github pull request
220227
version
221-
.replace(Regex("-dev\\.\\d+\\+[a-f0-9]+$"), "-dev+$githubHeadRef-SNAPSHOT")
228+
.replace(Regex("-dev\\.\\d+\\+[a-f0-9]+$"), "-dev+${githubHeadRef}_$githubHeadSHA-SNAPSHOT")
222229
} else {
223230
// local branch
224231
version
@@ -273,6 +280,16 @@ fun printDevSnapshotReleaseNote(groupId: String, artifactId: String, sanitizedVe
273280
println()
274281
}
275282

283+
fun printSanitizedVersion(sanitizedVersion: String) {
284+
val markdownMessage = """
285+
|## Sanitized Version
286+
|
287+
|**Version:** $sanitizedVersion
288+
|
289+
""".trimMargin()
290+
File("sanitized_version.md").writeText(markdownMessage)
291+
}
292+
276293
class SettingsProvider {
277294

278295
val gpgSigningKey: String?
@@ -290,6 +307,9 @@ class SettingsProvider {
290307
val githubHeadRef: String?
291308
get() = System.getenv(GITHUB_HEAD_REF_PROPERTY)
292309

310+
val githubHeadSHA: String?
311+
get() = System.getenv(GITHUB_HEAD_SHA_PROPERTY)
312+
293313
fun validateGPGSecrets() = require(
294314
value = !gpgSigningKey.isNullOrBlank() && !gpgSigningPassword.isNullOrBlank(),
295315
lazyMessage = {
@@ -310,6 +330,7 @@ class SettingsProvider {
310330
private const val OSSRH_USERNAME_PROPERTY = "OSSRH_USERNAME"
311331
private const val OSSRH_PASSWORD_PROPERTY = "OSSRH_PASSWORD"
312332
private const val GITHUB_HEAD_REF_PROPERTY = "GITHUB_HEAD_REF"
333+
private const val GITHUB_HEAD_SHA_PROPERTY = "GITHUB_HEAD_SHA"
313334
}
314335
}
315336

@@ -339,9 +360,11 @@ object PublicationSettings {
339360
object Consts {
340361
const val SLOW_TESTS_LOGGING_THRESHOLD_MS = 30_000L
341362
const val MAX_TEST_RETRIES_COUNT = 3
363+
const val MAX_HEAD_SHA_LENGTH = 8
342364
}
343365

344366
object Tasks {
345367
const val PRINT_FINAL_RELEASE_NOTE_TASK_NAME = "printFinalReleaseNote"
346368
const val PRINT_DEV_SNAPSHOT_RELEASE_NOTE_TASK_NAME = "printDevSnapshotReleaseNote"
369+
const val PRINT_SUMMARY_SANITIZED_TASK_NAME = "printDevSanitizedVersion"
347370
}

src/main/kotlin/com/ecwid/apiclient/v3/ApiClient.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ import com.ecwid.apiclient.v3.dto.customergroup.request.*
2626
import com.ecwid.apiclient.v3.dto.customergroup.result.*
2727
import com.ecwid.apiclient.v3.dto.instantsite.redirects.request.*
2828
import com.ecwid.apiclient.v3.dto.instantsite.redirects.result.*
29-
import com.ecwid.apiclient.v3.dto.order.request.*
30-
import com.ecwid.apiclient.v3.dto.order.result.*
3129
import com.ecwid.apiclient.v3.dto.productreview.request.*
3230
import com.ecwid.apiclient.v3.dto.productreview.result.*
3331
import com.ecwid.apiclient.v3.dto.producttype.request.*
@@ -55,6 +53,7 @@ import kotlin.reflect.KClass
5553
open class ApiClient private constructor(
5654
protected val apiClientHelper: ApiClientHelper,
5755
storeProfileApiClient: StoreProfileApiClient,
56+
brandsApiClient: BrandsApiClient,
5857
productsApiClient: ProductsApiClient,
5958
categoriesApiClient: CategoriesApiClient,
6059
ordersApiClient: OrdersApiClient,
@@ -76,6 +75,7 @@ open class ApiClient private constructor(
7675
storeExtrafieldsApiClient: StoreExtrafieldsApiClientImpl,
7776
) :
7877
StoreProfileApiClient by storeProfileApiClient,
78+
BrandsApiClient by brandsApiClient,
7979
ProductsApiClient by productsApiClient,
8080
CategoriesApiClient by categoriesApiClient,
8181
OrdersApiClient by ordersApiClient,
@@ -99,6 +99,7 @@ open class ApiClient private constructor(
9999
constructor(apiClientHelper: ApiClientHelper) : this(
100100
apiClientHelper = apiClientHelper,
101101
storeProfileApiClient = StoreProfileApiClientImpl(apiClientHelper),
102+
brandsApiClient = BrandsApiClientImpl(apiClientHelper),
102103
productsApiClient = ProductsApiClientImpl(apiClientHelper),
103104
categoriesApiClient = CategoriesApiClientImpl(apiClientHelper),
104105
ordersApiClient = OrdersApiClientImpl(apiClientHelper),
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.ecwid.apiclient.v3
2+
3+
import com.ecwid.apiclient.v3.dto.brand.request.BrandsSearchRequest
4+
import com.ecwid.apiclient.v3.dto.brand.result.BrandsSearchResult
5+
import com.ecwid.apiclient.v3.dto.common.PartialResult
6+
import kotlin.reflect.KClass
7+
8+
// Brands
9+
// https://api-docs.ecwid.com/reference/product-brands
10+
interface BrandsApiClient {
11+
fun searchBrands(request: BrandsSearchRequest): BrandsSearchResult
12+
fun <Result> searchBrands(request: BrandsSearchRequest, resultClass: KClass<Result>): Result
13+
where Result : PartialResult<BrandsSearchResult>
14+
}
15+
16+
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
17+
inline fun <reified Result : PartialResult<BrandsSearchResult>> BrandsApiClient.searchBrands(
18+
request: BrandsSearchRequest
19+
): Result {
20+
return searchBrands(request, resultClass = Result::class)
21+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.ecwid.apiclient.v3.dto.brand.request
2+
3+
import com.ecwid.apiclient.v3.dto.ApiRequest
4+
import com.ecwid.apiclient.v3.dto.common.PagingRequest
5+
import com.ecwid.apiclient.v3.impl.RequestInfo
6+
import com.ecwid.apiclient.v3.responsefields.ResponseFields
7+
8+
sealed class BrandsSearchRequest : ApiRequest {
9+
10+
data class ByFilters(
11+
val limit: Int = 100,
12+
override val offset: Int = 0,
13+
val lang: String? = null,
14+
val hiddenBrands: Boolean? = null,
15+
val baseUrl: String? = null,
16+
val cleanUrls: Boolean? = null,
17+
val sortBy: SortOrder? = null,
18+
val responseFields: ResponseFields = ResponseFields.All,
19+
) : BrandsSearchRequest(), PagingRequest<ByFilters> {
20+
override fun toRequestInfo() = RequestInfo.createGetRequest(
21+
pathSegments = listOf(
22+
"brands",
23+
),
24+
params = toParams(),
25+
responseFields = responseFields,
26+
)
27+
28+
private fun toParams(): Map<String, String> {
29+
val request = this
30+
return mutableMapOf<String, String>().apply {
31+
put("limit", request.limit.toString())
32+
put("offset", request.offset.toString())
33+
request.lang?.let { put("lang", it) }
34+
request.hiddenBrands?.let { put("hiddenBrands", it.toString()) }
35+
request.baseUrl?.let { put("baseUrl", it) }
36+
request.cleanUrls?.let { put("cleanUrls", it.toString()) }
37+
request.sortBy?.let { put("sortBy", it.name) }
38+
}.toMap()
39+
}
40+
41+
override fun copyWithOffset(offset: Int) = copy(offset = offset)
42+
}
43+
44+
@Suppress("unused")
45+
enum class SortOrder {
46+
PRODUCT_COUNT_DESC,
47+
NAME_ASC,
48+
}
49+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.ecwid.apiclient.v3.dto.brand.result
2+
3+
import com.ecwid.apiclient.v3.dto.common.ApiResultDTO
4+
5+
data class BrandsSearchResult(
6+
val items: List<FetchedBrand> = listOf(),
7+
val count: Int = 0,
8+
val total: Int = 0,
9+
val limit: Int = 0,
10+
val offset: Int = 0
11+
) : ApiResultDTO
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.ecwid.apiclient.v3.dto.brand.result
2+
3+
import com.ecwid.apiclient.v3.dto.common.ApiFetchedDTO
4+
import com.ecwid.apiclient.v3.dto.common.ApiResultDTO
5+
6+
data class FetchedBrand(
7+
val name: String = "",
8+
val nameTranslated: Map<String, String>? = null,
9+
val productsFilteredByBrandUrl: String? = null,
10+
) : ApiFetchedDTO, ApiResultDTO {
11+
override fun getModifyKind() = ApiFetchedDTO.ModifyKind.ReadOnly
12+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.ecwid.apiclient.v3.impl
2+
3+
import com.ecwid.apiclient.v3.ApiClientHelper
4+
import com.ecwid.apiclient.v3.BrandsApiClient
5+
import com.ecwid.apiclient.v3.dto.brand.request.BrandsSearchRequest
6+
import com.ecwid.apiclient.v3.dto.brand.result.BrandsSearchResult
7+
import com.ecwid.apiclient.v3.dto.common.PartialResult
8+
import kotlin.reflect.KClass
9+
10+
internal class BrandsApiClientImpl(
11+
private val apiClientHelper: ApiClientHelper,
12+
) : BrandsApiClient {
13+
14+
override fun searchBrands(request: BrandsSearchRequest) =
15+
apiClientHelper.makeObjectResultRequest<BrandsSearchResult>(request)
16+
17+
override fun <Result : PartialResult<BrandsSearchResult>> searchBrands(
18+
request: BrandsSearchRequest,
19+
resultClass: KClass<Result>
20+
): Result {
21+
return apiClientHelper.makeObjectPartialResultRequest(
22+
request = request,
23+
resultClass = resultClass,
24+
)
25+
}
26+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package com.ecwid.apiclient.v3.entity
2+
3+
import com.ecwid.apiclient.v3.dto.brand.request.BrandsSearchRequest
4+
import com.ecwid.apiclient.v3.dto.product.request.ProductCreateRequest
5+
import com.ecwid.apiclient.v3.dto.product.request.ProductsSearchRequest.ByFilters
6+
import com.ecwid.apiclient.v3.dto.product.request.UpdatedProduct
7+
import com.ecwid.apiclient.v3.dto.product.request.UpdatedProduct.*
8+
import com.ecwid.apiclient.v3.util.randomAlphanumeric
9+
import com.ecwid.apiclient.v3.util.randomPrice
10+
import org.junit.jupiter.api.Assertions.assertTrue
11+
import org.junit.jupiter.api.BeforeEach
12+
import kotlin.test.Test
13+
import kotlin.test.assertEquals
14+
15+
class BrandsTest : BaseEntityTest() {
16+
17+
@BeforeEach
18+
override fun beforeEach() {
19+
super.beforeEach()
20+
21+
initStoreProfile()
22+
removeAllProducts()
23+
}
24+
25+
@Test
26+
fun getBrands() {
27+
val brandedProductsCreateResult = createProductsWithBrands()
28+
29+
// Waiting till product became available for searching
30+
brandedProductsCreateResult.skus.forEach { sku ->
31+
waitForIndexedProducts(
32+
productsSearchRequest = ByFilters(sku = sku),
33+
desiredProductCount = 1
34+
)
35+
}
36+
37+
val result = apiClient.searchBrands(BrandsSearchRequest.ByFilters())
38+
assertEquals(
39+
brandedProductsCreateResult.brandNames,
40+
result.items.map { it.name }
41+
)
42+
}
43+
44+
private fun createProductsWithBrands(productsCount: Int = 5): BrandedProductsCreateResult {
45+
val brands = mutableListOf<String>()
46+
val skus = mutableListOf<String>()
47+
48+
for (i in 1..productsCount) {
49+
val randomBrand = randomAlphanumeric(8)
50+
val randomSku = randomAlphanumeric(10)
51+
val price = randomPrice()
52+
53+
val productCreateRequest = ProductCreateRequest(
54+
newProduct = UpdatedProduct(
55+
name = "Product $i ${randomAlphanumeric(8)}",
56+
sku = randomSku,
57+
price = price,
58+
compareToPrice = 2 * price,
59+
enabled = true,
60+
quantity = 10,
61+
attributes = listOf(
62+
AttributeValue.createBrandAttributeValue(randomBrand),
63+
),
64+
options = listOf(
65+
ProductOption.createSelectOption(
66+
name = "Color",
67+
choices = listOf(
68+
ProductOptionChoice("Black"),
69+
ProductOptionChoice("White"),
70+
ProductOptionChoice("Yellow"),
71+
ProductOptionChoice("Red")
72+
),
73+
defaultChoice = 0,
74+
required = true
75+
)
76+
)
77+
)
78+
)
79+
val productCreateResult = apiClient.createProduct(productCreateRequest)
80+
assertTrue(productCreateResult.id > 0)
81+
82+
skus.add(randomSku)
83+
brands.add(randomBrand)
84+
}
85+
86+
return BrandedProductsCreateResult(
87+
brandNames = brands,
88+
skus = skus,
89+
)
90+
}
91+
92+
data class BrandedProductsCreateResult(
93+
val brandNames: List<String>,
94+
val skus: List<String>,
95+
)
96+
}

src/test/kotlin/com/ecwid/apiclient/v3/entity/CategoriesTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ class CategoriesTest : BaseEntityTest() {
179179
// Searching categories with different combinations of baseUrl and cleanUrls parameters
180180
assertCategoryUrlMatchesRegex(
181181
categorySearchRequest = CategoriesSearchRequest(),
182-
urlPattern = "https://.*.company.site.*/products#!/Category-.*c.*"
182+
urlPattern = "https://.*.company.site.*/products/Category-.*c.*"
183183
)
184184
assertCategoryUrlMatchesRegex(
185185
categorySearchRequest = CategoriesSearchRequest(

0 commit comments

Comments
 (0)