diff --git a/core b/core index f4a8257154..c9bc84b64e 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit f4a8257154ab26279a20dad3f8fbae5e496f8105 +Subproject commit c9bc84b64e757d42826e45a6dd5b69290da49a54 diff --git a/customization-base/src/main/java/com/azure/autorest/customization/implementation/ls/EclipseLanguageServerFacade.java b/customization-base/src/main/java/com/azure/autorest/customization/implementation/ls/EclipseLanguageServerFacade.java index fb97c69902..c5c61cd9a4 100644 --- a/customization-base/src/main/java/com/azure/autorest/customization/implementation/ls/EclipseLanguageServerFacade.java +++ b/customization-base/src/main/java/com/azure/autorest/customization/implementation/ls/EclipseLanguageServerFacade.java @@ -53,12 +53,9 @@ public EclipseLanguageServerFacade(String pathToLanguageServerPlugin, Logger log if (javaVersion < 17) { // JAR to start v1.12.0 command.add("./plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar"); - } else if (javaVersion < 21) { - // JAR to start v1.29.0 - command.add("./plugins/org.eclipse.equinox.launcher_1.6.500.v20230717-2134.jar"); } else { - // JAR to start v1.31.0 - command.add("./plugins/org.eclipse.equinox.launcher_1.6.700.v20231214-2017.jar"); + // JAR to start v1.39.0 + command.add("./plugins/org.eclipse.equinox.launcher_1.6.900.v20240613-2009.jar"); } command.add("--add-modules=ALL-SYSTEM"); @@ -76,8 +73,7 @@ public EclipseLanguageServerFacade(String pathToLanguageServerPlugin, Logger log } logger.info("Starting Eclipse JDT language server at {}", languageServerPath); - server = new ProcessBuilder(command) - .redirectOutput(ProcessBuilder.Redirect.PIPE) + server = new ProcessBuilder(command).redirectOutput(ProcessBuilder.Redirect.PIPE) .redirectInput(ProcessBuilder.Redirect.PIPE) .redirectErrorStream(true) .directory(languageServerPath.toFile()) @@ -96,23 +92,16 @@ private static Path getLanguageServerDirectory(int javaVersion, Logger logger) t if (javaVersion < 17) { // Eclipse JDT language server version 1.12.0 is the last version that supports Java 11, which is // autorest.java's baseline. - downloadUrl = URI.create(DOWNLOAD_BASE_URL + "1.12.0/jdt-language-server-1.12.0-202206011637.tar.gz") - .toURL(); + downloadUrl + = URI.create(DOWNLOAD_BASE_URL + "1.12.0/jdt-language-server-1.12.0-202206011637.tar.gz").toURL(); languageServerPath = autorestLanguageServer.resolve("1.12.0"); - } else if (javaVersion < 21) { - // Eclipse JDT language server version 1.29.0 is the latest version that supports Java 17. - // In the future this else statement may need to be replaced with an else if as newer versions of - // Eclipse JDT language server may baseline on Java 21 (or later). - downloadUrl = URI.create(DOWNLOAD_BASE_URL + "1.29.0/jdt-language-server-1.29.0-202310261436.tar.gz") - .toURL(); - languageServerPath = autorestLanguageServer.resolve("1.29.0"); } else { - // Eclipse JDT language server version 1.31.0 is the latest version that supports Java 21. + // Eclipse JDT language server version 1.39.0 is the latest version that supports Java 17. // In the future this else statement may need to be replaced with an else if as newer versions of - // Eclipse JDT language server may baseline on Java 25 (or later). - downloadUrl = URI.create(DOWNLOAD_BASE_URL + "1.31.0/jdt-language-server-1.31.0-202401111522.tar.gz") - .toURL(); - languageServerPath = autorestLanguageServer.resolve("1.31.0"); + // Eclipse JDT language server may baseline on Java 21 (or later). + downloadUrl + = URI.create(DOWNLOAD_BASE_URL + "1.39.0/jdt-language-server-1.39.0-202408291433.tar.gz").toURL(); + languageServerPath = autorestLanguageServer.resolve("1.39.0"); } Path languageServer = languageServerPath.resolve("jdt-language-server"); diff --git a/package-lock.json b/package-lock.json index be7b4ec1dd..fc6fb4e5d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@autorest/java", - "version": "4.1.37", + "version": "4.1.38", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@autorest/java", - "version": "4.1.37", + "version": "4.1.38", "license": "MIT", "devDependencies": { "@microsoft.azure/autorest.testserver": "3.3.50", diff --git a/package.json b/package.json index e9997b75d7..b61fc97eb4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@autorest/java", - "version": "4.1.37", + "version": "4.1.38", "description": "The Java extension for classic generators in AutoRest.", "scripts": { "autorest": "autorest", diff --git a/protocol-sdk-integration-tests/.vscode/eclipse-format-azure-sdk-for-java.xml b/protocol-sdk-integration-tests/.vscode/eclipse-format-azure-sdk-for-java.xml new file mode 100644 index 0000000000..7866b52cda --- /dev/null +++ b/protocol-sdk-integration-tests/.vscode/eclipse-format-azure-sdk-for-java.xml @@ -0,0 +1,401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/README.md b/protocol-sdk-integration-tests/eng/code-quality-reports/README.md index 5bda4a678f..fbfed68343 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/README.md +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/README.md @@ -2,3 +2,5 @@ This module defines/configures the rules for code quality analysis tools such as checkstyle and spotbugs. For more information refer to [Checkstyle](https://checkstyle.org/) and [Spotbugs](https://spotbugs.github.io/). + +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-java%2Feng%2Fcode-quality-reports%2FREADME.png) diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/pom.xml b/protocol-sdk-integration-tests/eng/code-quality-reports/pom.xml index 6b1b7869cf..1297b297ca 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/pom.xml +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/pom.xml @@ -1,5 +1,5 @@ - + @@ -31,6 +31,15 @@ + + + + + com.google.guava + guava + 33.1.0-jre + + com.puppycrawl.tools checkstyle @@ -109,17 +118,17 @@ org.apache.maven.plugins maven-site-plugin - 3.7.1 + 3.12.1 org.apache.maven.plugins maven-project-info-reports-plugin - 3.0.0 + 3.5.0 org.apache.maven.plugins maven-surefire-plugin - 3.1.0 + 3.2.5 diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/BlacklistedWordsCheck.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/DenyListedWordsCheck.java similarity index 76% rename from protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/BlacklistedWordsCheck.java rename to protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/DenyListedWordsCheck.java index 35c4cf3308..33be27d49d 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/BlacklistedWordsCheck.java +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/DenyListedWordsCheck.java @@ -10,32 +10,30 @@ import com.puppycrawl.tools.checkstyle.utils.CheckUtil; import com.puppycrawl.tools.checkstyle.utils.ScopeUtil; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import java.util.stream.Collectors; /** - * Ensure that code is not using words or abbreviations that are blacklisted by this Checkstyle. - * blacklistedWords: the words that have been blacklisted in the checkstyle.xml config file - * - * Prints out a message stating the location and the class, method or variable as well as the list - * blacklisted words. + * Ensure that code is not using words or abbreviations that are deny listed by this Checkstyle. denyListedWords: the + * words that have been denied in the checkstyle.xml config file + *

+ * Prints out a message stating the location and the class, method or variable as well as the list of deny listed words. */ -public class BlacklistedWordsCheck extends AbstractCheck { - private final Set blacklistedWords = new HashSet<>(); +public class DenyListedWordsCheck extends AbstractCheck { + private final Set denyListedWords = new HashSet<>(); static final String ERROR_MESSAGE = "%s, All Public API Classes, Fields and Methods should follow " + "Camelcase standards for the following words: %s."; /** * Adds words that Classes, Methods and Variables that should follow Camelcasing standards - * @param blacklistedWords words that should follow normal Camelcasing standards + * + * @param denyListedWords words that should follow normal Camelcasing standards */ - public final void setBlacklistedWords(String... blacklistedWords) { - if (blacklistedWords != null) { - Collections.addAll(this.blacklistedWords, blacklistedWords); + public final void setDenyListedWords(String... denyListedWords) { + if (denyListedWords != null) { + Collections.addAll(this.denyListedWords, denyListedWords); } } @@ -51,7 +49,7 @@ public int[] getAcceptableTokens() { @Override public int[] getRequiredTokens() { - return new int[] {TokenTypes.CLASS_DEF, + return new int[]{TokenTypes.CLASS_DEF, TokenTypes.METHOD_DEF, TokenTypes.VARIABLE_DEF}; } @@ -67,7 +65,7 @@ public void visitToken(DetailAST token) { } final String tokenName = token.findFirstToken(TokenTypes.IDENT).getText(); - if (!hasBlacklistedWords(tokenName)) { + if (!hasDenyListedWords(tokenName)) { break; } @@ -76,7 +74,7 @@ public void visitToken(DetailAST token) { break; } - log(token, String.format(ERROR_MESSAGE, tokenName, String.join(", ", this.blacklistedWords))); + log(token, String.format(ERROR_MESSAGE, tokenName, String.join(", ", this.denyListedWords))); break; default: @@ -100,13 +98,13 @@ private boolean isPublicApi(DetailAST token) { /** * Gets the disallowed abbreviation contained in given String. + * * @param tokenName the given String. - * @return the disallowed abbreviation contained in given String as a - * separate String. + * @return the disallowed abbreviation contained in given String as a separate String. */ - private boolean hasBlacklistedWords(String tokenName) { - for (String blacklistedWord : blacklistedWords) { - if (tokenName.contains(blacklistedWord)) { + private boolean hasDenyListedWords(String tokenName) { + for (String denyListedWord : denyListedWords) { + if (tokenName.contains(denyListedWord)) { return true; } } diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/EnforceFinalFieldsCheck.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/EnforceFinalFieldsCheck.java index 34b71ddc48..f52fe3f70b 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/EnforceFinalFieldsCheck.java +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/EnforceFinalFieldsCheck.java @@ -5,12 +5,17 @@ import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CheckUtil; import com.puppycrawl.tools.checkstyle.utils.TokenUtil; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Set; /** @@ -19,7 +24,7 @@ * nonFinalFields: keep an array of non private fields as tokens (to keep line number) * assignmentsFromConstructor: Save a set of string for each field name that gets its value assigned in constructor * assignmentsFromMethods: Save a set of strings for each field name that gets updated in any method - * + *

* On finish tree, check what non-final fields get a value only in constructor and nowhere else by looking for * strings inside nonFinalFields AND assignmentsFromConstructor but NOT in assignmentsFromMethods */ @@ -36,6 +41,7 @@ public class EnforceFinalFieldsCheck extends AbstractCheck { private Set assignmentsFromMethods; private DetailAST scopeParent = null; private Set currentScopeParameterSet = null; + private Map variablesInScope = null; private String currentClassName = null; @Override @@ -108,6 +114,7 @@ public void visitToken(DetailAST token) { case TokenTypes.METHOD_DEF: case TokenTypes.CTOR_DEF: scopeParent = token; + variablesInScope = new HashMap<>(); break; default: // Checkstyle complains if there's no default block in switch @@ -122,6 +129,7 @@ public void leaveToken(DetailAST token) { case TokenTypes.CTOR_DEF: scopeParent = null; currentScopeParameterSet = null; + variablesInScope = null; break; default: break; @@ -160,6 +168,15 @@ private DetailAST getAssignedField(final DetailAST assignationToken) { token -> token.getText().equals(this.currentClassName)).isPresent()) { // Case when referencing same class for private static fields return assignationWithDot.getLastChild(); + } else if (assignationWithDot.getFirstChild().getType() == TokenTypes.IDENT) { + // Case where setting a field on a variable. + String variableNameToken = assignationWithDot.getFirstChild().getText(); + DetailAST variableDeclaration = variablesInScope.get(variableNameToken); + DetailAST parentScope = getParentScope(assignationToken); + if (variableDeclaration != null && parentScope != null + && CheckUtil.isBeforeInSource(variableDeclaration, parentScope)) { + return assignationWithDot.getLastChild(); + } } } else { final DetailAST variableNameToken = assignationToken.getFirstChild(); @@ -172,6 +189,17 @@ private DetailAST getAssignedField(final DetailAST assignationToken) { return null; } + private static DetailAST getParentScope(DetailAST ast) { + DetailAST parent = ast.getParent(); + do { + if (parent.getType() == TokenTypes.SLIST) { + return parent; + } + } while ((parent = parent.getParent()) != null); + + return null; + } + /* * Saves a field name to a container depending on the provided type */ @@ -197,7 +225,12 @@ private void checkAssignation(final DetailAST assignationToken) { final DetailAST assignationParent = assignationToken.getParent(); if (assignationParent != null && TokenTypes.VARIABLE_DEF == assignationParent.getType()) { - // Assignation for a variable definition. No need to check this assignation + String variableType = FullIdent.createFullIdentBelow(assignationParent.findFirstToken(TokenTypes.TYPE)).getText(); + if (Objects.equals(currentClassName, variableType)) { + // Track variable definitions of the class we're currently in. + variablesInScope.put(assignationParent.findFirstToken(TokenTypes.IDENT).getText(), assignationParent); + } + return; } diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ExternalDependencyExposedCheck.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ExternalDependencyExposedCheck.java index 0cc3238066..4271830977 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ExternalDependencyExposedCheck.java +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ExternalDependencyExposedCheck.java @@ -10,12 +10,8 @@ import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifierOption; import com.puppycrawl.tools.checkstyle.utils.CheckUtil; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; /** * No external dependency exposed in public API @@ -23,9 +19,6 @@ public class ExternalDependencyExposedCheck extends AbstractCheck { private static final String EXTERNAL_DEPENDENCY_ERROR = "Class ''%s'', is a class from external dependency. You should not use it as a %s type."; - private static final Set VALID_DEPENDENCY_SET = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( - "java", "com.azure", "reactor", "org.reactivestreams" - ))); private final Map simpleClassNameToQualifiedNameMap = new HashMap<>(); @@ -198,7 +191,12 @@ private boolean isValidClassDependency(String typeName) { } final String qualifiedName = simpleClassNameToQualifiedNameMap.get(typeName); - return VALID_DEPENDENCY_SET.stream() - .anyMatch(validPackageName -> qualifiedName.startsWith(validPackageName)); + + return "com.azure.".regionMatches(0, qualifiedName, 0, 10) + || "io.clientcore.".regionMatches(0, qualifiedName, 0, 14) + || "java.".regionMatches(0, qualifiedName, 0, 5) + || "javax.".regionMatches(0, qualifiedName, 0, 6) + || "reactor.".regionMatches(0, qualifiedName, 0, 8) + || "org.reactivestreams.".regionMatches(0, qualifiedName, 0, 20); } } diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/GoodLoggingCheck.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/GoodLoggingCheck.java index 5eef8042d3..18f48a3ff6 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/GoodLoggingCheck.java +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/GoodLoggingCheck.java @@ -35,13 +35,13 @@ public class GoodLoggingCheck extends AbstractCheck { private static final int[] REQUIRED_TOKENS = new int[]{ TokenTypes.IMPORT, TokenTypes.INTERFACE_DEF, + TokenTypes.ENUM_DEF, TokenTypes.CLASS_DEF, TokenTypes.LITERAL_NEW, TokenTypes.VARIABLE_DEF, TokenTypes.METHOD_CALL }; - static final String STATIC_LOGGER_ERROR = "Use a static ClientLogger instance in a static method."; static final String LOGGER_NAME_ERROR = "ClientLogger instance naming: use \"%s\" instead of \"%s\" for consistency."; static final String NOT_CLIENT_LOGGER_ERROR = "Do not use %s class. Use \"%s\" as a logging mechanism instead of \"%s\"."; static final String LOGGER_NAME_MISMATCH_ERROR = "Not newing a ClientLogger with matching class name. Use \"%s.class\" " @@ -78,7 +78,9 @@ public void finishTree(DetailAST ast) { @Override public void leaveToken(DetailAST ast) { - if (ast.getType() == TokenTypes.CLASS_DEF) { + if (ast.getType() == TokenTypes.CLASS_DEF + || ast.getType() == TokenTypes.INTERFACE_DEF + || ast.getType() == TokenTypes.ENUM_DEF) { classNameDeque.poll(); } } @@ -98,6 +100,7 @@ public void visitToken(DetailAST ast) { break; case TokenTypes.CLASS_DEF: case TokenTypes.INTERFACE_DEF: + case TokenTypes.ENUM_DEF: classNameDeque.offer(ast.findFirstToken(TokenTypes.IDENT).getText()); break; case TokenTypes.LITERAL_NEW: diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ImmutableClassCheck.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ImmutableClassCheck.java new file mode 100644 index 0000000000..dd250dce15 --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ImmutableClassCheck.java @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.tools.checkstyle.checks; + +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.Scope; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil; +import com.puppycrawl.tools.checkstyle.utils.ScopeUtil; + +import java.util.Stack; + +/** + * Verify the classes with annotation {@code @Immutable} should have the following rules: + *

    + *
  1. No public or protected fields
  2. + *
  3. No public or protected setter methods
  4. + *
+ */ +public class ImmutableClassCheck extends AbstractCheck { + private static final String IMMUTABLE_NOTATION = "Immutable"; + + static final String PUBLIC_FIELD_ERROR_TEMPLATE = + "Classes annotated with @Immutable cannot have non-final public or protect fields. " + + "Found non-final public field: %s."; + static final String SETTER_METHOD_ERROR_TEMPLATE = + "Classes annotated with @Immutable cannot have public or protected setter methods. " + + "Found public setter method: %s."; + + private Stack hasImmutableAnnotationStack; + + @Override + public int[] getDefaultTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { + return new int[]{ + TokenTypes.CLASS_DEF, + TokenTypes.VARIABLE_DEF, + TokenTypes.METHOD_DEF + }; + } + + @Override + public void beginTree(DetailAST root) { + hasImmutableAnnotationStack = new Stack<>(); + } + + @Override + public void visitToken(DetailAST token) { + switch (token.getType()) { + case TokenTypes.CLASS_DEF: + hasImmutableAnnotationStack.add(hasImmutableAnnotation(token)); + break; + + case TokenTypes.VARIABLE_DEF: + if (!hasImmutableAnnotationStack.isEmpty() && hasImmutableAnnotationStack.peek()) { + checkForPublicField(token); + } + break; + + case TokenTypes.METHOD_DEF: + if (!hasImmutableAnnotationStack.isEmpty() && hasImmutableAnnotationStack.peek()) { + checkForSetterMethod(token); + } + break; + + default: + // Checkstyle complains if there's no default block in switch + break; + } + } + + @Override + public void leaveToken(DetailAST ast) { + if (ast.getType() == TokenTypes.CLASS_DEF && !hasImmutableAnnotationStack.isEmpty()) { + hasImmutableAnnotationStack.pop(); + } + } + + /* + * Checks if the class is annotated with annotation {@literal @Immutable}. A class could have multiple annotations. + * + * @param classDefToken the CLASS_DEF AST node + * @return true if the class is annotated with {@literal @Immutable}, false otherwise. + */ + private static boolean hasImmutableAnnotation(DetailAST classDefinition) { + DetailAST immutableAnnotation = AnnotationUtil.getAnnotation(classDefinition, IMMUTABLE_NOTATION); + return immutableAnnotation != null; + } + + private void checkForPublicField(DetailAST variableDefinition) { + DetailAST modifiers = variableDefinition.findFirstToken(TokenTypes.MODIFIERS); + + // Field has no modifiers or is final, therefore it's immutable for all intents and purposes. + if (modifiers == null || modifiers.findFirstToken(TokenTypes.FINAL) != null) { + return; + } + + if (isScopeAndSurroundingScopePublic(variableDefinition)) { + // Field is 'public' or 'protected', immutable classes cannot have public fields. + log(variableDefinition, String.format(PUBLIC_FIELD_ERROR_TEMPLATE, + variableDefinition.findFirstToken(TokenTypes.IDENT).getText())); + } + } + + private void checkForSetterMethod(DetailAST methodDefinition) { + String methodName = methodDefinition.findFirstToken(TokenTypes.IDENT).getText(); + + if (!isSetterMethod(methodName)) { + return; + } + + if (isScopeAndSurroundingScopePublic(methodDefinition)) { + // Setter method is 'public' or 'protected', immutable classes cannot have public setters. + log(methodDefinition, String.format(SETTER_METHOD_ERROR_TEMPLATE, methodName)); + } + } + + private static boolean isSetterMethod(String methodName) { + return methodName.startsWith("set") && methodName.length() >= 4 && Character.isUpperCase(methodName.charAt(3)); + } + + private static boolean isScopeAndSurroundingScopePublic(DetailAST detailAST) { + Scope scope = ScopeUtil.getScope(detailAST); + Scope surroundingScope = ScopeUtil.getSurroundingScope(detailAST); + + return (scope == Scope.PUBLIC || scope == Scope.PROTECTED) + && (surroundingScope == Scope.PUBLIC || surroundingScope == Scope.PROTECTED); + } +} diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/JavadocThrowsChecks.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/JavadocThrowsChecks.java index e157bf2bab..d0fde3be06 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/JavadocThrowsChecks.java +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/JavadocThrowsChecks.java @@ -17,6 +17,9 @@ import java.util.HashSet; import java.util.Map; +/** + * Verifies that all throws in the public API have JavaDocs explaining why and when they are thrown. + */ public class JavadocThrowsChecks extends AbstractCheck { static final String MISSING_DESCRIPTION_MESSAGE = "@throws tag requires a description explaining when the error is thrown."; diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/NoImplInPublicAPI.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/NoImplInPublicAPI.java index 33d9d643b1..0398c34931 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/NoImplInPublicAPI.java +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/NoImplInPublicAPI.java @@ -17,6 +17,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +/** + * Verifies that: + * 1) no return classes are from the implementation package + * 2) no class of implementation package as method's parameters + */ public class NoImplInPublicAPI extends AbstractCheck { private static final String ALTERNATIVE_MOVE_TO_PUBLIC_API = "Alternatively, it can be removed from the " + "implementation package and made public API, after appropriate API review."; diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/OnlyFinalFieldsForImmutableClassCheck.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/OnlyFinalFieldsForImmutableClassCheck.java deleted file mode 100644 index 916c753385..0000000000 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/OnlyFinalFieldsForImmutableClassCheck.java +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.tools.checkstyle.checks; - -import com.puppycrawl.tools.checkstyle.api.AbstractCheck; -import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil; -import com.puppycrawl.tools.checkstyle.utils.TokenUtil; - -import java.util.Optional; - -/** - * Verify the classes with annotation {@code @Immutable} should have following rules: - *
    - *
  1. Only final fields allowed
  2. - *
- */ -public class OnlyFinalFieldsForImmutableClassCheck extends AbstractCheck { - private static final String IMMUTABLE_NOTATION = "Immutable"; - private static final String ERROR_MSG = "The variable field ''%s'' should be final." - + "Classes annotated with @Immutable are supposed to be immutable."; - - private boolean hasImmutableAnnotation; - - @Override - public int[] getDefaultTokens() { - return getRequiredTokens(); - } - - @Override - public int[] getAcceptableTokens() { - return getRequiredTokens(); - } - - @Override - public int[] getRequiredTokens() { - return new int[] { - TokenTypes.CLASS_DEF, - TokenTypes.OBJBLOCK - }; - } - - @Override - public void beginTree(DetailAST root) { - hasImmutableAnnotation = false; - } - - @Override - public void visitToken(DetailAST token) { - switch (token.getType()) { - case TokenTypes.CLASS_DEF: - hasImmutableAnnotation = hasImmutableAnnotation(token); - break; - case TokenTypes.OBJBLOCK: - if (hasImmutableAnnotation) { - checkForOnlyFinalFields(token); - } - break; - default: - // Checkstyle complains if there's no default block in switch - break; - } - } - - /* - * Checks if the class is annotated with annotation {@literal @Immutable}. A class could have multiple annotations. - * - * @param classDefToken the CLASS_DEF AST node - * @return true if the class is annotated with {@literal @Immutable}, false otherwise. - */ - private boolean hasImmutableAnnotation(DetailAST classDefToken) { - DetailAST immutableAnnotation = AnnotationUtil.getAnnotation(classDefToken, IMMUTABLE_NOTATION); - return immutableAnnotation != null; - } - - /* - * Checks all field definitions within the first level of a class are final - * - * @param objBlockToken the OBJBLOCK AST node - */ - private void checkForOnlyFinalFields(DetailAST objBlockToken) { - Optional nonFinalFieldFound = TokenUtil.findFirstTokenByPredicate(objBlockToken, - node -> TokenTypes.VARIABLE_DEF == node.getType() && !node.branchContains(TokenTypes.FINAL) - && !Utils.hasIllegalCombination(node.findFirstToken(TokenTypes.MODIFIERS))); - - if (nonFinalFieldFound.isPresent()) { - DetailAST field = nonFinalFieldFound.get().findFirstToken(TokenTypes.IDENT); - log(field, String.format(ERROR_MSG, field.getText())); - } - } - -} diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/StepVerifierCheck.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/StepVerifierCheck.java new file mode 100644 index 0000000000..a92bf04f6f --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/StepVerifierCheck.java @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.tools.checkstyle.checks; + +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +/** + * Ensures that test code doesn't use {@code StepVerifier.setDefaultTimeout}. + *

+ * This configures a default timeout used by all {@code StepVerifier} calls, which can lead to flaky tests as this may + * affect other tests. + */ +public class StepVerifierCheck extends AbstractCheck { + private static final String SET_DEFAULT_TIMEOUT = "setDefaultTimeout"; + private static final String FULLY_QUALIFIED = "reactor.test.StepVerifier.setDefaultTimeout"; + private static final String METHOD_CALL = "StepVerifier.setDefaultTimeout"; + + static final String ERROR_MESSAGE = "Do not use StepVerifier.setDefaultTimeout as it can affect other tests. " + + "Instead use expect* methods on StepVerifier and use verify(Duration) to " + + "set timeouts on a test-by-test basis."; + + private boolean hasStaticImport; + + @Override + public int[] getDefaultTokens() { + return new int[]{ + TokenTypes.METHOD_CALL, + TokenTypes.STATIC_IMPORT + }; + } + + @Override + public int[] getAcceptableTokens() { + return getDefaultTokens(); + } + + @Override + public int[] getRequiredTokens() { + return getDefaultTokens(); + } + + @Override + public void init() { + super.init(); + hasStaticImport = false; + } + + @Override + public void destroy() { + super.destroy(); + hasStaticImport = false; + } + + @Override + public void visitToken(DetailAST ast) { + if (ast.getType() == TokenTypes.STATIC_IMPORT) { + // Compare if the static import is for StepVerifier.setDefaultTimeout + hasStaticImport = FULLY_QUALIFIED.equals( + FullIdent.createFullIdent(ast.getFirstChild().getNextSibling()).getText()); + } else { + // Compare the method call against StepVerifier.setDefaultTimeout or setDefaultTimeout if there is a static + // import for StepVerifier.setDefaultTimeout + FullIdent fullIdent = FullIdent.createFullIdentBelow(ast); + if (hasStaticImport && SET_DEFAULT_TIMEOUT.equals(fullIdent.getText())) { + log(ast.getLineNo(), fullIdent.getColumnNo(), ERROR_MESSAGE); + } else if (METHOD_CALL.equals(fullIdent.getText())) { + log(ast.getLineNo(), fullIdent.getColumnNo(), ERROR_MESSAGE); + } else if (FULLY_QUALIFIED.equals(fullIdent.getText())) { + log(ast.getLineNo(), fullIdent.getColumnNo(), ERROR_MESSAGE); + } + } + } +} diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/UseCaughtExceptionCauseCheck.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/UseCaughtExceptionCauseCheck.java new file mode 100644 index 0000000000..5598892b87 --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/UseCaughtExceptionCauseCheck.java @@ -0,0 +1,201 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.tools.checkstyle.checks; + +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * This check ensures that an exception thrown includes the current caught exception cause. + * New exception should use the original/cause exception object to provide the full stack trace for the problem. + * + * // DO + * try { + * url = new URL(urlString); + * } catch (MalformedURLException ex) { + * throw new RuntimeException(ex); + * } + * + * // DON'T + * try { + * url = new URL(urlString); + * } catch (MalformedURLException ex) { + * throw new RuntimeException("Invalid URL string was given."); // "ex" is ignored. + * } + */ +public class UseCaughtExceptionCauseCheck extends AbstractCheck { + static final String UNUSED_CAUGHT_EXCEPTION_ERROR = "Caught and rethrown exceptions should include the caught" + + " exception as the cause in the rethrown exception. Dropping the causal exception makes it more difficult" + + " to troubleshoot issues when they arise. Include the caught exception variable %s as the cause."; + + @Override + public int[] getDefaultTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { + return new int[] {TokenTypes.LITERAL_CATCH}; + } + + @Override + public void visitToken(DetailAST catchBlockToken) { + // get the caught exception variable name from the catch block + final DetailAST catchStatement = catchBlockToken.findFirstToken(TokenTypes.PARAMETER_DEF); + final String caughtExceptionVariableName = catchStatement.findFirstToken(TokenTypes.IDENT).getText(); + + // get all throw statements from current catch block + final List throwStatements = getThrowStatements(catchBlockToken); + + // get possible exception names to which the original exception might be assigned to + final List wrappedExceptions = + getWrappedExceptions(catchBlockToken, catchBlockToken, caughtExceptionVariableName); + + throwStatements.forEach(throwToken -> { + final List throwParamNames = new LinkedList<>(); + getThrowParamNames(throwToken, throwParamNames); + // include the original exception name to the list to look for in throw statements + wrappedExceptions.add(caughtExceptionVariableName); + + // throwParamNames = [ex, p] + // exceptionsList = [ex, cause] + // Caught exception variable is used if an intersection is between the throw statements param names + // used and the actual exception names being thrown. + List intersect = + wrappedExceptions.stream().filter(throwParamNames::contains).collect(Collectors.toList()); + if (intersect.size() == 0) { + log(throwToken, String.format(UNUSED_CAUGHT_EXCEPTION_ERROR, caughtExceptionVariableName)); + } + }); + } + + /** + * Returns the list of exceptions that wrapped the current exception tokens + * + * @param currentCatchAST current catch block token + * @param detailAST catch block throw parent token + * @param caughtExceptionVariableName list containing the exception tokens + * @return list of wrapped exception tokens + */ + private List getWrappedExceptions(DetailAST currentCatchAST, DetailAST detailAST, + String caughtExceptionVariableName) { + + final List wrappedExceptionNames = new LinkedList<>(); + + for (DetailAST currentNode : getChildrenNodes(detailAST)) { + // Recursively traverse through the children of the parent node to collect references where the + // caught exception variable is used. + if (currentNode.getType() == TokenTypes.IDENT + && currentNode.getText().equals(caughtExceptionVariableName)) { + getWrappedExceptionVariable(currentCatchAST, wrappedExceptionNames, currentNode); + } + + // add collection in case of last node on this level + if (currentNode.getFirstChild() != null) { + wrappedExceptionNames.addAll( + getWrappedExceptions(currentCatchAST, currentNode, caughtExceptionVariableName)); + } + } + return wrappedExceptionNames; + } + + /** + * Returns the wrapped exception variable name + */ + private void getWrappedExceptionVariable(DetailAST currentCatchBlock, List wrappedExceptionNames, + DetailAST currentToken) { + DetailAST temp = currentToken; + + // Get the node assigning the caught exception variable, traversing upwards starting from the current node. + while (!temp.equals(currentCatchBlock) && temp.getType() != TokenTypes.ASSIGN) { + temp = temp.getParent(); + } + + if (temp.getType() == TokenTypes.ASSIGN) { + final DetailAST wrappedException; + // Get the variable definition param name to which the caught exception variable is assigned. + if (temp.getParent().getType() == TokenTypes.VARIABLE_DEF) { + wrappedException = temp.getParent().findFirstToken(TokenTypes.IDENT); + } else if (temp.findFirstToken(TokenTypes.DOT) != null) { + // Get the variable name if assigned to a 'this' variable + wrappedException = temp.findFirstToken(TokenTypes.DOT).findFirstToken(TokenTypes.IDENT); + } else { + wrappedException = temp.findFirstToken(TokenTypes.IDENT); + } + if (wrappedException != null) { + wrappedExceptionNames.add(wrappedException.getText()); + } + } + } + + /** + * Returns the parameter names for current throw keyword. + * + * @param throwParent The parent throw token + * @param paramNames The list containing the parameter names + * @return list of throw param names + */ + private List getThrowParamNames(DetailAST throwParent, List paramNames) { + // get all param names by recursively going through all the throw statements retrieving the token type IDENT + // for the text + getChildrenNodes(throwParent).forEach(currentNode -> { + if (currentNode.getType() == TokenTypes.IDENT) { + paramNames.add(currentNode.getText()); + } + if (currentNode.getFirstChild() != null) { + getThrowParamNames(currentNode, paramNames); + } + }); + return paramNames; + } + + /** + * Recursive method that searches for all the LITERAL_THROW on the current catch token. + * + * @param catchBlockToken A start token. + * @return list of throw tokens + */ + private List getThrowStatements(DetailAST catchBlockToken) { + final List throwStatements = new LinkedList<>(); + getChildrenNodes(catchBlockToken).forEach(currentNode -> { + if (TokenTypes.LITERAL_THROW == currentNode.getType()) { + throwStatements.add(currentNode); + } + if (currentNode.getFirstChild() != null) { + throwStatements.addAll(getThrowStatements(currentNode)); + } + }); + return throwStatements; + } + + /** + * Gets all the children by traversing the tree generated from the current parent node. + * + * @param token parent node. + * @return List of children of the current node. + */ + private static List getChildrenNodes(DetailAST token) { + final List result = new LinkedList<>(); + + DetailAST currNode = token.getFirstChild(); + + // Add all the nodes on the current level of the tree and then move to the next level + while (currNode != null) { + result.add(currNode); + currNode = currNode.getNextSibling(); + } + + return result; + } +} diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/Utils.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/Utils.java index 903c0a706d..96cfc89b06 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/Utils.java +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/Utils.java @@ -8,10 +8,7 @@ import com.puppycrawl.tools.checkstyle.utils.TokenUtil; import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; import java.util.Optional; -import java.util.Set; /** * Common utils amount custom checks @@ -19,22 +16,34 @@ public class Utils { /* * Set of modifiers that cannot be combined with final because it causes a violation. + * + * This is an int array instead of a Set as there are so few values and cache locality is better. */ - private static final Set INVALID_FINAL_COMBINATION = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( - TokenTypes.LITERAL_TRANSIENT, - TokenTypes.LITERAL_VOLATILE, - TokenTypes.LITERAL_DEFAULT, - TokenTypes.LITERAL_PROTECTED - ))); + private static final int[] INVALID_FINAL_COMBINATION; /* - * Set of annotations that cannot be combined with modifier 'final' because it would break serialization. + * Set of annotations that cannot be combined with modified 'final' because it would break serialization. + * + * This is a String array instead of a Set as there are so few values and cache locality is better. */ - private static final Set INVALID_FINAL_ANNOTATIONS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( - "JsonProperty", - "JsonAlias", - "JacksonXmlProperty" - ))); + private static final String[] INVALID_FINAL_ANNOTATIONS; + + static { + INVALID_FINAL_COMBINATION = new int[] { + TokenTypes.LITERAL_TRANSIENT, + TokenTypes.LITERAL_VOLATILE, + TokenTypes.LITERAL_DEFAULT, + TokenTypes.LITERAL_PROTECTED + }; + Arrays.sort(INVALID_FINAL_COMBINATION); + + INVALID_FINAL_ANNOTATIONS = new String[] { + "JacksonXmlProperty", + "JsonAlias", + "JsonProperty" + }; + Arrays.sort(INVALID_FINAL_ANNOTATIONS); + } /** * Check if variable modifiers contains any of the illegal combination with final modifier @@ -51,10 +60,19 @@ protected static boolean hasIllegalCombination(DetailAST modifiers) { Optional illegalCombination = TokenUtil.findFirstTokenByPredicate(modifiers, (node) -> { final int type = node.getType(); - return INVALID_FINAL_COMBINATION.contains(node.getType()) || (TokenTypes.ANNOTATION == type - && INVALID_FINAL_ANNOTATIONS.contains(node.findFirstToken(TokenTypes.IDENT).getText())); + + return invalidFinalCombination(type) || invalidFinalAnnotation(type, node); }); return illegalCombination.isPresent(); } + + private static boolean invalidFinalCombination(int type) { + return Arrays.binarySearch(INVALID_FINAL_COMBINATION, type) != -1; + } + + private static boolean invalidFinalAnnotation(int type, DetailAST ast) { + return type == TokenTypes.ANNOTATION + && Arrays.binarySearch(INVALID_FINAL_ANNOTATIONS, ast.findFirstToken(TokenTypes.IDENT).getText(), String::compareTo) != -1; + } } diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/filters/AzureSdkFilter.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/filters/AzureSdkFilter.java new file mode 100644 index 0000000000..1cf50aafb3 --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/filters/AzureSdkFilter.java @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.tools.checkstyle.filters; + +import com.puppycrawl.tools.checkstyle.api.AuditEvent; +import com.puppycrawl.tools.checkstyle.api.Filter; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A Checkstyle filter that filters out common Checkstyle violations that should be ignored by all SDKs. + *

+ * The following violations are ignored: + * + *

    + *
  • ExternalDependencyExposed checks in implementation code
  • + *
  • Missing Javadoc comments in sample and test code
  • + *
  • Star imports in test code
  • + *
  • Nested blocks in test code
  • + *
  • Azure SDK Checkstyle checks in sample and test code
  • + *
  • Missing package-info in sample and test code
  • + *
  • Line length in sample and test code
  • + *
  • Equals avoid null in sample code
  • + *
+ */ +public class AzureSdkFilter implements Filter { + // Pattern that matches sample, test, and test-shared files. + // This will capture the file type (sample, test, or test-shared) in group 1, which removes the need for multiple + // Patterns to match whether the file is a sample, test, or test-shared file to improve performance. + private static final Pattern SAMPLE_OR_TEST_FILE_PATTERN + = Pattern.compile(".*src[/\\\\](samples|test|test-shared)[/\\\\]java[/\\\\].*\\.java$"); + + // Pattern that matches implementation files. + private static final Pattern IMPLEMENTATION_FILE_PATTERN + = Pattern.compile(".*src[/\\\\].*[/\\\\]implementation[/\\\\].*\\.java$"); + + // The package name prefix for Azure SDK Checkstyle checks + private static final String AZURE_SDK_CHECK_START = "com.azure.tools.checkstyle.checks."; + + // The ExternalDependencyExposed Azure SDK Checkstyle check + private static final String EXTERNAL_DEPENDENCY_EXPOSED = AZURE_SDK_CHECK_START + "ExternalDependencyExposed"; + + @Override + public boolean accept(AuditEvent event) { + boolean shouldSkip = isIgnoredImplementation(event) || isIgnoredSampleOrTest(event); + + return !shouldSkip; + } + + private static boolean isIgnoredSampleOrTest(AuditEvent event) { + Matcher matcher = SAMPLE_OR_TEST_FILE_PATTERN.matcher(event.getFileName()); + + if (!matcher.matches()) { + // Not a test or sample file, so don't filter + return false; + } + + boolean isTestFile = matcher.group(1).startsWith("test"); + + String violation = event.getViolation().getSourceName(); + + if (violation.contains("Javadoc")) { + // Ignore missing Javadoc comments in test code + return true; + } else if (isTestFile && violation.contains("AvoidStarImport")) { + // Ignore star imports in test code + return true; + } else if (isTestFile && violation.contains("AvoidNestedBlocks")) { + // Ignore nested blocks in test code + return true; + } else if (violation.startsWith(AZURE_SDK_CHECK_START)) { + // Ignore Azure SDK Checkstyle checks in sample and test code + return true; + } else if (violation.contains("LineLength")) { + // Ignore line length in sample and test code + return true; + } else if (!isTestFile && violation.contains("EqualsAvoidNull")) { + // Ignore equals avoid null in sample code + return true; + } + + return false; + } + + private static boolean isIgnoredImplementation(AuditEvent event) { + Matcher matcher = IMPLEMENTATION_FILE_PATTERN.matcher(event.getFileName()); + + if (!matcher.matches()) { + // Not an implementation file, so don't filter + return false; + } + + String violation = event.getViolation().getSourceName(); + + return violation.startsWith(EXTERNAL_DEPENDENCY_EXPOSED); + } +} diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/filters/package-info.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/filters/package-info.java new file mode 100644 index 0000000000..0fba146619 --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/filters/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * This package contains classes for custom Checkstyle filters. + */ +package com.azure.tools.checkstyle.filters; diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/AzureSdkAllowedExternalApis.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/AzureSdkAllowedExternalApis.java new file mode 100644 index 0000000000..0ca3a54187 --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/AzureSdkAllowedExternalApis.java @@ -0,0 +1,165 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.tools.revapi.transforms; + +import org.revapi.Difference; +import org.revapi.Element; +import org.revapi.TransformationResult; +import org.revapi.base.BaseDifferenceTransform; +import org.revapi.java.spi.JavaTypeElement; + +import javax.annotation.Nullable; +import javax.lang.model.element.NestingKind; +import javax.lang.model.element.TypeElement; +import java.util.regex.Pattern; + +public final class AzureSdkAllowedExternalApis> extends BaseDifferenceTransform { + private static final Pattern DIFFERENCE_CODE_PATTERN = Pattern.compile("java.class.externalClassExposedInAPI", + Pattern.LITERAL); + + @Override + public Pattern[] getDifferenceCodePatterns() { + return new Pattern[] { DIFFERENCE_CODE_PATTERN }; + } + + @Override + public TransformationResult tryTransform(@Nullable E oldElement, @Nullable E newElement, Difference difference) { + if (newElement == null) { + // Missing element to compare. + return TransformationResult.keep(); + } + + if (!(newElement instanceof JavaTypeElement)) { + // Unknown element type. + return TransformationResult.keep(); + } + + TypeElement outermostElement = findOuterMostClass(((JavaTypeElement) newElement).getDeclaringElement()); + ExternalApiStatus shouldBeIgnored = shouldExternalApiBeIgnored(outermostElement); + + return shouldBeIgnored.ignore ? TransformationResult.discard() : TransformationResult.keep(); + } + + @Override + public String getExtensionId() { + return "azure-sdk-allowed-external-apis"; + } + + private static TypeElement findOuterMostClass(javax.lang.model.element.Element el) { + while (el != null && !(el instanceof TypeElement)) { + el = el.getEnclosingElement(); + } + + if (el == null) { + return null; + } + + return ((TypeElement) el).getNestingKind() == NestingKind.TOP_LEVEL + ? (TypeElement) el + : findOuterMostClass(el.getEnclosingElement()); + } + + + + private static ExternalApiStatus shouldExternalApiBeIgnored(TypeElement element) { + if (element == null) { + return ExternalApiStatus.KEEP; + } + + String className = element.getQualifiedName().toString(); + + if (className.startsWith("com.")) { + if ("azure.".regionMatches(0, className, 4, 6)) { + if ("communication.common.".regionMatches(0, className, 10, 21) + || "core.".regionMatches(0, className, 10, 5) + || "cosmos.".regionMatches(0, className, 10, 7) + || "data.schemaregistry.".regionMatches(0, className, 10, 20) + || "data.appconfiguration.".regionMatches(0, className, 10, 22) + || "identity.".regionMatches(0, className, 10, 9) + || "json.".regionMatches(0, className, 10, 5) + || "messaging.eventgrid.".regionMatches(0, className, 10, 20) + || "messaging.eventhubs.".regionMatches(0, className, 10, 20) + || "messaging.servicebus.".regionMatches(0, className, 10, 21) + || "resourcemanager.".regionMatches(0, className, 10, 16) + || "security.keyvault.".regionMatches(0, className, 10, 18) + || "spring.cloud.appconfiguration.config.".regionMatches(0, className, 10, 20) + || "spring.cloud.feature.".regionMatches(0, className, 10, 21) + || "storage.".regionMatches(0, className, 10, 8) + || "xml.".regionMatches(0, className, 10, 4)) { + return ExternalApiStatus.SDK_CLASSES; + } else if ("perf.test.core.".regionMatches(0, className, 10, 15)) { + return ExternalApiStatus.PERF_TEST; + } else if (className.length() == 53 + && className.endsWith("spring.cloud.config.AppConfigurationRefresh")) { + return ExternalApiStatus.APP_CONFIGURATION_REFRESH; + } + } else if ("mysql.cj.".regionMatches(0, className, 4, 9)) { + return ExternalApiStatus.MYSQL_CJ; + } + } else if (className.startsWith("io.")) { + if ("cloudevents.".regionMatches(0, className, 3, 12)) { + return ExternalApiStatus.CLOUD_EVENTS; + } else if ("opentelemetry.".regionMatches(0, className, 3, 14)) { + return ExternalApiStatus.OPEN_TELEMETRY; + } else if ("clientcore.".regionMatches(0, className, 3, 10)) { + return ExternalApiStatus.SDK_CLASSES; + } + } else if (className.startsWith("org.")) { + if ("json.".regionMatches(0, className, 4, 5)) { + return ExternalApiStatus.ORG_JSON; + } else if ("postgresql.".regionMatches(0, className, 4, 11)) { + return ExternalApiStatus.POSTGRESQL; + } else if ("reactivestreams.".regionMatches(0, className, 4, 16)) { + return ExternalApiStatus.REACTIVE_STREAMS; + } else if (className.length() == 37 && className.endsWith("springframework.util.ErrorHandler")) { + return ExternalApiStatus.SPRING_ERROR_HANDLER; + } + } else if (className.startsWith("redis.clients.jedis")) { + return ExternalApiStatus.JEDIS; + } + + return ExternalApiStatus.KEEP; + } + + private static final class ExternalApiStatus { + private static final ExternalApiStatus KEEP = new ExternalApiStatus(false); + private static final ExternalApiStatus MYSQL_CJ = new ExternalApiStatus("Mysql driver classes are allowed to " + + "be exposed by dependencies using them."); + private static final ExternalApiStatus SDK_CLASSES = new ExternalApiStatus("SDK classes are allowed to be " + + "exposed by dependencies using them."); + private static final ExternalApiStatus PERF_TEST = new ExternalApiStatus("perf-test classes are allowed to be " + + "exposed."); + private static final ExternalApiStatus APP_CONFIGURATION_REFRESH = new ExternalApiStatus("This isn't an " + + "external class"); + private static final ExternalApiStatus CLOUD_EVENTS = new ExternalApiStatus("Azure Event Grid cloud native " + + "cloud event is allowed to use CloudEvents types in public APIs as it implements interfaces defined by " + + "CloudEvents"); + private static final ExternalApiStatus OPEN_TELEMETRY = new ExternalApiStatus("Azure Monitor Exporter is " + + "allowed to use OpenTelemetry types in public APIs as it implements interfaces defined by OpenTelemetry"); + private static final ExternalApiStatus ORG_JSON = new ExternalApiStatus("To support the EventHubs " + + "JedisRedisCheckpointStore constructor"); + private static final ExternalApiStatus POSTGRESQL = new ExternalApiStatus("Postgresql driver classes are " + + "allowed to be exposed by dependencies using them."); + private static final ExternalApiStatus SPRING_ERROR_HANDLER = new ExternalApiStatus("Azure Spring Cloud " + + "Messaging need the Spring's public interface for error handler registration, it is a common class for " + + "users to handle runtime errors."); + private static final ExternalApiStatus REACTIVE_STREAMS = new ExternalApiStatus("Reactive streams types are " + + "allowed to be exposed."); + + private static final ExternalApiStatus JEDIS = new ExternalApiStatus("To support the EventHubs " + + "JedisRedisCheckpointStore constructor"); + private final boolean ignore; + private final String justification; + + ExternalApiStatus(boolean ignore) { + this.ignore = ignore; + this.justification = null; + } + + ExternalApiStatus(String justification) { + this.ignore = true; + this.justification = justification; + } + } +} diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/AzureSdkTreeFilterProvider.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/AzureSdkTreeFilterProvider.java new file mode 100644 index 0000000000..5819a50dc3 --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/AzureSdkTreeFilterProvider.java @@ -0,0 +1,214 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.tools.revapi.transforms; + +import org.revapi.AnalysisContext; +import org.revapi.ArchiveAnalyzer; +import org.revapi.Element; +import org.revapi.FilterStartResult; +import org.revapi.TreeFilter; +import org.revapi.TreeFilterProvider; +import org.revapi.base.IndependentTreeFilter; +import org.revapi.java.spi.JavaTypeElement; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.lang.model.element.NestingKind; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import java.io.Reader; +import java.util.Optional; + +public final class AzureSdkTreeFilterProvider implements TreeFilterProvider { + @Override + public > Optional> filterFor(ArchiveAnalyzer archiveAnalyzer) { + if (!"revapi.java".equals(archiveAnalyzer.getApiAnalyzer().getExtensionId())) { + return Optional.empty(); + } + + return Optional.of(new IndependentTreeFilter() { + @Override + protected FilterStartResult doStart(E element) { + if (!(element instanceof JavaTypeElement)) { + // Unknown element type. + return FilterStartResult.defaultResult(); + } + + TypeElement outermostClass = findOuterMostClass(((JavaTypeElement) element).getDeclaringElement()); + + // No guarantee there is an outermost class, the enclosing type could be an interface or enum. + boolean excludeClass = outermostClass != null + && excludeClass(outermostClass.getQualifiedName().toString()); + + if (excludeClass) { + // Class is being excluded, no need to inspect package. + return FilterStartResult.doesntMatch(); + } + + PackageElement packageElement = findPackage((JavaTypeElement) element); + + if (packageElement == null) { + // No Java package. + return FilterStartResult.defaultResult(); + } + + String packageName = packageElement.getQualifiedName().toString(); + boolean excludePackage = excludePackage(packageName); + + return excludePackage ? FilterStartResult.doesntMatch() : FilterStartResult.matchAndDescend(); + } + }); + } + + private static TypeElement findOuterMostClass(javax.lang.model.element.Element el) { + while (el != null && !(el instanceof TypeElement)) { + el = el.getEnclosingElement(); + } + + if (el == null) { + return null; + } + + return ((TypeElement) el).getNestingKind() == NestingKind.TOP_LEVEL + ? (TypeElement) el + : findOuterMostClass(el.getEnclosingElement()); + } + + static boolean excludeClass(String className) { + if (!className.startsWith("com.azure.")) { + return false; + } + + if ("core.".regionMatches(0, className, 10, 5)) { + // Exclude com.azure.core.util.Configuration + return className.length() == 33 && className.endsWith("util.Configuration"); + } else if ("cosmos.".regionMatches(0, className, 10, 6)) { + // Exclude + // + // - com.azure.cosmos.BridgeInternal + // - com.azure.cosmos.CosmosBridgeInternal + // - com.azure.cosmos.models.ModelBridgeInternal + // - com.azure.cosmos.util.UtilBridgeInternal + return (className.length() == 31 && className.endsWith("BridgeInternal")) + || (className.length() == 37 && className.endsWith("CosmosBridgeInternal")) + || (className.length() == 43 && className.endsWith("models.ModelBridgeInternal")) + || (className.length() == 40 && className.endsWith("util.UtilBridgeInternal")); + } else if ("spring.cloud.config.".regionMatches(0, className, 10, 20)) { + // Exclude + // + // - com.azure.spring.cloud.config.AppConfigurationBootstrapConfiguration + // - com.azure.spring.cloud.config.AppConfigurationRefresh + // - com.azure.spring.cloud.config.properties.AppConfigurationProviderProperties + // - com.azure.spring.cloud.config.web.AppConfigurationEndpoint + // - com.azure.spring.cloud.config.web.pushrefresh.AppConfigurationRefreshEvent + return (className.length() == 68 && className.endsWith("AppConfigurationBootstrapConfiguration")) + || (className.length() == 53 && className.endsWith("AppConfigurationRefresh")) + || (className.length() == 75 && className.endsWith("properties.AppConfigurationProviderProperties")) + || (className.length() == 58 && className.endsWith("web.AppConfigurationEndpoint")) + || (className.length() == 74 && className.endsWith("web.pushrefresh.AppConfigurationRefreshEvent")); + } + + return false; + } + + private static PackageElement findPackage(JavaTypeElement element) { + javax.lang.model.element.Element el = element.getDeclaringElement(); + while (el != null && !(el instanceof PackageElement)) { + el = el.getEnclosingElement(); + } + + return (PackageElement) el; + } + + static boolean excludePackage(String packageName) { + if (packageName.startsWith("com.")) { + if ("azure.".regionMatches(0, packageName, 4, 6)) { + if ("data.cosmos".regionMatches(0, packageName, 10, 11)) { + // Exclude com.azure.data.cosmos* + return true; + } else if (packageName.indexOf("implementation", 10) != -1 + || packageName.indexOf("samples", 10) != -1) { + // Exclude com.azure*.implementation*, com.azure.json*, com.azure*.samples*, and com.azure.xml* + return true; + } else if ("resourcemanager".regionMatches(0, packageName, 10, 15)) { + // Exclude com.azure.resourcemanager*.fluent.* but don't match fluentcore or confluent + int fluentIndex = packageName.indexOf("fluent", 25); + return fluentIndex != -1 && (fluentIndex + 6 == packageName.length() + || (packageName.charAt(fluentIndex - 1) == '.' && packageName.charAt(fluentIndex + 6) == '.')); + } else { + return false; + } + } else { + // Exclude com.fasterxml.jackson*, com.google.gson*, com.microsoft.azure*, and com.nimbusds* + return "fasterxml.jackson".regionMatches(0, packageName, 4, 17) + || "google.gson".regionMatches(0, packageName, 4, 11) + || "microsoft.azure".regionMatches(0, packageName, 4, 15) + || "nimbusds".regionMatches(0, packageName, 4, 8); + } + } + + if (packageName.startsWith("io.")) { + // Exclude io.micrometer*, io.netty*, and io.vertx* + return "micrometer".regionMatches(0, packageName, 3, 10) + || "netty".regionMatches(0, packageName, 3, 5) + || "vertx".regionMatches(0, packageName, 3, 5); + } + + if (packageName.startsWith("javax.")) { + // Exclude javax.jms* and javax.servlet* + return "jms".regionMatches(0, packageName, 6, 3) + || "servlet".regionMatches(0, packageName, 6, 7); + } + + if (packageName.startsWith("kotlin") + || packageName.startsWith("okhttp3") + || packageName.startsWith("okio")) { + // Exclude kotlin*, okhttp3*, and okio* + return true; + } + + if (packageName.startsWith("org.")) { + if ("apache.".regionMatches(0, packageName, 4, 7)) { + // Exclude org.apache.avro*, org.apache.commons*, and org.apache.qpid* + return "avro".regionMatches(0, packageName, 11, 4) + || "commons".regionMatches(0, packageName, 11, 7) + || "qpid".regionMatches(0, packageName, 11, 4); + } else { + // Exclude org.junit*, org.slf4j*, and org.springframework* + return "junit".regionMatches(0, packageName, 4, 5) + || "reactivestreams".regionMatches(0, packageName, 4, 15) + || "slf4j".regionMatches(0, packageName, 4, 5) + || "springframework".regionMatches(0, packageName, 4, 15); + } + } + + if (packageName.startsWith("reactor.")) { + // Exclude reactor.core*, reactor.netty*, and reactor.util* + return "core".regionMatches(0, packageName, 8, 4) + || "netty".regionMatches(0, packageName, 8, 5) + || "util".regionMatches(0, packageName, 8, 4); + } + + return false; + } + + @Override + public void close() { + } + + @Override + public String getExtensionId() { + return "azure-sdk-tree-provider"; + } + + @Nullable + @Override + public Reader getJSONSchema() { + return null; + } + + @Override + public void initialize(@Nonnull AnalysisContext analysisContext) { + } +} diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/JacksonDatabindRemovalTransform.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/JacksonDatabindRemovalTransform.java new file mode 100644 index 0000000000..6efe648864 --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/JacksonDatabindRemovalTransform.java @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.tools.revapi.transforms; + +import org.revapi.Criticality; +import org.revapi.Difference; +import org.revapi.Element; +import org.revapi.TransformationResult; +import org.revapi.base.BaseDifferenceTransform; + +import javax.annotation.Nullable; +import java.util.regex.Pattern; + +/** + * Transform that runs after RevApi generates API differences that removes Jackson Databind changes from the flagged + * differences set. + * + * @param Type of element to transform. + */ +public final class JacksonDatabindRemovalTransform> extends BaseDifferenceTransform { + private static final Pattern DIFFERENCE_CODE_PATTERN = Pattern.compile("java\\.annotation\\.removed"); + + @Override + public Pattern[] getDifferenceCodePatterns() { + // This indicates to RevApi that all differences should be inspected by this transform. + return new Pattern[] { DIFFERENCE_CODE_PATTERN }; + } + + @Override + public String getExtensionId() { + // Used to configure this transform in the RevApi pipeline. + return "jackson-databind-removal"; + } + + @Override + public TransformationResult tryTransform(@Nullable E oldElement, @Nullable E newElement, Difference difference) { + // RevApi should add 'annotationType' as an attachment for 'java.annotation.removed' differences. + String annotationType = difference.attachments.get("annotationType"); + + if (difference.criticality != Criticality.ERROR) { + // Only transform the Difference if the criticality is an error. If this isn't guarded it results in an + // infinite transformation loop as RevApi will keep running the transformation pipeline until there are no + // transformations applied in the pipeline run. + return TransformationResult.keep(); + } + + if (annotationType == null || annotationType.isEmpty()) { + // But if the annotationType wasn't included keep the current result as we can't determine if this is a + // Jackson Databind change. + return TransformationResult.keep(); + } + + if (!annotationType.contains("fasterxml.jackson") || !annotationType.contains("annotation")) { + // The annotation isn't from Jackson Databind, keep the current result. + return TransformationResult.keep(); + } + + // Now verify that this change is in a package that is allowed to make the change. + String packageName = difference.attachments.get("package"); + + if (packageName == null || packageName.isEmpty()) { + // But if the package wasn't included keep the current result as we can't determine if this package is + // allowed to remove Jackson Databind annotations. + return TransformationResult.keep(); + } + + return shouldDiscard(packageName) ? TransformationResult.discard() : TransformationResult.keep(); + } + + private static boolean shouldDiscard(String packageName) { + if (!packageName.startsWith("com.azure.")) { + // The package isn't from the Azure SDK, keep the current result. + return false; + } + + if (packageName.regionMatches(10, "containers.containerregistry.models", 0, 35)) { + // Container Registry + return true; + } else if (packageName.regionMatches(10, "search.documents", 0, 16)) { + // Search Documents + return packageName.regionMatches(26, ".models", 0, 7) + || packageName.regionMatches(26, ".indexes.models", 0, 13); + } else if (packageName.regionMatches(10, "security.", 0, 9)) { + if (packageName.regionMatches(19, "attestation.models", 0, 17)) { + // Attestation + return true; + } else if (packageName.regionMatches(19, "keyvault.", 0, 9)) { + // KeyVault + return packageName.regionMatches(28, "administration.models", 0, 21) + || packageName.regionMatches(28, "certificates.models", 0, 19) + || packageName.regionMatches(28, "keys.models", 0, 11) + || packageName.regionMatches(28, "keys.cryptography.models", 0, 24); + } + } else if (packageName.regionMatches(10, "ai.", 0, 3)) { + if (packageName.regionMatches(13, "textanalytics.models", 0, 20)) { + // Text Analytics + return true; + } else if (packageName.regionMatches(13, "formrecognizer.", 0, 15)) { + // Form Recognizer + return packageName.regionMatches(28, "models", 0, 6) + || packageName.regionMatches(28, "training.models", 0, 15) + || packageName.regionMatches(28, "documentanalysis.models", 0, 23) + || packageName.regionMatches(28, "documentanalysis.administration.models", 0, 38); + } else if (packageName.regionMatches(13, "metricsadvisor.", 0, 15)) { + // Metrics Advisor + return packageName.regionMatches(28, "models", 0, 6) + || packageName.regionMatches(28, "administration.models", 0, 21); + } else if (packageName.regionMatches(13, "contentsafety.models", 0, 20)) { + // Content Safety + return true; + } + } else if (packageName.regionMatches(10, "messaging.", 0, 10)) { + // Service Bus + if (packageName.regionMatches(20, "servicebus.", 0, 11)) { + return packageName.regionMatches(31, "models", 0, 6) + || packageName.regionMatches(31, "administration.models", 0, 21); + } else if (packageName.regionMatches(20, "eventgrid.systemevents", 0, 22)) { + // Event Grid + return true; + } + } else if (packageName.regionMatches(10, "monitor.query.models", 0, 20)) { + // Monitor Query + return true; + } else if (packageName.regionMatches(10, "data.tables.models", 0, 18)) { + // Tables + return true; + } else if (packageName.regionMatches(10, "storage.", 0, 8)) { + if (packageName.regionMatches(18, "file.datalake.models", 0, 20)) { + // DataLake + return true; + } else if (packageName.regionMatches(18, "file.share.models", 0, 17)) { + // Shares + return true; + } else if (packageName.regionMatches(18, "queue.models", 0, 12)) { + // Queue + return true; + } else if (packageName.regionMatches(18, "blob.", 0, 5)) { + // Blob + return packageName.regionMatches(23, "models", 0, 6) + || packageName.regionMatches(23, "options", 0, 7); + } + } else if (packageName.regionMatches(10, "communication.", 0, 14)) { + if (packageName.regionMatches(24, "jobrouter.models", 0, 16)) { + // Communication Job Router + return true; + } + } + + // The package is from the Azure SDK, but not in the allowed list, keep the current result. + return false; + } +} diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/TransitiveCoreChangesTransform.java b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/TransitiveCoreChangesTransform.java index 587b4a1caf..cb040ee458 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/TransitiveCoreChangesTransform.java +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/java/com/azure/tools/revapi/transforms/TransitiveCoreChangesTransform.java @@ -20,13 +20,13 @@ * @param Type of element to transform. */ public final class TransitiveCoreChangesTransform> extends BaseDifferenceTransform { - private static final Pattern CORE_ARCHIVE = Pattern.compile("com\\.azure:azure-core:.*"); + private static final Pattern DIFFERENCE_CODE_PATTERN = Pattern.compile(".*"); private static final String SUPPLEMENTARY = Archive.Role.SUPPLEMENTARY.toString(); @Override public Pattern[] getDifferenceCodePatterns() { // This indicates to RevApi that all differences should be inspected by this transform. - return new Pattern[] { Pattern.compile(".*") }; + return new Pattern[] { DIFFERENCE_CODE_PATTERN }; } @Override @@ -51,8 +51,10 @@ public TransformationResult tryTransform(@Nullable E oldElement, @Nullable E new return TransformationResult.keep(); } - if (!CORE_ARCHIVE.matcher(newArchive).matches()) { - // The difference isn't from the azure-core SDK, keep the current result. + if (!newArchive.startsWith("com.azure:azure-core:") + && !newArchive.startsWith("com.azure:azure-json:") + && !newArchive.startsWith("com.azure:azure-xml:")) { + // The difference isn't from the azure-core, azure-json, or azure-xml SDK, keep the current result. return TransformationResult.keep(); } diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/META-INF/services/org.revapi.DifferenceTransform b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/META-INF/services/org.revapi.DifferenceTransform new file mode 100644 index 0000000000..2933e6c3e3 --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/META-INF/services/org.revapi.DifferenceTransform @@ -0,0 +1,3 @@ +com.azure.tools.revapi.transforms.AzureSdkAllowedExternalApis +com.azure.tools.revapi.transforms.JacksonDatabindRemovalTransform +com.azure.tools.revapi.transforms.TransitiveCoreChangesTransform diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/META-INF/services/org.revapi.TreeFilterProvider b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/META-INF/services/org.revapi.TreeFilterProvider new file mode 100644 index 0000000000..28443e149c --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/META-INF/services/org.revapi.TreeFilterProvider @@ -0,0 +1 @@ +com.azure.tools.revapi.transforms.AzureSdkTreeFilterProvider diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml index 1df25e0a7f..5094af9ca2 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml @@ -9,24 +9,399 @@ + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle.xml b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle.xml index 69c3b16c56..ac4dc59d23 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle.xml +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle.xml @@ -9,12 +9,16 @@ what the following rules do, please see the checkstyle configuration page at http://checkstyle.sourceforge.net/config.html --> + + + + @@ -228,7 +232,13 @@ page at http://checkstyle.sourceforge.net/config.html --> - + + + + + + + @@ -268,11 +278,11 @@ page at http://checkstyle.sourceforge.net/config.html --> - - - + + + - + @@ -331,9 +341,10 @@ page at http://checkstyle.sourceforge.net/config.html --> - - + + + + @@ -387,8 +398,8 @@ page at http://checkstyle.sourceforge.net/config.html --> - - + + @@ -398,5 +409,11 @@ page at http://checkstyle.sourceforge.net/config.html --> + + + + + + diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/dependency-allowlist.html b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/dependency-allowlist.html new file mode 100644 index 0000000000..bdd3c61fae --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/dependency-allowlist.html @@ -0,0 +1,90 @@ + + + + + + Maven Allowlist Report + + + + + + +
+ +

Maven Allowlist Report

+ +

+ This report displays the allowlist of all maven dependencies. It is based on the machine-readable JSON report. +

+ + + + + + + + +
Maven and File PathAllowlist
+ +
+
+ + + + + + + +
Allowlist
+
+ + + + + +
Report generated with whitelist-generator
+ + diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/index.html b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/index.html new file mode 100644 index 0000000000..539c60d7b5 --- /dev/null +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/index.html @@ -0,0 +1,566 @@ + + + + + + + + + + Azure Java SDK + + + + + + + + +
+
+
+ +
+

Azure Java SDK

+

Refer to the links below for useful links and build documentation, generated from the Azure SDK for Java source code.

+
+ +
+ + + + +
+
+ +
+
+
+
+

Powered by Azure.

+
+
+
+
+ + + + + diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/revapi/revapi.json b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/revapi/revapi.json index 0d4f101c7a..9e632251c4 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/revapi/revapi.json +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/revapi/revapi.json @@ -1,2 +1,680 @@ [ + { + "extension": "revapi.java", + "configuration": { + "missing-classes": { + "behavior": "ignore", + "ignoreMissingAnnotations": false + }, + "matchOverloads": true + } + }, + { + "extension": "revapi.versions", + "configuration": { + "enabled": true, + "semantic0": false, + "versionIncreaseAllows": { + "major": { + "severity": "BREAKING" + }, + "minor": { + "severity": "NON_BREAKING" + }, + "patch": { + "severity": "EQUIVALENT" + } + }, + "onAllowed": { + "remove": true, + "attachments": { + "breaksVersioningRules": "false" + } + }, + "onDisallowed": { + "criticality": "error", + "attachments": { + "breaksVersioningRules": "true" + } + }, + "passThroughDifferences": [ + "java.class.nonPublicPartOfAPI" + ] + } + }, + { + "extension": "revapi.differences", + "configuration": { + "ignore": true, + "differences": [ + { + "regex": true, + "code": "java.class.nonPublicPartOfAPI", + "new": "(class|interface) com\\.azure\\.keyvault\\.jca\\.(com|org)\\..*", + "justification": "skip check for third party files." + }, + { + "regex": true, + "code": "java.class.nonPublicPartOfAPI", + "new": "(class|enum|interface) org\\.conscrypt\\..*", + "justification": "skip check for third party files." + }, + { + "regex": true, + "code": "java\\.method\\.addedToInterface", + "new": "method .* com\\.azure\\.resourcemanager\\..*", + "justification": "resourcemanager interfaces are allowed to add methods." + }, + { + "regex": true, + "code": "java\\.method\\.addedToInterface", + "new": "method (reactor\\.core\\.publisher\\.Mono<)?T>? com\\.azure\\.spring\\.data\\.cosmos\\.core\\.(Reactive)?CosmosOperations::patch\\(java\\.lang\\.Object, com\\.azure\\.cosmos\\.models\\.PartitionKey, java\\.lang\\.Class, com\\.azure\\.cosmos\\.models\\.CosmosPatchOperations(, com\\.azure\\.cosmos\\.models\\.CosmosPatchItemRequestOptions)?\\)", + "justification": "Spring interfaces are allowed to add methods." + }, + { + "regex": true, + "code": "java\\.method\\.addedToInterface", + "new": "method (reactor\\.core\\.publisher\\.Mono<)?S>? com\\.azure\\.spring\\.data\\.cosmos\\.repository\\.(Reactive)?CosmosRepository::save\\(ID, com\\.azure\\.cosmos\\.models\\.PartitionKey, java\\.lang\\.Class, com\\.azure\\.cosmos\\.models\\.CosmosPatchOperations(, com\\.azure\\.cosmos\\.models\\.CosmosPatchItemRequestOptions)?\\)", + "justification": "Spring interfaces are allowed to add methods." + }, + { + "code": "java.method.addedToInterface", + "new": "method void com.azure.spring.data.cosmos.core.CosmosOperations::deleteEntities(com.azure.spring.data.cosmos.repository.support.CosmosEntityInformation, java.lang.Iterable)", + "justification": "Spring interfaces are allowed to add methods." + }, + { + "code": "java.method.addedToInterface", + "new": "method java.lang.Iterable com.azure.spring.data.cosmos.core.CosmosOperations::insertAll(com.azure.spring.data.cosmos.repository.support.CosmosEntityInformation, java.lang.Iterable)", + "justification": "Spring interfaces are allowed to add methods." + }, + { + "code": "java.method.addedToInterface", + "new": "method reactor.core.publisher.Mono com.azure.spring.data.cosmos.core.ReactiveCosmosOperations::deleteEntities(com.azure.spring.data.cosmos.repository.support.CosmosEntityInformation, reactor.core.publisher.Flux)", + "justification": "Spring interfaces are allowed to add methods." + }, + { + "code": "java.method.addedToInterface", + "new": "method reactor.core.publisher.Flux com.azure.spring.data.cosmos.core.ReactiveCosmosOperations::insertAll(com.azure.spring.data.cosmos.repository.support.CosmosEntityInformation, reactor.core.publisher.Flux)", + "justification": "Spring interfaces are allowed to add methods." + }, + { + "code": "java.method.addedToInterface", + "new": "method reactor.core.publisher.Mono com.azure.spring.data.cosmos.core.ReactiveCosmosOperations::deleteEntities(com.azure.spring.data.cosmos.repository.support.CosmosEntityInformation, java.lang.Iterable)", + "justification": "Spring interfaces are allowed to add methods." + }, + { + "code": "java.method.addedToInterface", + "new": "method reactor.core.publisher.Flux com.azure.spring.data.cosmos.core.ReactiveCosmosOperations::insertAll(com.azure.spring.data.cosmos.repository.support.CosmosEntityInformation, java.lang.Iterable)", + "justification": "Spring interfaces are allowed to add methods." + }, + { + "regex": true, + "code": "java\\.annotation\\.(added|attributeValueChanged)", + "old": ".*", + "annotationType": "com\\.azure\\.core\\.annotation\\.Service(Method|Client)", + "justification": "These are SDK metadata annotations and don't affect runtime behavior." + }, + { + "regex": true, + "code": "java\\.annotation\\.(added|attributeValueChanged|attributeAdded)", + "new": "(class|method void|parameter void) com\\.azure\\.search\\.documents\\.indexes\\.models\\..*", + "justification": "Generated classes were moved into public API, these annotations were already being used in implementation used during serialization and deserialization." + }, + { + "regex": true, + "code": "java\\.annotation\\.removed", + "new": "(class|interface|method|parameter) com\\.azure\\.cosmos\\..*", + "justification": "Cosmos SDK removes Beta annotation to GA its APIs and classes." + }, + { + "code": "java.method.added", + "new": "method void com.azure.spring.cloud.autoconfigure.aadb2c.AadB2cOidcLoginConfigurer::(org.springframework.security.web.authentication.logout.LogoutSuccessHandler, org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver, org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient, org.springframework.boot.web.client.RestTemplateBuilder)", + "justification": "New method added to fix a bug." + }, + { + "code": "java.method.removed", + "old": "method java.lang.String com.azure.spring.cloud.autoconfigure.jms.properties.AzureServiceBusJmsProperties::getPassword()", + "justification": "Remove some meaningless jms properties" + }, + { + "code": "java.method.removed", + "old": "method java.lang.String com.azure.spring.cloud.autoconfigure.jms.properties.AzureServiceBusJmsProperties::getRemoteUrl()", + "justification": "Remove some meaningless jms properties" + }, + { + "code": "java.method.removed", + "old": "method java.lang.String com.azure.spring.cloud.autoconfigure.jms.properties.AzureServiceBusJmsProperties::getUsername()", + "justification": "Remove some meaningless jms properties" + }, + { + "code": "java.method.removed", + "old": "method void com.azure.spring.cloud.autoconfigure.jms.properties.AzureServiceBusJmsProperties::setPassword(java.lang.String)", + "justification": "Remove some meaningless jms properties" + }, + { + "code": "java.method.removed", + "old": "method void com.azure.spring.cloud.autoconfigure.jms.properties.AzureServiceBusJmsProperties::setRemoteUrl(java.lang.String)", + "justification": "Remove some meaningless jms properties" + }, + { + "code": "java.method.removed", + "old": "method void com.azure.spring.cloud.autoconfigure.jms.properties.AzureServiceBusJmsProperties::setUsername(java.lang.String)", + "justification": "Remove some meaningless jms properties" + }, + { + "regex": true, + "code": "java.method.numberOfParametersChanged", + "old": "method void com\\.azure\\.spring\\.cloud\\.config\\.stores\\..*", + "justification": "Not a public api" + }, + { + "regex": true, + "code": "java.method.removed", + "old": "method com.azure.spring.cloud.config.resource.ConnectionPool com.azure.spring.cloud.config.AppConfigurationBootstrapConfiguration::initConnectionString(com.azure.spring.cloud.config.properties.AppConfigurationProperties)", + "justification": "Not a public api" + }, + { + "regex": true, + "code": "java.class.removed", + "old": "class com\\.azure\\.spring\\.cloud\\.config\\.resource\\.ConnectionPool", + "justification": "Not a public api" + }, + { + "regex": true, + "code": "java.class.removed", + "old": "class com\\.azure\\.spring\\.cloud\\.config\\.resource\\.Connection", + "justification": "Not a public api" + }, + { + "regex": true, + "code": "java.class.removed", + "old": "class com.azure.spring.cloud.config.stores.ClientStore", + "justification": "Not a public api" + }, + { + "ignore": true, + "code": "java.class.externalClassExposedInAPI", + "new": "interface com.azure.spring.cloud.config.AppConfigurationRefresh", + "justification": "Thi isn't an external class" + }, + { + "regex": true, + "code": "java\\.class\\.externalClassExposedInAPI", + "new": "(interface|class|enum) com\\.mysql\\.cj\\..*", + "justification": "Mysql driver classes are allowed to be exposed by dependencies using them." + }, + { + "code": "java.method.addedToInterface", + "new": "method void com.azure.spring.cloud.resourcemanager.provisioning.ServiceBusProvisioner::provisionQueue(java.lang.String, java.lang.String, com.azure.spring.cloud.resourcemanager.provisioning.properties.ServiceBusQueueProperties)", + "justification": "New method added to support more properties." + }, + { + "code": "java.method.addedToInterface", + "new": "method void com.azure.spring.cloud.resourcemanager.provisioning.ServiceBusProvisioner::provisionSubscription(java.lang.String, java.lang.String, java.lang.String, com.azure.spring.cloud.resourcemanager.provisioning.properties.ServiceBusTopicProperties)", + "justification": "New method added to support more properties." + }, + { + "code": "java.method.addedToInterface", + "new": "method void com.azure.spring.cloud.resourcemanager.provisioning.ServiceBusProvisioner::provisionTopic(java.lang.String, java.lang.String, com.azure.spring.cloud.resourcemanager.provisioning.properties.ServiceBusTopicProperties)", + "justification": "New method added to support more properties." + }, + { + "regex": true, + "code": "java.class.externalClassExposedInAPI", + "new": "class com.azure.spring.cloud.resourcemanager.provisioning.properties.(ServiceBusTopicProperties|ServiceBusQueueProperties)", + "justification": "Provides new queue level properties." + }, + { + "regex": true, + "code": "java.class.externalClassExposedInAPI", + "new": "class com.azure.spring.cloud.stream.binder.servicebus.core.properties.(ServiceBusProducerProperties|ServiceBusConsumerProperties)", + "justification": "Support new properties." + }, + { + "regex": true, + "code": "java.method.parameterTypeParameterChanged", + "old": "parameter reactor\\.core\\.publisher\\.Mono com\\.azure\\.spring\\.data\\.cosmos\\.core\\.(ReactiveCosmosOperations|ReactiveCosmosTemplate)::insert\\(java\\.lang\\.String, ===java\\.lang\\.Object===, com\\.azure\\.cosmos\\.models\\.PartitionKey\\)", + "new": "parameter reactor\\.core\\.publisher\\.Mono com\\.azure\\.spring\\.data\\.cosmos\\.core\\.(ReactiveCosmosOperations|ReactiveCosmosTemplate)::insert\\(java\\.lang\\.String, ===T===, com\\.azure\\.cosmos\\.models\\.PartitionKey\\)", + "parameterIndex": "1", + "justification": "To support mono method chaining, without explicit typcast for upper bounded generics" + }, + { + "regex": true, + "code": "java.method.returnTypeChangedCovariantly", + "new": "method com.azure.search.documents.indexes.models.(CognitiveServicesAccountKey|ConditionalSkill|CustomEntityLookupSkill|DefaultCognitiveServicesAccount|DistanceScoringFunction|DocumentExtractionSkill|EntityRecognitionSkill|FreshnessScoringFunction|ImageAnalysisSkill|KeyPhraseExtractionSkill|LanguageDetectionSkill|MagnitudeScoringFunction|MergeSkill|OcrSkill|SentimentSkill|ShaperSkill|SplitSkill|TagScoringFunction|TextTranslationSkill|WebApiSkill) .*", + "justification": "Proper support for fluent setters in subtypes." + }, + { + "regex": true, + "code": "java.annotation.added", + "new": "class com.azure.ai.formrecognizer.documentanalysis.models.(DocumentField|DocumentLine)", + "justification": "Skip customized getters on class when serialization and deserialization." + }, + { + "code": "java.class.removed", + "old": "enum com.azure.messaging.eventhubs.checkpointstore.blob.Messages", + "justification": "Messages class was accidentally made public. Reverting the public change since this should be implementation detail." + }, + { + "ignore": true, + "code": "java.annotation.removed", + "new": "field com.azure.cosmos.models.PartitionKind.MULTI_HASH", + "justification": "removing beta tags on PartitionKind MultiHash for hierarchical partitioning GA" + }, + { + "ignore": true, + "code": "java.method.addedToInterface", + "new": "method java.lang.String com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.AzureEnvironmentOptions::getServiceBusDomainName()", + "justification": "support configuration of Service Bus domain name." + }, + { + "ignore": true, + "code": "java.field.constantValueChanged", + "old": "field com.azure.messaging.eventgrid.SystemEventNames.SERVICE_BUS_DEADLETTER_MESSAGES_AVAILABLE_WITH_NO_LISTENER", + "new": "field com.azure.messaging.eventgrid.SystemEventNames.SERVICE_BUS_DEADLETTER_MESSAGES_AVAILABLE_WITH_NO_LISTENER", + "justification": "Previous constant value had a typo and was never functional." + }, + { + "ignore": true, + "code": "java.field.constantValueChanged", + "old": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_CREATED", + "new": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_CREATED", + "justification": "Previous value did was incorrect." + }, + { + "ignore": true, + "code": "java.field.constantValueChanged", + "old": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_DELETED", + "new": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_DELETED", + "justification": "Previous value did was incorrect." + }, + { + "ignore": true, + "code": "java.field.constantValueChanged", + "old": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_RELEASE_CREATED", + "new": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_RELEASE_CREATED", + "justification": "Previous value did was incorrect." + }, + { + "ignore": true, + "code": "java.field.constantValueChanged", + "old": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_RELEASE_DELETED", + "new": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_RELEASE_DELETED", + "justification": "Previous value did was incorrect." + }, + { + "ignore": true, + "code": "java.field.constantValueChanged", + "old": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_RELEASE_UPDATED", + "new": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_RELEASE_UPDATED", + "justification": "Previous value did was incorrect." + }, + { + "ignore": true, + "code": "java.field.constantValueChanged", + "old": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_UPDATED", + "new": "field com.azure.messaging.eventgrid.SystemEventNames.API_MANAGEMENT_API_UPDATED", + "justification": "Previous value did was incorrect." + }, + { + "ignore": true, + "code": "java.method.returnTypeChangedCovariantly", + "old": "method com.azure.messaging.eventgrid.systemevents.AcsChatThreadEventBaseProperties com.azure.messaging.eventgrid.systemevents.AcsChatThreadEventBaseProperties::fromJson(com.azure.json.JsonReader) throws java.io.IOException @ com.azure.messaging.eventgrid.systemevents.AcsChatMemberAddedToThreadWithUserEventData", + "new": "method com.azure.messaging.eventgrid.systemevents.AcsChatMemberAddedToThreadWithUserEventData com.azure.messaging.eventgrid.systemevents.AcsChatMemberAddedToThreadWithUserEventData::fromJson(com.azure.json.JsonReader) throws java.io.IOException", + "justification": "Subtype was not updated by codegen for azure-json due to being deprecated and no longer in swagger." + }, + { + "ignore": true, + "code": "java.method.returnTypeChangedCovariantly", + "old": "method com.azure.messaging.eventgrid.systemevents.AcsChatThreadEventBaseProperties com.azure.messaging.eventgrid.systemevents.AcsChatThreadEventBaseProperties::fromJson(com.azure.json.JsonReader) throws java.io.IOException @ com.azure.messaging.eventgrid.systemevents.AcsChatMemberRemovedFromThreadWithUserEventData", + "new": "method com.azure.messaging.eventgrid.systemevents.AcsChatMemberRemovedFromThreadWithUserEventData com.azure.messaging.eventgrid.systemevents.AcsChatMemberRemovedFromThreadWithUserEventData::fromJson(com.azure.json.JsonReader) throws java.io.IOException", + "justification": "Subtype was not updated by codegen for azure-json due to being deprecated and no longer in swagger." + }, + { + "code" : "java.field.constantValueChanged", + "old" : "field com.azure.spring.cloud.feature.management.filters.TargetingFilter.GROUPS", + "new" : "field com.azure.spring.cloud.feature.management.filters.TargetingFilter.GROUPS", + "justification": "Previous value did was incorrect." + }, + { + "code" : "java.field.constantValueChanged", + "old" : "field com.azure.spring.cloud.feature.management.filters.TargetingFilter.USERS", + "new" : "field com.azure.spring.cloud.feature.management.filters.TargetingFilter.USERS", + "justification": "Previous value did was incorrect." + }, + { + "code": "java.field.removed", + "old": "field com.azure.spring.cloud.core.properties.profile.AzureEnvironmentProperties.AZURE_GERMANY", + "justification": "Remove this because AZURE_GERMANY is deprecated." + }, + { + "code": "java.method.addedToInterface", + "new": "method void com.azure.spring.cloud.resourcemanager.provisioning.ServiceBusProvisioner::provisionQueue(java.lang.String, java.lang.String, com.azure.spring.cloud.resourcemanager.provisioning.properties.ServiceBusQueueProperties)", + "justification": "New method added to support more properties." + }, + { + "regex": true, + "code": "java.class.externalClassExposedInAPI", + "new": "class com.azure.spring.cloud.stream.binder.servicebus.core.properties.(ServiceBusProducerProperties|ServiceBusConsumerProperties)", + "justification": "Support new properties." + }, + { + "regex": true, + "code": "java.field.enumConstantOrderChanged", + "old": "field com.mysql.cj.conf.PropertyKey.*", + "new": "field com.mysql.cj.conf.PropertyKey.*", + "justification": "Fix enum constants reordered." + }, + { + "code": "java.method.removed", + "old": "method int com.mysql.cj.protocol.ServerSession::getOldStatusFlags()", + "justification": "Fix method removed." + }, + { + "code": "java.method.removed", + "old": "method void com.mysql.cj.protocol.ServerSession::setOldStatusFlags(int)", + "justification": "Fix method removed." + }, + { + "regex": true, + "code": "java.method.(returnTypeTypeParametersChanged|parameterTypeChanged|returnTypeChanged)", + "new": ".* com.azure.security.attestation.*attestTpm.*" + }, + { + "code": "java.annotation.added", + "new": "class com.azure.cosmos.models.ChangeFeedMetaData", + "justification": "Fixes a bug to deserilize the conflictResolutionTimestamp Instant object." + }, + { + "code": "java.annotation.added", + "new": "class com.azure.cosmos.models.ChangeFeedProcessorItem", + "justification": "Modifies the type of changeFeedMetaData from ChangeFeedMetaData to JsonNode." + }, + { + "code" : "java.field.removed", + "old" : "field com.mysql.cj.conf.PropertyKey.ociConfigProfile", + "justification" : "Fix field removed." + }, + { + "code" : "java.method.addedToInterface", + "new" : "method int com.mysql.cj.protocol.ServerSession::getOldStatusFlags()", + "justification" : "Method was added to an interface." + }, + { + "code" : "java.method.addedToInterface", + "new" : "method void com.mysql.cj.protocol.ServerSession::setOldStatusFlags(int)", + "justification" : "Method was added to an interface." + }, + { + "code": "java.annotation.added", + "old": "method com.azure.cosmos.CosmosDiagnosticsContext com.azure.cosmos.CosmosDiagnostics::getDiagnosticsContext()", + "new": "method com.azure.cosmos.CosmosDiagnosticsContext com.azure.cosmos.CosmosDiagnostics::getDiagnosticsContext()", + "justification": "Ignore CosmosDiagnosticsContext in CosmosDiagnostics to avoid stackoverflow error." + }, + { + "regex": true, + "code": "java\\.annotation\\.added", + "old": ".*? com\\.azure\\.communication\\.jobrouter\\.models.*", + "new": ".*? com\\.azure\\.communication\\.jobrouter\\.models.*", + "justification": "Adding missing Jackson annotations to Job Router models." + }, + { + "regex": true, + "code": "java\\.method\\.removed", + "old": ".*? com\\.azure\\.communication\\.jobrouter\\.models.*", + "justification": "Remove setter for Value from RouterWorkerSelector/RouterQueueSelector since it's in the constructor." + }, + { + "regex": true, + "code": "java\\.method\\.numberOfParametersChanged", + "old": ".*? com\\.azure\\.communication\\.jobrouter\\.models.*", + "new": ".*? com\\.azure\\.communication\\.jobrouter\\.models.*", + "justification": "Make Value mandatory in RouterWorkerSelector/RouterQueueSelector constructor." + }, + { + "regex": true, + "code": "java\\.annotation\\.attributeValueChanged", + "old": ".*? com\\.azure\\.communication\\.jobrouter\\.models.*", + "new": ".*? com\\.azure\\.communication\\.jobrouter\\.models.*", + "justification": "Fix incorrect json attributes." + }, + { + "regex": true, + "code": "java\\.method\\.(parameterTypeChanged|returnTypeTypeParametersChanged|returnTypeChanged)", + "old": ".*?com\\.azure\\.communication\\.jobrouter.*", + "new": ".*?com\\.azure\\.communication\\.jobrouter\\.models.*", + "justification": "Accept and return Router models rather than BinaryData." + }, + { + "ignore": true, + "code": "java.field.addedStaticField", + "new": "field com.azure.data.schemaregistry.SchemaRegistryVersion.V2022_10", + "justification": "Another version of Schema Registry API released." + }, + { + "regex": true, + "ignore": true, + "code": "java.field.addedStaticField", + "new": "field com\\.azure\\.data\\.schemaregistry\\.models\\.SchemaFormat\\.(CUSTOM|JSON)", + "justification": "Additional schema formats are supported by Schema Registry." + }, + { + "regex": true, + "code": "java\\.annotation\\.(attributeRemoved|attributeAdded|removed)", + "old": ".*? com\\.azure\\.resourcemanager\\..*\\.models.*", + "justification": "Migration to azure-json." + }, + { + "regex": true, + "code": "java\\.annotation\\.(attributeRemoved|attributeAdded)", + "old": ".*? com\\.azure\\.communication\\.messages\\.models.*", + "justification": "Jackson annotation changed." + }, + { + "regex": true, + "code" : "java\\.annotation\\.removed", + "old" : ".*? com\\.azure\\.communication\\.phonenumbers\\.models.*", + "new" : ".*? com\\.azure\\.communication\\.phonenumbers\\.models.*", + "justification": "Migration to azure-json" + }, + { + "regex": true, + "code" : "java\\.annotation\\.removed", + "old" : ".*? com\\.azure\\.digitaltwins\\.core(\\.models)?.*", + "new" : ".*? com\\.azure\\.digitaltwins\\.core(\\.models)?.*", + "justification": "Migration to azure-json" + }, + { + "regex": true, + "code" : "java\\.annotation\\.removed", + "old" : ".*? com\\.azure\\.messaging\\.webpubsub\\.client\\.models.*", + "new" : ".*? com\\.azure\\.messaging\\.webpubsub\\.client\\.models.*", + "justification": "Migration to azure-json" + }, + { + "regex": true, + "code": "java\\.annotation\\.removed", + "old": ".*? com\\.azure\\.messaging\\.webpubsub\\.models.*", + "new": ".*? com\\.azure\\.messaging\\.webpubsub\\.models.*", + "justification": "Migration to azure-json" + }, + { + "regex": true, + "code" : "java\\.annotation\\.removed", + "old" : ".*? com\\.azure\\.ai\\.translation\\.text\\.models.*", + "new" : ".*? com\\.azure\\.ai\\.translation\\.text\\.models.*", + "justification": "Migration to azure-json" + }, + { + "regex": true, + "code" : "java\\.annotation\\.removed", + "old" : ".*? com\\.azure\\.communication\\.callautomation\\.models.*", + "new" : ".*? com\\.azure\\.communication\\.callautomation\\.models.*", + "justification": "Migration to azure-json" + }, + { + "regex": true, + "code" : "java\\.annotation\\.removed", + "old" : ".*? com\\.azure\\.communication\\.chat\\.models.*", + "new" : ".*? com\\.azure\\.communication\\.chat\\.models.*", + "justification": "Migration to azure-json" + }, + { + "regex": true, + "code" : "java\\.annotation\\.removed", + "old" : ".*? com\\.azure\\.communication\\.email\\.models.*", + "new" : ".*? com\\.azure\\.communication\\.email\\.models.*", + "justification": "Migration to azure-json" + }, + { + "regex": true, + "code": "java.class.nowFinal", + "old" : "class com.azure.resourcemanager.(eventhubs|servicebus).models.Identity", + "new" : "class com.azure.resourcemanager.(eventhubs|servicebus).models.Identity", + "justification": "Class is now final." + }, + { + "regex": true, + "code": "java.class.nowFinal", + "old" : "class com.azure.resourcemanager.(eventhubs|servicebus).models.UserAssignedIdentity", + "new" : "class com.azure.resourcemanager.(eventhubs|servicebus).models.UserAssignedIdentity", + "justification": "Class is now final." + }, + { + "ignore": true, + "code": "java.annotation.removed", + "old": "method com.azure.communication.identity.models.CommunicationTokenScope com.azure.communication.identity.models.CommunicationTokenScope::fromString(java.lang.String)", + "new": "method com.azure.communication.identity.models.CommunicationTokenScope com.azure.communication.identity.models.CommunicationTokenScope::fromString(java.lang.String)", + "annotation": "@com.fasterxml.jackson.annotation.JsonCreator", + "justification": "Migration to azure-json" + }, + { + "regex": true, + "code" : "java\\.annotation\\.removed", + "old" : ".*? com\\.azure\\.communication\\.messages\\.models(\\.channels)?.*", + "new" : ".*? com\\.azure\\.communication\\.messages\\.models(\\.channels)?.*", + "justification": "Migration to azure-json" + }, + { + "code": "java.method.returnTypeErasureChanged", + "old" : "method T com.azure.identity.AadCredentialBuilderBase>::clientId(java.lang.String) @ com.azure.identity.InteractiveBrowserCredentialBuilder", + "new" : "method com.azure.identity.InteractiveBrowserCredentialBuilder com.azure.identity.InteractiveBrowserCredentialBuilder::clientId(java.lang.String)", + "justification": "Override flags this as a potential binary breaking change, but it isn't." + }, + { + "code": "java.method.returnTypeErasureChanged", + "old" : "method T com.azure.identity.AadCredentialBuilderBase>::clientId(java.lang.String) @ com.azure.identity.DeviceCodeCredentialBuilder", + "new" : "method com.azure.identity.DeviceCodeCredentialBuilder com.azure.identity.DeviceCodeCredentialBuilder::clientId(java.lang.String)", + "justification": "Override flags this as a potential binary breaking change, but it isn't." + }, + { + "code": "java\\.annotation\\.removed", + "old": ".*? com\\.azure\\.compute\\.batch\\.models.*", + "justification": "Removing Jackson annotations from Azure Batch in transition to stream-style." + }, + { + "ignore": true, + "code": "java.method.returnTypeChanged", + "old": "method java.lang.Float com.azure.resourcemanager.appservice.models.FunctionsAlwaysReadyConfig::instanceCount()", + "new": "method java.lang.Integer com.azure.resourcemanager.appservice.models.FunctionsAlwaysReadyConfig::instanceCount()", + "justification": "Service bug fix." + }, + { + "ignore": true, + "code": "java.method.parameterTypeChanged", + "old": "parameter com.azure.resourcemanager.appservice.models.FunctionsAlwaysReadyConfig com.azure.resourcemanager.appservice.models.FunctionsAlwaysReadyConfig::withInstanceCount(===java.lang.Float===)", + "new": "parameter com.azure.resourcemanager.appservice.models.FunctionsAlwaysReadyConfig com.azure.resourcemanager.appservice.models.FunctionsAlwaysReadyConfig::withInstanceCount(===java.lang.Integer===)", + "parameterIndex": "0", + "justification": "Service bug fix." + }, + { + "ignore": true, + "code": "java.method.returnTypeChanged", + "old": "method java.lang.Float com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency::instanceMemoryMB()", + "new": "method java.lang.Integer com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency::instanceMemoryMB()", + "justification": "Service bug fix." + }, + { + "ignore": true, + "code": "java.method.returnTypeChanged", + "old": "method java.lang.Float com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency::maximumInstanceCount()", + "new": "method java.lang.Integer com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency::maximumInstanceCount()", + "justification": "Service bug fix." + }, + { + "ignore": true, + "code": "java.method.parameterTypeChanged", + "old": "parameter com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency::withInstanceMemoryMB(===java.lang.Float===)", + "new": "parameter com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency::withInstanceMemoryMB(===java.lang.Integer===)", + "parameterIndex": "0", + "justification": "Service bug fix." + }, + { + "ignore": true, + "code": "java.method.parameterTypeChanged", + "old": "parameter com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency::withMaximumInstanceCount(===java.lang.Float===)", + "new": "parameter com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrency::withMaximumInstanceCount(===java.lang.Integer===)", + "parameterIndex": "0", + "justification": "Service bug fix." + }, + { + "ignore": true, + "code": "java.method.returnTypeChanged", + "old": "method java.lang.Float com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrencyTriggersHttp::perInstanceConcurrency()", + "new": "method java.lang.Integer com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrencyTriggersHttp::perInstanceConcurrency()", + "justification": "Service bug fix." + }, + { + "ignore": true, + "code": "java.method.parameterTypeChanged", + "old": "parameter com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrencyTriggersHttp com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrencyTriggersHttp::withPerInstanceConcurrency(===java.lang.Float===)", + "new": "parameter com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrencyTriggersHttp com.azure.resourcemanager.appservice.models.FunctionsScaleAndConcurrencyTriggersHttp::withPerInstanceConcurrency(===java.lang.Integer===)", + "parameterIndex": "0", + "justification": "Service bug fix." + }, + { + "ignore": true, + "code": "java.class.nowFinal", + "old": "class com.azure.resourcemanager.sql.models.DatabaseIdentity", + "new": "class com.azure.resourcemanager.sql.models.DatabaseIdentity", + "justification": "Customer unlikely to subclass this class." + }, + { + "ignore": true, + "code": "java.class.nowFinal", + "old": "class com.azure.resourcemanager.sql.models.DatabaseUserIdentity", + "new": "class com.azure.resourcemanager.sql.models.DatabaseUserIdentity", + "justification": "Customer unlikely to subclass this class." + }, + { + "ignore": true, + "code": "java.class.nowFinal", + "old": "class com.azure.resourcemanager.sql.models.ResourceIdentity", + "new": "class com.azure.resourcemanager.sql.models.ResourceIdentity", + "justification": "Customer unlikely to subclass this class." + }, + { + "ignore": true, + "code": "java.class.nowFinal", + "old": "class com.azure.resourcemanager.sql.models.UserIdentity", + "new": "class com.azure.resourcemanager.sql.models.UserIdentity", + "justification": "Customer unlikely to subclass this class." + }, + { + "ignore": true, + "code": "java.annotation.removed", + "old": "method com.azure.communication.rooms.models.ParticipantRole com.azure.communication.rooms.models.ParticipantRole::fromString(java.lang.String)", + "new": "method com.azure.communication.rooms.models.ParticipantRole com.azure.communication.rooms.models.ParticipantRole::fromString(java.lang.String)", + "annotation": "@com.fasterxml.jackson.annotation.JsonCreator", + "justification": "Migration to azure-json" + }, + { + "ignore": true, + "code": "java.method.removed", + "old": "method com.azure.resourcemanager.compute.models.WindowsConfiguration com.azure.resourcemanager.compute.models.WindowsConfiguration::withEnableVMAgentPlatformUpdates(java.lang.Boolean)", + "justification": "Service changed the property to readOnly." + } + ] + } + } ] diff --git a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml index 6b0b0452c5..482a083ce2 100644 --- a/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml +++ b/protocol-sdk-integration-tests/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml @@ -1,9 +1,2151 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/protocol-sdk-integration-tests/sdk/parents/azure-client-sdk-parent/pom.xml b/protocol-sdk-integration-tests/sdk/parents/azure-client-sdk-parent/pom.xml index 22d351c08f..325e755a7d 100644 --- a/protocol-sdk-integration-tests/sdk/parents/azure-client-sdk-parent/pom.xml +++ b/protocol-sdk-integration-tests/sdk/parents/azure-client-sdk-parent/pom.xml @@ -208,10 +208,6 @@ true - - - false - true @@ -238,8 +234,8 @@ - com.azure.json,com.azure.core.* - ${basedir}/src/main/java:${basedir}/../../core/azure-core/src/main/java:${basedir}/../../core/azure-json/src/main/java + com.azure.json,com.azure.xml,com.azure.core.* + @@ -255,6 +251,11 @@ false + + + true + + @@ -263,7 +264,7 @@ org.jacoco org.jacoco.agent runtime - 0.8.11 + 0.8.12 test
@@ -292,24 +293,37 @@ - - - src/test/resources - - - ${project.parent.relativePath} - - simplelogger.properties - - - - + + + org.codehaus.mojo + animal-sniffer-maven-plugin + 1.23 + + + package + + check + + + ${animal.sniffer.skip} + + com.toasttab.android + gummy-bears-api-26 + 0.8.0 + + false + ${animal.sniffer.ignores} + + + + + org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 @@ -346,7 +360,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.2.2 + 3.3.0 ${packageOutputDirectory} @@ -361,7 +375,7 @@ com.azure.tools codesnippet-maven-plugin - 1.0.0-beta.8 + 1.0.0-beta.10 ${codesnippet.skip} **/*.md @@ -386,7 +400,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.0 + 3.6.3 attach-javadocs @@ -401,7 +415,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + 3.3.1 attach-sources @@ -419,7 +433,7 @@ org.apache.maven.plugins maven-antrun-plugin - 3.0.0 + 3.1.0 copy @@ -439,7 +453,7 @@ org.jacoco jacoco-maven-plugin - 0.8.11 + 0.8.12 ${project.build.directory}/jacoco.exec @@ -540,7 +554,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.3.0 + 3.5.0 attach-artifacts @@ -583,7 +597,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.0.0-M3 + 3.4.1 com.google.code.findbugs:jsr305:[3.0.2] @@ -653,7 +668,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 true true @@ -741,7 +756,7 @@ org.ow2.asm asm - 9.6 + 9.7
@@ -774,7 +789,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.0 + 3.6.3 1.8 Azure SDK for Java Reference Documentation @@ -898,6 +913,11 @@ ${parallelizeTests} + ${project.build.directory}/${project.artifactId}-test.log + true + dd MMM yyyy HH:mm:ss,SSS + info + debug 1 false @@ -912,14 +932,14 @@ org.ow2.asm asm - 9.6 + 9.7 org.jacoco org.jacoco.agent runtime - 0.8.11 + 0.8.12 @@ -942,6 +962,11 @@ ${parallelizeTests} + ${project.build.directory}/${project.artifactId}-test.log + true + dd MMM yyyy HH:mm:ss,SSS + info + debug 1 false @@ -956,14 +981,14 @@ org.ow2.asm asm - 9.6 + 9.7 org.jacoco org.jacoco.agent runtime - 0.8.11 + 0.8.12 @@ -982,7 +1007,7 @@ ^\d+\.\d+\.\d+$ - true + false ${revapi.failBuildOnProblemsFound} @@ -1024,7 +1049,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.1 + 3.5.2 ${shade.skip} @@ -1088,7 +1113,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.0 + 3.6.3 non-aggregate @@ -1101,7 +1126,7 @@ org.apache.maven.plugins maven-project-info-reports-plugin - 3.0.0 + 3.5.0 @@ -1153,7 +1178,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 1.8 1.8 @@ -1172,7 +1197,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.0 + 3.6.3 module-info.java @@ -1187,7 +1212,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.0 + 3.6.3 module-info.java @@ -1209,7 +1234,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 -Xlint:-module @@ -1352,7 +1377,7 @@ org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.2.0 generate-overview-from-readme @@ -1380,7 +1405,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.0 + 3.6.3 ${project.build.directory}/readme_overview.html @@ -1402,7 +1427,7 @@ org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.2.0 verify-readme-codesnippet @@ -1427,65 +1452,6 @@ - - - dependency-checker - - - dependency-checker - - - - - - net.jonathangiles.tools - dependencyChecker-maven-plugin - 1.0.6 - false - - - generateReport - package - - check - - - html - true - true - - - - - - net.jonathangiles.tools - whitelistgenerator-maven-plugin - 1.0.2 - - - generateAllowlistReport - package - - report - - - . - target/dependency-allowlist.json - - com.azure:azure-cosmos-benchmark - com.azure:azure-core-test - com.azure:azure-e2e - com.azure:azure-storage-perf - com.azure:perf-test-core - - - - - - - - - parallel-test-playback-no-azure-test-mode-env @@ -1637,7 +1603,7 @@ org.codehaus.mojo xml-maven-plugin - 1.0.2 + 1.1.0 verify @@ -1714,27 +1680,27 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + test-module-base-compile @@ -1749,7 +1715,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0