From 318ca981b5bb0de685192e11e24dbe017186bfd6 Mon Sep 17 00:00:00 2001 From: Ruud Senden <8635138+rsenden@users.noreply.github.com> Date: Mon, 27 May 2024 16:38:27 +0200 Subject: [PATCH] chore: Add/update `issue list` commands fix: `fcli ssc issue list`: Add `--include` option to allow for retrieving `hidden`, `fixed` and/or `suppressed` issues chore: Update behavior of `fcli fod issue list --include` option to allow retrieval of only fixed/suppressed issues, without `visible` issues --- .../issue/cli/mixin/FoDIssueIncludeMixin.java | 43 ++++++++++++-- .../cli/fod/i18n/FoDMessages.properties | 7 ++- .../issue/cli/cmd/SSCIssueListCommand.java | 2 + .../issue/cli/mixin/SSCIssueIncludeMixin.java | 57 +++++++++++++++++++ .../cli/ssc/i18n/SSCMessages.properties | 4 ++ 5 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/mixin/SSCIssueIncludeMixin.java diff --git a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/issue/cli/mixin/FoDIssueIncludeMixin.java b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/issue/cli/mixin/FoDIssueIncludeMixin.java index 171f2b0a33..5d8d270b7e 100644 --- a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/issue/cli/mixin/FoDIssueIncludeMixin.java +++ b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/issue/cli/mixin/FoDIssueIncludeMixin.java @@ -1,7 +1,10 @@ package com.fortify.cli.fod.issue.cli.mixin; -import java.util.List; +import java.util.Set; +import com.fasterxml.jackson.databind.JsonNode; +import com.fortify.cli.common.json.JsonHelper; +import com.fortify.cli.common.output.transform.IRecordTransformer; import com.fortify.cli.common.rest.unirest.IHttpRequestUpdater; import com.fortify.cli.common.util.DisableTest; import com.fortify.cli.common.util.DisableTest.TestType; @@ -11,23 +14,51 @@ import lombok.RequiredArgsConstructor; import picocli.CommandLine.Option; -public class FoDIssueIncludeMixin implements IHttpRequestUpdater { +public class FoDIssueIncludeMixin implements IHttpRequestUpdater, IRecordTransformer { @DisableTest(TestType.MULTI_OPT_PLURAL_NAME) - @Option(names = {"--include", "-i"}, split = ",", descriptionKey = "fcli.fod.issue.list.includeIssue", paramLabel="") - private List includes; + @Option(names = {"--include", "-i"}, split = ",", defaultValue = "visible", descriptionKey = "fcli.fod.issue.list.includeIssue", paramLabel="") + private Set includes; public HttpRequest updateRequest(HttpRequest request) { + // TODO Potentially if 'includes' contains ONLY suppressed, we could also + // add filters=isSuppressed:true to perform server-side filtering + // (note that FoD doesn't allow for server-side filtering on closedStatus, + // so we can't do the same for fixed issues). + // However, we'd need to check how to integrate this with any + // FoDFiltersParamGenerator defined on the command, i.e., how FoD + // reacts if there are multiple 'filters' parameters, and/or do + // some refactoring to generate only a single 'filters' parameter + // from multiple sources. Alternatively, instead of directly generating + // a 'filters' parameter, we could potentially amend the client-side + // query, which would then be picked up by any FoDFiltersParamGenerator, + // and also remove the need for having an explicit transformRecord() + // method to perform client-side filtering. if ( includes!=null ) { for ( var include : includes) { - request = request.queryString(include.getRequestParameterName(), "true"); + var queryParameterName = include.getRequestParameterName(); + if ( queryParameterName!=null ) { + request = request.queryString(queryParameterName, "true"); + } } } return request; } + + @Override + public JsonNode transformRecord(JsonNode record) { + // If includes doesn't include 'visible', we return null for any visible (non-suppressed + // & non-fixed) issues. We don't need explicit handling for other cases, as suppressed or + // fixed issues won't be returned by FoD if not explicitly specified through the --include + // option. + return !includes.contains(FoDIssueInclude.visible) + && JsonHelper.evaluateSpelExpression(record, "!isSuppressed && !closedStatus", Boolean.class) + ? null + : record; + } @RequiredArgsConstructor public static enum FoDIssueInclude { - fixed("includeFixed"), suppressed("includeSuppressed"); + visible(null), fixed("includeFixed"), suppressed("includeSuppressed"); @Getter private final String requestParameterName; diff --git a/fcli-core/fcli-fod/src/main/resources/com/fortify/cli/fod/i18n/FoDMessages.properties b/fcli-core/fcli-fod/src/main/resources/com/fortify/cli/fod/i18n/FoDMessages.properties index fdcdc2a4f4..cb1a7a6195 100644 --- a/fcli-core/fcli-fod/src/main/resources/com/fortify/cli/fod/i18n/FoDMessages.properties +++ b/fcli-core/fcli-fod/src/main/resources/com/fortify/cli/fod/i18n/FoDMessages.properties @@ -755,9 +755,10 @@ fcli.fod.issue.embed = Embed extra issue data. Due to FoD rate limits, this may Using the --output option, this extra data can be included in the output. Using the --query option, \ this extra data can be queried upon. To get an understanding of the structure and contents of the \ embedded data, use the --output json or --output yaml options. -fcli.fod.issue.list.includeIssue = By default, fixed or suppressed issues will not be included. \ - This option accepts 'fixed', 'suppressed' or 'fixed,suppressed' to include such issues in the \ - output. +fcli.fod.issue.list.includeIssue = By default, only visible issues will be returned. This option \ + accepts a comma-separated list to allow (also) fixed and/or suppressed issues to be returned, \ + for example `--include visible,fixed` (to return both visible and fixed issues) or `--include \ + fixed` (to return only fixed issues). Allowed values: ${COMPLETION-CANDIDATES}. # fcli fod report fcli.fod.report.usage.header = Manage FoD reports. diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/cmd/SSCIssueListCommand.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/cmd/SSCIssueListCommand.java index 1aa690e062..19995ec80d 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/cmd/SSCIssueListCommand.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/cmd/SSCIssueListCommand.java @@ -22,6 +22,7 @@ import com.fortify.cli.ssc.appversion.cli.mixin.SSCAppVersionResolverMixin; import com.fortify.cli.ssc.issue.cli.mixin.SSCIssueBulkEmbedMixin; import com.fortify.cli.ssc.issue.cli.mixin.SSCIssueFilterSetResolverMixin; +import com.fortify.cli.ssc.issue.cli.mixin.SSCIssueIncludeMixin; import com.fortify.cli.ssc.issue.helper.SSCIssueFilterHelper; import com.fortify.cli.ssc.issue.helper.SSCIssueFilterSetDescriptor; @@ -41,6 +42,7 @@ public class SSCIssueListCommand extends AbstractSSCBaseRequestOutputCommand imp @Mixin private SSCQParamMixin qParamMixin; @Mixin private SSCIssueBulkEmbedMixin bulkEmbedMixin; @Option(names="--filter", required=false) private String filter; + @Mixin private SSCIssueIncludeMixin includeMixin; // For some reason, SSC q param doesn't use same property names as returned by SSC, // so we list the proper mappings below. TODO Any other useful server-side queries? diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/mixin/SSCIssueIncludeMixin.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/mixin/SSCIssueIncludeMixin.java new file mode 100644 index 0000000000..3c8fb12155 --- /dev/null +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/mixin/SSCIssueIncludeMixin.java @@ -0,0 +1,57 @@ +package com.fortify.cli.ssc.issue.cli.mixin; + +import java.util.Set; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fortify.cli.common.json.JsonHelper; +import com.fortify.cli.common.output.transform.IRecordTransformer; +import com.fortify.cli.common.rest.unirest.IHttpRequestUpdater; +import com.fortify.cli.common.util.DisableTest; +import com.fortify.cli.common.util.DisableTest.TestType; + +import kong.unirest.HttpRequest; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import picocli.CommandLine.Option; + +public class SSCIssueIncludeMixin implements IHttpRequestUpdater, IRecordTransformer { + @DisableTest(TestType.MULTI_OPT_PLURAL_NAME) + @Option(names = {"--include", "-i"}, split = ",", defaultValue = "visible", descriptionKey = "fcli.ssc.issue.list.includeIssue", paramLabel="") + private Set includes; + + public HttpRequest updateRequest(HttpRequest request) { + // TODO Check whether we can potentially perform any server-side filtering + // to retrieve ONLY suppressed/fixed/hidden issues, although SSC doesn't + // seem to allow server-side filtering on the respective boolean fields. + // See FoDIssueIncludeMixin for additional details. + if ( includes!=null ) { + for ( var include : includes) { + var queryParameterName = include.getRequestParameterName(); + if ( queryParameterName!=null ) { + request = request.queryString(queryParameterName, "true"); + } + } + } + return request; + } + + @Override + public JsonNode transformRecord(JsonNode record) { + // If includes doesn't include 'visible', we return null for any visible (non-suppressed + // & non-fixed) issues. We don't need explicit handling for other cases, as suppressed or + // fixed issues won't be returned by FoD if not explicitly specified through the --include + // option. + return !includes.contains(SSCIssueInclude.visible) + && JsonHelper.evaluateSpelExpression(record, "!hidden && !removed && !suppressed", Boolean.class) + ? null + : record; + } + + @RequiredArgsConstructor + public static enum SSCIssueInclude { + visible(null), hidden("showhidden"), fixed("showremoved"), suppressed("showsuppressed"); + + @Getter + private final String requestParameterName; + } +} diff --git a/fcli-core/fcli-ssc/src/main/resources/com/fortify/cli/ssc/i18n/SSCMessages.properties b/fcli-core/fcli-ssc/src/main/resources/com/fortify/cli/ssc/i18n/SSCMessages.properties index e97d36e8a9..fa480f390a 100644 --- a/fcli-core/fcli-ssc/src/main/resources/com/fortify/cli/ssc/i18n/SSCMessages.properties +++ b/fcli-core/fcli-ssc/src/main/resources/com/fortify/cli/ssc/i18n/SSCMessages.properties @@ -422,6 +422,10 @@ fcli.ssc.issue.list.embed = Embed extra application version data. Allowed values Using the --output option, this extra data can be included in the output. Using the --query option, \ this extra data can be queried upon. To get an understanding of the structure and contents of the \ embedded data, use the --output json or --output yaml options. +fcli.ssc.issue.list.includeIssue = By default, only visible issues will be returned. This option \ + accepts a comma-separated list to allow (also) fixed, suppressed and/or hidden issues to be returned, \ + for example `--include visible,fixed` (to return both visible and fixed issues) or `--include \ + fixed` (to return only fixed issues). Allowed values: ${COMPLETION-CANDIDATES}. fcli.ssc.issue.get-filter.usage.header = Get issue filter details. fcli.ssc.issue.filter = Technical or friendly filter as returned by the 'fcli ssc issue list-filters' command. fcli.ssc.issue.list-filters.usage.header = List application version issue filters.