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 f2a2437 SLING-13095 : Add flag to include/exclude optional imports
for deprecated api checks
f2a2437 is described below
commit f2a2437018e2cb3e0bb1f590d5e479e1a89155ba
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Tue Feb 3 14:56:30 2026 +0100
SLING-13095 : Add flag to include/exclude optional imports for deprecated
api checks
---
README.md | 1 +
.../apiregions/analyser/CheckDeprecatedApi.java | 12 ++-
.../analyser/CheckDeprecatedApiTest.java | 102 +++++++++++++++++++++
3 files changed, 113 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 9a22f08..77d9783 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,7 @@ For more details see here: [Configuration
Regions](docs/api-regions.md#configura
* `regions` : The regions to check for such usage. This is a comma separate
string of region names. It defaults to `global`.
* `strict` : By default the analyser issues warnings. If this is set to
`true` errors are issued instead.
* `removal-period` : If deprecated api is used and that api has a
`for-removal` information with a date set, then this configuration can be used
to issue an error instead of a warning if the removal date is less than the
configured number of days away. For example setting this to 28 will result in
errors being generated four weeks ahead of the removal date.
+ * `check-optional-imports` : By default optional imports are ignored. If
this is set to `true` optional imports are reported as warnings or errors like
required imports.
* `artifact-rules` : This analyser validates the artifacts (bundles) against
rules in the feature model.
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 1cb45e3..944a761 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
@@ -47,6 +47,8 @@ public class CheckDeprecatedApi implements AnalyserTask {
private static final String CFG_REMOVAL_PERIOD = "removal-period";
+ private static final String CFG_CHECK_OPTIONAL_IMPORTS =
"check-optional-imports";
+
private static final String PROP_VERSION = "version";
@Override
@@ -70,13 +72,15 @@ public class CheckDeprecatedApi implements AnalyserTask {
Boolean.parseBoolean(context.getConfiguration().getOrDefault(CFG_STRICT,
"false"));
final Integer removalPeriod =
Integer.parseInt(context.getConfiguration().getOrDefault(CFG_REMOVAL_PERIOD,
"-1"));
+ final boolean checkOptionalImports =
+
Boolean.parseBoolean(context.getConfiguration().getOrDefault(CFG_CHECK_OPTIONAL_IMPORTS,
"false"));
final String regionNames =
context.getConfiguration().getOrDefault(CFG_REGIONS, ApiRegion.GLOBAL);
for (final String r : regionNames.split(",")) {
final ApiRegion region = regions.getRegionByName(r.trim());
if (region == null) {
context.reportExtensionError(ApiRegions.EXTENSION_NAME,
"Region not found:" + r.trim());
} else {
- checkBundlesForRegion(context, region, bundleRegions,
strict, removalPeriod);
+ checkBundlesForRegion(context, region, bundleRegions,
strict, removalPeriod, checkOptionalImports);
}
}
}
@@ -96,7 +100,8 @@ public class CheckDeprecatedApi implements AnalyserTask {
final ApiRegion region,
final Map<BundleDescriptor, Set<String>> bundleRegions,
final boolean strict,
- final int removalPeriod) {
+ final int removalPeriod,
+ final boolean checkOptionalImports) {
final Calendar checkDate;
if (removalPeriod > 0) {
checkDate = Calendar.getInstance();
@@ -114,6 +119,9 @@ public class CheckDeprecatedApi implements AnalyserTask {
for (final BundleDescriptor bd :
context.getFeatureDescriptor().getBundleDescriptors()) {
if (isInAllowedRegion(bundleRegions.get(bd), region.getName(),
allowedNames)) {
for (final PackageInfo pi : bd.getImportedPackages()) {
+ if (!checkOptionalImports && pi.isOptional()) {
+ continue;
+ }
final VersionRange importRange =
pi.getPackageVersionRange();
DeprecationInfo deprecationInfo = null;
for (final ApiExport exp : exports) {
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 cd111af..479765b 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
@@ -18,23 +18,43 @@
*/
package org.apache.sling.feature.extension.apiregions.analyser;
+import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
+import java.util.jar.Manifest;
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionState;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
import org.apache.sling.feature.extension.apiregions.api.ApiExport;
import org.apache.sling.feature.extension.apiregions.api.ApiRegion;
import org.apache.sling.feature.extension.apiregions.api.ApiRegions;
import org.apache.sling.feature.extension.apiregions.api.DeprecationInfo;
+import org.apache.sling.feature.scanner.BundleDescriptor;
+import org.apache.sling.feature.scanner.FeatureDescriptor;
+import org.apache.sling.feature.scanner.PackageInfo;
+import org.apache.sling.feature.scanner.impl.FeatureDescriptorImpl;
import org.junit.Test;
+import org.mockito.Mockito;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.never;
public class CheckDeprecatedApiTest {
+ private static final String API_REGIONS_JSON =
"[{\"name\":\"global\",\"feature-origins\":[\"g:feature:1\"],"
+ +
"\"exports\":[{\"name\":\"org.foo.deprecated\",\"deprecated\":\"deprecated\"}]}]";
+
@Test
public void testIsInAllowedRegion() {
final CheckDeprecatedApi analyser = new CheckDeprecatedApi();
@@ -92,4 +112,86 @@ public class CheckDeprecatedApiTest {
e1.getDeprecation().getPackageInfo().getMessage(),
exp.getDeprecation().getPackageInfo().getMessage());
}
+
+ @Test
+ public void testOptionalImportIgnoredByDefault() throws Exception {
+ final CheckDeprecatedApi analyser = new CheckDeprecatedApi();
+ final AnalyserTaskContext ctx = createContext(Collections.emptyMap(),
true);
+
+ analyser.execute(ctx);
+
+ Mockito.verify(ctx, never()).reportArtifactWarning(Mockito.any(),
Mockito.anyString());
+ Mockito.verify(ctx, never()).reportArtifactError(Mockito.any(),
Mockito.anyString());
+ }
+
+ @Test
+ public void testOptionalImportReportedWhenEnabled() throws Exception {
+ final CheckDeprecatedApi analyser = new CheckDeprecatedApi();
+ final Map<String, String> cfg = new HashMap<>();
+ cfg.put("check-optional-imports", "true");
+ final AnalyserTaskContext ctx = createContext(cfg, true);
+
+ analyser.execute(ctx);
+
+ Mockito.verify(ctx)
+ .reportArtifactWarning(
+ Mockito.eq(ArtifactId.fromMvnId("g:b:1.0.0")),
Mockito.contains("org.foo.deprecated"));
+ }
+
+ private AnalyserTaskContext createContext(final Map<String, String>
config, final boolean optionalImport) {
+ final Feature feature = new
Feature(ArtifactId.fromMvnId("g:feature:1"));
+ final Extension extension =
+ new Extension(ExtensionType.JSON, ApiRegions.EXTENSION_NAME,
ExtensionState.OPTIONAL);
+ extension.setJSON(API_REGIONS_JSON);
+ feature.getExtensions().add(extension);
+
+ final FeatureDescriptor fd = new FeatureDescriptorImpl(feature);
+
+ final Artifact bundle = new
Artifact(ArtifactId.fromMvnId("g:b:1.0.0"));
+ bundle.setFeatureOrigins(feature.getId());
+ final BundleDescriptor bd = new TestBundleDescriptor(bundle);
+ bd.getImportedPackages()
+ .add(new PackageInfo("org.foo.deprecated", "1.0",
optionalImport, Collections.emptySet()));
+ fd.getBundleDescriptors().add(bd);
+
+ final AnalyserTaskContext ctx =
Mockito.mock(AnalyserTaskContext.class);
+ Mockito.when(ctx.getFeature()).thenReturn(feature);
+ Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+ Mockito.when(ctx.getConfiguration()).thenReturn(config);
+ return ctx;
+ }
+
+ private static final class TestBundleDescriptor extends BundleDescriptor {
+ private final Artifact artifact;
+
+ TestBundleDescriptor(final Artifact artifact) {
+ super(artifact.getId().toMvnId());
+ this.artifact = artifact;
+ }
+
+ @Override
+ public URL getArtifactFile() {
+ return null;
+ }
+
+ @Override
+ public Artifact getArtifact() {
+ return artifact;
+ }
+
+ @Override
+ public Manifest getManifest() {
+ return null;
+ }
+
+ @Override
+ public String getBundleVersion() {
+ return null;
+ }
+
+ @Override
+ public String getBundleSymbolicName() {
+ return null;
+ }
+ }
}