diff --git a/.github/workflows/pr_build_jdk11_dependents.yml b/.github/workflows/pr_build_jdk11_dependents.yml index efc358086c..81ec441dc2 100644 --- a/.github/workflows/pr_build_jdk11_dependents.yml +++ b/.github/workflows/pr_build_jdk11_dependents.yml @@ -35,7 +35,42 @@ jobs: matrix: jdk-distribution: [ temurin ] java-version: [ 11, 17 ] - ruleset-test: [ WindupRulesTest, WindupRulesLinksTest] + ruleset-test: [ WindupRulesTest ] + tests-pattern: [ 'rules-reviewed/[a-d]', + 'rules-reviewed/e', + 'rules-reviewed/[f-z]', + 'rules-generated/' ] + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + repository: windup/windup-rulesets + ref: ${{ github.base_ref }} + - name: Set up JDK + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java-version }} + distribution: ${{ matrix.jdk-distribution }} + java-package: jdk + - name: Cache local Maven repository + uses: actions/cache@v3 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-windup-rulesets-build-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-maven-windup-build-${{ github.sha }} + - name: Test + run: mvn clean test -nsu -f rules -DrunTestsMatching=${{ matrix.tests-pattern }} -Dtest=${{ matrix.ruleset-test }} + + windup-rulesets-links-build: + runs-on: ubuntu-latest + needs: [windup-build] + strategy: + fail-fast: false + matrix: + jdk-distribution: [ temurin ] + java-version: [ 11, 17 ] + ruleset-test: [ WindupRulesLinksTest ] steps: - name: Checkout repo uses: actions/checkout@v3 @@ -62,7 +97,7 @@ jobs: windup-maven-plugin-build: runs-on: ubuntu-latest - needs: [windup-rulesets-build] + needs: [windup-rulesets-links-build] strategy: fail-fast: false matrix: diff --git a/bom/pom.xml b/bom/pom.xml index e08620419a..26610b4cdc 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -404,12 +404,12 @@ org.eclipse.platform org.eclipse.core.runtime - [3.13.0,4.0.0) + [3.13.0,3.27.0) org.eclipse.platform org.eclipse.core.resources - [3.14.0,4.0.0) + [3.14.0,3.19.0) io.netty @@ -419,7 +419,7 @@ org.jsoup jsoup - 1.14.3 + 1.15.3 com.google.guava diff --git a/config/api/src/main/java/org/jboss/windup/config/projecttraversal/ProjectTraversalCache.java b/config/api/src/main/java/org/jboss/windup/config/projecttraversal/ProjectTraversalCache.java index 765f75478b..6a7ce3460c 100644 --- a/config/api/src/main/java/org/jboss/windup/config/projecttraversal/ProjectTraversalCache.java +++ b/config/api/src/main/java/org/jboss/windup/config/projecttraversal/ProjectTraversalCache.java @@ -71,6 +71,11 @@ public static Set getApplicationsForProject(GraphContext context, return results; } + public static void clear() { + moduleToApplicationCache.clear(); + applicationToProjectCache.clear(); + } + private static Set getFromCache(ProjectModel project) { if (project == null) return null; diff --git a/config/impl/src/main/java/org/jboss/windup/config/loader/RuleLoaderImpl.java b/config/impl/src/main/java/org/jboss/windup/config/loader/RuleLoaderImpl.java index daedf05d82..65f00cfd47 100644 --- a/config/impl/src/main/java/org/jboss/windup/config/loader/RuleLoaderImpl.java +++ b/config/impl/src/main/java/org/jboss/windup/config/loader/RuleLoaderImpl.java @@ -57,7 +57,7 @@ private RuleProviderRegistry buildRegistry(RuleLoaderContext ruleLoaderContext) registry.setProviders(providers); // Get override rules from override providers (if any) - Map overrideRules = extractOverrideRules(providers); + Map overrideRules = extractOverrideRules(providers, ruleLoaderContext); // Add provider->rules mappings to the registry and, for each rule, inject parameters if applicable for (RuleProvider provider : providers) { @@ -166,10 +166,11 @@ private void printRulePhases(List allProviders) { LOG.info("Rule Phases: [\n" + rulePhaseSB.toString() + "]"); } - private Map extractOverrideRules(List providers) { + private Map extractOverrideRules(List providers, RuleLoaderContext ruleLoaderContext) { Map overrideRules = new HashMap<>(); providers.stream() .filter(provider -> provider.getMetadata().isOverrideProvider()) + .filter(provider -> ruleLoaderContext.getRuleProviderFilter() == null || ruleLoaderContext.getRuleProviderFilter().accept(provider)) .forEach(provider -> { provider.getConfiguration(null).getRules().forEach(rule -> { RuleKey ruleKey = new RuleKey(provider.getMetadata().getID(), rule.getId()); diff --git a/config/tests/src/test/java/org/jboss/windup/config/RuleProviderOverrideTest.java b/config/tests/src/test/java/org/jboss/windup/config/RuleProviderOverrideTest.java index f33980079b..d6bb5ca8c1 100644 --- a/config/tests/src/test/java/org/jboss/windup/config/RuleProviderOverrideTest.java +++ b/config/tests/src/test/java/org/jboss/windup/config/RuleProviderOverrideTest.java @@ -1,6 +1,7 @@ package org.jboss.windup.config; -import java.io.IOException; +import java.util.Collections; +import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; @@ -14,7 +15,9 @@ import org.jboss.windup.config.loader.RuleLoader; import org.jboss.windup.config.loader.RuleLoaderContext; import org.jboss.windup.config.metadata.MetadataBuilder; -import org.jboss.windup.graph.GraphContextFactory; +import org.jboss.windup.config.metadata.RuleMetadata; +import org.jboss.windup.config.metadata.Technology; +import org.jboss.windup.exec.rulefilters.SourceAndTargetPredicate; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -27,14 +30,13 @@ @RunWith(Arquillian.class) public class RuleProviderOverrideTest { - @Inject - private GraphContextFactory factory; @Inject private RuleLoader loader; @Deployment @AddonDependencies({ @AddonDependency(name = "org.jboss.windup.config:windup-config"), + @AddonDependency(name = "org.jboss.windup.exec:windup-exec"), @AddonDependency(name = "org.jboss.windup.graph:windup-graph"), @AddonDependency(name = "org.jboss.forge.furnace.container:cdi") }) @@ -43,15 +45,56 @@ public static AddonArchive getDeployment() { } @Test - public void testOverride() throws IOException { + public void testOverride() { RuleLoaderContext ruleLoaderContext = new RuleLoaderContext(); Configuration configuration = loader.loadConfiguration(ruleLoaderContext).getConfiguration(); int count = 0; + boolean foundTestOverrideProvider = false; + boolean foundTestOriginalWithTargetProvider = false; + for (Rule rule : configuration.getRules()) { + count++; + if (rule.toString().contains("(RuleOverride)")) foundTestOverrideProvider = true; + if (rule.toString().contains("(RuleOverrideWithTarget)")) foundTestOriginalWithTargetProvider = true; + } + Assert.assertTrue("RuleOverride", foundTestOverrideProvider); + Assert.assertTrue("RuleOverrideWithTarget", foundTestOriginalWithTargetProvider); + Assert.assertEquals(2, count); + } + + @Test + public void testOverrideWithTarget() { + final SourceAndTargetPredicate targetPredicate = new SourceAndTargetPredicate(Collections.emptyList(), List.of("test-target")); + RuleLoaderContext ruleLoaderContext = new RuleLoaderContext(Collections.emptyList(), targetPredicate); + Configuration configuration = loader.loadConfiguration(ruleLoaderContext).getConfiguration(); + int count = 0; + boolean foundTestOverrideProvider = false; + boolean foundTestOverrideWithTargetProvider = false; for (Rule rule : configuration.getRules()) { count++; - Assert.assertTrue("Override", rule.toString().contains("RuleOverride")); + if (rule.toString().contains("(RuleOverride)")) foundTestOverrideProvider = true; + if (rule.toString().contains("(RuleOverrideWithTarget)")) foundTestOverrideWithTargetProvider = true; } - Assert.assertEquals(1, count); + Assert.assertTrue("RuleOverride", foundTestOverrideProvider); + Assert.assertTrue("RuleOverrideWithTarget", foundTestOverrideWithTargetProvider); + Assert.assertEquals(2, count); + } + + @Test + public void testOverrideWithAnotherTarget() { + final SourceAndTargetPredicate targetPredicate = new SourceAndTargetPredicate(Collections.emptyList(), List.of("another-target")); + RuleLoaderContext ruleLoaderContext = new RuleLoaderContext(Collections.emptyList(), targetPredicate); + Configuration configuration = loader.loadConfiguration(ruleLoaderContext).getConfiguration(); + int count = 0; + boolean foundTestOverrideProvider = false; + boolean foundTestOverrideWithTargetProvider = false; + for (Rule rule : configuration.getRules()) { + count++; + if (rule.toString().contains("(RuleOverride)")) foundTestOverrideProvider = true; + if (rule.toString().contains("(OriginalRuleWithTarget)")) foundTestOverrideWithTargetProvider = true; + } + Assert.assertTrue("RuleOverride", foundTestOverrideProvider); + Assert.assertTrue("OriginalRuleWithTarget", foundTestOverrideWithTargetProvider); + Assert.assertEquals(2, count); } @Singleton @@ -116,5 +159,70 @@ public String toString() { }); } } + + @Singleton + public static class TestOriginalWithTargetProvider extends AbstractRuleProvider { + public TestOriginalWithTargetProvider() { + super(MetadataBuilder.forProvider(TestOriginalProvider.class, "TestRuleProviderWithTarget")); + } + + @Override + public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { + return ConfigurationBuilder.begin() + .addRule(new Rule() { + @Override + public void perform(Rewrite event, EvaluationContext context) { + } + + @Override + public boolean evaluate(Rewrite event, EvaluationContext context) { + return true; + } + + @Override + public String getId() { + return TestOriginalProvider.class.getSimpleName(); + } + + @Override + public String toString() { + return "OriginalRuleWithTarget"; + } + }); + } + } + + @Singleton + @RuleMetadata(targetTechnologies = {@Technology(id = "test-target")}) + public static class TestOverrideWithTargetProvider extends AbstractRuleProvider { + public TestOverrideWithTargetProvider() { + super(MetadataBuilder.forProvider(TestOverrideWithTargetProvider.class, "TestRuleProviderWithTarget").setOverrideProvider(true)); + } + + @Override + public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { + return ConfigurationBuilder.begin() + .addRule(new Rule() { + @Override + public void perform(Rewrite event, EvaluationContext context) { + } + + @Override + public boolean evaluate(Rewrite event, EvaluationContext context) { + return true; + } + + @Override + public String getId() { + return TestOriginalProvider.class.getSimpleName(); + } + + @Override + public String toString() { + return "RuleOverrideWithTarget"; + } + }); + } + } } } diff --git a/pf-ui/src/main/webapp/src/pages/application-edit/pages/dashboard/components/efforts-section.tsx b/pf-ui/src/main/webapp/src/pages/application-edit/pages/dashboard/components/efforts-section.tsx index e8b4eab418..a82877910b 100644 --- a/pf-ui/src/main/webapp/src/pages/application-edit/pages/dashboard/components/efforts-section.tsx +++ b/pf-ui/src/main/webapp/src/pages/application-edit/pages/dashboard/components/efforts-section.tsx @@ -172,6 +172,14 @@ export const EffortsSection: React.FC = ({ { + return e.totalIncidents === 0 && e.totalStoryPoints === 0; + }) + ? { y: [0, 9] } + : undefined + } domainPadding={{ x: 35 }} padding={{ bottom: 40, diff --git a/reporting-data/addon/src/main/java/org/jboss/windup/reporting/data/rules/DataGatheringRuleProvider.java b/reporting-data/addon/src/main/java/org/jboss/windup/reporting/data/rules/DataGatheringRuleProvider.java index 4e1d03b018..eaf0fa0a35 100644 --- a/reporting-data/addon/src/main/java/org/jboss/windup/reporting/data/rules/DataGatheringRuleProvider.java +++ b/reporting-data/addon/src/main/java/org/jboss/windup/reporting/data/rules/DataGatheringRuleProvider.java @@ -33,6 +33,8 @@ public void perform(GraphRewrite event, EvaluationContext context) { executorService.awaitTermination(2, TimeUnit.DAYS); } catch (InterruptedException e) { throw new WindupException("Failed to render reports due to a timeout: " + e.getMessage(), e); + } finally { + AbstractApiRuleProvider.executorServiceMap.remove(event.getGraphContext()); } } }); diff --git a/reporting/tests/src/test/java/org/jboss/windup/reporting/CSVExportingTest.java b/reporting/tests/src/test/java/org/jboss/windup/reporting/CSVExportingTest.java index 65223535a9..6379aad349 100644 --- a/reporting/tests/src/test/java/org/jboss/windup/reporting/CSVExportingTest.java +++ b/reporting/tests/src/test/java/org/jboss/windup/reporting/CSVExportingTest.java @@ -97,14 +97,14 @@ private void csvTest(boolean exportCSV) throws Exception { configuration.setExportingCSV(true); } processor.execute(configuration); - Assert.assertEquals(exportCSV, new File(outputPath + "/" + FILE1_NAME + ".csv").exists()); - Assert.assertEquals(exportCSV, new File(outputPath + "/" + FILE2_NAME + ".csv").exists()); + Assert.assertEquals(exportCSV, outputPath.resolve(FILE1_NAME + ".csv").toFile().exists()); + Assert.assertEquals(exportCSV, outputPath.resolve(FILE2_NAME + ".csv").toFile().exists()); if (exportCSV) { - Path resource = Paths.get("src/test/resources/test-exports/" + FILE1_NAME + ".csv"); - Path resource2 = Paths.get("src/test/resources/test-exports/" + FILE2_NAME + ".csv"); + Path resource = Paths.get("src", "test", "resources", "test-exports", FILE1_NAME + ".csv"); + Path resource2 = Paths.get("src", "test", "resources", "test-exports", FILE2_NAME + ".csv"); try { - Assert.assertTrue(checkFileAreSame(resource.toString(), outputPath + "/" + FILE1_NAME + ".csv")); - Assert.assertTrue(checkFileAreSame(resource2.toString(), outputPath + "/" + FILE2_NAME + ".csv")); + Assert.assertTrue(checkFileAreSame(resource.toString(), outputPath.resolve(FILE1_NAME + ".csv").toString())); + Assert.assertTrue(checkFileAreSame(resource2.toString(), outputPath.resolve(FILE2_NAME + ".csv").toString())); } catch (IOException ex) { Assert.fail("Exception was thrown while checking if the exported CSV file looks like expected. Exception: " + ex); } @@ -182,9 +182,39 @@ private boolean checkFileAreSame(String filePath1, String filePath2) throws IOEx if (linesFile1.size() != linesFile2.size()) return false; - for (String line1 : linesFile1) { - if (!linesFile2.contains(line1)) - return false; + final String csvColumnRegex = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"; + + String[][] file1RowsAndColumns = linesFile1.stream() + .map(row -> row.split(csvColumnRegex)) + .toArray(String[][]::new); + String[][] file2RowsAndColumns = linesFile2.stream() + .map(row -> row.split(csvColumnRegex)) + .toArray(String[][]::new); + + // Verify that each cell from file1 exists in file2 + for (int i = 0; i < file1RowsAndColumns.length; i++) { + for (int j = 0; j < file1RowsAndColumns[i].length; j++) { + // Skip 'File Path' column since its value is not deterministic + // and depends on the OS. + if (j == 7) { + continue; + } + + String cellFile1 = file1RowsAndColumns[i][j]; + boolean cellMatches = false; + + for (int x = 0; x < file2RowsAndColumns.length; x++) { + String cellFile2 = file2RowsAndColumns[x][j]; + if (cellFile1.equals(cellFile2)) { + cellMatches = true; + break; + } + } + + if (!cellMatches) { + return false; + } + } } return true; diff --git a/rules-java/api/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/ClearProjectTraversalCacheRuleProvider.java b/rules-java/api/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/ClearProjectTraversalCacheRuleProvider.java new file mode 100644 index 0000000000..1bd39efe70 --- /dev/null +++ b/rules-java/api/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/ClearProjectTraversalCacheRuleProvider.java @@ -0,0 +1,30 @@ +package org.jboss.windup.rules.apps.java.scan.provider; + +import org.jboss.windup.config.AbstractRuleProvider; +import org.jboss.windup.config.GraphRewrite; +import org.jboss.windup.config.loader.RuleLoaderContext; +import org.jboss.windup.config.metadata.RuleMetadata; +import org.jboss.windup.config.operation.GraphOperation; +import org.jboss.windup.config.phase.FinalizePhase; +import org.jboss.windup.config.projecttraversal.ProjectTraversalCache; +import org.ocpsoft.rewrite.config.Configuration; +import org.ocpsoft.rewrite.config.ConfigurationBuilder; +import org.ocpsoft.rewrite.context.EvaluationContext; + +/** + * Clear the caches used in the {@link ProjectTraversalCache} + */ +@RuleMetadata(phase = FinalizePhase.class) +public class ClearProjectTraversalCacheRuleProvider extends AbstractRuleProvider { + @Override + public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { + return ConfigurationBuilder.begin() + .addRule() + .perform(new GraphOperation() { + @Override + public void perform(GraphRewrite event, EvaluationContext context) { + ProjectTraversalCache.clear(); + } + }); + } +}