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

Feature/marp 975 display compatibility range in marketplace items #260

Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ private void createDetailResource(ProductDetailModel model, Product product) {
model.setContactUs(product.getContactUs());
model.setCost(product.getCost());
model.setInstallationCount(product.getInstallationCount());
model.setCompatibilityRange(product.getCompatibilityRange());
model.setProductModuleContent(ImageUtils.mappingImageForProductModuleContent(product.getProductModuleContent()));
if (StringUtils.isNotBlank(product.getVendorImage())) {
Link vendorLink = linkTo(methodOn(ImageController.class).findImageById(product.getVendorImage())).withSelfRel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ public class CommonConstants {
public static final String ID_WITH_NUMBER_PATTERN = "%s-%s";
public static final String ERROR = "error";
public static final String MESSAGE = "message";
public static final String COMPATIBILITY_RANGE_FORMAT = "%s - %s";
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ public class Product implements Serializable {
private String bestMatchVersion;
@Transient
private boolean isMavenDropins;
@Transient
private String compatibilityRange;

@Override
public int hashCode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class ProductDetailModel extends ProductModel {
private int installationCount;
@Schema(description = "The api url to get metadata from product.json")
private String metaProductJsonUrl;
private String compatibilityRange;
private boolean isMavenDropins;

@Override
Expand Down
tvtphuc-axonivy marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.axonivy.market.service.impl;

import com.axonivy.market.bo.Artifact;
import com.axonivy.market.constants.CommonConstants;
import com.axonivy.market.constants.GitHubConstants;
import com.axonivy.market.constants.MavenConstants;
import com.axonivy.market.constants.MetaConstants;
Expand All @@ -23,13 +22,15 @@
import com.axonivy.market.github.service.GHAxonIvyProductRepoService;
import com.axonivy.market.github.service.GitHubService;
import com.axonivy.market.github.util.GitHubUtils;
import com.axonivy.market.model.VersionAndUrlModel;
import com.axonivy.market.repository.*;
import com.axonivy.market.service.ExternalDocumentService;
import com.axonivy.market.service.ImageService;
import com.axonivy.market.service.MetadataService;
import com.axonivy.market.service.ProductContentService;
import com.axonivy.market.service.ProductMarketplaceDataService;
import com.axonivy.market.service.ProductService;
import com.axonivy.market.service.VersionService;
import com.axonivy.market.util.MavenUtils;
import com.axonivy.market.util.MetadataReaderUtils;
import com.axonivy.market.util.VersionUtils;
Expand Down Expand Up @@ -60,7 +61,7 @@
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.axonivy.market.constants.CommonConstants.SLASH;
import static com.axonivy.market.constants.CommonConstants.*;
import static com.axonivy.market.constants.MavenConstants.*;
import static com.axonivy.market.constants.ProductJsonConstants.EN_LANGUAGE;
import static com.axonivy.market.constants.ProductJsonConstants.LOGO_FILE;
Expand Down Expand Up @@ -94,6 +95,7 @@ public class ProductServiceImpl implements ProductService {
private final ProductMarketplaceDataService productMarketplaceDataService;
private final ProductMarketplaceDataRepository productMarketplaceDataRepo;
private GHCommit lastGHCommit;
private final VersionService versionService;
private GitHubRepoMeta marketRepoMeta;
@Value("${market.github.market.branch}")
private String marketRepoBranch;
Expand All @@ -106,7 +108,7 @@ public ProductServiceImpl(ProductRepository productRepo, ProductModuleContentRep
MetadataSyncRepository metadataSyncRepo, MetadataRepository metadataRepo, ImageService imageService,
ProductContentService productContentService, MetadataService metadataService,
ProductMarketplaceDataService productMarketplaceDataService, ExternalDocumentService externalDocumentService,
ProductMarketplaceDataRepository productMarketplaceDataRepo) {
ProductMarketplaceDataRepository productMarketplaceDataRepo, VersionService versionService) {
this.productRepo = productRepo;
this.productModuleContentRepo = productModuleContentRepo;
this.axonIvyMarketRepoService = axonIvyMarketRepoService;
Expand All @@ -125,6 +127,7 @@ public ProductServiceImpl(ProductRepository productRepo, ProductModuleContentRep
this.productMarketplaceDataService = productMarketplaceDataService;
this.externalDocumentService = externalDocumentService;
this.productMarketplaceDataRepo = productMarketplaceDataRepo;
this.versionService = versionService;
}

@Override
Expand Down Expand Up @@ -191,7 +194,7 @@ private List<String> updateLatestChangeToProductsFromGithubRepo() {
Map<String, List<GitHubFile>> groupGitHubFiles = new HashMap<>();
for (var file : gitHubFileChanges) {
String filePath = file.getFileName();
var parentPath = filePath.substring(0, filePath.lastIndexOf(CommonConstants.SLASH) + 1);
var parentPath = filePath.substring(0, filePath.lastIndexOf(SLASH) + 1);
var files = groupGitHubFiles.getOrDefault(parentPath, new ArrayList<>());
files.add(file);
files.sort((file1, file2) -> GitHubUtils.sortMetaJsonFirst(file1.getFileName(), file2.getFileName()));
Expand Down Expand Up @@ -582,15 +585,15 @@ public String getCompatibilityFromOldestVersion(String oldestVersion) {
if (StringUtils.isBlank(oldestVersion)) {
return Strings.EMPTY;
}
if (!oldestVersion.contains(CommonConstants.DOT_SEPARATOR)) {
if (!oldestVersion.contains(DOT_SEPARATOR)) {
return oldestVersion + ".0+";
}
int firstDot = oldestVersion.indexOf(CommonConstants.DOT_SEPARATOR);
int secondDot = oldestVersion.indexOf(CommonConstants.DOT_SEPARATOR, firstDot + 1);
int firstDot = oldestVersion.indexOf(DOT_SEPARATOR);
int secondDot = oldestVersion.indexOf(DOT_SEPARATOR, firstDot + 1);
if (secondDot == -1) {
return oldestVersion.concat(CommonConstants.PLUS);
return oldestVersion.concat(PLUS);
}
return oldestVersion.substring(0, secondDot).concat(CommonConstants.PLUS);
return oldestVersion.substring(0, secondDot).concat(PLUS);
}

@Override
Expand All @@ -599,6 +602,10 @@ public Product fetchProductDetail(String id, Boolean isShowDevVersion) {
return Optional.ofNullable(product).map(productItem -> {
int installationCount = productMarketplaceDataService.updateProductInstallationCount(id);
productItem.setInstallationCount(installationCount);

String compatibilityRange = getCompatibilityRange(id);
productItem.setCompatibilityRange(compatibilityRange);

return productItem;
}).orElse(null);
}
Expand All @@ -614,6 +621,10 @@ public Product fetchBestMatchProductDetail(String id, String version) {
return Optional.ofNullable(product).map(productItem -> {
int installationCount = productMarketplaceDataService.updateProductInstallationCount(id);
productItem.setInstallationCount(installationCount);

String compatibilityRange = getCompatibilityRange(id);
productItem.setCompatibilityRange(compatibilityRange);

productItem.setBestMatchVersion(bestMatchVersion);
return productItem;
}).orElse(null);
Expand Down Expand Up @@ -749,4 +760,31 @@ public boolean syncFirstPublishedDateOfAllProducts() {
return false;
}
}

/**
* MARP-975: Retrieve the list containing all versions for the designer and
* split the versions to obtain the first prefix,then format them for compatibility range.
* ex: 11.0+ , 10.0 - 12.0+ , ...
*/
private String getCompatibilityRange(String productId) {
return Optional.of(versionService.getVersionsForDesigner(productId))
.filter(ObjectUtils::isNotEmpty)
.map(versions -> versions.stream().map(VersionAndUrlModel::getVersion).toList())
.map(versions -> {
if (versions.size() == 1) {
return splitVersion(versions.get(0)).concat(PLUS);
}
String maxVersion = splitVersion(versions.get(0)).concat(PLUS);
String minVersion = splitVersion(versions.get(versions.size() - 1));
return VersionUtils.getPrefixOfVersion(minVersion).equals(VersionUtils.getPrefixOfVersion(maxVersion)) ?
minVersion.concat(PLUS) : String.format(COMPATIBILITY_RANGE_FORMAT, minVersion, maxVersion);
}).orElse(null);
}

private String splitVersion(String version) {
int firstDot = version.indexOf(DOT_SEPARATOR);
int secondDot = version.indexOf(DOT_SEPARATOR, firstDot + 1);
return version.substring(0, secondDot);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.axonivy.market.constants.CommonConstants.DOT_SEPARATOR;
import static com.axonivy.market.constants.MavenConstants.*;
@Log4j2
@NoArgsConstructor(access = AccessLevel.PRIVATE)
Expand Down Expand Up @@ -145,4 +146,8 @@ public static List<String> getInstallableVersionsFromMetadataList(List<Metadata>
metadata -> metadata.getVersions().stream().sorted(new LatestVersionComparator()).collect(
Collectors.toList())).orElse(new ArrayList<>());
}

public static String getPrefixOfVersion(String version) {
return version.substring(0, version.indexOf(DOT_SEPARATOR));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.axonivy.market.enums.Language;
import com.axonivy.market.enums.SortOption;
import com.axonivy.market.model.MavenArtifactModel;
import com.axonivy.market.model.VersionAndUrlModel;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
Expand Down Expand Up @@ -265,4 +266,56 @@ protected static ProductJsonContent getMockProductJsonContentContainMavenDropins
protected ProductMarketplaceData getMockProductMarketplaceData() {
return ProductMarketplaceData.builder().id(MOCK_PRODUCT_ID).installationCount(3).build();
}

protected List<VersionAndUrlModel> mockVersionAndUrlModels() {
VersionAndUrlModel versionAndUrlModel = VersionAndUrlModel.builder()
.version("10.0.21")
.url("/api/product-details/portal/10.0.21/json")
.build();

VersionAndUrlModel versionAndUrlModel2 = VersionAndUrlModel.builder()
.version("10.0.22")
.url("/api/product-details/portal/10.0.22/json")
.build();

return List.of(versionAndUrlModel, versionAndUrlModel2);
}

protected List<VersionAndUrlModel> mockVersionModels() {
VersionAndUrlModel versionAndUrlModel = VersionAndUrlModel.builder()
.version("11.3.1")
.build();

VersionAndUrlModel versionAndUrlModel2 = VersionAndUrlModel.builder()
.version("10.0.22")
.build();

return List.of(versionAndUrlModel, versionAndUrlModel2);
}

protected List<VersionAndUrlModel> mockVersionModels2() {
VersionAndUrlModel versionAndUrlModel = VersionAndUrlModel.builder()
.version("11.3.2")
.build();

List<VersionAndUrlModel> versionAndUrlModels = new ArrayList<>(mockVersionModels());
versionAndUrlModels.add(0,versionAndUrlModel);

return versionAndUrlModels;
}

protected List<VersionAndUrlModel> mockVersionModels3() {
VersionAndUrlModel versionAndUrlModel = VersionAndUrlModel.builder()
.version("11.3.2")
.build();

VersionAndUrlModel versionAndUrlModel2 = VersionAndUrlModel.builder()
.version("12.0.0")
.build();

List<VersionAndUrlModel> versionAndUrlModels = new ArrayList<>(mockVersionModels());
versionAndUrlModels.add(0,versionAndUrlModel);
versionAndUrlModels.add(0,versionAndUrlModel2);
return versionAndUrlModels;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.axonivy.market.enums.Language;
import com.axonivy.market.model.MavenArtifactVersionModel;
import com.axonivy.market.model.ProductDetailModel;
import com.axonivy.market.model.VersionAndUrlModel;
import com.axonivy.market.service.ProductService;
import com.axonivy.market.service.VersionService;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down Expand Up @@ -170,26 +169,14 @@ void findProductVersionsById() {

assertEquals(2, Objects.requireNonNull(result.getBody()).size());
assertEquals("10.0.21", Objects.requireNonNull(result.getBody()).get(0).getVersion());
assertEquals("/api/product-details/productjsoncontent/portal/10.0.21",
assertEquals("/api/product-details/portal/10.0.21/json",
Objects.requireNonNull(result.getBody()).get(0).getUrl());
assertEquals("10.0.22", Objects.requireNonNull(result.getBody()).get(1).getVersion());
assertEquals("/api/product-details/productjsoncontent/portal/10.0.22",
assertEquals("/api/product-details/portal/10.0.22/json",
Objects.requireNonNull(result.getBody()).get(1).getUrl());
}

private List<VersionAndUrlModel> mockVersionAndUrlModels() {
VersionAndUrlModel versionAndUrlModel = VersionAndUrlModel.builder()
.version("10.0.21")
.url("/api/product-details/productjsoncontent/portal/10.0.21")
.build();

VersionAndUrlModel versionAndUrlModel2 = VersionAndUrlModel.builder()
.version("10.0.22")
.url("/api/product-details/productjsoncontent/portal/10.0.22")
.build();

return List.of(versionAndUrlModel, versionAndUrlModel2);
}

@Test
void findProductJsonContentByIdAndVersion() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.axonivy.market.service.MetadataService;
import com.axonivy.market.service.ProductContentService;
import com.axonivy.market.service.ProductMarketplaceDataService;
import com.axonivy.market.service.VersionService;
import com.axonivy.market.util.MavenUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -129,6 +130,8 @@ class ProductServiceImplTest extends BaseSetup {
private ProductMarketplaceDataService productMarketplaceDataService;
@Mock
private ProductMarketplaceDataRepository productMarketplaceDataRepo;
@Mock
private VersionService versionService;
@InjectMocks
private ProductServiceImpl productService;

Expand Down Expand Up @@ -401,6 +404,32 @@ void testFetchProductDetail() {
assertNull(result);
}

@Test
void testGetCompatibilityRangeAfterFetchProductDetail() {
MavenArtifactVersion mockMavenArtifactVersion = getMockMavenArtifactVersionWithData();
when(mavenArtifactVersionRepo.findById(MOCK_PRODUCT_ID)).thenReturn(
Optional.ofNullable(mockMavenArtifactVersion));


when(productRepo.getProductByIdAndVersion(MOCK_PRODUCT_ID, MOCK_SNAPSHOT_VERSION))
.thenReturn(getMockProduct());
when(versionService.getVersionsForDesigner(MOCK_PRODUCT_ID))
.thenReturn(mockVersionAndUrlModels(), mockVersionModels(), mockVersionModels2(), mockVersionModels3());


Product result = productService.fetchProductDetail(MOCK_PRODUCT_ID, true);
assertEquals("10.0+", result.getCompatibilityRange());

result = productService.fetchProductDetail(MOCK_PRODUCT_ID, true);
assertEquals("10.0 - 11.3+", result.getCompatibilityRange());

result = productService.fetchProductDetail(MOCK_PRODUCT_ID, true);
assertEquals("10.0 - 11.3+", result.getCompatibilityRange());

result = productService.fetchProductDetail(MOCK_PRODUCT_ID, true);
assertEquals("10.0 - 12.0+", result.getCompatibilityRange());
}

@Test
void testGetProductByIdWithNewestReleaseVersion() {
MavenArtifactVersion mockMavenArtifactVersion = getMockMavenArtifactVersionWithData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,7 @@
alt="Logo Vendor" />
</a>
</div>
<hr class="border-top-0" />
<div class="d-flex flex-row justify-content-between p-0">
<span [lang]="languageService.selectedLanguage()" class="text-secondary">
{{ 'common.product.detail.information.value.version' | translate }}
</span>
<span class="text-primary">
{{ displayVersion }}
</span>
</div>
@if (productDetail.compatibility) {
@if (productDetail.compatibilityRange) {
<hr class="border-top-0" />
<div class="d-flex flex-row justify-content-between p-0">
<span
Expand All @@ -43,7 +34,7 @@
}}
</span>
<span class="text-primary">
{{ productDetail.compatibility }}
{{ productDetail.compatibilityRange }}
</span>
</div>
}
Expand Down Expand Up @@ -77,7 +68,7 @@
target="_blank">
{{
displayExternalDocName ??
'common.product.detail.information.value.defaultDocName'
'common.product.detail.information.value.defaultDocName'
| translate
}}
</a>
Expand All @@ -91,6 +82,15 @@
<span class="text-primary text-capitalize">{{ productDetail.type }}</span>
</div>
<hr class="border-top-0" />
<div class="d-flex flex-row justify-content-between p-0">
<span [lang]="languageService.selectedLanguage()" class="text-secondary">
{{ 'common.product.detail.information.value.version' | translate }}
</span>
<span class="text-primary">
{{ displayVersion }}
</span>
</div>
<hr class="border-top-0" />
<div class="d-flex flex-row justify-content-between p-0">
<span [lang]="languageService.selectedLanguage()" class="text-secondary">
{{ 'common.product.detail.information.value.tag' | translate }}
Expand Down
Loading
Loading