diff --git a/core/src/main/java/com/devonfw/tools/solicitor/SolicitorSetup.java b/core/src/main/java/com/devonfw/tools/solicitor/SolicitorSetup.java index c561eb66..5549d1d5 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/SolicitorSetup.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/SolicitorSetup.java @@ -35,7 +35,7 @@ public static class ReaderSetup { private UsagePattern usagePattern; private String repoType; - + private String packageType; private Map configuration; @@ -99,6 +99,7 @@ public String getPackageType() { return this.packageType; } + /** * This method gets the field configuration. * @@ -168,7 +169,7 @@ public void setRepoType(String repoType) { this.repoType = repoType; } - + /** * This method sets the field packageType. * @@ -180,9 +181,10 @@ public void setPackageType(String packageType) { } } - private String engagementName; + private List reportingGroups; + private List readerSetups = new ArrayList<>(); private List ruleSetups = new ArrayList<>(); @@ -209,6 +211,26 @@ public void setEngagementName(String engagementName) { this.engagementName = engagementName; } + /** + * This method gets the field reportingGroups. + * + * @return reportingGroups + */ + public List getReportingGroups() { + + return this.reportingGroups; + } + + /** + * This method sets the field reportingGroups. + * + * @param reportingGroups new value of {@link #getReportingGroups}. + */ + public void setReportingGroups(List reportingGroups) { + + this.reportingGroups = reportingGroups; + } + /** * This method gets the field readerSetups. * diff --git a/core/src/main/java/com/devonfw/tools/solicitor/common/LogMessages.java b/core/src/main/java/com/devonfw/tools/solicitor/common/LogMessages.java index 432fbd86..b20ca3db 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/common/LogMessages.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/common/LogMessages.java @@ -29,7 +29,8 @@ public enum LogMessages { FINISHED_WRITER(16, "Finished writing report with writer '{}' using template '{}' to file '{}'"), // INIT_SQL(17, "Initializing SQL reporting database with Solicitor model data"), // INIT_SQL_OLD(18, "Initializing SQL reporting database with OLD Solicitor model data"), // - EXECUTE_SQL(19, "Creating data of result table '{}' by executing SQL statement given in '{}'"), // + EXECUTE_SQL(19, + "Creating data of result table '{}' by executing SQL statement given in '{}' with reportingGroup '{}'"), // CREATING_DIFF(20, "Calculating DIFF information for result table '{}'"), // FILE_EXISTS(21, "At least '{}' already exists. Please remove existing files and retry."), // PROJECT_CREATED(22, @@ -111,7 +112,15 @@ public enum LogMessages { UNKNOWN_PACKAGE_TYPE(75, "The CSV file contains packageType '{}' which is not supported and will be ignored. Solicitor reports might be incomplete"), // CONTENT_FILE_TOO_LARGE(76, - "The size of the content file '{}' is '{}' (max. allowed is '{}'). Reading will be skipped."); + "The size of the content file '{}' is '{}' (max. allowed is '{}'). Reading will be skipped."), // + ILLEGAL_CHARACTER_IN_REPORTING_GROUP(77, + "The name of the reporting group '{}' consists of illegal characters. Allowed are alphanumeric characters (US-ASCII), hyphen, underscore and space. The reporting group name must start with an alphanumeric character."), // + REPORTING_GROUP_NOT_MATCHING_FILTER(78, + "The reporting group '{}' does not match the filter expression. Processing of writer for " + + "template source '{}' will be skipped for this reporting group"), // + REPORTING_GROUP_FILTER_EXPRESSION_SET_TO_NONDEFAULT(79, + "The filter expression for reporting groups to be processed is set to a non default value: '{}'"), // + REPORTING_GROUPS_DETECTED(80, "The following reporting groups are defined in this project: {} "); private final String message; diff --git a/core/src/main/java/com/devonfw/tools/solicitor/common/ReportingGroupHandler.java b/core/src/main/java/com/devonfw/tools/solicitor/common/ReportingGroupHandler.java new file mode 100644 index 00000000..29d20c07 --- /dev/null +++ b/core/src/main/java/com/devonfw/tools/solicitor/common/ReportingGroupHandler.java @@ -0,0 +1,253 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + */ +package com.devonfw.tools.solicitor.common; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Component which provides several methods for dealing with reporting groups. + */ +@Component +public class ReportingGroupHandler { + + private static final Logger LOG = LoggerFactory.getLogger(ReportingGroupHandler.class); + + /** + * Regular expression pattern string to check the validity of reporting group names. The name might only consist of + * alphanumeric characters (US-ASCII), underscore, hyphen and space. It must begin with an alphanumeric character. + * Other characters are forbidden to ensure list matching using {@value #REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER} + * and to prevent SQL injection in the SQLs used in the reporting mechanism. + */ + private static final String VALID_REPORTING_GROUP_REGEX = "[a-zA-Z0-9][a-zA-Z0-9_ -]*"; + + /** + * Java pattern representation of {@link #VALID_REPORTING_GROUP_REGEX}. + */ + private static Pattern VALID_REPORTING_GROUP_PATTERN = Pattern.compile(VALID_REPORTING_GROUP_REGEX); + + /** + * Name of the default reporting group to be used if no specific is given. + */ + public static final String DEFAULT_REPORTING_GROUP_NAME = "default"; + + /** + * The delimiter / prefix / suffix to be used when storing a collection of reporting groups as a string. + */ + public static final String REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER = "#"; + + /** + * Stringified list of reporting groups with only the default reporting group. To be used as default when reading + * model data which does not contain information on the reporting group. + */ + public static final String DEFAULT_REPORTING_GROUP_LIST = REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER + + DEFAULT_REPORTING_GROUP_NAME + REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER; + + private static final String DEFAULT_REPORTING_GROUP_FILTER = ".*"; + + private Pattern reportingGroupActivationFilterPattern = Pattern.compile(DEFAULT_REPORTING_GROUP_FILTER); + + /** + * Sets the regex pattern which is used to determine if a specific reporting group is activated. Reporting groups are + * activated if their name matches the given regular expression. Default is .* which matches any name. + * + * @param filterPattern the new value of the filter pattern + */ + @Value("${solicitor.reportinggroups.filterpattern:.*}") + public void setReportingGroupActivationFilterPattern(String filterPattern) { + + if (!DEFAULT_REPORTING_GROUP_FILTER.equals(filterPattern)) { + LOG.info(LogMessages.REPORTING_GROUP_FILTER_EXPRESSION_SET_TO_NONDEFAULT.msg(), filterPattern); + } + + this.reportingGroupActivationFilterPattern = Pattern.compile(filterPattern); + } + + /** + * Validates that the reporting group name consists only of permitted characters: Uppercase or lowercase, digits, + * spaces, hyphens or underscores. + * + * @param reportingGroup the reporting group which should be validated + * @throws SolicitorRuntimeException if the validation fails + */ + public void validateReportingGroup(String reportingGroup) { + + if (!VALID_REPORTING_GROUP_PATTERN.matcher(reportingGroup).matches()) { + LOG.error(LogMessages.ILLEGAL_CHARACTER_IN_REPORTING_GROUP.msg(), reportingGroup); + throw new SolicitorRuntimeException("Illegal character in reportingGroup"); + } + + } + + /** + * Splits a stringified list of reporting groups into a list. This includes validation. + * + * @param reportingGroups the stringified reporting group list which should be split + * @return the list of reporting groups as strings + * @throws SolicitorRuntimeException if the given argument is not a valid stringified list of reporting groups + */ + public List splitReportingGroupList(String reportingGroups) { + + if (!reportingGroups.startsWith("#")) { + throw new SolicitorRuntimeException("Stringified reporting group list must start with #"); + } + if (!reportingGroups.endsWith("#")) { + throw new SolicitorRuntimeException("Stringified reporting group list must end with #"); + } + String[] groups = reportingGroups.substring(1, reportingGroups.length() - 1) + .split(REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER); + for (String oneGroup : groups) { + validateReportingGroup(oneGroup); + } + return Arrays.asList(groups); + } + + /** + * Validates a stringified list of reporting groups. + * + * @param reportingGroups the stringified reporting group list which should be validated + * @throws SolicitorRuntimeException if the given argument is not a valid stringified list of reporting groups + */ + public void validateReportingGroupList(String reportingGroups) { + + // just delegate + splitReportingGroupList(reportingGroups); + } + + /** + * Normalizes and validates the list of reporting groups. In case that the list is null then a set containing the + * default reporting groups will be returned. Otherwise the elements will be validated. Possible duplicates are + * removed due to return datatype being a {@link Set}. + * + * @param reportingGroups the list of reporting groups to be normalized + * @return the normalized set of reporting groups + */ + public Set normalizeReportingGroups(List reportingGroups) { + + Set normalizedReportingGroups = new TreeSet<>(); + if (reportingGroups == null) { + normalizedReportingGroups.add(DEFAULT_REPORTING_GROUP_NAME); + } else { + for (String oneGroup : reportingGroups) { + validateReportingGroup(oneGroup); + normalizedReportingGroups.add(oneGroup); + } + } + return normalizedReportingGroups; + } + + /** + * Converts the set of reporting groups to a single string via concatenation. All reporting group values are + * surrounded with a # to enable easy finding / pattern matching. + * + * @param normalizedReportingGroups set of reporting groups + * @return single string with all reporting groups + */ + public String stringifyReportingGroups(Set normalizedReportingGroups) { + + StringBuilder sb = new StringBuilder(REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER); + for (String oneGroup : normalizedReportingGroups) { + sb.append(oneGroup).append(REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER); + } + return sb.toString(); + } + + /** + * Replaces the placeholder (if any) in the given sql string so that the actual reporting group value is used. SQL + * injection is prevented because of previous validation of the possible reportingGroup values. (See + * {@link ReportingGroupHandler#validateReportingGroup(String)} ). + *

+ * The placeholder in the sql statement needs to be "#reportingGroup#. It will be replaced by the given + * reporting group value surrounded by {@value ReportingGroupHandler#REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER}.
+ * So a."reportingGroups" LIKE '%#reportingGroup#%' AND
+ * will become a."reportingGroups" LIKE '%#default#%' AND if the current reporting group value is + * default, + * + * @param sql the sql which possibly contains the placeholder(s) to be replaced. + * @param reportingGroup the value of the current reporting group + * @return the sql statement with replaced placeholder(s) + */ + public String replacePlaceholderInSql(String sql, String reportingGroup) { + + return sql.replace("#reportingGroup#", + REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER + reportingGroup + REPORTING_GROUP_STRINGIFIED_LIST_DELIMITER); + } + + /** + * Expands the reporting group name placeholders in the writer output filename (if any). Spaces which exist in the + * reporting group name will be replaced by an underscore. + *

+ * In case that the reporting group equals {@link #DEFAULT_REPORTING_GROUP_NAME} then the placeholders + * ${reportingGroup}, ${-reportingGroup}, ${_reportingGroup} and + * ${/reportingGroup} will be replaced by an empty string - thus removing the placeholder. Otherwise the + * placeholders will be replaced with the reporting group name (prepending -, _ or + * / if applicable). + * + * @param rawFilename the raw filename with possible placeholder(s) ${reportingGroup}. + * @param reportingGroup the current reporting group + * @return the filename with replaced placeholder(s) + */ + public String expandReportingGroupInFileName(String rawFilename, String reportingGroup) { + + String targetFilename; + if (DEFAULT_REPORTING_GROUP_NAME.equals(reportingGroup)) { + targetFilename = rawFilename// + .replace("${-reportingGroup}", "")// + .replace("${_reportingGroup}", "")// + .replace("${/reportingGroup}", "")// + .replace("${reportingGroup}", ""); + } else { + String reportingGroupUnderscored = reportingGroup.replace(" ", "_"); + targetFilename = rawFilename// + .replace("${-reportingGroup}", "-" + reportingGroupUnderscored)// + .replace("${_reportingGroup}", "_" + reportingGroupUnderscored)// + .replace("${/reportingGroup}", "/" + reportingGroupUnderscored)// + .replace("${reportingGroup}", reportingGroupUnderscored); + } + return targetFilename; + } + + /** + * Checks if the given reporting group matches the filter expression given by + * {@link #reportingGroupActivationFilterPattern}. + * + * @param reportingGroup the reporting group name to check + * @return true if the given argument matches the regular expression, false otherwise + */ + public boolean matchesReportingGroupFilter(String reportingGroup) { + + return this.reportingGroupActivationFilterPattern.matcher(reportingGroup).matches(); + + } + + /** + * Logs the given reporting group names on INFO level. Any reporting groups which do not match the filter from + * {@link #matchesReportingGroupFilter(String)} will be commented as disabled. + * + * @param reportingGroups the list of reporting groups + */ + public void logReportingGroups(Collection reportingGroups) { + + List commentedReportingGroups = new ArrayList<>(); + for (String oneGroup : reportingGroups) { + if (matchesReportingGroupFilter(oneGroup)) { + commentedReportingGroups.add("'" + oneGroup + "'"); + } else { + commentedReportingGroups.add("'" + oneGroup + "'" + " (disabled via filter)"); + } + } + LOG.info(LogMessages.REPORTING_GROUPS_DETECTED.msg(), String.join(", ", commentedReportingGroups)); + + } +} diff --git a/core/src/main/java/com/devonfw/tools/solicitor/config/ApplicationConfig.java b/core/src/main/java/com/devonfw/tools/solicitor/config/ApplicationConfig.java index 38001ebc..753b8b1e 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/config/ApplicationConfig.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/config/ApplicationConfig.java @@ -26,6 +26,9 @@ public class ApplicationConfig { @JsonProperty private String programmingEcosystem; + @JsonProperty + private List reportingGroups; + @JsonProperty private List readers = new ArrayList<>(); @@ -79,6 +82,16 @@ public String getSourceRepo() { return this.sourceRepo; } + /** + * This method gets the field reportingGroups. + * + * @return the field reportingGroups + */ + public List getReportingGroups() { + + return this.reportingGroups; + } + /** * This method sets the field name. * @@ -128,4 +141,14 @@ public void setSourceRepo(String sourceRepo) { this.sourceRepo = sourceRepo; } + + /** + * This method sets the field reportingGroups. + * + * @param reportingGroups the new value of the field reportingGroups + */ + public void setReportingGroups(List reportingGroups) { + + this.reportingGroups = reportingGroups; + } } diff --git a/core/src/main/java/com/devonfw/tools/solicitor/config/ConfigFactory.java b/core/src/main/java/com/devonfw/tools/solicitor/config/ConfigFactory.java index 37371ba9..33afaa03 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/config/ConfigFactory.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/config/ConfigFactory.java @@ -11,7 +11,9 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.TreeMap; +import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -25,6 +27,7 @@ import com.devonfw.tools.solicitor.SolicitorSetup.ReaderSetup; import com.devonfw.tools.solicitor.common.DeprecationChecker; import com.devonfw.tools.solicitor.common.LogMessages; +import com.devonfw.tools.solicitor.common.ReportingGroupHandler; import com.devonfw.tools.solicitor.model.ModelFactory; import com.devonfw.tools.solicitor.model.ModelRoot; import com.devonfw.tools.solicitor.model.masterdata.Application; @@ -57,6 +60,9 @@ public class ConfigFactory { @Autowired private DeprecationChecker deprecationChecker; + @Autowired + private ReportingGroupHandler reportingGroupHandler; + @Value("${solicitor.base-config-url}") private String baseConfigUrl; @@ -114,10 +120,16 @@ public ModelRoot createConfig(String url) { engagement.setContractAllowsOss(sc.isContractAllowsOss()); engagement.setOssPolicyFollowed(sc.isOssPolicyFollowed()); engagement.setCustomerProvidesOss(sc.isCustomerProvidesOss()); + Set allReportingGroups = new TreeSet<>(); for (ApplicationConfig ac : sc.getApplications()) { + List reportingGroups = ac.getReportingGroups(); + Set normalizedReportingGroups = this.reportingGroupHandler.normalizeReportingGroups(reportingGroups); + allReportingGroups.addAll(normalizedReportingGroups); + LOG.info(LogMessages.CREATING_APPLICATION.msg(), ac.getName()); Application app = this.modelFactory.newApplication(ac.getName(), ac.getReleaseId(), "-UNDEFINED-", - ac.getSourceRepo(), ac.getProgrammingEcosystem()); + ac.getSourceRepo(), ac.getProgrammingEcosystem(), + this.reportingGroupHandler.stringifyReportingGroups(normalizedReportingGroups)); app.setEngagement(engagement); for (ReaderConfig rc : ac.getReaders()) { SolicitorSetup.ReaderSetup rs = new SolicitorSetup.ReaderSetup(); @@ -138,6 +150,8 @@ public ModelRoot createConfig(String url) { this.solicitorSetup.getReaderSetups().add(rs); } } + this.reportingGroupHandler.logReportingGroups(allReportingGroups); + this.solicitorSetup.setReportingGroups(List.copyOf(allReportingGroups)); this.solicitorSetup.setRuleSetups(resolvePlaceholdersInRules(sc.getRules(), placeHolderMap)); this.solicitorSetup.setWriterSetups(resolvePlaceholdersInWriters(sc.getWriters(), placeHolderMap)); return modelRoot; diff --git a/core/src/main/java/com/devonfw/tools/solicitor/config/WriterConfig.java b/core/src/main/java/com/devonfw/tools/solicitor/config/WriterConfig.java index b46b790c..6b95feb9 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/config/WriterConfig.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/config/WriterConfig.java @@ -27,6 +27,9 @@ public class WriterConfig { @JsonProperty private String description; + @JsonProperty + private boolean enableReportingGroups; + @JsonProperty private Map dataTables; @@ -98,6 +101,16 @@ public String getType() { return this.type; } + /** + * This method gets the field enableReportingGroups. + * + * @return enableReportingGroups + */ + public boolean isEnableReportingGroups() { + + return this.enableReportingGroups; + } + /** * This method sets the field dataTables. * @@ -147,4 +160,15 @@ public void setType(String type) { this.type = type; } + + /** + * This method sets the field enableReportingGroups. + * + * @param enableReportingGroups new value of {@link #isEnableReportingGroups}. + */ + public void setEnableReportingGroups(boolean enableReportingGroups) { + + this.enableReportingGroups = enableReportingGroups; + } + } diff --git a/core/src/main/java/com/devonfw/tools/solicitor/doc-files/solicitor_beans.drawio b/core/src/main/java/com/devonfw/tools/solicitor/doc-files/solicitor_beans.drawio index d0c21534..bb960e37 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/doc-files/solicitor_beans.drawio +++ b/core/src/main/java/com/devonfw/tools/solicitor/doc-files/solicitor_beans.drawio @@ -1 +1,547 @@ -7V1te6o4E/41/dhzEQhvH6327Tntbrfd9nTPl3NRSZVTJDwB27q/fkFBBSKCBRKQL62GBGFyz9zDzCScSMPZ5yUx3OktNpF9Igrm54k0OhFFIGhK8C9sWaxaNCFqmBDLjDptGh6sf1E8MmqdWybyEh19jG3fcpONY+w4aOwn2gxC8Eey2yu2k7/qGhOUaXgYG3a29Ydl+tOoFSj65sAVsibT6Kc1UV0dmBlx5+hOvKlh4o+tJun8RBoSjP3Vp9nnENmh8GK5rMZd7Di6vjCCHL/IgL/Uc/3Snf+8//n9+Zfx9Db5DeApgKvTvBv2PLpj2xojx0M++vS96Mr9RSyO4Cbc8ON8Zl8QYxZ8PPuYWj56cI1x2P4RoCBom/ozO/gGgo+eT/DbWnZSOCD6rAlhz1h2Uvjt1bLtIbYxWf6aNJLPtRHM3mh07++IBFe51RTd+CXCM+STRdAlOirJwjd5NSjCoSpF0/KxmVVV1+Ne060pXc+gEWFpsj7/RtzBh0jidOlPFHA2VmR19q7/7+3MH5ji4O9TIOgZ8ZO5jZAzsRxUgfDp8pTOcDDC8kNRKAJ1jiqQuSwLCYmLclbiQBey8oawPnlrWXkjw0Sk5bKWwH5Zr01qM7JWxYxMkRmY1ugrJv4UT7Bj2Oeb1jOC546JwtOGotr0ucHYjcT8G/n+IuIJY+7j5CTslKWH52SM8rARkYtBJsjP6xepbHgzuVNDkG341nuSR6oXM+ymmDmTssxCyujT8p/D4QErrb79s3Vk9BmdefllEX9xgvvdGhR+/Wf72GbY8ls8rv4ZlWHVU7ocOiDEWGx1cLHlrByX6Mx3YcPGVCpK0lRqMOk17ekuQiG3v6ZJef2DD6sL3mBxfedfgKfSw/Or8JQ0PuApgxx41gQfjSl8tsCzgVLb4CNzgR49aawiTNcLHr0t4KkfBPEJOfFaNKEtU8OvXkt8zShgOqOdIHpR4cJUK7CcHwrL+aFQBHn96+GCOG6xia6ciIodTMaZmwCt8v95GPU8mwVzZTkn0iA4Krifwd8lAoRV+6kf4jM8pmwdC+OSp4ZtTaJx4wAoYfwmPmfwaRL9X/7yS9zwgG1rbPmYxEeCW3xJ9w7a3HTblGxaUsoXXcfIRq/hcfyOyKu9DPKG0aCkFhHsB3DCzj6gl4iwaUlMqHH0cjvCBilRH6WuoI9IAcCOwNoYz1zsLG9+ZX7ikJgWN6zD6pAqrlwEFpYhyEhMpAgsbitnEjJKeSrCxITB5Anw66sXmK70JFSgmFIrFPMB+XO3M9oJ1ZSB15irZzbZ07B6SmWFeBzqKbdCPZ8Q8UIN6YqCiin2hApzBVVYK6hcVojHoaAqzwr6SOxrx537ZRWTg0t/8AkyZhfGODAvi7zrfyGtNjW6rqTqD4AKaNZGUhu0NtlkeMPWRi0rx85ZmwX4fXXzC8LTqzfv3n00XxbTwWn7gjwgEeL5pq5DPpVHeaJoM4NQ7EFRHk1OpQOFPWGbdNFMyf5AaiBflC1a4ohS7tEKQ3/jFvLhhWWjIXYtlBukajkZqpqYIkMOHo3j4ih2ZKiXlWPnyJDupDBNTsefyyWxkmxYHxmCwkVrlaenv6ZsXCcKhrbheXdh+Xb7COQHehnioK/j3xH8bpmdJhIlXkvAUQQHiKx5BJSW43EQCeA6CTKyCBr7j8TujQ7fRkeHGn9Gh3liB/SZHbr3yrQ6jnPvVS7qvfJVhAW4TteFIYSHheej2dAYTy1n0hMK34Siqip/hMI8EQn6TCSdUNSeUHZiRi1KKHzVaQOu08vXzi2aYbK4NUrXZnFw9UdFJVDiMCDCPMsM+jQzPfvevjyz8E1sajVB4UQzH8taQWrp1771AaKo5fWvaX0A15nj5eY114EFCswEOf9c/S9LedxyA0iVO3KQc42viCE19ElXei6a7cpBrteZrbehagkzSKkSJKDsYQYlt39NzCBkVb9/ri2LOGZx0nMgXsvThXptDX5cPf5553x/Xl9Nb0OKzShVhnxUMWZMiJpvQvb0r8eErF0iLp3LIXZerUmBSvdWOZUij6V8sRfJzq08wDs/CrdSY7pPEeckDwuSfBzO4iV4LbANIx0yqYC7SeWrPlOk1ZNwQ6XLOE3XmBToaSblIXgv0kodmqVSWFqSR0GlMtM88EFWtzkqVQpa3TgGzonZlVuzlRrHcxrv683JnCpsI6kdmVORrzltn8fL4ZxWHh3/mqdDq3jjxuW9X25S3zWfN/tWBlGX2Pu8tGqsZn1epawkj8Pn1Znuwn5Y+GhrL4SaUwpaUaeXj7SknHplBRTyN8BM91dBfn9R1/L615SDoBW7ccMiQ+/9PnrbSWcZRFI5YBBamVOzDKKVleSRMEgLExCNMUj85NxaBtmzhXIrGCSeBD4Z5JIYpo06TyJQZk8iEq2coVESWUOxJ5EkibRwCVZzJCK2m0RkpQskIvJMIrfGO3I6zyGyxAGH0LY8aZZDxLKSPBIOaeGuZs1xSNGqGU45RIFd4BCua4D+cGedZxAFcMAgzAuA1jjsGSQpF64TliOCse2N0Ng65JURHNzA38ZL5wIdcqZan4tAB/N8q9TnW+kbBPSrQHdjpmi6NdYlTupcgMB2Wd5hTx6JSQXsJ5WvDekkrrPO93MbnTvBeVGHiJTHwiWJedpZ6tPO9ILRvrB7Lz/ut7mVv7f3a+9S5DpRu3r+Ck2v18KHr26Wu2ZZg4diJcg8z7zWpJ41kjkCtqxx2ONXUzkCKBakDU5yBArMrO9ch3d3x/3VfWPqif3HwuWT25brf6+Q7ZYPzWX39+SYLWAmoyywZwvmGeU1Nnu2SAV22hita4wuWpZSBoLSJr7gOld8j7y57Y8M33gxvNJBKA5u4MAHoRaRnZ7Z/UJS2e9+AZknv2Gf/KYH1CBTrjvhOqBWdAW2LFZNdV9bVc90dWdX5pSvbCPkukjlB7H8g8OMLWJXDXDJrszrPmBf90GXC9f55NCRX1ZnjazX1ype59IiTdY3aWaOEs+QeeIZ9onnXHeAT01+QjYeWwEEljx8VIqcpWQeSjFl5rnANWB7RaY+q/GpyM+21+vwCR8ZGpl5hmaN1V6HkwEONpuPNF4aLRfNtUC+KrqUFq7rbyoAVXxO+cif6Zn0mSTuS59lx0BBaSJ9prRwMTB/wKt8L+fDgKceALz9Y+oBHhDaF3Nv7N0NhZFX+WKQg4Cnxo9OawjlLypP9wfRuxBrBVwsUz4fY9b5AMMsXSbQ6ucWHoKIMvNk+xqc/XNLkiVANor4ET3u75ig+cy+IMYsZIuPadDzwTWWtvaDGG4S3iHgh9jGZHkCaSSfa8s5w8EIyw9vVQlh7/kEv6F4mqVqFEHVkiZQjE3i1oRKKmVGIaxAC/Le98enfVy9w65ji+Kzr7ADKmjSGlJxQAv31WUMc4F4vLbwyjYm//6aPbvaz4urP135ZjQzc/QzJ945Qi5B4xVuMweHUzR+2+gTNUqaOfd+Y7BSeGHzd5d2J5V1h2pGJqKccobYscaGPYhOMrNMc/kAUYHW6rqS1loha7xBvLdE1TpLxUaTOpsLzuPV2b/Uc/3Snf+8//n9+Zfx9Db5DWCOzprWO1WRyjKk5xrObta0DS/oEEg4nzJpJwmal9eYbG3ksi/nyPOQeWMFZ9lbNc3ZtT+SwKcMxjv+HcHv1n53pfj1s3PDChlqNj6UIigJ1dZUii2uy3+i6nyTtjjX6PS2OCEWWnKyWsNQLO9MMwI1Wqv1zz34xPDRZF+1aROXEln2wFauTH2ujaQKsTePBZ3VODfBjXmkhWEbNY9SWRkeh3mkxUBrUv8Ly0bewvPRbGiMp5YzqUL9GXimgf1ql3Pae6YNml5VVTkzvbQVMY2aXrmsDI/D9NJWozRoFa6dWzTDZHFruO0yZ32coLfGRS0JlHiLE9BWOjVqjdWyMjwOa0xJOWcmBjnmgJAleMdhjNUan+zYmkSDysnW5iTfBHFPsVHw5Q4RK7iLMOvBqPQtlvZ2AVIehvYWIG1hRqZgRq4GM3KsrPFrDNSU8q5uPBq1gU52y6z0azXE1IlWgsmcqGzllARA4nf0KJNUVSUUHeAFltoUBTg3FZx56NyLYsAVihUxXRZwOI4z5Z1FkVwZ2MQKwHYgcA4B6eFgkwuCrWjNZg+28mArsACpDst2OGg6CwZZSJ9KA/VwKABS+qdSNFpkiAbzh1DuB1bM1RhPpYm+mD/Ozac/7j7VgXBDLSDoJFWDgtZT5kph0g6nmq7OLKou6XrQGME1WM5fw9dXyf88Hdw5g6eLH6OL8QAcVlw2sO3vlmN62SN3xvjNmKDH+5srwzHtvBqz46k6yzxoUzSlRNWZqNFKResqO6OipoBv96UQxh6J7UZyZ0MYwVeCQ1hvuhPDnS73JQ4a/wM= \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/main/java/com/devonfw/tools/solicitor/doc-files/solicitor_beans.png b/core/src/main/java/com/devonfw/tools/solicitor/doc-files/solicitor_beans.png index e38fabd7..9cd6c46d 100644 Binary files a/core/src/main/java/com/devonfw/tools/solicitor/doc-files/solicitor_beans.png and b/core/src/main/java/com/devonfw/tools/solicitor/doc-files/solicitor_beans.png differ diff --git a/core/src/main/java/com/devonfw/tools/solicitor/model/ModelFactory.java b/core/src/main/java/com/devonfw/tools/solicitor/model/ModelFactory.java index 9fbe0b21..f23fcc67 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/model/ModelFactory.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/model/ModelFactory.java @@ -33,10 +33,11 @@ public abstract class ModelFactory { * @param releaseDate the date of the release * @param sourceRepo pointer to the source repo * @param programmingEcosystem name of the programming ecosystem + * @param reportingGroups the reporting groups this application belongs to in concatenated form * @return the new instance */ public abstract Application newApplication(String name, String releaseId, String releaseDate, String sourceRepo, - String programmingEcosystem); + String programmingEcosystem, String reportingGroups); /** * Creates a new {@link ApplicationComponent} diff --git a/core/src/main/java/com/devonfw/tools/solicitor/model/ModelImporterExporter.java b/core/src/main/java/com/devonfw/tools/solicitor/model/ModelImporterExporter.java index f0ef849a..02015a06 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/model/ModelImporterExporter.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/model/ModelImporterExporter.java @@ -12,6 +12,7 @@ import org.springframework.stereotype.Component; import com.devonfw.tools.solicitor.common.IOHelper; +import com.devonfw.tools.solicitor.common.ReportingGroupHandler; import com.devonfw.tools.solicitor.common.SolicitorRuntimeException; import com.devonfw.tools.solicitor.model.impl.ModelFactoryImpl; import com.devonfw.tools.solicitor.model.impl.ModelRootImpl; @@ -56,6 +57,9 @@ public class ModelImporterExporter { @Autowired private ModelFactoryImpl modelFactory; + @Autowired + private ReportingGroupHandler reportingGroupHandler; + /** * Loads the data model from a JSON file. The loaded data model is represented by a root object of type * {@code ModelRootImpl}. @@ -216,9 +220,15 @@ private void readApplications(EngagementImpl engagement, JsonNode applicationsNo String releaseDate = applicationNode.get("releaseDate").asText(null); String sourceRepo = applicationNode.get("sourceRepo").asText(null); String programmingEcosystem = applicationNode.get("programmingEcosystem").asText(null); + String reportingGroups = ReportingGroupHandler.DEFAULT_REPORTING_GROUP_LIST; + JsonNode reportingGroupsNode = applicationNode.get("reportingGroups"); + if (reportingGroupsNode != null) { + reportingGroups = reportingGroupsNode.asText(); + this.reportingGroupHandler.validateReportingGroupList(reportingGroups); + } JsonNode applicationComponentsNode = applicationNode.get("applicationComponents"); ApplicationImpl application = this.modelFactory.newApplication(name, releaseId, releaseDate, sourceRepo, - programmingEcosystem); + programmingEcosystem, reportingGroups); application.setEngagement(engagement); readApplicationComponents(application, applicationComponentsNode, readModelVersion); diff --git a/core/src/main/java/com/devonfw/tools/solicitor/model/ModelRoot.java b/core/src/main/java/com/devonfw/tools/solicitor/model/ModelRoot.java index 128f6c9e..8638b61a 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/model/ModelRoot.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/model/ModelRoot.java @@ -80,6 +80,14 @@ public interface ModelRoot { */ public String getExtensionBuilddate(); + /** + * This method gets the field reportingGroup. Note that the value of the field is volatile and is set to + * the reportingGroup that is currently processed. + * + * @return the field reportingGroup + */ + public String getReportingGroup(); + /** * This method sets the field engagement. * @@ -150,6 +158,14 @@ public interface ModelRoot { */ public void setExtensionBuilddate(String extensionBuilddate); + /** + * This method sets the field reportingGroup. This might be set/changed throughout the Solicitor run if + * multiple reporting groups are processed. + * + * @param reportingGroup the new value of the field reportingGroup + */ + public void setReportingGroup(String reportingGroup); + /** * Complete the data of this object by setting members which are derived from other members. */ diff --git a/core/src/main/java/com/devonfw/tools/solicitor/model/impl/ModelFactoryImpl.java b/core/src/main/java/com/devonfw/tools/solicitor/model/impl/ModelFactoryImpl.java index e69f9e20..1e0a92c3 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/model/impl/ModelFactoryImpl.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/model/impl/ModelFactoryImpl.java @@ -80,9 +80,9 @@ public Collection getAllModelObjects(ModelRoot modelRoot) { /** {@inheritDoc} */ @Override public ApplicationImpl newApplication(String name, String releaseId, String releaseDate, String sourceRepo, - String programmingEcosystem) { + String programmingEcosystem, String reportingGroups) { - return new ApplicationImpl(name, releaseId, releaseDate, sourceRepo, programmingEcosystem); + return new ApplicationImpl(name, releaseId, releaseDate, sourceRepo, programmingEcosystem, reportingGroups); } /** {@inheritDoc} */ diff --git a/core/src/main/java/com/devonfw/tools/solicitor/model/impl/ModelRootImpl.java b/core/src/main/java/com/devonfw/tools/solicitor/model/impl/ModelRootImpl.java index 3222b416..406970b3 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/model/impl/ModelRootImpl.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/model/impl/ModelRootImpl.java @@ -7,13 +7,14 @@ import com.devonfw.tools.solicitor.model.ModelRoot; import com.devonfw.tools.solicitor.model.masterdata.Engagement; +import com.fasterxml.jackson.annotation.JsonIgnore; /** * Implementation class of the root of the Solicitor data model. */ public class ModelRootImpl extends AbstractModelObject implements ModelRoot { - private static final int DEFAULT_MODEL_VERSION = 6; + private static final int DEFAULT_MODEL_VERSION = 7; private String executionTime; @@ -33,6 +34,8 @@ public class ModelRootImpl extends AbstractModelObject implements ModelRoot { private String extensionBuilddate; + private String reportingGroup; + private Engagement engagement; private TextPool textPool; @@ -55,7 +58,7 @@ public String[] getDataElements() { return new String[] { this.executionTime, Integer.toString(this.modelVersion), this.solicitorVersion, this.solicitorGitHash, this.solicitorBuilddate, this.extensionArtifactId, this.extensionVersion, - this.extensionGitHash, this.extensionBuilddate }; + this.extensionGitHash, this.extensionBuilddate, this.reportingGroup }; } /** {@inheritDoc} */ @@ -77,7 +80,7 @@ public String getExecutionTime() { public String[] getHeadElements() { return new String[] { "executionTime", "modelVersion", "solicitorVersion", "solicitorGitHash", "solicitorBuilddate", - "extensionArtifactId", "extensionVersion", "extensionGitHash", "extensionBuilddate" }; + "extensionArtifactId", "extensionVersion", "extensionGitHash", "extensionBuilddate", "reportingGroup" }; } /** {@inheritDoc} */ @@ -136,6 +139,14 @@ public String getExtensionBuilddate() { return this.extensionBuilddate; } + /** {@inheritDoc} */ + @Override + @JsonIgnore + public String getReportingGroup() { + + return this.reportingGroup; + } + /** {@inheritDoc} */ @Override public void setEngagement(Engagement engagement) { @@ -206,6 +217,13 @@ public void setExtensionBuilddate(String extensionBuilddate) { this.extensionBuilddate = extensionBuilddate; } + /** {@inheritDoc} */ + @Override + public void setReportingGroup(String reportingGroup) { + + this.reportingGroup = reportingGroup; + } + /** * @return textPool */ diff --git a/core/src/main/java/com/devonfw/tools/solicitor/model/impl/masterdata/ApplicationImpl.java b/core/src/main/java/com/devonfw/tools/solicitor/model/impl/masterdata/ApplicationImpl.java index 75a0ff9a..57151969 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/model/impl/masterdata/ApplicationImpl.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/model/impl/masterdata/ApplicationImpl.java @@ -32,6 +32,8 @@ public class ApplicationImpl extends AbstractModelObject implements Application private Engagement engagement; + private String reportingGroups; + /** * Constructor. * @@ -42,7 +44,7 @@ public class ApplicationImpl extends AbstractModelObject implements Application * @param programmingEcosystem name of the programming ecosystem */ public ApplicationImpl(String name, String releaseId, String releaseDate, String sourceRepo, - String programmingEcosystem) { + String programmingEcosystem, String reportingGroups) { super(); this.name = name; @@ -50,6 +52,7 @@ public ApplicationImpl(String name, String releaseId, String releaseDate, String this.releaseDate = releaseDate; this.sourceRepo = sourceRepo; this.programmingEcosystem = programmingEcosystem; + this.reportingGroups = reportingGroups; } /** {@inheritDoc} */ @@ -77,7 +80,8 @@ public List getApplicationComponents() { @Override public String[] getDataElements() { - return new String[] { this.name, this.releaseId, this.releaseDate, this.sourceRepo, this.programmingEcosystem }; + return new String[] { this.name, this.releaseId, this.releaseDate, this.sourceRepo, this.programmingEcosystem, + this.reportingGroups }; } /** {@inheritDoc} */ @@ -92,7 +96,8 @@ public Engagement getEngagement() { @Override public String[] getHeadElements() { - return new String[] { "applicationName", "releaseId", "releaseDate", "sourceRepo", "programmingEcosystem" }; + return new String[] { "applicationName", "releaseId", "releaseDate", "sourceRepo", "programmingEcosystem", + "reportingGroups" }; } /** {@inheritDoc} */ @@ -130,6 +135,13 @@ public String getSourceRepo() { return this.sourceRepo; } + /** {@inheritDoc} */ + @Override + public String getReportingGroups() { + + return this.reportingGroups; + } + /** {@inheritDoc} */ @Override public void setEngagement(Engagement engagement) { @@ -176,6 +188,13 @@ public void setSourceRepo(String sourceRepo) { this.sourceRepo = sourceRepo; } + /** {@inheritDoc} */ + @Override + public void setReportingGroups(String reportingGroups) { + + this.reportingGroups = reportingGroups; + } + /** {@inheritDoc} */ @Override public void completeData() { diff --git a/core/src/main/java/com/devonfw/tools/solicitor/model/masterdata/Application.java b/core/src/main/java/com/devonfw/tools/solicitor/model/masterdata/Application.java index 337ca829..2fa9f893 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/model/masterdata/Application.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/model/masterdata/Application.java @@ -65,6 +65,14 @@ public interface Application { */ String getSourceRepo(); + /** + * This method gets the field reportingGroups. Reporting groups are stored within one String in + * concatenated form. + * + * @return the field reportingGroups + */ + String getReportingGroups(); + /** * Sets the {@link Engagement} to which this {@link Application} belongs. * @@ -107,6 +115,14 @@ public interface Application { */ void setSourceRepo(String sourceRepo); + /** + * This method sets the field reportingGroups. Reporting groups are stored within one String in + * concatenated form. + * + * @param reportingGroups the new value of the field reportingGroups + */ + void setReportingGroups(String reportingGroups); + /** * Complete the data of this object by setting members which are derived from other members. */ diff --git a/core/src/main/java/com/devonfw/tools/solicitor/ruleengine/drools/ModelHelper.java b/core/src/main/java/com/devonfw/tools/solicitor/ruleengine/drools/ModelHelper.java index 6bea8fcc..9c6c4713 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/ruleengine/drools/ModelHelper.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/ruleengine/drools/ModelHelper.java @@ -114,19 +114,20 @@ public static void appendTraceToNormalizedLicense(NormalizedLicense license, Str /** * Creates a new {@link Application} by calling - * {@link ModelFactory#newApplication(String, String, String, String, String)}. + * {@link ModelFactory#newApplication(String, String, String, String, String, String)}. * * @param name the application name * @param releaseId the release id. * @param releaseDate the date of the release * @param sourceRepo pointer to the source repo * @param programmingEcosystem name of the programming ecosystem + * @param reportingGroups the reporting groups this application belongs to (concatenated form) * @return the new instance */ public static Application newApplication(String name, String releaseId, String releaseDate, String sourceRepo, - String programmingEcosystem) { + String programmingEcosystem, String reportingGroups) { - return modelFactory.newApplication(name, releaseId, releaseDate, sourceRepo, programmingEcosystem); + return modelFactory.newApplication(name, releaseId, releaseDate, sourceRepo, programmingEcosystem, reportingGroups); } /** diff --git a/core/src/main/java/com/devonfw/tools/solicitor/writer/ResultDatabaseFactory.java b/core/src/main/java/com/devonfw/tools/solicitor/writer/ResultDatabaseFactory.java index 934eb32d..086dcb4a 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/writer/ResultDatabaseFactory.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/writer/ResultDatabaseFactory.java @@ -23,6 +23,7 @@ import com.devonfw.tools.solicitor.common.IOHelper; import com.devonfw.tools.solicitor.common.InputStreamFactory; import com.devonfw.tools.solicitor.common.LogMessages; +import com.devonfw.tools.solicitor.common.ReportingGroupHandler; import com.devonfw.tools.solicitor.common.SolicitorRuntimeException; import com.devonfw.tools.solicitor.model.ModelFactory; import com.devonfw.tools.solicitor.model.ModelRoot; @@ -51,13 +52,16 @@ public class ResultDatabaseFactory { @Autowired private ModelFactory modelFactory; + @Autowired + private ReportingGroupHandler reportingGroupHandler; + private Set> definedTablesSet = new HashSet<>(); private Map allModelObjectInstances = new TreeMap<>(); /** * Creates a database table for storing the given {@link AbstractModelObject}. - * + * * @param modelObject the model object for which the table should be defined */ private void createTable(AbstractModelObject modelObject) { @@ -76,7 +80,7 @@ private void createTable(AbstractModelObject modelObject) { sb.append(" );"); LOG.debug("Creating Reporting table '{}'", name); String sql = sb.toString(); - jdbcTemplate.execute(sql); + this.jdbcTemplate.execute(sql); } @@ -93,7 +97,7 @@ public String determineTableName(Class tableClass /** * Drop the database table which corresponds to the given {@link AbstractModelObject}. - * + * * @param oneTable the model class for which the corresponding database table should be dropped */ private void dropExistingTable(Class oneTable) { @@ -103,26 +107,29 @@ private void dropExistingTable(Class oneTable) { sb.append("drop table ").append(name).append(";"); LOG.debug("Dropping Reporting table '{}'", name); String sql = sb.toString(); - jdbcTemplate.execute(sql); + this.jdbcTemplate.execute(sql); } /** * Creates a {@link DataTable} by executing the referenced SQL. * * @param sqlResourceUrl URL which references an SQL statement + * @param reportingGroup parameter which denotes the reportingGroup to select data from * @return the result of the SQL statement */ - public DataTable getDataTable(String sqlResourceUrl) { + public DataTable getDataTable(String sqlResourceUrl, String reportingGroup) { String sql; - try (InputStream inp = inputStreamFactory.createInputStreamFor(sqlResourceUrl)) { + try (InputStream inp = this.inputStreamFactory.createInputStreamFor(sqlResourceUrl)) { sql = IOHelper.readStringFromInputStream(inp); } catch (IOException e) { throw new SolicitorRuntimeException("Could not read SQL statement", e); } - List> rawResult = jdbcTemplate.queryForList(sql); + sql = this.reportingGroupHandler.replacePlaceholderInSql(sql, reportingGroup); + + List> rawResult = this.jdbcTemplate.queryForList(sql); // put the final data in a result DataTable @@ -162,7 +169,7 @@ public DataTable getDataTable(String sqlResourceUrl) { /** * Checks if the referenced field name starts with prefix "ID_" if yes then return the {@link AbstractModelObject} * given by its id. - * + * * @param oneRow the row of data * @param fieldname the name of the field * @return the {@link AbstractModelObject} or null if the field does not start with "ID_" @@ -170,7 +177,7 @@ public DataTable getDataTable(String sqlResourceUrl) { private Object getEntity(Map oneRow, String fieldname) { if (fieldname.startsWith("ID_")) { - return allModelObjectInstances.get(oneRow.get(fieldname)); + return this.allModelObjectInstances.get(oneRow.get(fieldname)); } else { return null; } @@ -178,29 +185,29 @@ private Object getEntity(Map oneRow, String fieldname) { /** * Initializes the database with the data of the internal data model. - * + * * @param modelRoot the root object of the internal data model which gives access to the complete data model */ public void initDataModel(ModelRoot modelRoot) { // delete all possibly existing entries in the model instances map - allModelObjectInstances.clear(); + this.allModelObjectInstances.clear(); // drop any already existing tables - for (Class oneTable : definedTablesSet) { + for (Class oneTable : this.definedTablesSet) { dropExistingTable(oneTable); } - definedTablesSet.clear(); + this.definedTablesSet.clear(); // create all needed tables and add all data; also store object in map // to access it via given id - for (Object amo : modelFactory.getAllModelObjects(modelRoot)) { + for (Object amo : this.modelFactory.getAllModelObjects(modelRoot)) { saveToDatabase((AbstractModelObject) amo); - allModelObjectInstances.put(((AbstractModelObject) amo).getId(), (AbstractModelObject) amo); + this.allModelObjectInstances.put(((AbstractModelObject) amo).getId(), (AbstractModelObject) amo); } } /** * Logs the data of the given table on level {@link Level#TRACE}. - * + * * @param dataTable the data to log */ private void logData(DataTable dataTable) { @@ -220,7 +227,7 @@ private void logData(DataTable dataTable) { /** * Modifies the array of header strings by replacing any prefixes "ID_" with "OBJ_". - * + * * @param finalHeaders the array of strings to modify * @return the modified array */ @@ -241,7 +248,7 @@ private String[] modifyHeaders(String[] finalHeaders) { /** * Save the given {@link AbstractModelObject} to the database. In case that no appropriate database table exist it * will be created. - * + * * @param modelObject the object to save */ public void saveToDatabase(AbstractModelObject modelObject) { @@ -249,8 +256,8 @@ public void saveToDatabase(AbstractModelObject modelObject) { String[] params = modelObject.getDataElements(); Class clazz = modelObject.getClass(); - if (!definedTablesSet.contains(clazz)) { - definedTablesSet.add(clazz); + if (!this.definedTablesSet.contains(clazz)) { + this.definedTablesSet.add(clazz); createTable(modelObject); } StringBuilder sb = new StringBuilder(); @@ -267,7 +274,7 @@ public void saveToDatabase(AbstractModelObject modelObject) { sb.append(" );"); String sql = sb.toString(); params = AbstractModelObject.concatRow(params, new String[] { modelObject.getId() }); - jdbcTemplate.update(sql, (Object[]) params); + this.jdbcTemplate.update(sql, (Object[]) params); } diff --git a/core/src/main/java/com/devonfw/tools/solicitor/writer/Writer.java b/core/src/main/java/com/devonfw/tools/solicitor/writer/Writer.java index c8891d9b..62334e85 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/writer/Writer.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/writer/Writer.java @@ -15,7 +15,7 @@ public interface Writer { /** * Determines if the {@link Writer} instance is capable of handling the given template type. - * + * * @param type the template type * @return true if the writer is capable of handling this type, false otherwise */ diff --git a/core/src/main/java/com/devonfw/tools/solicitor/writer/WriterFacade.java b/core/src/main/java/com/devonfw/tools/solicitor/writer/WriterFacade.java index 4ee14041..7aac705f 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/writer/WriterFacade.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/writer/WriterFacade.java @@ -12,7 +12,7 @@ public interface WriterFacade { /** * Write the result of processing to the configured reports. - * + * * @param modelRoot the model representing the result of processing * @param oldModelRoot an optional old model loaded from the filesystem to which the current result will be compared * to; might be null diff --git a/core/src/main/java/com/devonfw/tools/solicitor/writer/WriterFacadeImpl.java b/core/src/main/java/com/devonfw/tools/solicitor/writer/WriterFacadeImpl.java index c3e5b8b4..f0bf6257 100644 --- a/core/src/main/java/com/devonfw/tools/solicitor/writer/WriterFacadeImpl.java +++ b/core/src/main/java/com/devonfw/tools/solicitor/writer/WriterFacadeImpl.java @@ -3,7 +3,9 @@ */ package com.devonfw.tools.solicitor.writer; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.slf4j.Logger; @@ -13,6 +15,7 @@ import com.devonfw.tools.solicitor.SolicitorSetup; import com.devonfw.tools.solicitor.common.LogMessages; +import com.devonfw.tools.solicitor.common.ReportingGroupHandler; import com.devonfw.tools.solicitor.config.WriterConfig; import com.devonfw.tools.solicitor.model.ModelRoot; import com.devonfw.tools.solicitor.writer.data.DataTable; @@ -38,6 +41,9 @@ public class WriterFacadeImpl implements WriterFacade { @Autowired private DataTableDiffer dataTableDiffer; + @Autowired + private ReportingGroupHandler reportingGroupHandler; + /** * Constructor. */ @@ -48,35 +54,42 @@ public WriterFacadeImpl() { /** * Execute the configured transformations via the embedded SQL database and generated the data tables which will be * input for the report generation via XLS or velocity templating. - * + * * @param modelRoot the current model * @param oldModelRoot the old modelto compare to; might be null * @param writerConfig the configuration of a {@link Writer} which also defines the SQL queries to perform + * @param reportingGroup the name of the reporting group to be selected; the parameter will have no effect if the SQL + * statements do not contain the respective placeholder * @return a map of transformed data tables */ - private Map getDataTables(ModelRoot modelRoot, ModelRoot oldModelRoot, WriterConfig writerConfig) { + private Map getDataTables(ModelRoot modelRoot, ModelRoot oldModelRoot, WriterConfig writerConfig, + String reportingGroup) { // create the table for the current data model LOG.info(LogMessages.INIT_SQL.msg()); - resultDatabaseFactory.initDataModel(modelRoot); + modelRoot.setReportingGroup(reportingGroup); + this.resultDatabaseFactory.initDataModel(modelRoot); Map result = new HashMap<>(); for (Map.Entry table : writerConfig.getDataTables().entrySet()) { - LOG.info(LogMessages.EXECUTE_SQL.msg(), table.getKey(), table.getValue()); - result.put(table.getKey(), resultDatabaseFactory.getDataTable(table.getValue())); + LOG.info(LogMessages.EXECUTE_SQL.msg(), table.getKey(), table.getValue(), reportingGroup); + result.put(table.getKey(), this.resultDatabaseFactory.getDataTable(table.getValue(), reportingGroup)); } + modelRoot.setReportingGroup(null); // if old model data is defined then transform it and create diff // between new and old if (oldModelRoot != null) { LOG.info(LogMessages.INIT_SQL_OLD.msg()); - resultDatabaseFactory.initDataModel(oldModelRoot); + oldModelRoot.setReportingGroup(reportingGroup); + this.resultDatabaseFactory.initDataModel(oldModelRoot); for (Map.Entry table : writerConfig.getDataTables().entrySet()) { DataTable newTable = result.get(table.getKey()); - LOG.info(LogMessages.EXECUTE_SQL.msg(), table.getKey() + " (old)", table.getValue()); - DataTable oldTable = resultDatabaseFactory.getDataTable(table.getValue()); + LOG.info(LogMessages.EXECUTE_SQL.msg(), table.getKey() + " (old)", table.getValue(), reportingGroup); + DataTable oldTable = this.resultDatabaseFactory.getDataTable(table.getValue(), reportingGroup); LOG.info(LogMessages.CREATING_DIFF.msg(), table.getKey()); - DataTable diffTable = dataTableDiffer.diff(newTable, oldTable); + DataTable diffTable = this.dataTableDiffer.diff(newTable, oldTable); result.put(table.getKey(), diffTable); } + oldModelRoot.setReportingGroup(null); } return result; @@ -85,14 +98,30 @@ private Map getDataTables(ModelRoot modelRoot, ModelRoot oldM @Override public void writeResult(ModelRoot modelRoot, ModelRoot oldModelRoot) { - for (WriterConfig writerConfig : solicitorSetup.getWriterSetups()) { - LOG.info(LogMessages.PREPARING_FOR_WRITER.msg(), writerConfig.getType(), writerConfig.getTemplateSource(), - writerConfig.getTarget()); - Writer writer = writerFactory.writerFor(writerConfig.getType()); - writer.writeReport(writerConfig.getTemplateSource(), writerConfig.getTarget(), - getDataTables(modelRoot, oldModelRoot, writerConfig)); - LOG.info(LogMessages.FINISHED_WRITER.msg(), writerConfig.getType(), writerConfig.getTemplateSource(), - writerConfig.getTarget()); + for (WriterConfig writerConfig : this.solicitorSetup.getWriterSetups()) { + List writerReportingGroups; + if (writerConfig.isEnableReportingGroups()) { + writerReportingGroups = this.solicitorSetup.getReportingGroups(); + } else { + writerReportingGroups = Collections.singletonList(ReportingGroupHandler.DEFAULT_REPORTING_GROUP_NAME); + } + String rawFilename = writerConfig.getTarget(); + for (String reportingGroup : writerReportingGroups) { + if (this.reportingGroupHandler.matchesReportingGroupFilter(reportingGroup)) { + String targetFilename = this.reportingGroupHandler.expandReportingGroupInFileName(rawFilename, + reportingGroup); + LOG.info(LogMessages.PREPARING_FOR_WRITER.msg(), writerConfig.getType(), writerConfig.getTemplateSource(), + targetFilename); + Writer writer = this.writerFactory.writerFor(writerConfig.getType()); + writer.writeReport(writerConfig.getTemplateSource(), targetFilename, + getDataTables(modelRoot, oldModelRoot, writerConfig, reportingGroup)); + LOG.info(LogMessages.FINISHED_WRITER.msg(), writerConfig.getType(), writerConfig.getTemplateSource(), + targetFilename); + } else { + LOG.info(LogMessages.REPORTING_GROUP_NOT_MATCHING_FILTER.msg(), reportingGroup, + writerConfig.getTemplateSource()); + } + } } } diff --git a/core/src/main/resources/application.properties b/core/src/main/resources/application.properties index 1bb57763..e3b42e15 100644 --- a/core/src/main/resources/application.properties +++ b/core/src/main/resources/application.properties @@ -43,6 +43,10 @@ solicitor.classpath-guessedlicenseurl-cache-locations=licenseurls # Deprecated features are deactivated by default. If set to true they might be (temporarily) activated. solicitor.deprecated-features-allowed=false +# Regular expression filter pattern which needs to be matched for a reporting group to be active. If a reporting +# group does not match this pattern, then no report will be written for this reporting group +# solicitor.reportinggroups.filterpattern=.* + ## Feature flags for activation of non-standard/experimental functionality # Incorporate scancode infos into model solicitor.feature-flag.scancode=false diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/config/solicitor_base.cfg b/core/src/main/resources/com/devonfw/tools/solicitor/config/solicitor_base.cfg index a94128b3..a4a56f9f 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/config/solicitor_base.cfg +++ b/core/src/main/resources/com/devonfw/tools/solicitor/config/solicitor_base.cfg @@ -116,8 +116,9 @@ "writers" : [ { "type" : "xls", "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Output_Template_Sample.xlsx", - "target" : "${cfgdir}/output/OSS-Inventory_${project}.xlsx", + "target" : "${cfgdir}/output${/reportingGroup}/OSS-Inventory_${project}${_reportingGroup}.xlsx", "description" : "The XLS OSS-Inventory document", + "enableReportingGroups" : true, "dataTables" : { "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", "APPLICATION" : "classpath:com/devonfw/tools/solicitor/sql/allden_applications.sql", @@ -128,8 +129,9 @@ },{ "type" : "xls", "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Output_Template_Sample.xlsx", - "target" : "${cfgdir}/output/OSS-Inventory_aggregated_${project}.xlsx", + "target" : "${cfgdir}/output${/reportingGroup}/OSS-Inventory_aggregated_${project}${_reportingGroup}.xlsx", "description" : "The XLS OSS-Inventory document", + "enableReportingGroups" : true, "dataTables" : { "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", "APPLICATION" : "classpath:com/devonfw/tools/solicitor/sql/allden_applications.sql", @@ -139,8 +141,9 @@ },{ "type" : "velo", "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Output_Template_Sample.vm", - "target" : "${cfgdir}/output/OSS-Report_${project}.html", + "target" : "${cfgdir}/output${/reportingGroup}/OSS-Report_${project}${_reportingGroup}.html", "description" : "The HTML OSS-Report", + "enableReportingGroups" : true, "dataTables" : { "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", @@ -150,9 +153,11 @@ },{ "type" : "velo", "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Attributions.vm", - "target" : "${cfgdir}/output/Attributions_${project}.html", + "target" : "${cfgdir}/output${/reportingGroup}/Attributions_${project}${_reportingGroup}.html", "description" : "A document containing the license information and attributions required by the OSS licenses", + "enableReportingGroups" : true, "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", "OSSLICENSES" : "classpath:com/devonfw/tools/solicitor/sql/ossapplicationcomponents.sql", "UNIQUELICENSES" : "classpath:com/devonfw/tools/solicitor/sql/uniquelicenses_with_application_components.sql", @@ -161,55 +166,61 @@ "NONCOMMERCIALCOMPONENTS_LICENSES" : "classpath:com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses_with_licenses.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Diff_Template_Sample.vm", - "target" : "${cfgdir}/output/Diff-Sample_${project}.html", - "description" : "Difference Sample", - "dataTables" : { - "LICENSE" : "classpath:com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql" + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Diff_Template_Sample.vm", + "target" : "${cfgdir}/output${/reportingGroup}/Diff-Sample_${project}${_reportingGroup}.html", + "description" : "Difference Sample", + "enableReportingGroups" : true, + "dataTables" : { + "LICENSE" : "classpath:com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Source_Download_Script.vm", - "target" : "${cfgdir}/output/download_sources_${project}.sh", - "description" : "Script for downloading sources which need to be included in the distribution", - "dataTables" : { - "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", - "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/sources_tobeincluded.sql" + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Source_Download_Script.vm", + "target" : "${cfgdir}/output${/reportingGroup}/download_sources_${project}${_reportingGroup}.sh", + "description" : "Script for downloading sources which need to be included in the distribution", + "enableReportingGroups" : true, + "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", + "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/sources_tobeincluded.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Quality_Report.vm", - "target" : "${cfgdir}/output/Quality_Report_${project}.html", - "description" : "Quality Report", - "dataTables" : { - "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", - "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", - "MULTIPLE_EFFECTIVE_LICENSES" : "classpath:com/devonfw/tools/solicitor/sql/multiple_effective_licenses.sql" + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Quality_Report.vm", + "target" : "${cfgdir}/output${/reportingGroup}/Quality_Report_${project}${_reportingGroup}.html", + "description" : "Quality Report", + "enableReportingGroups" : true, + "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", + "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", + "MULTIPLE_EFFECTIVE_LICENSES" : "classpath:com/devonfw/tools/solicitor/sql/multiple_effective_licenses.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/ScancodeScript.vm", - "target" : "${cfgdir}/output/scancode_${project}.sh", - "description" : "Script for downloading sources and running them through scancode to create a copyright report", - "dataTables" : { - "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", - "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/scancode_sources.sql" + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/ScancodeScript.vm", + "target" : "${cfgdir}/output${/reportingGroup}/scancode_${project}${_reportingGroup}.sh", + "description" : "Script for downloading sources and running them through scancode to create a copyright report", + "enableReportingGroups" : true, + "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", + "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/scancode_sources.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/ScancodeScanScript.vm", - "target" : "${cfgdir}/output/scancodeScan.sh", - "description" : "Script for running and copying scancode output to directory", - "dataTables" : { - "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", - "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/scancode_sources.sql" - } + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/ScancodeScanScript.vm", + "target" : "${cfgdir}/output${/reportingGroup}/scancodeScan.sh", + "description" : "Script for running and copying scancode output to directory", + "enableReportingGroups" : true, + "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", + "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/scancode_sources.sql" + } },{ "type": "velo", "templateSource": "classpath:com/devonfw/tools/solicitor/templates/Statistics.vm", - "target": "${cfgdir}/output/Statistics.json", + "target": "${cfgdir}/output${/reportingGroup}/Statistics${_reportingGroup}.json", "description": "Generates a JSON report of categories and their counts", + "enableReportingGroups" : true, "dataTables": { "STATISTICS": "classpath:com/devonfw/tools/solicitor/sql/statistics.sql" } diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_applicationcomponents.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_applicationcomponents.sql index e9b630fc..e131c5af 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_applicationcomponents.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_applicationcomponents.sql @@ -13,6 +13,7 @@ from APPLICATIONCOMPONENT ac where e.ID_ENGAGEMENT = a.PARENT_APPLICATION AND + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT order by UPPER("ID_APPLICATION"), -- sort by ID so assuring we have the same order as defined in config diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_applications.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_applications.sql index fb639532..94ba9d40 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_applications.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_applications.sql @@ -9,6 +9,7 @@ from ENGAGEMENT e, APPLICATION a where - e.ID_ENGAGEMENT = a.PARENT_APPLICATION + e.ID_ENGAGEMENT = a.PARENT_APPLICATION AND + a."reportingGroups" LIKE '%#reportingGroup#%' order by UPPER("ID_APPLICATION") -- sort by ID so assuring we have the same order as defined in config diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql index 6234f2b8..3b529008 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql @@ -17,6 +17,7 @@ from NORMALIZEDLICENSE l where e.ID_ENGAGEMENT = a.PARENT_APPLICATION AND + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE order by diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses.sql index 4ff98d50..96dc72d0 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses.sql @@ -17,6 +17,7 @@ from APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND l."normalizedLicenseType" NOT in ('COMMERCIAL', 'IGNORE') diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses_with_licenses.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses_with_licenses.sql index 36df5b73..2599e056 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses_with_licenses.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses_with_licenses.sql @@ -15,6 +15,7 @@ from APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND l."normalizedLicenseType" NOT in ('COMMERCIAL', 'IGNORE') diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/multiple_effective_licenses.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/multiple_effective_licenses.sql index 2c0f09ac..dde74cb3 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/multiple_effective_licenses.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/multiple_effective_licenses.sql @@ -29,6 +29,7 @@ from ( APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND l."effectiveNormalizedLicenseType" != 'IGNORE' diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/normalizedlicenses_aggregated_applications.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/normalizedlicenses_aggregated_applications.sql index a67e9a71..e8abad00 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/normalizedlicenses_aggregated_applications.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/normalizedlicenses_aggregated_applications.sql @@ -81,6 +81,7 @@ from ( APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE group by diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/noticefiles.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/noticefiles.sql index 9ada6f53..bdfb3901 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/noticefiles.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/noticefiles.sql @@ -11,6 +11,7 @@ from APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND ac."noticeFileUrl" is not null AND diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossapplicationcomponents.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossapplicationcomponents.sql index 18b1f3f1..fd9374c2 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossapplicationcomponents.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossapplicationcomponents.sql @@ -17,6 +17,7 @@ from APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND (l."effectiveNormalizedLicenseType" LIKE 'OSS-%' OR l."effectiveNormalizedLicenseType" = 'SCANCODE') diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossapplicationcomponents_guessedlicenses.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossapplicationcomponents_guessedlicenses.sql index 87234ef5..0cdf1b7b 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossapplicationcomponents_guessedlicenses.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossapplicationcomponents_guessedlicenses.sql @@ -15,6 +15,7 @@ from APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND l."effectiveNormalizedLicenseType" like 'OSS-%' diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossden_normalizedlicenses.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossden_normalizedlicenses.sql index 735e5406..343a19a4 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossden_normalizedlicenses.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/ossden_normalizedlicenses.sql @@ -17,6 +17,7 @@ from NORMALIZEDLICENSE l where e.ID_ENGAGEMENT = a.PARENT_APPLICATION AND + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND l."normalizedLicenseType" not in ('COMMERCIAL', 'IGNORE') diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/scancode_sources.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/scancode_sources.sql index 83cd8d15..fd1fcf94 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/scancode_sources.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/scancode_sources.sql @@ -15,6 +15,7 @@ from APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND l."normalizedLicenseType" not in ('COMMERCIAL') diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/sources_tobeincluded.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/sources_tobeincluded.sql index 0895ea9b..bb5fa683 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/sources_tobeincluded.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/sources_tobeincluded.sql @@ -16,6 +16,7 @@ from APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND l."includeSource" != 'no' diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/statistics.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/statistics.sql index 0aac44bc..bd8a1f45 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/statistics.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/statistics.sql @@ -1,11 +1,23 @@ -- Selects the category "legal-evaluation" and trims any whitespace SELECT TRIM('legal-evaluation') AS category, NVL(l."legalApproved", 'blank') AS value, COUNT(*) AS count -FROM NormalizedLicense l +FROM + APPLICATION a, + APPLICATIONCOMPONENT ac, + NORMALIZEDLICENSE l +where + a."reportingGroups" LIKE '%#reportingGroup#%' AND + a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND + ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE GROUP BY NVL(l."legalApproved", 'blank') UNION ALL -- Combines the results of this query with the next, including duplicates -- Selects the category "data-status" and trims any whitespace SELECT TRIM('data-status') AS category, ac."dataStatus" AS value, COUNT(*) AS count -FROM ApplicationComponent ac +FROM + APPLICATION a, + APPLICATIONCOMPONENT ac +where + a."reportingGroups" LIKE '%#reportingGroup#%' AND + a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT GROUP BY ac."dataStatus"; diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniqueguessedlicenses.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniqueguessedlicenses.sql deleted file mode 100644 index 779ea5b1..00000000 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniqueguessedlicenses.sql +++ /dev/null @@ -1,18 +0,0 @@ --- SPDX-License-Identifier: Apache-2.0 --- --- returns all distinct _guessed_ OSS-Licenses texts -select distinct - l."effectiveNormalizedLicense", - GROUP_CONCAT(DISTINCT l."guessedLicenseUrl" ORDER BY "guessedLicenseUrl" DESC SEPARATOR ', ') as "guessedLicenseUrl", - ARRAY_AGG(DISTINCT l."guessedLicenseContent" ORDER BY "guessedLicenseContent" DESC)[1] as "guessedLicenseContent", - UCASE(REGEXP_REPLACE(l."guessedLicenseContent",'\s','')) as "unifiedGuessedLicenseContent" -from - NORMALIZEDLICENSE l -where - l."effectiveNormalizedLicenseType" like 'OSS-%' -group by - "unifiedGuessedLicenseContent", - "effectiveNormalizedLicense" -order by - "effectiveNormalizedLicense", - "guessedLicenseUrl" diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniquelicenses.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniquelicenses.sql index f9dd28e5..90513677 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniquelicenses.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniquelicenses.sql @@ -7,8 +7,13 @@ select distinct ARRAY_AGG(DISTINCT l."effectiveNormalizedLicenseContent" ORDER BY "effectiveNormalizedLicenseContent" DESC)[1] as "effectiveNormalizedLicenseContent", UCASE(REGEXP_REPLACE(l."effectiveNormalizedLicenseContent",'\s','')) as "unifiedEffectiveNormalizedLicenseContent" from + APPLICATION a, + APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND + a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND + ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND l."effectiveNormalizedLicenseType" like 'OSS-%' group by "unifiedEffectiveNormalizedLicenseContent", diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniquelicenses_with_application_components.sql b/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniquelicenses_with_application_components.sql index 3a0d150e..a19c1a8e 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniquelicenses_with_application_components.sql +++ b/core/src/main/resources/com/devonfw/tools/solicitor/sql/uniquelicenses_with_application_components.sql @@ -12,6 +12,7 @@ from APPLICATIONCOMPONENT ac, NORMALIZEDLICENSE l where + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE AND l."normalizedLicenseType" NOT in ('COMMERCIAL', 'IGNORE') AND diff --git a/core/src/main/resources/com/devonfw/tools/solicitor/templates/Attributions.vm b/core/src/main/resources/com/devonfw/tools/solicitor/templates/Attributions.vm index 562ee775..464c7010 100644 --- a/core/src/main/resources/com/devonfw/tools/solicitor/templates/Attributions.vm +++ b/core/src/main/resources/com/devonfw/tools/solicitor/templates/Attributions.vm @@ -36,7 +36,7 @@ td.licenses {

Thirdparty Components

-THE FOLLOWING SETS FORTH ATTRIBUTION NOTICES FOR THIRD PARTY SOFTWARE THAT MAY BE CONTAINED IN PORTIONS OF THE $ENGAGEMENT.getDataRow(0).engagementName PRODUCT. +THE FOLLOWING SETS FORTH ATTRIBUTION NOTICES FOR THIRD PARTY SOFTWARE THAT MAY BE CONTAINED IN PORTIONS OF THE $ENGAGEMENT.getDataRow(0).engagementName / $MODELROOT.getDataRow(0).reportingGroup PRODUCT.

This document has 3 sections:

    diff --git a/core/src/test/java/com/devonfw/tools/solicitor/common/ReportingGroupHandlerTest.java b/core/src/test/java/com/devonfw/tools/solicitor/common/ReportingGroupHandlerTest.java new file mode 100644 index 00000000..eee4a793 --- /dev/null +++ b/core/src/test/java/com/devonfw/tools/solicitor/common/ReportingGroupHandlerTest.java @@ -0,0 +1,182 @@ +package com.devonfw.tools.solicitor.common; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import java.util.Set; +import java.util.regex.PatternSyntaxException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Tests for {@link ReportingGroupHandler}. + */ +class ReportingGroupHandlerTest { + + private ReportingGroupHandler handlerUnderTest; + + /** + * @throws java.lang.Exception + */ + @BeforeEach + void setUp() throws Exception { + + this.handlerUnderTest = new ReportingGroupHandler(); + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#setReportingGroupActivationFilterPattern(java.lang.String)}. + */ + @Test + void testSetReportingGroupActivationFilterPattern() { + + this.handlerUnderTest.setReportingGroupActivationFilterPattern("some pattern"); + assertThrows(PatternSyntaxException.class, + () -> this.handlerUnderTest.setReportingGroupActivationFilterPattern("[A-Z")); + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#validateReportingGroup(java.lang.String)}. + */ + @Test + void testValidateReportingGroup() { + + this.handlerUnderTest.validateReportingGroup("abcexyzABYZ_-09 "); + // empty value + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.validateReportingGroup("")); + // disallowed characters + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.validateReportingGroup("a#")); + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.validateReportingGroup("aƤ")); + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.validateReportingGroup("a(")); + // not starting alphanumeric + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.validateReportingGroup("_a")); + + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#validateReportingGroupList(java.lang.String)}. + */ + @Test + void testValidateReportingGroupList() { + + this.handlerUnderTest.validateReportingGroupList("#a b#c#"); + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.validateReportingGroupList("#a/b#c#")); + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.validateReportingGroupList("a b#c#")); + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.validateReportingGroupList("#a b#c")); + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#splitReportingGroupList(java.lang.String)}. + */ + @Test + void testSplitReportingGroupList() { + + List result = this.handlerUnderTest.splitReportingGroupList("#a b#c#"); + assertEquals(2, result.size()); + assertEquals("a b", result.get(0)); + assertEquals("c", result.get(1)); + + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.validateReportingGroupList("#a/b#c#")); + + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#normalizeReportingGroups(java.util.List)}. + */ + @Test + void testNormalizeReportingGroups() { + + Set result; + + result = this.handlerUnderTest.normalizeReportingGroups(null); + assertEquals(1, result.size()); + assertTrue(result.contains("default")); + + result = this.handlerUnderTest.normalizeReportingGroups(List.of("a", "b", "c", "b")); + assertEquals(3, result.size()); + assertTrue(result.containsAll(List.of("a", "b", "c"))); + + assertThrows(SolicitorRuntimeException.class, () -> this.handlerUnderTest.normalizeReportingGroups(List.of("/"))); + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#stringifyReportingGroups(java.util.Set)}. + */ + @Test + void testStringifyReportingGroups() { + + String result = this.handlerUnderTest.stringifyReportingGroups(Set.of("a", "b")); + + assertTrue(result.equals("#a#b#") || result.equals("#b#a#")); + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#replacePlaceholderInSql(java.lang.String, java.lang.String)}. + */ + @Test + void testReplacePlaceholderInSql() { + + String result; + result = this.handlerUnderTest.replacePlaceholderInSql("some sql #reportingGroup#with placeholder", "test"); + assertEquals("some sql #test#with placeholder", result); + result = this.handlerUnderTest.replacePlaceholderInSql("some sql reportingGroup without placeholder", "test"); + assertEquals("some sql reportingGroup without placeholder", result); + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#expandReportingGroupInFileName(java.lang.String, java.lang.String)}. + */ + @Test + void testExpandReportingGroupInFileName() { + + String result; + result = this.handlerUnderTest.expandReportingGroupInFileName( + "some${/reportingGroup}/test${_reportingGroup}/file${_reportingGroup}${-reportingGroup}.txt", "foo"); + assertEquals("some/foo/test_foo/file_foo-foo.txt", result); + + result = this.handlerUnderTest.expandReportingGroupInFileName( + "some${/reportingGroup}/test${_reportingGroup}/file${_reportingGroup}${-reportingGroup}.txt", "default"); + assertEquals("some/test/file.txt", result); + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#matchesReportingGroupFilter(java.lang.String)}. + */ + @Test + void testMatchesReportingGroupFilter() { + + assertTrue(this.handlerUnderTest.matchesReportingGroupFilter("some string")); + this.handlerUnderTest.setReportingGroupActivationFilterPattern("foo|bar"); + assertTrue(this.handlerUnderTest.matchesReportingGroupFilter("foo")); + assertTrue(this.handlerUnderTest.matchesReportingGroupFilter("bar")); + assertFalse(this.handlerUnderTest.matchesReportingGroupFilter("test")); + assertFalse(this.handlerUnderTest.matchesReportingGroupFilter("foo|bar")); + + } + + /** + * Test method for + * {@link com.devonfw.tools.solicitor.common.ReportingGroupHandler#logReportingGroups(java.util.Collection)}. + */ + @Test + void testLogReportingGroups() { + + this.handlerUnderTest.setReportingGroupActivationFilterPattern("bar"); + this.handlerUnderTest.logReportingGroups(List.of("foo", "bar")); + // no assertion of actual log message; just assuring no exception is thrown + } + +} diff --git a/core/src/test/java/com/devonfw/tools/solicitor/model/ModelImporterExporterTest.java b/core/src/test/java/com/devonfw/tools/solicitor/model/ModelImporterExporterTest.java index 492a3e71..a086f7e9 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/model/ModelImporterExporterTest.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/model/ModelImporterExporterTest.java @@ -75,10 +75,18 @@ public void testLoadModelVersion5() { /** * Test method for {@link com.devonfw.tools.solicitor.model.ModelImporterExporter#loadModel(java.lang.String)}. */ - @Test public void testLoadModelVersion6() { - ModelRoot modelRoot = this.mie.loadModel("src/test/resources/models/model_version_6.json"); + this.mie.loadModel("src/test/resources/models/model_version_6.json"); + } + + /** + * Test method for {@link com.devonfw.tools.solicitor.model.ModelImporterExporter#loadModel(java.lang.String)}. + */ + @Test + public void testLoadModelVersion7() { + + ModelRoot modelRoot = this.mie.loadModel("src/test/resources/models/model_version_7.json"); // Assert Assertions.assertNotNull(modelRoot); @@ -89,6 +97,7 @@ public void testLoadModelVersion6() { Application application = applications.get(0); Assertions.assertNotNull(application); + Assertions.assertEquals("#default#", application.getReportingGroups()); List applicationComponents = application.getApplicationComponents(); Assertions.assertFalse(applicationComponents.isEmpty()); @@ -115,7 +124,7 @@ public void testLoadModelVersion6() { @Test public void testSaveModel() throws IOException { - ModelRoot mr = this.mie.loadModel("src/test/resources/models/model_version_6.json"); + ModelRoot mr = this.mie.loadModel("src/test/resources/models/model_version_7.json"); File tempFile = File.createTempFile("solicitor_model", "json"); String fileName = tempFile.getPath(); diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/csv/CsvReaderTests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/csv/CsvReaderTests.java index 5c52174d..3d9eab7f 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/csv/CsvReaderTests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/csv/CsvReaderTests.java @@ -59,7 +59,8 @@ public CsvReaderTests() { ModelFactory modelFactory = new ModelFactoryImpl(); - this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Java8"); + this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Java8", + "#default#"); CsvReader csvr = new CsvReader(); csvr.setModelFactory(modelFactory); csvr.setInputStreamFactory(new FileInputStreamFactory()); @@ -132,7 +133,8 @@ public void testFindNpmPackageUrl() { Application application; ModelFactory modelFactory = new ModelFactoryImpl(); - application = modelFactory.newApplication("testAppNpm", "0.0.0.TEST", "1.1.2111", "http://bla.com", "NPM"); + application = modelFactory.newApplication("testAppNpm", "0.0.0.TEST", "1.1.2111", "http://bla.com", "NPM", + "#default#"); CsvReader csvr = new CsvReader(); csvr.setModelFactory(modelFactory); csvr.setInputStreamFactory(new FileInputStreamFactory()); @@ -160,7 +162,8 @@ public void testFindPypiPackageUrl() { Application application; ModelFactory modelFactory = new ModelFactoryImpl(); - application = modelFactory.newApplication("testAppPypi", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Python"); + application = modelFactory.newApplication("testAppPypi", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Python", + "#default#"); // configuration settings Map configuration = new HashMap(); @@ -196,7 +199,8 @@ public void testNullPackageUrl() { Application application; ModelFactory modelFactory = new ModelFactoryImpl(); - application = modelFactory.newApplication("testAppNull", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Python"); + application = modelFactory.newApplication("testAppNull", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Python", + "#default#"); CsvReader csvr = new CsvReader(); csvr.setModelFactory(modelFactory); csvr.setInputStreamFactory(new FileInputStreamFactory()); @@ -210,7 +214,7 @@ public void testNullPackageUrl() { } catch (Exception e) { // Capture the log messages ArgumentCaptor logEntry1 = ArgumentCaptor.forClass(String.class); - verify(logger).warn(logEntry1.capture()); + verify(this.logger).warn(logEntry1.capture()); assertEquals(expectedLogMessage, logEntry1.getValue()); } diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/cyclonedx/CyclonedxReaderTests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/cyclonedx/CyclonedxReaderTests.java index 1b2fda39..84af9bac 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/cyclonedx/CyclonedxReaderTests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/cyclonedx/CyclonedxReaderTests.java @@ -44,7 +44,7 @@ public void readMavenFileAndCheckSize() { Mockito.when(this.delegatingPurlHandler.pathFor(Mockito.startsWith("pkg:maven/"))).thenReturn("foo"); Application application = this.modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", - "Java8"); + "Java8", "#default#"); this.cdxr.setModelFactory(this.modelFactory); this.cdxr.setInputStreamFactory(new FileInputStreamFactory()); this.cdxr.setDelegatingPackageURLHandler(this.delegatingPurlHandler); @@ -80,7 +80,7 @@ public void readMavenFileAndCheckSizeNegative() { new SolicitorPackageURLException("No applicable SingleKindPackageURLHandler found for type 'maven'")); Application application = this.modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", - "Java8"); + "Java8", "#default#"); this.cdxr.setModelFactory(this.modelFactory); this.cdxr.setInputStreamFactory(new FileInputStreamFactory()); this.cdxr.setDelegatingPackageURLHandler(this.delegatingPurlHandler); @@ -103,7 +103,7 @@ public void readMavenFileAndCheckSingleContentSize() { Mockito.when(this.delegatingPurlHandler.pathFor(Mockito.startsWith("pkg:maven/"))).thenReturn("foo"); Application application = this.modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", - "Java8"); + "Java8", "#default#"); this.cdxr.setModelFactory(this.modelFactory); this.cdxr.setInputStreamFactory(new FileInputStreamFactory()); this.cdxr.setDelegatingPackageURLHandler(this.delegatingPurlHandler); @@ -165,7 +165,7 @@ public void readNpmFileAndCheckSize() { Mockito.when(this.delegatingPurlHandler.pathFor(Mockito.startsWith("pkg:npm/"))).thenReturn("foo"); Application application = this.modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", - "Angular"); + "Angular", "#default#"); this.cdxr.setModelFactory(this.modelFactory); this.cdxr.setInputStreamFactory(new FileInputStreamFactory()); this.cdxr.setDelegatingPackageURLHandler(this.delegatingPurlHandler); @@ -196,7 +196,7 @@ public void readExpression() { Mockito.when(this.delegatingPurlHandler.pathFor(Mockito.startsWith("pkg:maven/"))).thenReturn("foo"); Application application = this.modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", - "Angular"); + "Angular", "#default#"); this.cdxr.setModelFactory(this.modelFactory); this.cdxr.setInputStreamFactory(new FileInputStreamFactory()); this.cdxr.setDelegatingPackageURLHandler(this.delegatingPurlHandler); diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/gradle/GradleLicenseReportReaderTest.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/gradle/GradleLicenseReportReaderTest.java index bfe8084b..1fe2ab4f 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/gradle/GradleLicenseReportReaderTest.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/gradle/GradleLicenseReportReaderTest.java @@ -21,7 +21,8 @@ class GradleLicenseReportReaderTest { public GradleLicenseReportReaderTest() { ModelFactory modelFactory = new ModelFactoryImpl(); - this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Java8"); + this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Java8", + "#default#"); GradleLicenseReportReader gr = new GradleLicenseReportReader(); gr.setModelFactory(modelFactory); gr.setInputStreamFactory(new FileInputStreamFactory()); diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/gradle/GradleReader2Tests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/gradle/GradleReader2Tests.java index c7ab1aaa..0b1d10a6 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/gradle/GradleReader2Tests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/gradle/GradleReader2Tests.java @@ -30,7 +30,8 @@ public GradleReader2Tests() { ModelFactory modelFactory = new ModelFactoryImpl(); - this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Java8"); + this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Java8", + "#default#"); GradleReader2 gr = new GradleReader2(); gr.setDeprecationChecker(new DeprecationChecker() { diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/maven/MavenReaderTests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/maven/MavenReaderTests.java index ac89fed3..b8a24166 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/maven/MavenReaderTests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/maven/MavenReaderTests.java @@ -34,7 +34,7 @@ public void readFileAndCheckSize() { ModelFactory modelFactory = new ModelFactoryImpl(); Application application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", - "Java8"); + "Java8", "#default#"); MavenReader mr = new MavenReader(); mr.setModelFactory(modelFactory); mr.setInputStreamFactory(new FileInputStreamFactory()); @@ -67,7 +67,7 @@ public void testProtectionAgainstXxe() { ModelFactory modelFactory = new ModelFactoryImpl(); Application application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", - "Java8"); + "Java8", "#default#"); MavenReader mr = new MavenReader(); mr.setModelFactory(modelFactory); mr.setInputStreamFactory(new FileInputStreamFactory()); diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/npmlicensechecker/NpmLicenseCheckerReaderTests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/npmlicensechecker/NpmLicenseCheckerReaderTests.java index 1ea36e16..811e9e5b 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/npmlicensechecker/NpmLicenseCheckerReaderTests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/npmlicensechecker/NpmLicenseCheckerReaderTests.java @@ -29,7 +29,8 @@ public NpmLicenseCheckerReaderTests() { ModelFactory modelFactory = new ModelFactoryImpl(); - this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Angular"); + this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Angular", + "#default#"); NpmLicenseCheckerReader gr = new NpmLicenseCheckerReader(); gr.setModelFactory(modelFactory); gr.setInputStreamFactory(new FileInputStreamFactory()); diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/npmlicensecrawler/NpmLicenseCrawlerReaderTests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/npmlicensecrawler/NpmLicenseCrawlerReaderTests.java index ee0dcbe4..497f934c 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/npmlicensecrawler/NpmLicenseCrawlerReaderTests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/npmlicensecrawler/NpmLicenseCrawlerReaderTests.java @@ -30,7 +30,8 @@ public class NpmLicenseCrawlerReaderTests { public NpmLicenseCrawlerReaderTests() { ModelFactory modelFactory = new ModelFactoryImpl(); - this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Angular"); + this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Angular", + "#default#"); NpmLicenseCrawlerReader nr = new NpmLicenseCrawlerReader(); nr.setDeprecationChecker(new DeprecationChecker() { @@ -42,8 +43,8 @@ public void check(boolean warnOnly, String detailsString) { }); nr.setModelFactory(modelFactory); nr.setInputStreamFactory(new FileInputStreamFactory()); - nr.readInventory("npm", "src/test/resources/npmlicenses.csv", this.application, UsagePattern.DYNAMIC_LINKING, "npm", null, - null); + nr.readInventory("npm", "src/test/resources/npmlicenses.csv", this.application, UsagePattern.DYNAMIC_LINKING, "npm", + null, null); } @Test diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/ort/OrtReaderTests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/ort/OrtReaderTests.java index c97dca1d..ab42583c 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/ort/OrtReaderTests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/ort/OrtReaderTests.java @@ -29,12 +29,13 @@ public OrtReaderTests() { ModelFactory modelFactory = new ModelFactoryImpl(); - this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Python"); + this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Python", + "#default#"); OrtReader pr = new OrtReader(); pr.setModelFactory(modelFactory); pr.setInputStreamFactory(new FileInputStreamFactory()); - pr.readInventory("ort", "src/test/resources/analyzer-result.json", this.application, UsagePattern.DYNAMIC_LINKING, "ort", null, - null); + pr.readInventory("ort", "src/test/resources/analyzer-result.json", this.application, UsagePattern.DYNAMIC_LINKING, + "ort", null, null); } @@ -67,7 +68,8 @@ public void testFindLicenseIfSingle() { List lapc = this.application.getApplicationComponents(); boolean found = false; for (ApplicationComponent ap : lapc) { - if (ap.getArtifactId().equals("testArtifactId") && ap.getRawLicenses().get(0).getDeclaredLicense().equals("Apache License, Version 2.0")) { + if (ap.getArtifactId().equals("testArtifactId") + && ap.getRawLicenses().get(0).getDeclaredLicense().equals("Apache License, Version 2.0")) { found = true; break; } diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/piplicenses/PipReaderTests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/piplicenses/PipReaderTests.java index 19e5689e..99fd5402 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/piplicenses/PipReaderTests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/piplicenses/PipReaderTests.java @@ -29,12 +29,13 @@ public PipReaderTests() { ModelFactory modelFactory = new ModelFactoryImpl(); - this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Python"); + this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Python", + "#default#"); PipLicensesReader pr = new PipLicensesReader(); pr.setModelFactory(modelFactory); pr.setInputStreamFactory(new FileInputStreamFactory()); - pr.readInventory("pip", "src/test/resources/pipReport.json", this.application, UsagePattern.DYNAMIC_LINKING, "pip", null, - null); + pr.readInventory("pip", "src/test/resources/pipReport.json", this.application, UsagePattern.DYNAMIC_LINKING, "pip", + null, null); } diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/yarn/YarnReaderTests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/yarn/YarnReaderTests.java index 2ee47a1a..42e4204a 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/yarn/YarnReaderTests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/yarn/YarnReaderTests.java @@ -29,7 +29,8 @@ public YarnReaderTests() { ModelFactory modelFactory = new ModelFactoryImpl(); - this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Angular"); + this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Angular", + "#default#"); YarnReader yr = new YarnReader(); yr.setModelFactory(modelFactory); yr.setInputStreamFactory(new FileInputStreamFactory()); diff --git a/core/src/test/java/com/devonfw/tools/solicitor/reader/yarnmodern/YarnModernReaderTests.java b/core/src/test/java/com/devonfw/tools/solicitor/reader/yarnmodern/YarnModernReaderTests.java index 49a96c00..f1eca8c4 100644 --- a/core/src/test/java/com/devonfw/tools/solicitor/reader/yarnmodern/YarnModernReaderTests.java +++ b/core/src/test/java/com/devonfw/tools/solicitor/reader/yarnmodern/YarnModernReaderTests.java @@ -35,7 +35,8 @@ public YarnModernReaderTests() { ModelFactory modelFactory = new ModelFactoryImpl(); - this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Angular"); + this.application = modelFactory.newApplication("testApp", "0.0.0.TEST", "1.1.2111", "http://bla.com", "Angular", + "#default#"); YarnModernReader yr = new YarnModernReader(); yr.setModelFactory(modelFactory); yr.setInputStreamFactory(new FileInputStreamFactory()); diff --git a/core/src/test/resources/models/model_version_7.json b/core/src/test/resources/models/model_version_7.json new file mode 100644 index 00000000..3837ae00 --- /dev/null +++ b/core/src/test/resources/models/model_version_7.json @@ -0,0 +1,125 @@ +{ + "executionTime" : "Fri Oct 01 18:38:31 CEST 2021", + "modelVersion" : 7, + "solicitorVersion" : "1.3.0-SNAPSHOT", + "solicitorGitHash" : "a507f22", + "solicitorBuilddate" : "2021-10-01 18:34:12 +0200", + "extensionArtifactId" : "cap-solicitor-extension", + "extensionVersion" : "1.3.0-RC1", + "extensionGitHash" : "043a961", + "extensionBuilddate" : "2021-09-13 22:24:45", + "engagement" : { + "engagementName" : "Some Engagement", + "engagementType" : "INTERN", + "clientName" : "none", + "goToMarketModel" : "LICENSE", + "contractAllowsOss" : true, + "ossPolicyFollowed" : true, + "customerProvidesOss" : false, + "applications" : [ { + "name" : "Some Application", + "releaseId" : "1.2.3-SNAPSHOT", + "releaseDate" : "-UNDEFINED-", + "sourceRepo" : "https://point/to/your/repo.git", + "programmingEcosystem" : "Java8", + "reportingGroups" : "#default#", + "applicationComponents" : [ { + "usagePattern" : "DYNAMIC_LINKING", + "ossModified" : false, + "ossHomepage" : null, + "sourceRepoUrl" : "https://github.com/qos-ch/logback", + "noticeFileUrl" : "http://some.url", + "noticeFileContentKey" : "31cb574375eadadae8835a406879719d85da9fbb5f0f0c6fdc62da741dc49de5", + "groupId" : "ch.qos.logback", + "artifactId" : "logback-classic", + "version" : "1.2.3", + "repoType" : "maven", + "packageUrl" : "pkg:maven/ch.qos.logback/logback-classic@1.2.3", + "copyrights" : null, + "packageDownloadUrl" : "https://repo.maven.apache.org/maven2/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar", + "sourceDownloadUrl" : "https://github.com/qos-ch/logback/archive/refs/tags/logback-1.2.3.zip", + "normalizedLicenses" : [ { + "declaredLicense" : "Eclipse Public License - v 1.0", + "licenseUrl" : "http://www.eclipse.org/legal/epl-v10.html", + "declaredLicenseContentKey" : "cf630ee3446f9e10c1b0814fb8a652f4733b491eaea9d5d1f89f803daaaa6075", + "normalizedLicenseType" : "OSS-SPDX", + "normalizedLicense" : "EPL-1.0", + "normalizedLicenseUrl" : "http://www.eclipse.org/legal/epl-v10.html", + "normalizedLicenseContentKey" : "cf630ee3446f9e10c1b0814fb8a652f4733b491eaea9d5d1f89f803daaaa6075", + "effectiveNormalizedLicenseType" : "IGNORE", + "effectiveNormalizedLicense" : "Ignore", + "effectiveNormalizedLicenseUrl" : null, + "effectiveNormalizedLicenseContentKey" : "9d086420212f290c944042014500f00716c30d53f316d224b4cdd0c20756ab6b", + "legalPreApproved" : "N/A", + "copyLeft" : "N/A", + "licenseCompliance" : "N/A", + "licenseRefUrl" : "http://another.url", + "licenseRefContentKey" : "7dbd9399a4684cdc5c1c51d6359294caea160c648f1792e273a9489e46321b88", + "includeLicense" : "no", + "includeSource" : "no", + "reviewedForRelease" : null, + "comments" : null, + "legalApproved" : "N/A", + "legalComments" : null, + "trace" : "+ Component/License info read in '[maven]' format from 'file:./input/licenses_starter.xml'\r\n+ Rule Group: LicenseNameMappingDefaults; RuleId: 57; Matching: declaredLicense==Eclipse Public License - v 1.0; Setting: normalizedLicenseType=OSS-SPDX, normalizedLicense=EPL-1.0, normalizedLicenseUrl=http://www.eclipse.org/legal/epl-v10.html (taking data from input)\r\n+ Rule Group: MultiLicenseSelection; RuleId: 6; Matching: groupId==ch.qos.logback, normalizedLicense==EPL-1.0; Setting: effectiveNormalizedLicenseType=IGNORE (multilicensing: ignore this, prefer LGPL-2.1), effectiveNormalizedLicense=Ignore\r\n+ Rule Group: LegalPreEvaluation; RuleId: 29; Matching: effectiveNormalizedLicenseType==IGNORE; Setting: legalPreApproved=N/A, copyLeft=N/A, licenseCompliance=N/A, includeLicense=no, includeSource=no\r\n+ Rule Group: LegalEvaluation; RuleId: 1; Matching: effectiveNormalizedLicenseType==IGNORE; Setting: legalApproved=N/A", + "guessedLicenseUrl" : null, + "guessedLicenseContentKey" : "90fa1cb2ff3629e0f7a3c78dc887134e5e05224de1b13fed1dedb33b1e920724", + "guessedLicenseUrlAuditInfo" : null + }, { + "declaredLicense" : "GNU Lesser General Public License", + "licenseUrl" : "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html", + "declaredLicenseContentKey" : "cf630ee3446f9e10c1b0814fb8a652f4733b491eaea9d5d1f89f803daaaa6075", + "normalizedLicenseType" : "OSS-SPDX", + "normalizedLicense" : "LGPL-2.1", + "normalizedLicenseUrl" : "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html", + "normalizedLicenseContentKey" : "cf630ee3446f9e10c1b0814fb8a652f4733b491eaea9d5d1f89f803daaaa6075", + "effectiveNormalizedLicenseType" : "OSS-SPDX", + "effectiveNormalizedLicense" : "LGPL-2.1", + "effectiveNormalizedLicenseUrl" : "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html", + "effectiveNormalizedLicenseContentKey" : "cf630ee3446f9e10c1b0814fb8a652f4733b491eaea9d5d1f89f803daaaa6075", + "legalPreApproved" : "no", + "copyLeft" : "weak", + "licenseCompliance" : "check legal", + "licenseRefUrl" : "https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt", + "licenseRefContentKey" : "7dbd9399a4684cdc5c1c51d6359294caea160c648f1792e273a9489e46321b88", + "includeLicense" : "yes", + "includeSource" : "yes", + "reviewedForRelease" : null, + "comments" : null, + "legalApproved" : "Conditional", + "legalComments" : "OK, in case of dynamic linking.", + "trace" : "+ Component/License info read in '[maven]' format from 'file:./input/licenses_starter.xml'\r\n+ Rule Group: LicenseNameMappingDefaults; RuleId: 101; Matching: licenseUrl==REGEX:https?://www.gnu.org/licenses/old-licenses/lgpl-2.1.*; Setting: normalizedLicenseType=OSS-SPDX, normalizedLicense=LGPL-2.1, normalizedLicenseUrl=http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html (taking data from input)\r\n+ Rule Group: LicenseSelection; RuleId: DEFAULT; Matching: -default-; Setting: effectiveNormalizedLicenseType=OSS-SPDX (taking data from input), effectiveNormalizedLicense=LGPL-2.1 (taking data from input), effectiveNormalizedLicenseUrl=http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html (taking data from input)\r\n+ Rule Group: LegalPreEvaluation; RuleId: 6; Matching: effectiveNormalizedLicenseType==OSS-SPDX, effectiveNormalizedLicense==LGPL-2.1; Setting: legalPreApproved=no, copyLeft=weak, licenseCompliance=check legal, licenseRefUrl=https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt, includeLicense=yes, includeSource=yes\r\n+ Rule Group: LegalEvaluation; RuleId: 14; Matching: usagePattern==DYNAMIC_LINKING, effectiveNormalizedLicenseType==OSS-SPDX, effectiveNormalizedLicense==LGPL-2.1; Setting: legalApproved=Conditional, legalComments=OK, in case of dynamic linking.", + "guessedLicenseUrl" : "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html", + "guessedLicenseContentKey" : "90fa1cb2ff3629e0f7a3c78dc887134e5e05224de1b13fed1dedb33b1e920724", + "guessedLicenseUrlAuditInfo" : "" + } ], + "rawLicenses" : [ { + "declaredLicense" : "Eclipse Public License - v 1.0", + "licenseUrl" : "http://www.eclipse.org/legal/epl-v10.html", + "declaredLicenseContentKey" : null, + "trace" : "+ Component/License info read in '[maven]' format from 'file:./input/licenses_starter.xml'", + "origin" : "scancode", + "specialHandling" : true + }, { + "declaredLicense" : "GNU Lesser General Public License", + "licenseUrl" : "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html", + "declaredLicenseContentKey" : null, + "trace" : "+ Component/License info read in '[maven]' format from 'file:./input/licenses_starter.xml'", + "origin" : "scancode", + "specialHandling" : true + } ], + "dataStatus" : "DA:NO_ISSUES", + "traceabilityNotes" : "" + } ] + } ] + }, + "textPool" : { + "dataMap" : { + "31cb574375eadadae8835a406879719d85da9fbb5f0f0c6fdc62da741dc49de5" : "Some content of a NOTICE file", + "7dbd9399a4684cdc5c1c51d6359294caea160c648f1792e273a9489e46321b88" : "Even some other license text", + "90fa1cb2ff3629e0f7a3c78dc887134e5e05224de1b13fed1dedb33b1e920724" : "Some license text", + "9d086420212f290c944042014500f00716c30d53f316d224b4cdd0c20756ab6b" : "Yet another license text", + "cf630ee3446f9e10c1b0814fb8a652f4733b491eaea9d5d1f89f803daaaa6075" : "Some other license text" + } + } +} \ No newline at end of file diff --git a/documentation/files/allden_normalizedlicenses.sql b/documentation/files/allden_normalizedlicenses.sql index 86417bfb..3b529008 100644 --- a/documentation/files/allden_normalizedlicenses.sql +++ b/documentation/files/allden_normalizedlicenses.sql @@ -17,6 +17,7 @@ from NORMALIZEDLICENSE l where e.ID_ENGAGEMENT = a.PARENT_APPLICATION AND + a."reportingGroups" LIKE '%#reportingGroup#%' AND a.ID_APPLICATION = ac.PARENT_APPLICATIONCOMPONENT AND ac.ID_APPLICATIONCOMPONENT = l.PARENT_NORMALIZEDLICENSE order by @@ -25,4 +26,5 @@ order by UPPER("artifactId"), UPPER("version"), UPPER("effectiveNormalizedLicense"), - UPPER("normalizedLicense") \ No newline at end of file + UPPER("normalizedLicense"), + UPPER("declaredLicense") \ No newline at end of file diff --git a/documentation/files/application.properties b/documentation/files/application.properties index 1bb57763..e3b42e15 100644 --- a/documentation/files/application.properties +++ b/documentation/files/application.properties @@ -43,6 +43,10 @@ solicitor.classpath-guessedlicenseurl-cache-locations=licenseurls # Deprecated features are deactivated by default. If set to true they might be (temporarily) activated. solicitor.deprecated-features-allowed=false +# Regular expression filter pattern which needs to be matched for a reporting group to be active. If a reporting +# group does not match this pattern, then no report will be written for this reporting group +# solicitor.reportinggroups.filterpattern=.* + ## Feature flags for activation of non-standard/experimental functionality # Incorporate scancode infos into model solicitor.feature-flag.scancode=false diff --git a/documentation/files/solicitor_base.cfg b/documentation/files/solicitor_base.cfg index d58b80d4..a4a56f9f 100644 --- a/documentation/files/solicitor_base.cfg +++ b/documentation/files/solicitor_base.cfg @@ -26,7 +26,7 @@ "templateSource" : "classpath:com/devonfw/tools/solicitor/rules/rule_templates/LicenseAssignment.drt", "ruleGroup" : "LicenseAssignmentProject", "description" : "setting license in case that no one was detected or overwriting a wrongly detected license (project overrides; 'old' rule structure)", - "deprecationWarnOnly" : true, + "deprecationWarnOnly" : false, "deprecationDetails" : "Use of decision table LicenseAssignmentProject is deprecated, use LicenseAssignmentV2Project instead. See release notes of release 1.4.0 for migration hints" },{ "type" : "dt", @@ -116,8 +116,9 @@ "writers" : [ { "type" : "xls", "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Output_Template_Sample.xlsx", - "target" : "${cfgdir}/output/OSS-Inventory_${project}.xlsx", + "target" : "${cfgdir}/output${/reportingGroup}/OSS-Inventory_${project}${_reportingGroup}.xlsx", "description" : "The XLS OSS-Inventory document", + "enableReportingGroups" : true, "dataTables" : { "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", "APPLICATION" : "classpath:com/devonfw/tools/solicitor/sql/allden_applications.sql", @@ -128,8 +129,9 @@ },{ "type" : "xls", "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Output_Template_Sample.xlsx", - "target" : "${cfgdir}/output/OSS-Inventory_aggregated_${project}.xlsx", + "target" : "${cfgdir}/output${/reportingGroup}/OSS-Inventory_aggregated_${project}${_reportingGroup}.xlsx", "description" : "The XLS OSS-Inventory document", + "enableReportingGroups" : true, "dataTables" : { "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", "APPLICATION" : "classpath:com/devonfw/tools/solicitor/sql/allden_applications.sql", @@ -139,8 +141,9 @@ },{ "type" : "velo", "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Output_Template_Sample.vm", - "target" : "${cfgdir}/output/OSS-Report_${project}.html", + "target" : "${cfgdir}/output${/reportingGroup}/OSS-Report_${project}${_reportingGroup}.html", "description" : "The HTML OSS-Report", + "enableReportingGroups" : true, "dataTables" : { "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", @@ -150,9 +153,11 @@ },{ "type" : "velo", "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Attributions.vm", - "target" : "${cfgdir}/output/Attributions_${project}.html", + "target" : "${cfgdir}/output${/reportingGroup}/Attributions_${project}${_reportingGroup}.html", "description" : "A document containing the license information and attributions required by the OSS licenses", + "enableReportingGroups" : true, "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", "OSSLICENSES" : "classpath:com/devonfw/tools/solicitor/sql/ossapplicationcomponents.sql", "UNIQUELICENSES" : "classpath:com/devonfw/tools/solicitor/sql/uniquelicenses_with_application_components.sql", @@ -161,50 +166,64 @@ "NONCOMMERCIALCOMPONENTS_LICENSES" : "classpath:com/devonfw/tools/solicitor/sql/applicationcomponents_with_noncommerciallicenses_with_licenses.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Diff_Template_Sample.vm", - "target" : "${cfgdir}/output/Diff-Sample_${project}.html", - "description" : "Difference Sample", - "dataTables" : { - "LICENSE" : "classpath:com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql" + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Solicitor_Diff_Template_Sample.vm", + "target" : "${cfgdir}/output${/reportingGroup}/Diff-Sample_${project}${_reportingGroup}.html", + "description" : "Difference Sample", + "enableReportingGroups" : true, + "dataTables" : { + "LICENSE" : "classpath:com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Source_Download_Script.vm", - "target" : "${cfgdir}/output/download_sources_${project}.sh", - "description" : "Script for downloading sources which need to be included in the distribution", - "dataTables" : { - "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", - "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/sources_tobeincluded.sql" + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Source_Download_Script.vm", + "target" : "${cfgdir}/output${/reportingGroup}/download_sources_${project}${_reportingGroup}.sh", + "description" : "Script for downloading sources which need to be included in the distribution", + "enableReportingGroups" : true, + "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", + "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/sources_tobeincluded.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Quality_Report.vm", - "target" : "${cfgdir}/output/Quality_Report_${project}.html", - "description" : "Quality Report", - "dataTables" : { - "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", - "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", - "MULTIPLE_EFFECTIVE_LICENSES" : "classpath:com/devonfw/tools/solicitor/sql/multiple_effective_licenses.sql" + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/Quality_Report.vm", + "target" : "${cfgdir}/output${/reportingGroup}/Quality_Report_${project}${_reportingGroup}.html", + "description" : "Quality Report", + "enableReportingGroups" : true, + "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", + "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", + "MULTIPLE_EFFECTIVE_LICENSES" : "classpath:com/devonfw/tools/solicitor/sql/multiple_effective_licenses.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/ScancodeScript.vm", - "target" : "${cfgdir}/output/scancode_${project}.sh", - "description" : "Script for downloading sources and running them through scancode to create a copyright report", - "dataTables" : { - "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", - "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/scancode_sources.sql" + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/ScancodeScript.vm", + "target" : "${cfgdir}/output${/reportingGroup}/scancode_${project}${_reportingGroup}.sh", + "description" : "Script for downloading sources and running them through scancode to create a copyright report", + "enableReportingGroups" : true, + "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", + "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/scancode_sources.sql" } },{ - "type" : "velo", - "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/ScancodeScanScript.vm", - "target" : "${cfgdir}/output/scancodeScan.sh", - "description" : "Script for running and copying scancode output to directory", - "dataTables" : { - "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", - "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/scancode_sources.sql" + "type" : "velo", + "templateSource" : "classpath:com/devonfw/tools/solicitor/templates/ScancodeScanScript.vm", + "target" : "${cfgdir}/output${/reportingGroup}/scancodeScan.sh", + "description" : "Script for running and copying scancode output to directory", + "enableReportingGroups" : true, + "dataTables" : { + "MODELROOT" : "classpath:com/devonfw/tools/solicitor/sql/modelroot.sql", + "ARTIFACTS" : "classpath:com/devonfw/tools/solicitor/sql/scancode_sources.sql" + } + },{ + "type": "velo", + "templateSource": "classpath:com/devonfw/tools/solicitor/templates/Statistics.vm", + "target": "${cfgdir}/output${/reportingGroup}/Statistics${_reportingGroup}.json", + "description": "Generates a JSON report of categories and their counts", + "enableReportingGroups" : true, + "dataTables": { + "STATISTICS": "classpath:com/devonfw/tools/solicitor/sql/statistics.sql" + } } - }] - + ] } \ No newline at end of file diff --git a/documentation/master-solicitor.asciidoc b/documentation/master-solicitor.asciidoc index d9fa7883..0dcc28f4 100644 --- a/documentation/master-solicitor.asciidoc +++ b/documentation/master-solicitor.asciidoc @@ -110,7 +110,8 @@ The internal business data model consists of 6 entities: | extensionArtifactId | String | artifactId of the active _Solicitor_ Extension ("NONE" if no extension) | extensionVersion | String | Version of the active Extension (or "NONE") | extensionGitHash | String | Buildnumber / GitHash of the Extension (or "NONE") -| extensionBuilddate | String build date of the Extension (or "NONE") +| extensionBuilddate | String | build date of the Extension (or "NONE") +| reportingGroup | String | name of the reporting group currently being processed; the value is volatile/changing and is only defined when processing writers; see <> |=== ==== Engagement @@ -135,6 +136,7 @@ The internal business data model consists of 6 entities: | releaseDate | Sting | release data of the application | sourceRepo | String | URL of the source repo of the application (should be an URL) | programmingEcosystem | String | programming ecosystem (e.g. Java8; Android/Java, iOS / Objective C) +| reportingGroups | String | concatenated list of reporting groups this application is assigned to within _Solicitor_; used to create reports for subsets of Applications; see <> |=== ==== ApplicationComponent @@ -336,12 +338,16 @@ Within this section the different applications (=deliverables) of the engagement "releaseId" : "3.1.0-SNAPSHOT", <2> "sourceRepo" : "https://github.com/devonfw/devon4j.git", <3> "programmingEcosystem" : "Java8", <4> - "readers" : [ { <5> - "type" : "maven", <6> - "source" : "classpath:samples/licenses_devon4j.xml", <7> <10> - "usagePattern" : "DYNAMIC_LINKING", <8> - "repoType" : "maven" <9> - "packageType" : "maven" <11> + "reportingGroups" : [ <5> + "default", + "web app" + ], + "readers" : [ { <6> + "type" : "maven", <7> + "source" : "classpath:samples/licenses_devon4j.xml", <8> <11> + "usagePattern" : "DYNAMIC_LINKING", <9> + "repoType" : "maven" <10> + "packageType" : "maven" <12> } ] } ], @@ -349,13 +355,14 @@ Within this section the different applications (=deliverables) of the engagement <2> Version identifier of the application (any string) <3> URL of the source repo of the application (string; should be an URL) <4> programming ecosystem (any string; e.g. Java8; Android/Java, iOS / Objective C) -<5> multiple readers might be defined per application -<6> the type of reader; for possible values see <> -<7> location of the source file to read (ResourceLoader-URL) -<8> usage pattern; possible values: `DYNAMIC_LINKING`, `STATIC_LINKING`, `STANDALONE_PRODUCT`; see description below -<9> repoType: `repoType` to be set in the `ApplicationComponent` . *This parameter is deprecated and should no longer be used*, see <>. The value of `repoType` in `ApplicationComponent` will otherwise be determined from the type info in the PackageURL of the component. -<10> _placeholder patterns might be used here_ -<11> packageType: type of the packages in the input data. Must be a valid packageUrl type (see https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst). Relevant when using the CSV reader. +<5> optional definition of the reporting groups this Application will be assigned to; if not defined then the Application will be assigned to the reporting group `default`; see <> +<6> multiple readers might be defined per application +<7> the type of reader; for possible values see <> +<8> location of the source file to read (ResourceLoader-URL) +<9> usage pattern; possible values: `DYNAMIC_LINKING`, `STATIC_LINKING`, `STANDALONE_PRODUCT`; see description below +<10> repoType: `repoType` to be set in the `ApplicationComponent` . *This parameter is deprecated and should no longer be used*, see <>. The value of `repoType` in `ApplicationComponent` will otherwise be determined from the type info in the PackageURL of the component. +<11> _placeholder patterns might be used here_ +<12> packageType: type of the packages in the input data. Must be a valid packageUrl type (see https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst). Relevant when using the CSV reader. ===== Usage Patterns The usage pattern describes how the ``ApplicationComponent``s (libraries, packages) which are read in via the Reader are linked (in)to the ``Application``s executable. The kind of linking might affect the legal evaluation of the license compliance. @@ -431,10 +438,11 @@ The writer configuration defines how the processed data will be exported and/or [listing] "writers" : [ { "type" : "xls", <1> - "templateSource" : "classpath:samples/Solicitor_Output_Template_Sample.xlsx", <2> <6> - "target" : "OSS-Inventory-devonfw.xlsx", <3> <6> + "templateSource" : "classpath:samples/Solicitor_Output_Template_Sample.xlsx", <2> <7> + "target" : "OSS-Inventory-devonfw${-reportingGroup}.xlsx", <3> <7> <8> "description" : "The XLS OSS-Inventory document", <4> - "dataTables" : { <5> + "enableReportingGroups" : true, <5> + "dataTables" : { <6> "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", "LICENSE" : "classpath:com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql" } @@ -444,8 +452,10 @@ The writer configuration defines how the processed data will be exported and/or <2> path to the template to be used <3> location of the output file <4> some textual description -<5> reference to SQL statements used to transform the internal data model to data tables used for reporting -<6> _placeholder patterns might be used here_ +<5> flag which enables use of reporting groups for this writer (optional, see <>) +<6> reference to SQL statements used to transform the internal data model to data tables used for reporting +<7> _placeholder patterns might be used here_ +<8> for the `target` value special additional placeholders are available to handle reporting group information. See <>. If a `writers` section is defined in the project configuration then it will replace the writer configuration given in the builtin default configuration. @@ -500,11 +510,11 @@ of the https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boo The default property values are given in <>. -In case that a property shall be overridden when executing _Solicitor_ this can easiest be done via the command line when executing -_Solicitor_: +In case that a property shall be overridden when executing _Solicitor_ this can easiest be done via the command line when executing _Solicitor_. +In case that the property value contains whitespaces it needs to be enclosed in double quotes: [listing] -java -Dsome.property.name1=value -Dsome.property.name2=another_value -jar solicitor.jar +java -Dsome.property.name1=value -Dsome.property.name2="another value with spaces" -jar solicitor.jar == Reading License Information with Readers Different Readers are available to import raw component / license information for different @@ -574,12 +584,12 @@ Additionally, an optional configuration can be set in order to customize the giv "source" : "file:path/to/the/file.csv", "usagePattern" : "DYNAMIC_LINKING", "configuration" : { - "charset" = "UTF-8", - "artifactId" : "0", - "version" : "1", - "format" : "EXCEL", - "skipHeaderRecord" : "true", - "delimiter" : ";" + "charset" = "UTF-8", + "artifactId" : "0", + "version" : "1", + "format" : "EXCEL", + "skipHeaderRecord" : "true", + "delimiter" : ";" } } ] ---- @@ -1017,7 +1027,7 @@ In Solicitor, the data is read with the following part of the config "type" : "cyclonedx", "source" : "file:$/input/sbom.json", "usagePattern" : "DYNAMIC_LINKING" - } ] + } ] ---- NOTE: Currently, Solicitor only has packageUrlHandlers for maven, npm and pip. For all other package types, Solicitor will ignore the packageUrl. @@ -1310,6 +1320,8 @@ include::files/allden_normalizedlicenses.sql[] NOTE: Above example also shows how the case sensitive column names have to be handled within the SQL +NOTE: The handling of reporting groups as included in the above statement (`a."reportingGroups" LIKE '%\#reportingGroup#%'`) is described in <>. + === Writers The above described SQL processing is identical for all Writers. Writers only differ in the @@ -1357,20 +1369,158 @@ The Generic Excel Writer exists purely for debugging purposes. This writer write [listing] "additionalWriters" : [ { "type" : "genericxls", - "templateSource" : "", <1> - "target" : "${cfgdir}/output/GenericXLS.xlsx", - "description" : "Excel workbook with a separate sheet for each defined dataTable", - "dataTables" : { - "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", - "APPLICATIONCOMPONENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_applicationcomponents.sql", - "LICENSE" : "classpath:com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql", - "OSSLICENSES" : "classpath:com/devonfw/tools/solicitor/sql/ossapplicationcomponents.sql", - ... - } + "templateSource" : "", <1> + "target" : "${cfgdir}/output/GenericXLS.xlsx", + "description" : "Excel workbook with a separate sheet for each defined dataTable", + "dataTables" : { + "ENGAGEMENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_engagements.sql", + "APPLICATIONCOMPONENT" : "classpath:com/devonfw/tools/solicitor/sql/allden_applicationcomponents.sql", + "LICENSE" : "classpath:com/devonfw/tools/solicitor/sql/allden_normalizedlicenses.sql", + "OSSLICENSES" : "classpath:com/devonfw/tools/solicitor/sql/ossapplicationcomponents.sql", + ... + } } ] <1> This is unused and can be left empty. +=== Reporting Groups +Reporting Groups is an advanced reporting feature which might be used to create reports for defined subsets of the `Applications` defined in the project configuration. This might be useful if e.g. separate and dedicated attribution documents need to be created for some of the applications which might then be included into each of those applications. + +==== Default Behavior +Without any dedicated configuration each `Application` is assigned to the reporting group `default`. Each defined report (defined in the `writers` or `additionalWriters` section of the configuration) will then be written for the `default` reporting group. The templating mechanism for determining the reports target file includes some special handling so that the reporting group name `default` is not propagated to the final filename. Overall the introduction of the feature "Reporting Groups" (with _Solicitor_ 1.28.0) does not change any report output unless reporting groups are explicitly defined. + +==== Defining Reporting Groups and assigning `Applications` +Reporting groups are implicitly created by assigning `Applications` to them. So in case that an `Application` +shall be assigned to reporting groups `default` and `web app` then an additional `reportingGroups` node has to be defined within the configuration of the `Application`, see the configuration example in <>. Note that in this case it is also required to explicitly include the `default` reporting group if the `Application` shall be assigned to it. + +Reporting Group names might only consist of US-ASCII uppercase (A-Z) and lowercase characters (a-z), digits (0-9), hyphens ("-"), underscores ("_") and spaces (" "). The name must start with an alphanumeric character. + +==== Enabling Reports/Writers to support Reporting Groups +Due to compatibility reasons with prior Solicitor configurations it is required to explicitly enable support for reporting groups for each configured writer/report. This is done by setting property `enableReportingGroups` to true in the configuration as shown in the configuration snippet in <>. + +NOTE: All writers/reports which are predefined in the _Solicitor_ base configuration are enabled for reporting groups. + +Besides enabling/activating the reporting group feature within the writer configuration it is also required to adopt the SQL statements and target filename pattern to support reporting groups as given in the following. + +===== Evaluation of the Reporting Group in SQL +Reporting groups are used to write reports for a subset of the defined `Applications` or even for single `Applications`. To do so it is normally required to include specific selection criteria into the SQL statements which limit the selected data to only those `Applications` which belong to the reporting group currently processed. To enable this the `Application` entity includes the field `reportingGroups` which stores the list of reporting groups this `Application` is assigned to. The list is stored as concatenated string, where `\#` is used as prefix, suffix and delimiter, which results in `#default#wepp app#` in the above case. + +Within the WHERE clause of the SQL statement the following snippet can be used to limit the selection of data to only those `Applications` which belong to the currently processed reporting group (see <> for the complete sample). + +---- +a."reportingGroups" LIKE '%#reportingGroup#%'` +---- + +Writers/Reports which are enabled for reporting group processing will replace any occurrence of `\#reportingGroup#` in the SQL with the current value of the reporting group (resulting in `\#default#` and `\#web app#` in the above example). Writers where the reporting group processing is not enabled will replace `\#reportingGroup#` with `\#default#`. + +NOTE: All SQL statements which are included in the _Solicitor_ built in configuration are supporting reporting groups. + +===== Using Reporting Group Information in Report Filename +If writing the same report for different reporting groups it is required to control the target filename depending on the reporting group being processed. To support this a set of special placeholders is available for the target property of the writer configuration if the writer is enabled for reporting groups (see also sample in <>). + + +.Placeholders for reporting group within the target property of the writer configuration +[width="100%",options="header"] +|==================== +| Placeholder | Replacement for reporting group `default` | Replacement for other reporting groups (using `web app` as sample value); spaces in the reporting group name will be repaced by "_") +| `${reportingGroup}` | _empty String_ | `web_app` +| `${-reportingGroup}` | _empty String_ | `-web_app` +| `${_reportingGroup}` | _empty String_ | `_web_app` +| `${/reportingGroup}` | _empty String_ | `/web_app` +|==================== + +These placeholders allow to include the reporting groups name also with leading hyphen, underscore or slash, which will be omitted in case of the "default" reporting group. This enables to preserve the prior naming scheme for the "default" reporting group. It also allows to store the report of non default reporting groups to dedicated subdirectories. + +===== Using Reporting Group Information in Report Content +The reporting group currently being processed is accessible via the property `reportingGroup` of entity `ModelRoot`, see <>. + +==== Controlling which Reporting Groups to process +When defining and processing additional reporting groups the execution time of _Solicitor_ increases as well as the number of generated report files. Often it not required or desired to always create reports for all reporting groups. The application property `solicitor.reportinggroups.filterpattern` is used to define a (java) regular expression pattern which must be matched by the name of a reporting group for this reporting group to be processed. The default is + +---- +solicitor.reportinggroups.filterpattern=.* +---- + +which matches any processing group. In the above sample this might e.g. be changed to + +---- +solicitor.reportinggroups.filterpattern=web app +---- + +to only generate reports of this reporting group. The property might also be defined on command line (see <>) to change it for a single execution of _Solicitor_. + +==== Configuration Example + +The below given excerpt from a project configuration file illustrates the interaction of writer configurations and reporting group definitions of `Applications`. + +---- +{ + . + . + . + "applications" : [ <1> + { + "name" : "App1", + "reportingGroups" : [ + "deliverableA", + "web app" + ] + },{ + "name" : "App2", + "reportingGroups" : [ + "default", + "deliverableA", + "backend" + ] + },{ + "name" : "App3" <2> + } + ], + . + . + . + "additionalWriters" : [ <1> <3> + { + "target" : "out${/reportingGroup}/report1${-reportingGroup}.txt", + "enableReportingGroups" : true + },{ + "target" : "out/report2.txt" <4> + } + ] +} + +---- + +<1> parameters which might be required but are not relevant for the sample are omitted here +<2> no reporting groups defined here +<3> this sample makes use of the `additionalWriters` section; same applies for `writers`. +<4> `enableReportingGroups` not set here + +The following table shows the reporting groups and corresponding application assignments resulting from this configuration: + +[width="100%",cols="<3,^2,^2,^2,^2"] +|==================== +| | default | deliverableA | web app | backend +|App1 | | X | X | +|App2 | X | X | | X +|App3 | X | | | +|==================== + +Assuming the setting +---- +solicitor.reportinggroups.filterpattern=default|deliverableA|backend +---- +the following reports will be created: + +[width="100%",options="header",cols="1,2,1"] +|==================== +|Reporting Group | Report File | Applications contained in Report +|default | out/report1.txt | App2, App3 +|default | out/report2.txt | App2, App3 +|deliverableA |out/deliverableA/report1-deliverableA.txt | App1, App2 +|backend |out/backend/report1-backend.txt | App2 +|==================== + == Resolving of License URLs @@ -1438,16 +1588,16 @@ To use license guessing in a template, an `additionalWriter` (see <> and requires ScanCode to be used to collect all necessary information. + [appendix] == Extending Solicitor `Solicitor` comes with a sample rule data set and sample reporting templates. In general it will @@ -2002,7 +2153,8 @@ Spring beans implementing this interface will be called at certain points in the [appendix] == Release Notes Changes in 1.28.0:: -https://github.com/devonfw/solicitor/issues/12: New `statistics` Velocity and SQL template which can be used in a build-breaker. +* https://github.com/devonfw/solicitor/issues/288: New feature "reporting groups" for creating reports for subsets of Applications. See <>. +* https://github.com/devonfw/solicitor/issues/12: New `statistics` Velocity and SQL template which can be used in a build-breaker. Changes in 1.27.0:: * https://github.com/devonfw/solicitor/issues/283: New Reader for data generated by the Gradle License Report Plugin. See <>. Reader `gradle2` deprecated (stage 2). Reader `gradle` removed. diff --git a/solicitor.dict b/solicitor.dict index 2ea7f287..ac1a5c7c 100644 --- a/solicitor.dict +++ b/solicitor.dict @@ -4,6 +4,7 @@ CDXGEN cfgdir conf CycloneDX +deliverableA deliverables Dloader Dpropertyname