This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-extension-apiregions.git
The following commit(s) were added to refs/heads/master by this push:
new 146c81c SLING-13129 : Add optional library info to deprecated package
146c81c is described below
commit 146c81ccc811a00a084481886aac5001989bdffd
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Fri Feb 27 09:00:42 2026 +0100
SLING-13129 : Add optional library info to deprecated package
---
.../apiregions/analyser/CheckDeprecatedApi.java | 77 +++++++++++++++++-----
.../extension/apiregions/api/ApiExport.java | 35 +++++++++-
.../extension/apiregions/api/package-info.java | 2 +-
.../analyser/CheckApiRegionsDuplicatesTest.java | 1 -
.../analyser/CheckDeprecatedApiTest.java | 58 ++++++++++++++++
5 files changed, 153 insertions(+), 20 deletions(-)
diff --git
a/src/main/java/org/apache/sling/feature/extension/apiregions/analyser/CheckDeprecatedApi.java
b/src/main/java/org/apache/sling/feature/extension/apiregions/analyser/CheckDeprecatedApi.java
index fdd7d7f..c8cf216 100644
---
a/src/main/java/org/apache/sling/feature/extension/apiregions/analyser/CheckDeprecatedApi.java
+++
b/src/main/java/org/apache/sling/feature/extension/apiregions/analyser/CheckDeprecatedApi.java
@@ -26,6 +26,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -120,6 +121,10 @@ public class CheckDeprecatedApi implements AnalyserTask {
for (final BundleDescriptor bd :
context.getFeatureDescriptor().getBundleDescriptors()) {
if (isInAllowedRegion(bundleRegions.get(bd), region.getName(),
allowedNames)) {
+ // Collect all deprecation findings, grouped by library (null
= no library)
+ final Map<String, String> libraryErrors = new TreeMap<>();
+ final Map<String, String> libraryWarnings = new TreeMap<>();
+
for (final PackageInfo pi : bd.getImportedPackages()) {
if (!checkOptionalImports && pi.isOptional()) {
continue;
@@ -130,19 +135,30 @@ public class CheckDeprecatedApi implements AnalyserTask {
deprecationInfo = deprecatedPackage.isDeprecated(pi);
}
if (deprecationInfo != null) {
- String msg = "Usage of deprecated package found : "
- .concat(pi.getName())
- .concat(" : ")
- .concat(deprecationInfo.getMessage());
- if (deprecationInfo.getSince() != null) {
- msg = msg.concat(" Deprecated since
").concat(deprecationInfo.getSince());
- }
boolean isError;
if (deprecationInfo.getMode() != null) {
isError = deprecationInfo.getMode() ==
DeprecationValidationMode.STRICT;
} else {
isError = strict;
}
+ String msg;
+ final String library =
deprecatedPackage.getExport().getLibrary();
+ if (library != null) {
+ msg = "Usage of deprecated library found : "
+ .concat(library)
+ .concat(", package(s) : <start>");
+ } else {
+ msg = "Usage of deprecated package found : ";
+ }
+ msg = msg.concat(pi.getName());
+ if (library != null) {
+ msg = msg.concat("<end>");
+ }
+ msg = msg.concat(" :
").concat(deprecationInfo.getMessage());
+
+ if (deprecationInfo.getSince() != null) {
+ msg = msg.concat(" Deprecated since
").concat(deprecationInfo.getSince());
+ }
if (deprecationInfo.isForRemoval()) {
boolean printRemoval = true;
if (checkDate != null) {
@@ -160,13 +176,38 @@ public class CheckDeprecatedApi implements AnalyserTask {
msg = msg.concat(" For removal :
").concat(deprecationInfo.getForRemoval());
}
}
- if (isError) {
-
context.reportArtifactError(bd.getArtifact().getId(), msg);
+ if (library != null) {
+ final Map<String, String> target = isError ?
libraryErrors : libraryWarnings;
+ // check if entry exists for library
+ String entry = target.get(library);
+ if (entry == null) {
+ entry = msg;
+ } else {
+ entry = entry.replace(
+ "<end>", ",
".concat(pi.getName()).concat("<end>"));
+ }
+ target.put(library, entry);
} else {
-
context.reportArtifactWarning(bd.getArtifact().getId(), msg);
+ if (isError) {
+
context.reportArtifactError(bd.getArtifact().getId(), msg);
+ } else {
+
context.reportArtifactWarning(bd.getArtifact().getId(), msg);
+ }
}
}
}
+
+ // Report grouped messages per library
+ for (final String entry : libraryErrors.values()) {
+ context.reportArtifactError(
+ bd.getArtifact().getId(),
+ entry.replace("<start>", "").replace("<end>", ""));
+ }
+ for (final String entry : libraryWarnings.values()) {
+ context.reportArtifactWarning(
+ bd.getArtifact().getId(),
+ entry.replace("<start>", "").replace("<end>", ""));
+ }
}
}
}
@@ -233,7 +274,7 @@ public class CheckDeprecatedApi implements AnalyserTask {
}
}
}
- return new DeprecatedPackage(export.getDeprecation().getPackageInfo(),
deprecatedList, nonDeprecatedList);
+ return new DeprecatedPackage(export, deprecatedList,
nonDeprecatedList);
}
private Set<String> getBundleRegions(final BundleDescriptor info, final
ApiRegions regions) {
@@ -248,12 +289,16 @@ public class CheckDeprecatedApi implements AnalyserTask {
* Represents a deprecated package with its deprecation information and
package versions.
*/
static final class DeprecatedPackage {
- private final DeprecationInfo deprecationInfo;
+ private final ApiExport export;
private final List<PackageInfo> deprecatedList;
private final List<PackageInfo> nonDeprecatedList;
public DeprecationInfo getDeprecationInfo() {
- return deprecationInfo;
+ return export.getDeprecation().getPackageInfo();
+ }
+
+ public ApiExport getExport() {
+ return export;
}
/**
@@ -264,10 +309,10 @@ public class CheckDeprecatedApi implements AnalyserTask {
* @param nonDeprecatedList list of non-deprecated package versions
*/
public DeprecatedPackage(
- final DeprecationInfo deprecationInfo,
+ final ApiExport export,
final List<PackageInfo> deprecatedList,
final List<PackageInfo> nonDeprecatedList) {
- this.deprecationInfo = deprecationInfo;
+ this.export = export;
this.deprecatedList = deprecatedList;
this.nonDeprecatedList = nonDeprecatedList;
}
@@ -291,7 +336,7 @@ public class CheckDeprecatedApi implements AnalyserTask {
for (final PackageInfo deprecated : deprecatedList) {
final Version exportVersion = deprecated.getPackageVersion();
if (exportVersion == null || importVersion == null ||
importVersion.includes(exportVersion)) {
- return deprecationInfo;
+ return this.getDeprecationInfo();
}
}
// not found, do not report
diff --git
a/src/main/java/org/apache/sling/feature/extension/apiregions/api/ApiExport.java
b/src/main/java/org/apache/sling/feature/extension/apiregions/api/ApiExport.java
index 369ecc6..36ba64f 100644
---
a/src/main/java/org/apache/sling/feature/extension/apiregions/api/ApiExport.java
+++
b/src/main/java/org/apache/sling/feature/extension/apiregions/api/ApiExport.java
@@ -56,10 +56,15 @@ public class ApiExport implements Comparable<ApiExport> {
private static final String PREVIOUS_ARTIFACT_ID_KEY =
"previous-artifact-id";
+ private static final String LIBRARY_KEY = "library";
+
private final String name;
private String toggle;
+ /** Optional library information */
+ private String library;
+
/** If the package is behind a toggle, this is the previous artifact
containing the package not behind a toggle */
private ArtifactId previousArtifactId;
@@ -144,6 +149,24 @@ public class ApiExport implements Comparable<ApiExport> {
return this.deprecation;
}
+ /**
+ * Get the optional library information.
+ * @return The library or {@code null}
+ * @since 2.1.0
+ */
+ public String getLibrary() {
+ return library;
+ }
+
+ /**
+ * Set the library information.
+ * @param value The library
+ * @since 2.1.0
+ */
+ public void setLibrary(final String value) {
+ this.library = value;
+ }
+
/**
* Internal method to parse the extension JSON
* @param dValue The JSON value
@@ -310,6 +333,10 @@ public class ApiExport implements Comparable<ApiExport> {
expBuilder.add(DEPRECATED_KEY, depValue);
}
+ if (this.getLibrary() != null) {
+ expBuilder.add(LIBRARY_KEY, this.getLibrary());
+ }
+
for (final Map.Entry<String, String> entry :
this.getProperties().entrySet()) {
expBuilder.add(entry.getKey(), entry.getValue());
}
@@ -355,6 +382,9 @@ public class ApiExport implements Comparable<ApiExport> {
final JsonValue dValue = expObj.get(DEPRECATED_KEY);
export.parseDeprecation(dValue);
+ } else if (LIBRARY_KEY.equals(key)) {
+ export.setLibrary(expObj.getString(key));
+
// everything else is stored as a string property
} else {
export.getProperties().put(key, expObj.getString(key));
@@ -375,12 +405,12 @@ public class ApiExport implements Comparable<ApiExport> {
@Override
public String toString() {
return "ApiExport [name=" + name + ", toggle=" + toggle + ",
previousArtifactId=" + previousArtifactId
- + ", properties=" + properties + "]";
+ + ", library=" + library + ", properties=" + properties + "]";
}
@Override
public int hashCode() {
- return Objects.hash(deprecation, name, previousArtifactId, properties,
toggle);
+ return Objects.hash(deprecation, name, previousArtifactId, properties,
toggle, library);
}
@Override
@@ -399,6 +429,7 @@ public class ApiExport implements Comparable<ApiExport> {
&& Objects.equals(name, other.name)
&& Objects.equals(previousArtifactId, other.previousArtifactId)
&& Objects.equals(properties, other.properties)
+ && Objects.equals(library, other.library)
&& Objects.equals(toggle, other.toggle);
}
}
diff --git
a/src/main/java/org/apache/sling/feature/extension/apiregions/api/package-info.java
b/src/main/java/org/apache/sling/feature/extension/apiregions/api/package-info.java
index bc1d240..6bd8e02 100644
---
a/src/main/java/org/apache/sling/feature/extension/apiregions/api/package-info.java
+++
b/src/main/java/org/apache/sling/feature/extension/apiregions/api/package-info.java
@@ -17,5 +17,5 @@
* under the License.
*/
[email protected]("2.0.0")
[email protected]("2.1.0")
package org.apache.sling.feature.extension.apiregions.api;
diff --git
a/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsDuplicatesTest.java
b/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsDuplicatesTest.java
index 81b99f8..2d789f1 100644
---
a/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsDuplicatesTest.java
+++
b/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsDuplicatesTest.java
@@ -40,7 +40,6 @@ public class CheckApiRegionsDuplicatesTest extends
AbstractApiRegionsAnalyserTas
assertFalse(errors.isEmpty());
assertEquals(1, errors.size());
- System.out.println(errors);
assertTrue(
errors.iterator()
.next()
diff --git
a/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckDeprecatedApiTest.java
b/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckDeprecatedApiTest.java
index a16a337..8ea809d 100644
---
a/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckDeprecatedApiTest.java
+++
b/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckDeprecatedApiTest.java
@@ -23,6 +23,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.Manifest;
@@ -358,6 +359,63 @@ public class CheckDeprecatedApiTest {
return ctx;
}
+ @Test
+ public void testLibraryGrouping() throws Exception {
+ final CheckDeprecatedApi analyser = new CheckDeprecatedApi();
+
+ final Feature feature = new
Feature(ArtifactId.fromMvnId("g:feature:1"));
+ final Extension extension =
+ new Extension(ExtensionType.JSON, ApiRegions.EXTENSION_NAME,
ExtensionState.OPTIONAL);
+
extension.setJSON("[{\"name\":\"global\",\"feature-origins\":[\"g:feature:1\"],"
+ + "\"exports\":["
+ +
"{\"name\":\"org.foo.a\",\"deprecated\":{\"msg\":\"deprecated
a\"},\"library\":\"com.example:lib:1\"},"
+ +
"{\"name\":\"org.foo.b\",\"deprecated\":{\"msg\":\"deprecated
b\"},\"library\":\"com.example:lib:1\"},"
+ + "{\"name\":\"org.foo.c\",\"deprecated\":\"deprecated c\"}"
+ + "]}]");
+ feature.getExtensions().add(extension);
+
+ final FeatureDescriptor fd = new FeatureDescriptorImpl(feature);
+
+ // API bundles exporting the packages
+ final Artifact apiBundle = new
Artifact(ArtifactId.fromMvnId("g:api:1.0.0"));
+ apiBundle.setFeatureOrigins(feature.getId());
+ final BundleDescriptor apiDesc = new TestBundleDescriptor(apiBundle);
+ apiDesc.getExportedPackages().add(new PackageInfo("org.foo.a", "1.0",
false, Collections.emptySet()));
+ apiDesc.getExportedPackages().add(new PackageInfo("org.foo.b", "1.0",
false, Collections.emptySet()));
+ apiDesc.getExportedPackages().add(new PackageInfo("org.foo.c", "1.0",
false, Collections.emptySet()));
+ fd.getBundleDescriptors().add(apiDesc);
+
+ // Importer bundle importing all three packages
+ final Artifact importBundle = new
Artifact(ArtifactId.fromMvnId("g:importer:1.0.0"));
+ importBundle.setFeatureOrigins(feature.getId());
+ final BundleDescriptor importBd = new
TestBundleDescriptor(importBundle);
+ importBd.getImportedPackages().add(new PackageInfo("org.foo.a", "1.0",
false, Collections.emptySet()));
+ importBd.getImportedPackages().add(new PackageInfo("org.foo.b", "1.0",
false, Collections.emptySet()));
+ importBd.getImportedPackages().add(new PackageInfo("org.foo.c", "1.0",
false, Collections.emptySet()));
+ fd.getBundleDescriptors().add(importBd);
+
+ final AnalyserTaskContext ctx =
Mockito.mock(AnalyserTaskContext.class);
+ Mockito.when(ctx.getFeature()).thenReturn(feature);
+ Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+
Mockito.when(ctx.getConfiguration()).thenReturn(Collections.emptyMap());
+
+ analyser.execute(ctx);
+
+ final ArtifactId importerId = ArtifactId.fromMvnId("g:importer:1.0.0");
+
+ // Exactly two warnings total for this bundle (one grouped, one
individual)
+ final org.mockito.ArgumentCaptor<String> msgCaptor =
org.mockito.ArgumentCaptor.forClass(String.class);
+ Mockito.verify(ctx,
Mockito.times(2)).reportArtifactWarning(Mockito.eq(importerId),
msgCaptor.capture());
+ Mockito.verify(ctx, never()).reportArtifactError(Mockito.any(),
Mockito.anyString());
+
+ final List<String> msgs = msgCaptor.getAllValues();
+ // one message must contain the library name and both package names
+ assertTrue(msgs.stream()
+ .anyMatch(m -> m.contains("com.example:lib:1") &&
m.contains("org.foo.a") && m.contains("org.foo.b")));
+ // one message must contain the individual package name without
library grouping prefix
+ assertTrue(msgs.stream().anyMatch(m -> m.contains("org.foo.c") &&
!m.contains("com.example:lib:1")));
+ }
+
private static final class TestBundleDescriptor extends BundleDescriptor {
private final Artifact artifact;