diff --git a/.github/workflows/koupleless_runtime_release.yml b/.github/workflows/koupleless_runtime_release.yml index 2585b6b0f..dcb7029d0 100644 --- a/.github/workflows/koupleless_runtime_release.yml +++ b/.github/workflows/koupleless_runtime_release.yml @@ -132,23 +132,42 @@ jobs: run: | # 创建一个映射来存储模块名到 JDK 版本的映射 modules=(${{ join(fromJSON(steps.find-maven-modules.outputs.modules-list), ' ') }}) - modules_in_right_jdk="" + modules_in_right_jdk_array=() for module in "${modules[@]}"; do # 读取模块中的 pom.xml 来确定 JDK 版本 jdk_version=$(grep -m 1 '' $module/pom.xml | sed 's/<[^>]*>//g' | xargs) echo "${module} JDK version: ${jdk_version}" - # 如果是目标 jdk 版本,则执行 release 操作 - + + # 如果是目标 jdk 版本,则记录 if [[ "${jdk_version}" == "1.8" ]]; then - modules_in_right_jdk="${modules_in_right_jdk}${module}," + modules_in_right_jdk_array+=(${module}) + fi + done + + # 过滤出需要发布的 adapter,过滤条件:adapter 版本与 pom.xml 中的版本一致 + adapter_release_version=$(grep '' pom.xml | sed -e 's/.*\(.*\)<\/revision>.*/\1/' | tr -d ' ') + modules_in_release_version="" + for module in "${modules_in_right_jdk_array[@]}"; do + # 如果没有 adapter-mapping.yaml,则跳过( koupleless-adapter-configs 没有 adapter-mapping.yaml) + if [[ ! -f $module/conf/adapter-mapping.yaml ]]; then + continue + fi + + # 读取模块中的 adapter-mapping.yaml 来确定 adapter 版本 + adapter_version=$(grep 'version:' $module/conf/adapter-mapping.yaml | sed -e 's/.*version:\(.*\)/\1/' | tr -d ' ') + echo "${module} adapter version: ${adapter_version}" + + # 如果是目标 adapter 版本,则记录 + if [[ "${adapter_version}" == "${adapter_release_version}" ]]; then + modules_in_release_version="${modules_in_release_version}${module}," fi done - if [[ -n ${modules_in_right_jdk} ]]; then - modules_in_right_jdk="${modules_in_right_jdk:0:-1}" - echo "release for module ${modules_in_right_jdk}" - mvn --batch-mode deploy -Prelease -pl ${modules_in_right_jdk} -am -amd -B -U - echo "release completed for module ${modules_in_right_jdk}" + if [[ -n ${modules_in_release_version} ]]; then + modules_in_release_version="${modules_in_release_version:0:-1}" + echo "release for module ${modules_in_release_version}" + mvn --batch-mode deploy -Prelease -pl ${modules_in_release_version} -am -amd -B -U + echo "release completed for module ${modules_in_release_version}" fi working-directory: adapter/ env: diff --git a/.github/workflows/koupleless_runtime_release_2.1.x.yml b/.github/workflows/koupleless_runtime_release_2.1.x.yml index b9524f183..01d2da1c5 100644 --- a/.github/workflows/koupleless_runtime_release_2.1.x.yml +++ b/.github/workflows/koupleless_runtime_release_2.1.x.yml @@ -131,6 +131,7 @@ jobs: # 创建一个映射来存储模块名到 JDK 版本的映射 modules=(${{ join(fromJSON(steps.find-maven-modules.outputs.modules-list), ' ') }}) modules_in_right_jdk="" + modules_in_right_jdk_array=() for module in "${modules[@]}"; do # 读取模块中的 pom.xml 来确定 JDK 版本 jdk_version=$(grep -m 1 '' $module/pom.xml | sed 's/<[^>]*>//g' | xargs) @@ -139,15 +140,38 @@ jobs: if [[ "${jdk_version}" == "17" ]]; then modules_in_right_jdk="${modules_in_right_jdk}${module}," + modules_in_right_jdk_array+=(${module}) fi done - if [[ -n ${modules_in_right_jdk} ]]; then - modules_in_right_jdk="${modules_in_right_jdk:0:-1}" - echo "release for module ${modules_in_right_jdk}" - mvn --batch-mode deploy -Prelease -pl ${modules_in_right_jdk} -am -amd -B -U - echo "release completed for module ${modules_in_right_jdk}" + # 过滤出需要发布的 adapter,过滤条件:adapter 版本与 pom.xml 中的版本一致 + adapter_release_version=$(grep '' pom.xml | sed -e 's/.*\(.*\)<\/revision>.*/\1/' | tr -d ' ') + modules_in_release_version="" + for module in "${modules_in_right_jdk_array[@]}"; do + # 如果没有 adapter-mapping.yaml,则跳过(koupleless-adapter-configs 没有 adapter-mapping.yaml) + if [[ ! -f $module/conf/adapter-mapping.yaml ]]; then + continue + fi + + # 读取模块中的 adapter-mapping.yaml 来确定 adapter 版本 + adapter_version=$(grep 'version:' $module/conf/adapter-mapping.yaml | sed -e 's/.*version:\(.*\)/\1/' | tr -d ' ') + echo "${module} adapter version: ${adapter_version}" + + # 如果是目标 adapter 版本,则记录 + if [[ "${adapter_version}" == "${adapter_release_version}" ]]; then + modules_in_release_version="${modules_in_release_version}${module}," + fi + done + + if [[ -n ${modules_in_release_version} ]]; then + modules_in_release_version="${modules_in_release_version:0:-1}" + echo "release for module ${modules_in_release_version}" + mvn --batch-mode deploy -Prelease -pl ${modules_in_release_version} -am -amd -B -U + echo "release completed for module ${modules_in_release_version}" fi + + # 请在发布 koupleless-adapter-configs 之前,发布 jdk8 和 jdk17 所有的 koupleless-adapters + mvn --batch-mode deploy -Prelease -pl koupleless-adapter-configs -am -amd -B -U working-directory: adapter/ env: MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} diff --git a/.github/workflows/koupleless_runtime_snapshot.yml b/.github/workflows/koupleless_runtime_snapshot.yml index 6d7bbd2a6..22cd509cd 100644 --- a/.github/workflows/koupleless_runtime_snapshot.yml +++ b/.github/workflows/koupleless_runtime_snapshot.yml @@ -131,23 +131,42 @@ jobs: run: | # 创建一个映射来存储模块名到 JDK 版本的映射 modules=(${{ join(fromJSON(steps.find-maven-modules.outputs.modules-list), ' ') }}) - modules_in_right_jdk="" + modules_in_right_jdk_array=() for module in "${modules[@]}"; do # 读取模块中的 pom.xml 来确定 JDK 版本 jdk_version=$(grep -m 1 '' $module/pom.xml | sed 's/<[^>]*>//g' | xargs) echo "${module} JDK version: ${jdk_version}" - # 如果是目标 jdk 版本,则执行 release 操作 - + + # 如果是目标 jdk 版本,则记录 if [[ "${jdk_version}" == "1.8" ]]; then - modules_in_right_jdk="${modules_in_right_jdk}${module}," + modules_in_right_jdk_array+=(${module}) + fi + done + + # 过滤出需要发布的 adapter,过滤条件:adapter 版本与 pom.xml 中的版本一致 + adapter_snapshot_version=$(grep '' pom.xml | sed -e 's/.*\(.*\)<\/revision>.*/\1/' | tr -d ' ') + modules_in_snapshot_version="" + for module in "${modules_in_right_jdk_array[@]}"; do + # 如果没有 adapter-mapping.yaml,则跳过( koupleless-adapter-configs 没有 adapter-mapping.yaml) + if [[ ! -f $module/conf/adapter-mapping.yaml ]]; then + continue + fi + + # 读取模块中的 adapter-mapping.yaml 来确定 adapter 版本 + adapter_version=$(grep 'version:' $module/conf/adapter-mapping.yaml | sed -e 's/.*version:\(.*\)/\1/' | tr -d ' ') + echo "${module} adapter version: ${adapter_version}" + + # 如果是目标 adapter 版本,则记录 + if [[ "${adapter_version}" == "${adapter_snapshot_version}" ]]; then + modules_in_snapshot_version="${modules_in_snapshot_version}${module}," fi done - if [[ -n ${modules_in_right_jdk} ]]; then - modules_in_right_jdk="${modules_in_right_jdk:0:-1}" - echo "release for module ${modules_in_right_jdk}" - mvn --batch-mode deploy -Psnapshot -pl ${modules_in_right_jdk} -am -amd -B -U - echo "release completed for module ${modules_in_right_jdk}" + if [[ -n ${modules_in_snapshot_version} ]]; then + modules_in_snapshot_version="${modules_in_snapshot_version:0:-1}" + echo "release for module ${modules_in_snapshot_version}" + mvn --batch-mode deploy -Psnapshot -pl ${modules_in_snapshot_version} -am -amd -B -U + echo "release completed for module ${modules_in_snapshot_version}" fi working-directory: adapter/ env: diff --git a/.github/workflows/koupleless_runtime_snapshot_2.1.x.yml b/.github/workflows/koupleless_runtime_snapshot_2.1.x.yml index 3eca05596..a368e1cec 100644 --- a/.github/workflows/koupleless_runtime_snapshot_2.1.x.yml +++ b/.github/workflows/koupleless_runtime_snapshot_2.1.x.yml @@ -127,24 +127,46 @@ jobs: run: | # 创建一个映射来存储模块名到 JDK 版本的映射 modules=(${{ join(fromJSON(steps.find-maven-modules.outputs.modules-list), ' ') }}) - modules_in_right_jdk="" + modules_in_right_jdk_array=() for module in "${modules[@]}"; do # 读取模块中的 pom.xml 来确定 JDK 版本 jdk_version=$(grep -m 1 '' $module/pom.xml | sed 's/<[^>]*>//g' | xargs) echo "${module} JDK version: ${jdk_version}" - # 如果是目标 jdk 版本,则执行 release 操作 + # 如果是目标 jdk 版本,则记录 if [[ "${jdk_version}" == "17" ]]; then - modules_in_right_jdk="${modules_in_right_jdk}${module}," + modules_in_right_jdk_array+=(${module}) fi done - if [[ -n ${modules_in_right_jdk} ]]; then - modules_in_right_jdk="${modules_in_right_jdk:0:-1}" - echo "release for module ${modules_in_right_jdk}" - mvn --batch-mode deploy -Psnapshot -pl ${modules_in_right_jdk} -am -amd -B -U - echo "release completed for module ${modules_in_right_jdk}" + # 过滤出需要发布的 adapter,过滤条件:adapter 版本与 pom.xml 中的版本一致 + adapter_snapshot_version=$(grep '' pom.xml | sed -e 's/.*\(.*\)<\/revision>.*/\1/' | tr -d ' ') + modules_in_snapshot_version="" + for module in "${modules_in_right_jdk_array[@]}"; do + # 如果没有 adapter-mapping.yaml,则跳过( koupleless-adapter-configs 没有 adapter-mapping.yaml) + if [[ ! -f $module/conf/adapter-mapping.yaml ]]; then + continue + fi + + # 读取模块中的 adapter-mapping.yaml 来确定 adapter 版本 + adapter_version=$(grep 'version:' $module/conf/adapter-mapping.yaml | sed -e 's/.*version:\(.*\)/\1/' | tr -d ' ') + echo "${module} adapter version: ${adapter_version}" + + # 如果是目标 adapter 版本,则记录 + if [[ "${adapter_version}" == "${adapter_snapshot_version}" ]]; then + modules_in_snapshot_version="${modules_in_snapshot_version}${module}," + fi + done + + if [[ -n ${modules_in_snapshot_version} ]]; then + modules_in_snapshot_version="${modules_in_snapshot_version:0:-1}" + echo "release for module ${modules_in_snapshot_version}" + mvn --batch-mode deploy -Psnapshot -pl ${modules_in_snapshot_version} -am -amd -B -U + echo "release completed for module ${modules_in_snapshot_version}" fi + + # 请在发布 koupleless-adapter-configs 之前,发布 jdk8 和 jdk17 所有的 koupleless-adapters + mvn --batch-mode deploy -Psnapshot -pl koupleless-adapter-configs -am -amd -B -U working-directory: adapter/ env: MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/pom.xml b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/pom.xml index 39f0ec324..24a90d96f 100644 --- a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/pom.xml +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/pom.xml @@ -16,6 +16,13 @@ + + + org.apache.maven.resolver + maven-resolver-util + 1.9.18 + + org.apache.maven maven-plugin-api @@ -60,10 +67,12 @@ com.fasterxml.jackson.core jackson-databind + - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml + org.yaml + snakeyaml + org.apache.commons commons-collections4 diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/KouplelessBaseBuildPrePackageMojo.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/KouplelessBaseBuildPrePackageMojo.java index 140c0fb19..fb56d33df 100644 --- a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/KouplelessBaseBuildPrePackageMojo.java +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/KouplelessBaseBuildPrePackageMojo.java @@ -34,13 +34,11 @@ import com.alipay.sofa.koupleless.base.build.plugin.adapter.AdapterCopyService; import com.alipay.sofa.koupleless.base.build.plugin.common.JarFileUtils; -import com.alipay.sofa.koupleless.base.build.plugin.model.KouplelessAdapterConfig; +import com.alipay.sofa.koupleless.base.build.plugin.model.CompositeKouplelessAdapterConfig; import com.alipay.sofa.koupleless.base.build.plugin.model.MavenDependencyAdapterMapping; import com.alipay.sofa.koupleless.base.build.plugin.model.MavenDependencyMatcher; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.google.common.base.Preconditions; -import org.apache.commons.collections4.CollectionUtils; +import com.google.common.base.Strings; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.maven.execution.MavenSession; @@ -57,17 +55,19 @@ import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResult; +import org.eclipse.aether.version.InvalidVersionSpecificationException; import java.io.File; -import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.regex.Pattern; +import java.util.stream.Collectors; /** * Goal which touches a timestamp file. @@ -78,36 +78,37 @@ @Mojo(name = "add-patch", defaultPhase = LifecyclePhase.PROCESS_CLASSES) public class KouplelessBaseBuildPrePackageMojo extends AbstractMojo { - String MAPPING_FILE = "adapter-mapping.yaml"; - @Parameter(defaultValue = "${project.build.directory}", readonly = true) - File outputDirectory; + File outputDirectory; @Parameter(defaultValue = "${project}", required = true, readonly = true) - MavenProject project; + public MavenProject project; @Parameter(defaultValue = "${session}", required = true, readonly = true) - MavenSession session; + public MavenSession session; + + @Parameter(defaultValue = "${project.basedir}", required = true) + public File baseDir; @Component - RepositorySystem repositorySystem; + public RepositorySystem repositorySystem; - private ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); + protected CompositeKouplelessAdapterConfig kouplelessAdapterConfig; - KouplelessAdapterConfig kouplelessAdapterConfig; + @Parameter(defaultValue = "", required = false) + public String kouplelessAdapterConfigVersion; - AdapterCopyService adapterCopyService = new AdapterCopyService(); + @Parameter(defaultValue = "", required = false) + public String customAdaptorMapping = ""; - String defaultGroupId = ""; - String defaultVersion = ""; + AdapterCopyService adapterCopyService = new AdapterCopyService(); + + String defaultGroupId = ""; + String defaultVersion = ""; void initKouplelessAdapterConfig() throws Exception { if (kouplelessAdapterConfig == null) { - InputStream mappingConfigIS = this.getClass().getClassLoader() - .getResourceAsStream(MAPPING_FILE); - - kouplelessAdapterConfig = yamlMapper.readValue(mappingConfigIS, - KouplelessAdapterConfig.class); + kouplelessAdapterConfig = new CompositeKouplelessAdapterConfig(this); } Properties properties = new Properties(); @@ -116,13 +117,6 @@ void initKouplelessAdapterConfig() throws Exception { defaultVersion = properties.getProperty("project.version"); } - String getArtifactFullId(org.apache.maven.artifact.Artifact artifact) { - return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" - + artifact.getBaseVersion() + ":" + artifact.getType() - + (StringUtils.isNotEmpty(artifact.getClassifier()) ? ":" + artifact.getClassifier() - : ""); - } - // visible for testing List getDependenciesToAdd() throws Exception { List adapterDependencies = new ArrayList<>(); @@ -135,9 +129,6 @@ List getDependenciesToAdd() throws Exception { adapterDependencies.addAll(kouplelessAdapterConfig.getCommonDependencies()); } - Collection adapterMappings = CollectionUtils - .emptyIfNull(kouplelessAdapterConfig.getAdapterMappings()); - // get resolvedArtifacts from project by reflection Field field = MavenProject.class.getDeclaredField("resolvedArtifacts"); field.setAccessible(true); @@ -146,25 +137,30 @@ List getDependenciesToAdd() throws Exception { if (resolvedArtifacts == null) { return adapterDependencies; } - for (org.apache.maven.artifact.Artifact artifact : resolvedArtifacts) { - for (MavenDependencyAdapterMapping adapterMapping : adapterMappings) { - MavenDependencyMatcher matcher = adapterMapping.getMatcher(); - if (matcher != null && matcher.getRegexp() != null) { - String regexp = matcher.getRegexp(); - String dependencyId = getArtifactFullId(artifact); - if (Pattern.compile(regexp).matcher(dependencyId).matches()) { - adapterDependencies.add(adapterMapping.getAdapter()); - getLog().info(String.format("koupleless adapter matched %s with %s", regexp, - artifact)); - break; - } - } - } - } + + // get dependencies by matching + adapterDependencies.addAll(getDependenciesByMatching(resolvedArtifacts)); return adapterDependencies; } + List getDependenciesByMatching(Collection resolvedArtifacts) throws InvalidVersionSpecificationException { + Map matchedArtifact = kouplelessAdapterConfig + .matches(resolvedArtifacts); + for (Entry entry : matchedArtifact + .entrySet()) { + MavenDependencyMatcher matcher = entry.getKey().getMatcher(); + getLog().info("koupleless adapter matched artifact: " + entry.getValue() + + " with matcher: " + matcher); + } + + List result = new ArrayList<>(); + for (MavenDependencyAdapterMapping mapping : matchedArtifact.keySet()) { + result.add(mapping.getAdapter()); + } + return result; + } + void addDependenciesDynamically() throws Exception { if (kouplelessAdapterConfig == null) { getLog().info("kouplelessAdapterConfig is null, skip adding dependencies."); @@ -174,17 +170,16 @@ void addDependenciesDynamically() throws Exception { Collection dependencies = getDependenciesToAdd(); for (Dependency dependency : dependencies) { try { - if (StringUtils.isBlank(dependency.getVersion())) { - dependency.setVersion(kouplelessAdapterConfig.getVersion()); - } - if (StringUtils.isBlank(dependency.getGroupId())) { - dependency.setGroupId(defaultGroupId); - } - getLog().debug("start downloading dependency: " + dependency.toString()); - Artifact artifact = downloadAdapterDependency(dependency); - getLog().debug("start add dependency to project root: " + dependency.toString()); + Preconditions.checkArgument(StringUtils.isNotEmpty(dependency.getVersion()), + "dependency version is empty: " + dependency); + Preconditions.checkArgument(StringUtils.isNotEmpty(dependency.getGroupId()), + "dependency groupId is empty: " + dependency); + + getLog().debug("start downloading dependency: " + dependency); + Artifact artifact = downloadDependency(dependency); + getLog().debug("start add dependency to project root: " + dependency); addArtifactToProjectRoot(artifact); - getLog().info("success add dependency: " + dependency.toString()); + getLog().info("success add dependency: " + dependency); } catch (Throwable t) { getLog().error("error add dependency: " + dependency.toString(), t); throw new RuntimeException(t); @@ -192,7 +187,7 @@ void addDependenciesDynamically() throws Exception { } } - Artifact downloadAdapterDependency(Dependency dependency) { + public Artifact downloadDependency(Dependency dependency) { DefaultArtifact patchArtifact = new DefaultArtifact( dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion()); diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/AdapterConfig.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/AdapterConfig.java new file mode 100644 index 000000000..5934ee5fb --- /dev/null +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/AdapterConfig.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.koupleless.base.build.plugin.model; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.model.Dependency; +import org.eclipse.aether.version.InvalidVersionSpecificationException; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * @author lianglipeng.llp@alibaba-inc.com + * @version $Id: AdapterConfig.java, v 0.1 2024年11月27日 11:40 立蓬 Exp $ + */ +public interface AdapterConfig { + /** + * a mapping rule only map to an artifact; but an artifact can be mapped to multiple mapping rules + * mapping -> artifact: 1 -> 1 + * artifact -> mapping: 1 -> N + * + */ + Map matches(Collection resolvedArtifacts); + + List getCommonDependencies(); +} \ No newline at end of file diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/CompositeKouplelessAdapterConfig.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/CompositeKouplelessAdapterConfig.java new file mode 100644 index 000000000..60d3868c4 --- /dev/null +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/CompositeKouplelessAdapterConfig.java @@ -0,0 +1,268 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.koupleless.base.build.plugin.model; + +import com.alipay.sofa.koupleless.base.build.plugin.KouplelessBaseBuildPrePackageMojo; +import com.alipay.sofa.koupleless.base.build.plugin.common.JarFileUtils; +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import lombok.SneakyThrows; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.maven.model.Dependency; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRangeResolutionException; +import org.eclipse.aether.resolution.VersionRangeResult; +import org.eclipse.aether.version.Version; +import org.yaml.snakeyaml.Yaml; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import static com.alipay.sofa.koupleless.base.build.plugin.constant.Constants.ARK_CONF_BASE_DIR; +import static com.alipay.sofa.koupleless.base.build.plugin.constant.Constants.STRING_COLON; +import static com.alipay.sofa.koupleless.base.build.plugin.utils.MavenUtils.getDependencyIdentity; +import static com.google.common.collect.Maps.newHashMap; + +/** + * @author lianglipeng.llp@alibaba-inc.com + * @version $Id: CompositeKouplelessAdapterConfig.java, v 0.1 2024年11月26日 17:47 立蓬 Exp $ + */ +public class CompositeKouplelessAdapterConfig implements AdapterConfig { + + private static final String CUSTOM_MAPPING_FILE = "adapter-mapping.yaml"; + + private static final String REMOTE_ADAPTER_CONFIGS = "com.alipay.sofa.koupleless:koupleless-adapter-configs"; + + private static final String DEFAULT_MAPPING_FILE = "adapter-mapping-default.yaml"; + + /** + * 用户自定义配置:用户配置的 ${baseDir}/adapter-mapping.yaml + */ + private KouplelessAdapterConfig customConfig; + + /** + * 远程配置:读取最新的 koupleless-adapter-configs 中的配置 + */ + private List remoteConfigs = new ArrayList<>(); + + /** + * 插件默认配置:如果远程配置不存在,则使用插件默认配置 + */ + private KouplelessAdapterConfig defaultConfig; + + public CompositeKouplelessAdapterConfig() { + } + + public CompositeKouplelessAdapterConfig(KouplelessBaseBuildPrePackageMojo mojo) { + initCustomConfig(mojo); + + initRemoteConfig(mojo); + + initDefaultConfig(); + } + + /** + * priority:custom > remote > default + * @return java.util.List + */ + @Override + public List getCommonDependencies() { + Map custom = Maps.newHashMap(); + if (null != customConfig) { + custom = toMapWithIdAsKey(customConfig.getCommonDependencies()); + } + + Map remote = Maps.newHashMap(); + for (KouplelessAdapterConfig config : remoteConfigs) { + remote.putAll(toMapWithIdAsKey(config.getCommonDependencies())); + } + + Map defaulted = Maps.newHashMap(); + if (null != defaultConfig) { + defaulted = toMapWithIdAsKey(defaultConfig.getCommonDependencies()); + } + + // 优先级:custom > remote > defaulted + Map res = newHashMap(); + res.putAll(defaulted); + res.putAll(remote); + res.putAll(custom); + return new ArrayList<>(res.values()); + } + + private Map toMapWithIdAsKey(List dependencies) { + if (CollectionUtils.isEmpty(dependencies)) { + return Collections.emptyMap(); + } + + Map res = newHashMap(); + dependencies.forEach(d -> { + String key = d.getGroupId() + STRING_COLON + d.getArtifactId(); + res.put(key, d); + }); + return res; + } + + /** + * no priority, all configs are activated + * @param resolvedArtifacts project resolved artifacts + * @return java.util.Map + */ + @Override + public Map matches(Collection resolvedArtifacts) { + Map custom = newHashMap(); + if (null != customConfig) { + custom = customConfig.matches(resolvedArtifacts); + } + + Map remote = newHashMap(); + for (KouplelessAdapterConfig config : remoteConfigs) { + remote.putAll(config.matches(resolvedArtifacts)); + } + + Map defaulted = newHashMap(); + if (null != defaultConfig) { + defaulted = defaultConfig.matches(resolvedArtifacts); + } + + Map res = newHashMap(); + res.putAll(defaulted); + res.putAll(remote); + res.putAll(custom); + return res; + } + + @SneakyThrows + protected void initCustomConfig(KouplelessBaseBuildPrePackageMojo mojo) { + File configFile = FileUtils.getFile(mojo.baseDir, ARK_CONF_BASE_DIR, CUSTOM_MAPPING_FILE); + if (!configFile.exists()) { + mojo.getLog().info(String.format( + "koupleless-base-build-plugin: custom-adapter-mapping-config %s not found, will not config it", + configFile.getPath())); + return; + } + + InputStream mappingConfigIS = new FileInputStream(configFile); + Yaml yaml = new Yaml(); + customConfig = yaml.loadAs(mappingConfigIS, KouplelessAdapterConfig.class); + } + + protected void initDefaultConfig() { + // 如果远程配置存在,则无需初始化插件默认配置 + if (CollectionUtils.isNotEmpty(remoteConfigs)) { + return; + } + + InputStream mappingConfigIS = this.getClass().getClassLoader() + .getResourceAsStream(DEFAULT_MAPPING_FILE); + + Yaml yaml = new Yaml(); + defaultConfig = yaml.loadAs(mappingConfigIS, KouplelessAdapterConfig.class); + } + + protected void initRemoteConfig(KouplelessBaseBuildPrePackageMojo mojo) { + String kouplelessAdapterConfigVersion = parseRemoteConfigVersion(mojo); + Artifact artifact = downloadAdapterConfigsJar(mojo, kouplelessAdapterConfigVersion); + remoteConfigs = parseConfigs(artifact); + } + + private Artifact downloadAdapterConfigsJar(KouplelessBaseBuildPrePackageMojo mojo, + String kouplelessAdapterConfigVersion) { + if (StringUtils.isEmpty(kouplelessAdapterConfigVersion)) { + return null; + } + + try { + return mojo.downloadDependency( + parseDependency(REMOTE_ADAPTER_CONFIGS + ":" + kouplelessAdapterConfigVersion)); + } catch (Exception e) { + mojo.getLog() + .warn("Failed to resolve koupleless-adapter-configs, use default config only."); + } + return null; + } + + private List parseConfigs(Artifact artifact) { + if (null == artifact) { + return Collections.emptyList(); + } + + File file = artifact.getFile(); + Map entryToContent = JarFileUtils.getFileContentAsLines(file, + Pattern.compile("(.*\\.yaml)")); + + for (Map.Entry entry : entryToContent.entrySet()) { + InputStream inputStream = new ByteArrayInputStream( + ArrayUtils.toPrimitive(entry.getValue())); + Yaml yaml = new Yaml(); + KouplelessAdapterConfig config = yaml.loadAs(inputStream, + KouplelessAdapterConfig.class); + remoteConfigs.add(config); + } + return remoteConfigs; + } + + private String parseRemoteConfigVersion(KouplelessBaseBuildPrePackageMojo mojo) { + if (StringUtils.isNotEmpty(mojo.kouplelessAdapterConfigVersion)) { + return mojo.kouplelessAdapterConfigVersion; + } + + // 从远端获取最新版本 + String version = ""; + try { + VersionRangeRequest rangeRequest = new VersionRangeRequest() + .setArtifact(new org.eclipse.aether.artifact.DefaultArtifact( + REMOTE_ADAPTER_CONFIGS + ":(,)")) + .setRepositories(mojo.project.getRemoteProjectRepositories()); + + VersionRangeResult rangeResult = mojo.repositorySystem + .resolveVersionRange(mojo.session.getRepositorySession(), rangeRequest); + Version latestVersion = rangeResult.getHighestVersion(); + version = latestVersion.toString(); + } catch (VersionRangeResolutionException e) { + mojo.getLog().warn( + "Failed to resolve latest version of koupleless-adapter-configs, use default config only."); + } + + return version; + } + + private Dependency parseDependency(String dependencyStr) { + String[] dependencyParts = StringUtils.split(dependencyStr, ":"); + + Preconditions.checkState(dependencyParts.length == 3, + "Invalid dependency format: " + dependencyStr); + + Dependency d = new Dependency(); + d.setGroupId(dependencyParts[0]); + d.setArtifactId(dependencyParts[1]); + d.setVersion(dependencyParts[2]); + return d; + } +} \ No newline at end of file diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/KouplelessAdapterConfig.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/KouplelessAdapterConfig.java index 02bd304a2..c6b558f42 100644 --- a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/KouplelessAdapterConfig.java +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/KouplelessAdapterConfig.java @@ -17,9 +17,22 @@ package com.alipay.sofa.koupleless.base.build.plugin.model; import lombok.*; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Dependency; +import org.eclipse.aether.util.version.GenericVersionScheme; +import org.eclipse.aether.version.InvalidVersionSpecificationException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import static com.alipay.sofa.koupleless.base.build.plugin.utils.ParseUtils.parseVersion; +import static com.alipay.sofa.koupleless.base.build.plugin.utils.ParseUtils.parseVersionRange; /** *

