Skip to content

Commit

Permalink
Enhance inconsistent version check (apache#12038)
Browse files Browse the repository at this point in the history
* Enhance inconsistent version check

* Fix seperate

* Fix load

* Fix load

* Fix test

* Update pom.xml

* Print tree

* use zip instead

* Fix test
  • Loading branch information
AlbumenJ authored Apr 11, 2023
1 parent 463ec03 commit 412471a
Show file tree
Hide file tree
Showing 11 changed files with 331 additions and 104 deletions.
107 changes: 107 additions & 0 deletions .artifacts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# 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.
#

# Please add new modules to the end of the list.

dubbo
dubbo-auth
dubbo-apache-release
dubbo-bom
dubbo-build-tools
dubbo-cluster
dubbo-common
dubbo-compatible
dubbo-compiler
dubbo-config
dubbo-config-api
dubbo-config-spring
dubbo-configcenter
dubbo-configcenter-apollo
dubbo-configcenter-nacos
dubbo-configcenter-zookeeper
dubbo-container
dubbo-container-api
dubbo-container-spring
dubbo-core-spi
dubbo-dependencies
dubbo-dependencies-all
dubbo-dependencies-bom
dubbo-dependencies-zookeeper
dubbo-dependencies-zookeeper-curator5
dubbo-distribution
dubbo-filter
dubbo-filter-cache
dubbo-filter-validation
dubbo-kubernetes
dubbo-maven-plugin
dubbo-metadata
dubbo-metadata-api
dubbo-metadata-definition-protobuf
dubbo-metadata-processor
dubbo-metadata-report-nacos
dubbo-metadata-report-redis
dubbo-metadata-report-zookeeper
dubbo-metrics
dubbo-metrics-api
dubbo-metrics-default
dubbo-metrics-metadata
dubbo-metrics-prometheus
dubbo-metrics-registry
dubbo-monitor
dubbo-monitor-api
dubbo-monitor-default
dubbo-native
dubbo-native-plugin
dubbo-parent
dubbo-plugin
dubbo-qos
dubbo-qos-api
dubbo-reactive
dubbo-registry
dubbo-registry-api
dubbo-registry-multicast
dubbo-registry-multiple
dubbo-registry-nacos
dubbo-registry-zookeeper
dubbo-remoting
dubbo-remoting-api
dubbo-remoting-http
dubbo-remoting-netty
dubbo-remoting-netty4
dubbo-remoting-zookeeper
dubbo-remoting-zookeeper-curator5
dubbo-rpc
dubbo-rpc-api
dubbo-rpc-dubbo
dubbo-rpc-injvm
dubbo-rpc-rest
dubbo-rpc-triple
dubbo-security
dubbo-serialization
dubbo-serialization-api
dubbo-serialization-fastjson2
dubbo-serialization-hessian2
dubbo-serialization-jdk
dubbo-spring-boot
dubbo-spring-boot-actuator
dubbo-spring-boot-actuator-compatible
dubbo-spring-boot-autoconfigure
dubbo-spring-boot-autoconfigure-compatible
dubbo-spring-boot-compatible
dubbo-spring-boot-observability-starter
dubbo-spring-boot-starter
dubbo-spring-security
dubbo-xds
6 changes: 4 additions & 2 deletions .github/workflows/build-and-test-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,17 @@ jobs:
cd ./dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Pack class result"
run: 7z a ${{ github.workspace }}/class.zip */target/classes/* -r
run: |
shopt -s globstar
zip ${{ github.workspace }}/class.zip **/target/classes/* -r
- name: "Upload class result"
uses: actions/upload-artifact@v3
with:
name: "class-file"
path: ${{ github.workspace }}/class.zip
- name: "Pack checkstyle file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
run: zip ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
- name: "Upload checkstyle file if failure"
if: failure()
uses: actions/upload-artifact@v3
Expand Down
33 changes: 0 additions & 33 deletions dubbo-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,37 +101,4 @@
<artifactId>javax.annotation-api</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>get-version-infos</id>
<phase>compile</phase>
<configuration>
<failOnError>true</failOnError>
<target>
<property name="version_file"
value="${project.build.outputDirectory}/META-INF/version"/>
<!-- get the current version of dubbo -->
<echo message="revision=${revision}${line.separator}" file="${version_file}"/>
<echo message="git.commit.id=" file="${version_file}" append="true"/>
<!-- get the latest commit id -->
<exec executable="git" output="${version_file}" error=".git.exec.error" append="true"
timeout="3000" failifexecutionfails="false">
<arg line="rev-parse HEAD"/>
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
128 changes: 83 additions & 45 deletions dubbo-common/src/main/java/org/apache/dubbo/common/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,18 @@

import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.ConfigUtils;
import org.apache.dubbo.common.utils.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.CodeSource;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -64,25 +62,38 @@ public final class Version {
private static final Map<String, Integer> VERSION2INT = new HashMap<String, Integer>();

static {
// check if there's duplicated jar
Version.checkDuplicate(Version.class);

// get dubbo version and last commit id
try {
Properties properties =
ConfigUtils.loadProperties(Collections.emptySet(), "META-INF/version");

VERSION = Optional.ofNullable(properties.getProperty("revision"))
.filter(StringUtils::isNotBlank)
.orElseGet(() -> getVersion(Version.class, ""));
LATEST_COMMIT_ID = Optional.ofNullable(properties.getProperty("git.commit.id")).orElse("");
tryLoadVersionFromResource();
checkDuplicate();
} catch (Throwable e) {
logger.warn(COMMON_UNEXPECTED_EXCEPTION, "", "", "continue the old logic, ignore exception " + e.getMessage(), e);
}
if (StringUtils.isEmpty(VERSION)) {
VERSION = getVersion(Version.class, "");
}
if (StringUtils.isEmpty(LATEST_COMMIT_ID)) {
LATEST_COMMIT_ID = "";
}
}

private static void tryLoadVersionFromResource() throws IOException {
Enumeration<URL> configLoader = Version.class.getClassLoader().getResources("META-INF/versions/dubbo-common");
if (configLoader.hasMoreElements()) {
URL url = configLoader.nextElement();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("revision=")) {
VERSION = line.substring("revision=".length());
} else if (line.startsWith("git.commit.id=")) {
LATEST_COMMIT_ID = line.substring("git.commit.id=".length());
}
}
}
}
}

private Version() {
}

Expand Down Expand Up @@ -266,48 +277,75 @@ private static String getFromFile(String file) {
return file;
}

public static void checkDuplicate(Class<?> cls, boolean failOnError) {
checkDuplicate(cls.getName().replace('.', '/') + ".class", failOnError);
private static void checkDuplicate() {
try {
checkArtifacts(loadArtifactIds());
} catch (Throwable e) {
logger.error(COMMON_UNEXPECTED_EXCEPTION, "", "", e.getMessage(), e);
}
}

public static void checkDuplicate(Class<?> cls) {
checkDuplicate(cls, false);
private static void checkArtifacts(Set<String> artifactIds) throws IOException {
if (!artifactIds.isEmpty()) {
for (String artifactId : artifactIds) {
checkArtifact(artifactId);
}
}
}

public static void checkDuplicate(String path, boolean failOnError) {
try {
// search in caller's classloader
Set<String> files = getResources(path);
// duplicated jar is found
if (files.size() > 1) {
String error = "Duplicate class " + path + " in " + files.size() + " jar " + files;
if (failOnError) {
throw new IllegalStateException(error);
} else {
logger.error(COMMON_UNEXPECTED_EXCEPTION, "", "", error);
private static void checkArtifact(String artifactId) throws IOException {
Enumeration<URL> artifactEnumeration = Version.class.getClassLoader().getResources("META-INF/versions/" + artifactId);
while (artifactEnumeration.hasMoreElements()) {
URL url = artifactEnumeration.nextElement();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("#")) {
continue;
}
String[] artifactInfo = line.split("=");
if (artifactInfo.length == 2) {
String key = artifactInfo[0];
String value = artifactInfo[1];
checkVersion(artifactId, url, key, value);
}
}
}
} catch (Throwable e) {
logger.error(COMMON_UNEXPECTED_EXCEPTION, "", "", e.getMessage(), e);
}
}

/**
* search resources in caller's classloader
*/
private static Set<String> getResources(String path) throws IOException {
Enumeration<URL> urls = ClassUtils.getCallerClassLoader(Version.class).getResources(path);
Set<String> files = new HashSet<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url != null) {
String file = url.getFile();
if (StringUtils.isNotEmpty(file)) {
files.add(file);
private static void checkVersion(String artifactId, URL url, String key, String value) {
if ("revision".equals(key) && !value.equals(VERSION)) {
String error = "Inconsistent version " + value + " found in " + artifactId + " from " + url.getPath() + ", " +
"expected dubbo-common version is " + VERSION;
logger.error(COMMON_UNEXPECTED_EXCEPTION, "", "", error);
}
if ("git.commit.id".equals(key) && !value.equals(LATEST_COMMIT_ID)) {
String error = "Inconsistent git build commit id " + value + " found in " + artifactId + " from " + url.getPath() + ", " +
"expected dubbo-common version is " + LATEST_COMMIT_ID;
logger.error(COMMON_UNEXPECTED_EXCEPTION, "", "", error);
}
}

private static Set<String> loadArtifactIds() throws IOException {
Enumeration<URL> artifactsEnumeration = Version.class.getClassLoader().getResources("META-INF/versions/.artifacts");
Set<String> artifactIds = new HashSet<>();
while (artifactsEnumeration.hasMoreElements()) {
URL url = artifactsEnumeration.nextElement();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("#")) {
continue;
}
if (StringUtils.isEmpty(line)) {
continue;
}
artifactIds.add(line);
}
}
}
return files;
return artifactIds;
}

}
Loading

0 comments on commit 412471a

Please sign in to comment.