KouplelessAdapterConfig class.

@@ -28,20 +41,89 @@ * @since 2024/2/6 * @version 1.0.0 */ -@NoArgsConstructor +@Data @AllArgsConstructor +@NoArgsConstructor @Builder -@Data -public class KouplelessAdapterConfig { - String version; // 依赖包的版本。 +public class KouplelessAdapterConfig implements AdapterConfig { + String version; // 依赖包的版本。 /** * 存在一些通用的依赖,需要用户引入。 */ - List commonDependencies; + @Builder.Default + List commonDependencies = new ArrayList<>(); /** * 适配的依赖。 */ - List adapterMappings; + @Builder.Default + List adapterMappings = new ArrayList<>(); + + @Override + public Map matches(Collection resolvedArtifacts) { + Map adapterMatches = new HashMap<>(); + if (CollectionUtils.isEmpty(adapterMappings)) { + return adapterMatches; + } + + for (org.apache.maven.artifact.Artifact artifact : resolvedArtifacts) { + for (MavenDependencyAdapterMapping adapterMapping : adapterMappings) { + MavenDependencyMatcher matcher = adapterMapping.getMatcher(); + if (matches(matcher, artifact)) { + // use the default version if not configured + Dependency adapter = adapterMapping.getAdapter(); + if (StringUtils.isEmpty(adapter.getVersion())) { + adapter.setVersion(version); + } + + adapterMatches.put(adapterMapping, artifact); + } + } + } + return adapterMatches; + } + + private boolean matches(MavenDependencyMatcher matcher, Artifact artifact) { + if (null == matcher) { + return false; + } + + // match with regexp + if (regexpMatches(matcher, artifact)) { + return true; + } + + // match with versionRange + return versionRangeMatches(matcher, artifact); + } + + private boolean regexpMatches(MavenDependencyMatcher matcher, + org.apache.maven.artifact.Artifact artifact) { + if (null == matcher || null == matcher.getRegexp()) { + return false; + } + + String regexp = matcher.getRegexp(); + String dependencyId = getArtifactFullId(artifact); + return Pattern.compile(regexp).matcher(dependencyId).matches(); + } + + private boolean versionRangeMatches(MavenDependencyMatcher matcher, + org.apache.maven.artifact.Artifact artifact) { + if (null == matcher || null == matcher.getGenericVersionRange()) { + return false; + } + + return StringUtils.equals(matcher.getGroupId(), artifact.getGroupId()) + && StringUtils.equals(matcher.getArtifactId(), artifact.getArtifactId()) && matcher + .getGenericVersionRange().containsVersion(parseVersion(artifact.getVersion())); + } + + private String getArtifactFullId(org.apache.maven.artifact.Artifact artifact) { + return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + + artifact.getBaseVersion() + ":" + artifact.getType() + + (StringUtils.isNotEmpty(artifact.getClassifier()) ? ":" + artifact.getClassifier() + : ""); + } } diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/MavenDependencyMatcher.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/MavenDependencyMatcher.java index fe541b43f..6a24d8908 100644 --- a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/MavenDependencyMatcher.java +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/model/MavenDependencyMatcher.java @@ -16,10 +16,15 @@ */ package com.alipay.sofa.koupleless.base.build.plugin.model; -import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Data; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.aether.version.InvalidVersionSpecificationException; +import org.eclipse.aether.version.VersionRange; + +import static com.alipay.sofa.koupleless.base.build.plugin.utils.ParseUtils.parseVersionRange; /** *

MavenDependencyMatcher class.

@@ -29,12 +34,69 @@ * @version 1.0.0 */ @NoArgsConstructor -@AllArgsConstructor -@Data -@Builder public class MavenDependencyMatcher { /** * 用正则表达式匹配用户的依赖。 */ - private String regexp; + @Getter + @Setter + @Deprecated + private String regexp; + + /** + * 依赖的groupId,如:org.springframework.boot + */ + @Getter + @Setter + private String groupId; + + /** + * 依赖的artifactId,如:spring-boot + */ + @Getter + @Setter + private String artifactId; + + /** + * 适配的版本范围,比如: + * [1.0,2.0) 表示从 1.0(包含)到 2.0(不包含)的版本。 + * [1.0,2.0] 表示从 1.0(包含)到 2.0(包含)的版本。 + * (,1.0] 表示小于或等于 1.0 的版本。 + * [2.0,) 表示大于或等于 2.0 的版本。 + */ + @Getter + private String versionRange; + + @Getter + private VersionRange genericVersionRange; + + @Builder + public MavenDependencyMatcher(String regexp, String groupId, String artifactId, + String versionRange) throws InvalidVersionSpecificationException { + this.regexp = regexp; + this.groupId = groupId; + this.artifactId = artifactId; + this.versionRange = versionRange; + this.genericVersionRange = initGenericVersionRange(); + } + + public void setVersionRange(String versionRange) throws InvalidVersionSpecificationException { + this.versionRange = versionRange; + this.genericVersionRange = initGenericVersionRange(); + } + + private VersionRange initGenericVersionRange() throws InvalidVersionSpecificationException { + if (StringUtils.isEmpty(versionRange)) { + return null; + } + + return parseVersionRange(versionRange); + } + + @Override + public String toString() { + return String.format( + "MavenDependencyMatcher{regexp=%s,groupId=%s,artifactId=%s,versionRange=%s}", regexp, + groupId, artifactId, versionRange); + } } diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/utils/ParseUtils.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/utils/ParseUtils.java index 4a3943ef2..689d968d2 100644 --- a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/utils/ParseUtils.java +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/java/com/alipay/sofa/koupleless/base/build/plugin/utils/ParseUtils.java @@ -17,6 +17,9 @@ package com.alipay.sofa.koupleless.base.build.plugin.utils; import org.apache.commons.lang3.StringUtils; +import org.eclipse.aether.util.version.GenericVersionScheme; +import org.eclipse.aether.version.Version; +import org.eclipse.aether.version.VersionRange; import java.util.List; import java.util.Map; @@ -31,6 +34,8 @@ * @version $Id: CommonUtils.java, v 0.1 2024年06月26日 13:16 立蓬 Exp $ */ public class ParseUtils { + private static final GenericVersionScheme versionScheme = new GenericVersionScheme(); + public static Set getSetValues(Properties prop, String confKey) { if (null == prop) { return newHashSet(); @@ -45,4 +50,21 @@ public static Set getStringSet(Map yaml, String confKey) } return newHashSet(); } + + public static VersionRange parseVersionRange(String versionRange) { + try { + return versionScheme.parseVersionRange(versionRange); + } catch (Exception e) { + throw new RuntimeException("parse version range failed, version range: " + versionRange, + e); + } + } + + public static Version parseVersion(String version) { + try { + return versionScheme.parseVersion(version); + } catch (Exception e) { + throw new RuntimeException("parse version failed, version: " + version, e); + } + } } \ No newline at end of file diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/resources/adapter-mapping-default.yaml b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/resources/adapter-mapping-default.yaml new file mode 100644 index 000000000..c0b300647 --- /dev/null +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/resources/adapter-mapping-default.yaml @@ -0,0 +1,120 @@ +version: 1.2.2 +adapterMappings: + - matcher: + regexp: ".*spring-boot-starter-logging:3.*" + adapter: + artifactId: koupleless-adapter-logback-spring-starter-3.2 + - matcher: + groupId: org.springframework.boot + artifactId: spring-boot + versionRange: "[2.5.1,2.7.14]" + adapter: + artifactId: koupleless-adapter-spring-boot-logback-2.7.14 + - matcher: + groupId: org.springframework.boot + artifactId: spring-boot-starter-logging + versionRange: "(,)" + adapter: + artifactId: koupleless-adapter-logback + - matcher: + groupId: org.springframework + artifactId: spring-aop + versionRange: "[6.0.8,6.0.9]" + adapter: + artifactId: koupleless-adapter-spring-aop-6.0.8 + - matcher: + groupId: org.springframework + artifactId: spring-aop + versionRange: "[5.3.27,5.3.27]" + adapter: + artifactId: koupleless-adapter-spring-aop-5.3.27 + - matcher: + groupId: org.apache.rocketmq + artifactId: rocketmq-client + versionRange: "[4.4.0,4.4.0]" + adapter: + artifactId: koupleless-adapter-rocketmq-4.4 + - matcher: + groupId: com.ctrip.framework.apollo + artifactId: apollo-client + versionRange: "(,)" + adapter: + artifactId: koupleless-adapter-apollo-1.6 + - matcher: + groupId: com.alibaba + artifactId: dubbo-dependencies-bom + versionRange: "[2.6.1,2.7.0)" + adapter: + artifactId: koupleless-adapter-dubbo-2.6 + - matcher: + groupId: com.alibaba + artifactId: dubbo + versionRange: "[2.6.0,2.7.0)" + adapter: + artifactId: koupleless-adapter-dubbo-2.6 + - matcher: + groupId: org.apache.dubbo + artifactId: dubbo-spring-boot-starter + versionRange: "[2.7.0,2.8.0)" + adapter: + artifactId: koupleless-adapter-dubbo-2.7 + - matcher: + groupId: org.apache.dubbo + artifactId: dubbo + versionRange: "[2.7.0,2.8.0)" + adapter: + artifactId: koupleless-adapter-dubbo-2.7 + - matcher: + groupId: org.apache.dubbo + artifactId: dubbo-common + versionRange: "[3.2.0,3.3.0)" + adapter: + artifactId: koupleless-adapter-dubbo-3.2 + - matcher: + groupId: org.apache.dubbo + artifactId: dubbo-common + versionRange: "[3.1.0,3.2.0)" + adapter: + artifactId: koupleless-adapter-dubbo-3.1 + - matcher: + groupId: org.springframework.boot + artifactId: spring-boot-starter-log4j2 + versionRange: "[2.1.0,2.4.0)" + adapter: + artifactId: koupleless-adapter-log4j2-spring-starter-2.1 + - matcher: + groupId: org.springframework.boot + artifactId: spring-boot-starter-log4j2 + versionRange: "[2.4.0,2.7.0)" + adapter: + artifactId: koupleless-adapter-log4j2-spring-starter-2.4 + - matcher: + groupId: org.springframework.boot + artifactId: spring-boot-starter-log4j2 + versionRange: "[2.7.0,3.0.0)" + adapter: + artifactId: koupleless-adapter-log4j2-spring-starter-2.7 + - matcher: + groupId: org.springframework.boot + artifactId: spring-boot-starter-log4j2 + versionRange: "[3.0.0,3.2.0)" + adapter: + artifactId: koupleless-adapter-log4j2-spring-starter-3.0 + - matcher: + groupId: org.springframework.boot + artifactId: spring-boot-starter-log4j2 + versionRange: "[3.2.0,)" + adapter: + artifactId: koupleless-adapter-log4j2-spring-starter-3.2 + - matcher: + groupId: org.springframework.boot + artifactId: spring-boot-starter-logging + versionRange: "[3.0.0,3.2.0)" + adapter: + artifactId: koupleless-adapter-logback-spring-starter-3.0 + - matcher: + groupId: org.springframework.boot + artifactId: spring-boot-starter-logging + versionRange: "[3.2.0,)" + adapter: + artifactId: koupleless-adapter-logback-spring-starter-3.2 \ No newline at end of file diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/resources/adapter-mapping.yaml b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/resources/adapter-mapping.yaml deleted file mode 100644 index 5e2bb99e4..000000000 --- a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/main/resources/adapter-mapping.yaml +++ /dev/null @@ -1,66 +0,0 @@ -version: 1.2.2 -adapterMappings: - - matcher: - regexp: ".*com\\.ctrip\\.framework\\.apollo:apollo-client.*" - adapter: - artifactId: koupleless-adapter-apollo-1.6 - - matcher: - regexp: ".*(com\\.alibaba:dubbo-dependencies-bom:2\\.6|com\\.alibaba:dubbo:2\\.6).*" - adapter: - artifactId: koupleless-adapter-dubbo-2.6 - - matcher: - regexp: ".*(dubbo-spring-boot-starter:2\\.7|com\\.alibaba:dubbo:2\\.7).*" - adapter: - artifactId: koupleless-adapter-dubbo-2.7 - - matcher: - regexp: ".*(org\\.apache\\.dubbo:dubbo.*:3\\.2).*" - adapter: - artifactId: koupleless-adapter-dubbo-3.2 - - matcher: - regexp: ".*(org\\.apache\\.dubbo:dubbo.*:3\\.1).*" - adapter: - artifactId: koupleless-adapter-dubbo-3.1 - - matcher: - regexp: ".*spring-boot-starter-log4j2:3\\.(0|1).*" - adapter: - artifactId: koupleless-adapter-log4j2-spring-starter-3.0 - - matcher: - regexp: ".*spring-boot-starter-log4j2:3.*" - adapter: - artifactId: koupleless-adapter-log4j2-spring-starter-3.2 - - matcher: - regexp: ".*spring-boot-starter-log4j2:2\\.(1|2|3).*" - adapter: - artifactId: koupleless-adapter-log4j2-spring-starter-2.1 - - matcher: - regexp: ".*spring-boot-starter-log4j2:2\\.(4|5|6).*" - adapter: - artifactId: koupleless-adapter-log4j2-spring-starter-2.4 - - matcher: - regexp: ".*spring-boot-starter-log4j2.*" - adapter: - artifactId: koupleless-adapter-log4j2-spring-starter-2.7 - - matcher: - regexp: ".*spring-boot-starter-logging:3\\.(0|1).*" - adapter: - artifactId: koupleless-adapter-logback-spring-starter-3.0 - - matcher: - regexp: ".*spring-boot-starter-logging:3.*" - adapter: - artifactId: koupleless-adapter-logback-spring-starter-3.2 - - matcher: - regexp: ".*spring-boot-starter-logging:.*" - adapter: - artifactId: koupleless-adapter-logback - - matcher: - regexp: ".*(org\\.apache\\.rocketmq:rocketmq-client:4\\.4\\.0).*" - adapter: - artifactId: koupleless-adapter-rocketmq-4.4 - - matcher: - regexp: ".*(org\\.springframework:spring-aop:5\\.3\\.27).*" - adapter: - artifactId: koupleless-adapter-spring-aop-5.3.27 - - matcher: - regexp: ".*(org\\.springframework:spring-aop:6\\.0\\.(8|9)).*" - adapter: - artifactId: koupleless-adapter-spring-aop-6.0.8 diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/KouplelessBaseBuildPrePackageMojoTest.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/KouplelessBaseBuildPrePackageMojoTest.java index 11fd54742..96ca506bc 100644 --- a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/KouplelessBaseBuildPrePackageMojoTest.java +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/KouplelessBaseBuildPrePackageMojoTest.java @@ -16,9 +16,11 @@ */ package com.alipay.sofa.koupleless.base.build.plugin; -import com.alipay.sofa.koupleless.base.build.plugin.model.MavenDependencyAdapterMapping; +import com.alipay.sofa.koupleless.base.build.plugin.model.CompositeKouplelessAdapterConfig; import com.alipay.sofa.koupleless.base.build.plugin.model.KouplelessAdapterConfig; +import com.alipay.sofa.koupleless.base.build.plugin.model.MavenDependencyAdapterMapping; import com.alipay.sofa.koupleless.base.build.plugin.model.MavenDependencyMatcher; +import org.apache.commons.lang3.StringUtils; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Dependency; import org.apache.maven.project.MavenProject; @@ -40,10 +42,14 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -52,51 +58,38 @@ * @author CodeNoobKing * @since 2024/2/19 */ -@RunWith(MockitoJUnitRunner.class) public class KouplelessBaseBuildPrePackageMojoTest { - @InjectMocks - private KouplelessBaseBuildPrePackageMojo mojo; - // create a tmp directory using os tmp - private File outputDirectory = null; - - @Mock - MavenProject project; - - @Mock - MavenSession session; - - @Mock - RepositorySystem repositorySystem; - - @Before - public void setUp() { - mojo.MAPPING_FILE = "adapter-mapping-ext.yml"; - } + private File outputDirectory = null; @Test public void testLazyInitKouplelessAdapterConfig() throws Exception { - Dependency mockDependency = new Dependency(); - mockDependency.setGroupId("XXX"); - mockDependency.setArtifactId("YYY"); - mockDependency.setVersion("ZZZ"); - - List commonDependencies = new ArrayList<>(); - commonDependencies.add(mockDependency); - - List mappings = new ArrayList<>(); - mappings.add(MavenDependencyAdapterMapping.builder().adapter(mockDependency) - .matcher(MavenDependencyMatcher.builder().regexp(".*").build()).build()); + KouplelessBaseBuildPrePackageMojo mojo = new KouplelessBaseBuildPrePackageMojo(); + mojo.kouplelessAdapterConfig = mock(CompositeKouplelessAdapterConfig.class); mojo.initKouplelessAdapterConfig(); - KouplelessAdapterConfig expected = KouplelessAdapterConfig.builder() - .commonDependencies(commonDependencies).adapterMappings(mappings).build(); - - Assert.assertEquals(expected.toString(), mojo.kouplelessAdapterConfig.toString()); + assertEquals("com.alipay.sofa.koupleless", mojo.defaultGroupId); + assertTrue(StringUtils.isNoneEmpty(mojo.defaultVersion)); } @Test public void testAddDependencyDynamically() throws Exception { + KouplelessBaseBuildPrePackageMojo mojo = new KouplelessBaseBuildPrePackageMojo(); + mojo.project = mock(MavenProject.class); + // init maven project + Set artifacts = new HashSet<>(); + org.apache.maven.artifact.Artifact artifact = mock( + org.apache.maven.artifact.Artifact.class); + doReturn("A").when(artifact).getGroupId(); + // doReturn("B").when(artifact).getArtifactId(); + doReturn("C").when(artifact).getBaseVersion(); + artifacts.add(artifact); + doReturn(artifacts).when(mojo.project).getArtifacts(); + // set resolvedArtifacts in project + Field field = MavenProject.class.getDeclaredField("resolvedArtifacts"); + field.setAccessible(true); + field.set(mojo.project, artifacts); + { // init the adapter config Dependency mockDependency = new Dependency(); @@ -107,28 +100,15 @@ public void testAddDependencyDynamically() throws Exception { List commonDependencies = new ArrayList<>(); commonDependencies.add(mockDependency); + Map matchedResult = new HashMap<>(); + mojo.kouplelessAdapterConfig = mock(CompositeKouplelessAdapterConfig.class); + doReturn(commonDependencies).when(mojo.kouplelessAdapterConfig).getCommonDependencies(); + List mappings = new ArrayList<>(); mappings.add(MavenDependencyAdapterMapping.builder().adapter(mockDependency) .matcher(MavenDependencyMatcher.builder().regexp(".*A:B:C.*").build()).build()); - - mojo.kouplelessAdapterConfig = KouplelessAdapterConfig.builder() - .commonDependencies(commonDependencies).adapterMappings(mappings).build(); - } - - { - // init maven project - Set artifacts = new HashSet<>(); - org.apache.maven.artifact.Artifact artifact = mock( - org.apache.maven.artifact.Artifact.class); - doReturn("A").when(artifact).getGroupId(); - // doReturn("B").when(artifact).getArtifactId(); - doReturn("C").when(artifact).getBaseVersion(); - artifacts.add(artifact); - project.setArtifacts(artifacts); - // set resolvedArtifacts in project - Field field = MavenProject.class.getDeclaredField("resolvedArtifacts"); - field.setAccessible(true); - field.set(project, artifacts); + matchedResult.put(mappings.get(0), artifact); + doReturn(matchedResult).when(mojo.kouplelessAdapterConfig).matches(any()); } { @@ -139,9 +119,18 @@ public void testAddDependencyDynamically() throws Exception { URL demoJarUrl = getClass().getClassLoader().getResource("demo.jar"); doReturn(new File(demoJarUrl.toURI())).when(mockArtifact).getFile(); + + RepositorySystem repositorySystem = mock(RepositorySystem.class); + mojo.repositorySystem = repositorySystem; doReturn(mockArtifactResult).when(repositorySystem).resolveArtifact(any(), any()); } + { + // mock the session + MavenSession session = mock(MavenSession.class); + mojo.session = session; + } + { // init output directory mojo.outputDirectory = Files.createTempDirectory("mojotest").toFile(); diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/MatcherUtilsTest.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/MatcherUtilsTest.java new file mode 100644 index 000000000..358842a9f --- /dev/null +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/MatcherUtilsTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.koupleless.base.build.plugin; + +import com.alipay.sofa.koupleless.base.build.plugin.model.KouplelessAdapterConfig; +import com.alipay.sofa.koupleless.base.build.plugin.model.MavenDependencyAdapterMapping; +//import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import org.apache.commons.collections4.CollectionUtils; +import org.yaml.snakeyaml.Yaml; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; + +/** + * @author lianglipeng.llp@alibaba-inc.com + * @version $Id: MatcherUtils.java, v 0.1 2024年11月21日 10:56 立蓬 Exp $ + */ +public class MatcherUtilsTest { + + String MAPPING_FILE = "mockBaseDir/conf/ark/adapter-mapping-test.yaml"; + + private KouplelessBaseBuildPrePackageMojo mojo = new KouplelessBaseBuildPrePackageMojo(); + + KouplelessAdapterConfig kouplelessAdapterConfig = loadConfig(); + + Collection adapterMappings = CollectionUtils + .emptyIfNull(kouplelessAdapterConfig.getAdapterMappings()); + + public MatcherUtilsTest() throws IOException { + } + + private KouplelessAdapterConfig loadConfig() throws IOException { + InputStream mappingConfigIS = this.getClass().getClassLoader() + .getResourceAsStream(MAPPING_FILE); + + Yaml yaml = new Yaml(); + return yaml.loadAs(mappingConfigIS, KouplelessAdapterConfig.class); + } + + /** + * test for adaptor: koupleless-adapter-apollo-1.6 + * matcher: + * groupId: com.ctrip.framework.apollo + * artifactId: apollo-client + * versionRange: "(,)" + * adapter: + * artifactId: koupleless-adapter-apollo-1.6 + */ + +} \ No newline at end of file diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/TestAdapterFile.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/TestAdapterFile.java deleted file mode 100644 index dc8767e06..000000000 --- a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/TestAdapterFile.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alipay.sofa.koupleless.base.build.plugin; - -import com.alipay.sofa.koupleless.base.build.plugin.model.KouplelessAdapterConfig; -import com.alipay.sofa.koupleless.base.build.plugin.model.MavenDependencyAdapterMapping; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import org.junit.Assert; -import org.junit.Test; - -import java.io.InputStream; - -/** - * @author CodeNoobKing - * @since 2024/4/30 - **/ -public class TestAdapterFile { - - private ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); - - String getMappingArtifact(KouplelessAdapterConfig config, String targetArtifactId) { - for (MavenDependencyAdapterMapping mapping : config.getAdapterMappings()) { - if (targetArtifactId.matches(mapping.getMatcher().getRegexp())) { - return mapping.getAdapter().getArtifactId(); - } - } - return null; - } - - @Test - public void testAdapterFile() throws Exception { - InputStream is = this.getClass().getClassLoader() - .getResourceAsStream("adapter-mapping.yaml"); - KouplelessAdapterConfig config = yamlMapper.readValue(is, KouplelessAdapterConfig.class); - - Assert.assertEquals("koupleless-adapter-apollo-1.6", - getMappingArtifact(config, "com.ctrip.framework.apollo:apollo-client:1.6.0:jar")); - - Assert.assertEquals("koupleless-adapter-dubbo-2.6", - getMappingArtifact(config, "com.alibaba:dubbo:2.6.1:jar")); - - Assert.assertEquals("koupleless-adapter-dubbo-2.7", - getMappingArtifact(config, "dubbo-spring-boot-starter:2.7.3:jar")); - - Assert.assertEquals("koupleless-adapter-dubbo-2.7", - getMappingArtifact(config, "com.alibaba:dubbo:2.7.3:jar")); - - Assert.assertEquals("koupleless-adapter-dubbo-3.2", - getMappingArtifact(config, "org.apache.dubbo:dubbo:3.2.1:jar")); - - Assert.assertEquals("koupleless-adapter-dubbo-3.1", - getMappingArtifact(config, "org.apache.dubbo:dubbo:3.1.1:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-3.0", - getMappingArtifact(config, "spring-boot-starter-log4j2:3.0.0:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-3.0", - getMappingArtifact(config, "spring-boot-starter-log4j2:3.1.0:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-3.2", - getMappingArtifact(config, "spring-boot-starter-log4j2:3.2.0:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-2.1", - getMappingArtifact(config, "spring-boot-starter-log4j2:2.1.0:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-2.1", - getMappingArtifact(config, "spring-boot-starter-log4j2:2.2.0:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-2.1", - getMappingArtifact(config, "spring-boot-starter-log4j2:2.3.0:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-2.4", - getMappingArtifact(config, "spring-boot-starter-log4j2:2.4.0:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-2.4", - getMappingArtifact(config, "spring-boot-starter-log4j2:2.5.0:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-2.4", - getMappingArtifact(config, "spring-boot-starter-log4j2:2.6.0:jar")); - - Assert.assertEquals("koupleless-adapter-log4j2-spring-starter-2.7", - getMappingArtifact(config, "spring-boot-starter-log4j2:2.7.0:jar")); - - Assert.assertEquals("koupleless-adapter-logback-spring-starter-3.0", - getMappingArtifact(config, "spring-boot-starter-logging:3.0:jar")); - - Assert.assertEquals("koupleless-adapter-logback-spring-starter-3.0", - getMappingArtifact(config, "spring-boot-starter-logging:3.1:jar")); - - Assert.assertEquals("koupleless-adapter-logback-spring-starter-3.2", - getMappingArtifact(config, "spring-boot-starter-logging:3.2:jar")); - - Assert.assertEquals("koupleless-adapter-logback", - getMappingArtifact(config, "spring-boot-starter-logging:1.1:jar")); - - } -} diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/model/CompositeKouplelessAdapterConfigTest.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/model/CompositeKouplelessAdapterConfigTest.java new file mode 100644 index 000000000..74540b759 --- /dev/null +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/model/CompositeKouplelessAdapterConfigTest.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.koupleless.base.build.plugin.model; + +import com.alipay.sofa.koupleless.base.build.plugin.KouplelessBaseBuildPrePackageMojo; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Dependency; +import org.apache.maven.project.MavenProject; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.VersionRangeResolutionException; +import org.eclipse.aether.resolution.VersionRangeResult; +import org.eclipse.aether.version.Version; +import org.junit.Test; + +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.alipay.sofa.koupleless.utils.MockUtils.getResourceAsFile; +import static com.alipay.sofa.koupleless.utils.ReflectionUtils.getField; +import static com.alipay.sofa.koupleless.utils.ReflectionUtils.setField; +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + +/** + * @author lianglipeng.llp@alibaba-inc.com + * @version $Id: CompositeKouplelessAdapterConfigTest.java, v 0.1 2024年12月01日 19:20 立蓬 Exp $ + */ +public class CompositeKouplelessAdapterConfigTest { + @Test + public void testInitCustomConfig() throws URISyntaxException { + KouplelessBaseBuildPrePackageMojo mojo = new KouplelessBaseBuildPrePackageMojo(); + mojo.baseDir = getResourceAsFile("mockBaseDir"); + + CompositeKouplelessAdapterConfig config = new CompositeKouplelessAdapterConfig(); + config.initCustomConfig(mojo); + + KouplelessAdapterConfig customConfig = getField("customConfig", config); + assertNotNull(customConfig); + } + + @Test + public void testInitRemoteConfig() throws VersionRangeResolutionException, URISyntaxException { + KouplelessBaseBuildPrePackageMojo mojo = spy(new KouplelessBaseBuildPrePackageMojo()); + + { + // mock for parseRemoteConfigVersion + RepositorySystem repositorySystem = mock(RepositorySystem.class); + + VersionRangeResult rangeResult = mock(VersionRangeResult.class); + doReturn(new Version() { + @Override + public int compareTo(Version o) { + return 0; + } + + @Override + public String toString() { + return "1.0.0"; + } + }).when(rangeResult).getHighestVersion(); + doReturn(rangeResult).when(repositorySystem).resolveVersionRange(any(), any()); + + mojo.repositorySystem = repositorySystem; + + List remoteRepositories = Collections.emptyList(); + mojo.project = mock(MavenProject.class); + doReturn(remoteRepositories).when(mojo.project).getRemoteProjectRepositories(); + + RepositorySystemSession repositorySystemSession = mock(RepositorySystemSession.class); + mojo.session = mock(MavenSession.class); + doReturn(repositorySystemSession).when(mojo.session).getRepositorySession(); + } + + { + // mock for downloadAdapterConfigsJar + Artifact artifact = mock(Artifact.class); + doReturn(getResourceAsFile("koupleless-adapter-configs-1.2.3.jar")).when(artifact) + .getFile(); + doReturn(artifact).when(mojo).downloadDependency(any()); + } + + CompositeKouplelessAdapterConfig config = new CompositeKouplelessAdapterConfig(); + config.initRemoteConfig(mojo); + + List remoteConfigs = getField("remoteConfigs", config); + assertEquals(18, remoteConfigs.size()); + } + + @Test + public void testInitDefaultConfig() { + CompositeKouplelessAdapterConfig config = new CompositeKouplelessAdapterConfig(); + config.initDefaultConfig(); + + KouplelessAdapterConfig defaultConfig = getField("defaultConfig", config); + assertNotNull(defaultConfig); + } + + @Test + public void testGetCommonDependencies() { + CompositeKouplelessAdapterConfig config = new CompositeKouplelessAdapterConfig(); + + KouplelessAdapterConfig customConfig = mock(KouplelessAdapterConfig.class); + doReturn(asList(mockDependency("com.alipay.sofa", "customConfig", "1.0.0"), + mockDependency("com.alipay.sofa", "repeated", "1.0.0"))).when(customConfig) + .getCommonDependencies(); + setField("customConfig", config, customConfig); + + List remoteConfigs = getField("remoteConfigs", config); + KouplelessAdapterConfig remoteConfig = mock(KouplelessAdapterConfig.class); + remoteConfigs.add(remoteConfig); + doReturn(asList(mockDependency("com.alipay.sofa", "remoteConfig", "1.0.0"), + mockDependency("com.alipay.sofa", "repeated", "2.0.0"))).when(remoteConfig) + .getCommonDependencies(); + + KouplelessAdapterConfig defaultConfig = mock(KouplelessAdapterConfig.class); + doReturn(asList(mockDependency("com.alipay.sofa", "defaultConfig", "1.0.0"), + mockDependency("com.alipay.sofa", "repeated", "3.0.0"))).when(defaultConfig) + .getCommonDependencies(); + setField("defaultConfig", config, defaultConfig); + + List commonDependencies = config.getCommonDependencies(); + assertEquals(4, commonDependencies.size()); + assertEquals("1.0.0", commonDependencies.stream() + .filter(d -> d.getArtifactId().equals("repeated")).findFirst().get().getVersion()); + } + + @Test + public void testMatches() { + CompositeKouplelessAdapterConfig config = new CompositeKouplelessAdapterConfig(); + + KouplelessAdapterConfig customConfig = mock(KouplelessAdapterConfig.class); + Map custom = new HashMap<>(); + custom.put(mock(MavenDependencyAdapterMapping.class), + mock(org.apache.maven.artifact.Artifact.class)); + doReturn(custom).when(customConfig).matches(any()); + setField("customConfig", config, customConfig); + + List remoteConfigs = getField("remoteConfigs", config); + KouplelessAdapterConfig remoteConfig = mock(KouplelessAdapterConfig.class); + remoteConfigs.add(remoteConfig); + Map remote = new HashMap<>(); + remote.put(mock(MavenDependencyAdapterMapping.class), + mock(org.apache.maven.artifact.Artifact.class)); + doReturn(remote).when(remoteConfig).matches(any()); + + KouplelessAdapterConfig defaultConfig = mock(KouplelessAdapterConfig.class); + Map defaulted = new HashMap<>(); + defaulted.put(mock(MavenDependencyAdapterMapping.class), + mock(org.apache.maven.artifact.Artifact.class)); + doReturn(defaulted).when(defaultConfig).matches(any()); + setField("defaultConfig", config, defaultConfig); + + Map matches = config + .matches(asList(mock(org.apache.maven.artifact.Artifact.class))); + assertEquals(3, matches.size()); + } + + private Dependency mockDependency(String groupId, String artifactId, String version) { + Dependency dependency = new Dependency(); + dependency.setGroupId(groupId); + dependency.setArtifactId(artifactId); + dependency.setVersion(version); + return dependency; + } +} \ No newline at end of file diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/model/KouplelessAdapterConfigTest.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/model/KouplelessAdapterConfigTest.java new file mode 100644 index 000000000..b4c05df4c --- /dev/null +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/base/build/plugin/model/KouplelessAdapterConfigTest.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.koupleless.base.build.plugin.model; + +import edu.emory.mathcs.backport.java.util.Collections; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.model.Dependency; +import org.eclipse.aether.version.InvalidVersionSpecificationException; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +/** + * @author lianglipeng.llp@alibaba-inc.com + * @version $Id: KouplelessAdapterConfigTest.java, v 0.1 2024年12月01日 19:20 立蓬 Exp $ + */ +public class KouplelessAdapterConfigTest { + @Test + public void testMatches() throws InvalidVersionSpecificationException { + KouplelessAdapterConfig config = new KouplelessAdapterConfig(); + + // init dependency + Dependency dependency = new Dependency(); + dependency.setArtifactId("YYY"); + dependency.setGroupId("XXX"); + dependency.setVersion("1.0.0"); + + // init artifacts + List artifacts = new ArrayList<>(); + Artifact regexpArtifact = mockArtifact("groupId", "regexpArtifactId", "1.0.0", "classifier", + "type"); + Artifact versionRangeArtifact = mockArtifact("groupId", "versionRangeArtifactId", "1.0.0", + null, null); + artifacts.add(regexpArtifact); + artifacts.add(versionRangeArtifact); + + // match null + assertEquals(0, config.matches(artifacts).size()); + + // match with regexp + MavenDependencyAdapterMapping regexpMapping = MavenDependencyAdapterMapping.builder() + .matcher(MavenDependencyMatcher.builder().regexp(".*regexpArtifactId:1.*").build()) + .adapter(dependency).build(); + config.setAdapterMappings(Collections.singletonList(regexpMapping)); + assertEquals(1, config.matches(artifacts).size()); + + // match with versionRange + MavenDependencyAdapterMapping versionRangeMapping = MavenDependencyAdapterMapping.builder() + .matcher(MavenDependencyMatcher.builder().groupId("groupId") + .artifactId("versionRangeArtifactId").versionRange("[1.0.0,]").build()) + .adapter(dependency).build(); + config.setAdapterMappings(Collections.singletonList(versionRangeMapping)); + assertEquals(1, config.matches(artifacts).size()); + } + + private Artifact mockArtifact(String groupId, String artifactId, String version, + String classifier, String type) { + Artifact artifact = mock(Artifact.class); + doReturn(groupId).when(artifact).getGroupId(); + doReturn(artifactId).when(artifact).getArtifactId(); + doReturn(version).when(artifact).getBaseVersion(); + doReturn(version).when(artifact).getVersion(); + doReturn(classifier).when(artifact).getClassifier(); + doReturn(type).when(artifact).getType(); + return artifact; + } +} \ No newline at end of file diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/utils/ReflectionUtils.java b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/utils/ReflectionUtils.java index 7dc478969..5d644e53f 100644 --- a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/utils/ReflectionUtils.java +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/java/com/alipay/sofa/koupleless/utils/ReflectionUtils.java @@ -44,4 +44,18 @@ public static void setField(String fieldName, Object o, T value) { } } } + + public static T getField(String fieldName, Object o) { + Class klass = o.getClass(); + while (klass != null) { + try { + Field f = klass.getDeclaredField(fieldName); + f.setAccessible(true); + return (T) f.get(o); + } catch (Exception e) { + klass = klass.getSuperclass(); + } + } + return null; + } } \ No newline at end of file diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/resources/koupleless-adapter-configs-1.2.3.jar b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/resources/koupleless-adapter-configs-1.2.3.jar new file mode 100644 index 000000000..c3aacdee2 Binary files /dev/null and b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/resources/koupleless-adapter-configs-1.2.3.jar differ diff --git a/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/resources/mockBaseDir/conf/ark/adapter-mapping.yaml b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/resources/mockBaseDir/conf/ark/adapter-mapping.yaml new file mode 100644 index 000000000..316c648b4 --- /dev/null +++ b/koupleless-ext/koupleless-build-plugin/koupleless-base-build-plugin/src/test/resources/mockBaseDir/conf/ark/adapter-mapping.yaml @@ -0,0 +1,8 @@ +version: 1.2.2 +adapterMappings: + - matcher: + groupId: com.ctrip.framework.apollo + artifactId: apollo-client + versionRange: "(,)" + adapter: + artifactId: koupleless-adapter-apollo-1.6 \ No newline at end of file diff --git a/koupleless-ext/koupleless-build-plugin/pom.xml b/koupleless-ext/koupleless-build-plugin/pom.xml index d53b16ac7..95ab753ce 100644 --- a/koupleless-ext/koupleless-build-plugin/pom.xml +++ b/koupleless-ext/koupleless-build-plugin/pom.xml @@ -68,6 +68,11 @@ jackson-dataformat-yaml 2.13.5 + + org.yaml + snakeyaml + 2.3 + org.apache.commons commons-collections4