Skip to content

Commit

Permalink
chore: Action updates
Browse files Browse the repository at this point in the history
  • Loading branch information
rsenden committed Apr 10, 2024
1 parent 3b8424c commit b6ab770
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ public static final class ActionStepDescriptor implements IActionIfSupplier {
@JsonProperty("throw") private TemplateExpression _throw;
/** Optional set operations */
private List<ActionStepSetDescriptor> set;
/** Optional unset operations */
private List<ActionStepUnsetDescriptor> unset;
/** Optional write operations */
private List<ActionStepWriteDescriptor> write;
/** Optional forEach operation */
Expand Down Expand Up @@ -295,6 +297,22 @@ public static enum ActionStepSetOperation {
}
}

/**
* This class describes an operation to explicitly unset a data property.
*/
@Reflectable @NoArgsConstructor
@Data
public static final class ActionStepUnsetDescriptor implements IActionIfSupplier {
/** Optional if-expression, executing this step only if condition evaluates to true */
@JsonProperty("if") private SimpleExpression _if;
/** Required name for this step element */
private String name;

public void postLoad(ActionDescriptor action) {
checkNotBlank("set name", name, this);
}
}

/**
* This class describes a 'write' step.
*/
Expand Down Expand Up @@ -327,6 +345,8 @@ public static final class ActionStepForEachDescriptor implements IActionIfSuppli
/** Processor that runs the forEach steps. This expression must evaluate to an
* IActionStepForEachProcessor instance. */
private SimpleExpression processor;
/** Values to iterate over */
private SimpleExpression values;
/** Optional if-expression, executing steps only if condition evaluates to true */
@JsonProperty("if") private SimpleExpression _if;
/** Optional break-expression, terminating forEach if condition evaluates to true */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import com.fortify.cli.common.action.helper.ActionDescriptor.ActionStepRequestDescriptor.ActionStepRequestType;
import com.fortify.cli.common.action.helper.ActionDescriptor.ActionStepSetDescriptor;
import com.fortify.cli.common.action.helper.ActionDescriptor.ActionStepSetDescriptor.ActionStepSetOperation;
import com.fortify.cli.common.action.helper.ActionDescriptor.ActionStepUnsetDescriptor;
import com.fortify.cli.common.action.helper.ActionDescriptor.ActionStepWriteDescriptor;
import com.fortify.cli.common.action.helper.ActionDescriptor.ActionValidationException;
import com.fortify.cli.common.action.helper.ActionDescriptor.ActionValueTemplateDescriptor;
Expand Down Expand Up @@ -311,6 +312,7 @@ private final void processStep(ActionStepDescriptor step) {
processSupplier(step::getRequests, this::processRequestsStep);
processSupplier(step::getForEach, this::processForEachStep);
processAll(step::getSet, this::processSetStep);
processAll(step::getUnset, this::processUnsetStep);
processAll(step::getWrite, this::processWriteStep);
}
}
Expand Down Expand Up @@ -344,11 +346,20 @@ private void processSetStep(ActionStepSetDescriptor set) {
var value = getValueForSetStep(set);
setDataValue(name, value);
}

private void processUnsetStep(ActionStepUnsetDescriptor unset) {
unsetDataValue(unset.getName());
}

private void setDataValue(String name, JsonNode value) {
localData.set(name, value);
if ( parent!=null ) { parent.setDataValue(name, value); }
}

private void unsetDataValue(String name) {
localData.remove(name);
if ( parent!=null ) { parent.unsetDataValue(name); }
}

private JsonNode getValueForSetStep(ActionStepSetDescriptor set) {
var valueExpression = set.getValue();
Expand Down Expand Up @@ -451,8 +462,15 @@ private void processThrowStep(TemplateExpression message) {
}

private void processForEachStep(ActionStepForEachDescriptor forEach) {
spelEvaluator.evaluate(forEach.getProcessor(), localData, IActionStepForEachProcessor.class)
.process(node->processForEachStepNode(forEach, node));
var processorExpression = forEach.getProcessor();
var valuesExpression = forEach.getValues();
if ( processorExpression!=null ) {
var processor = spelEvaluator.evaluate(processorExpression, localData, IActionStepForEachProcessor.class);
if ( processor!=null ) { processor.process(node->processForEachStepNode(forEach, node)); }
} else if ( valuesExpression!=null ) {
var values = spelEvaluator.evaluate(valuesExpression, localData, ArrayNode.class);
if ( values!=null ) { values.forEach(value->processForEachStepNode(forEach, value)); }
}
}

private boolean processForEachStepNode(ActionStepForEachDescriptor forEach, JsonNode node) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -84,6 +85,15 @@ public static final String abbreviate(String text, int maxWidth) {
return StringUtils.abbreviate(text, maxWidth);
}

public static final String repeat(String text, int count) {
if ( count<0 ) { return ""; }
StringBuilder sb = new StringBuilder();
for ( int i=0; i<count; i++ ) {
sb.append(text);
}
return sb.toString();
}

/**
* @param html to be converted to plain text
* @return Formatted plain-text string for the given HTML contents
Expand Down Expand Up @@ -121,7 +131,12 @@ private static String _htmlToText(Document document) {
Matcher m = CODE_PATTERN.matcher(s);
while(m.find()){
String code = m.group(1);
m.appendReplacement(sb, Parser.unescapeEntities(code, false));
// Code may contain regex-related characters like ${..}, which we don't
// want to interpret as regex groups. So, we append an empty replacement
// (have Matcher append all text before the code block), then manually
// append the code block. See https://stackoverflow.com/a/948381
m.appendReplacement(sb, "");
sb.append(Parser.unescapeEntities(code, false));
}
m.appendTail(sb);
return sb.toString();
Expand Down Expand Up @@ -191,10 +206,17 @@ public static final String uriPart(String uriString, String part) {
* @param dateString JSON string representation of date to be formatted
* @return Formatted date
*/
public static final String formatDateTime(String pattern, String dateString) {
public static final String formatDateTime(String pattern, String... dateStrings) {
var dateString = dateStrings==null||dateStrings.length==0
? currentDateTime()
: dateStrings[0];
return formatDateTimeWithZoneId(pattern, dateString, ZoneId.systemDefault());
}

public static final String currentDateTime() {
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
}

/**
* Parse the given dateString in the given time zone id as a JSON date (see {@link JSONDateTimeConverter},
* then format it using the given {@link DateTimeFormatter} pattern.
Expand Down Expand Up @@ -233,6 +255,10 @@ public static final String formatDateTimewithZoneIdAsUTC(String pattern, String
return DateTimeFormatter.ofPattern(pattern).format(utcDateTime);
}

public static final <T> Iterable<T> asIterable(Iterator<T> iterator) {
return () -> iterator;
}

public static final String copyright() {
return String.format("Copyright (c) %s Open Text", Year.now().getValue());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public JSONDateTimeConverter(DateTimeFormatter fmtDateTime, ZoneId defaultZoneId
this.defaultZoneId = defaultZoneId!=null ? defaultZoneId : ZoneId.systemDefault();
}

private static final DateTimeFormatter createDefaultDateTimeFormatter() {
public static final DateTimeFormatter createDefaultDateTimeFormatter() {
return DateTimeFormatter.ofPattern("yyyy-MM-dd[['T'][' ']HH:mm:ss[.SSS][.SS]][ZZZZ][Z][XXX][XX][X]");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,9 @@ public static final String indent(String str, String indentStr) {
if ( str==null ) { return null; }
return Stream.of(str.split("\n")).collect(Collectors.joining("\n"+indentStr, indentStr, ""));
}

// For use in SpEL expressions
public static final String fmt(String fmt, Object... input) {
return String.format(fmt, input);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
usage:
header: Generate release summary.
description: |
This action generates a short summary listing issue counts and other statistics
for a given release.
defaults:
requestTarget: fod

parameters:
- name: file
cliAliases: f
description: "Optional output file name (or 'stdout' / 'stderr'). Default value: stdout"
required: false
defaultValue: stdout
- name: release
cliAliases: rel
description: "Required release id or <appName>:[<microserviceName>:]<releaseName>"
type: release_single

steps:
- set:
# Add short alias for release object, as we reference it a lot
- name: r
value: ${parameters.release}
# Define output date format
- name: dateFmt
value: YYYY-MM-dd HH:mm
- write:
- to: ${parameters.file}
valueTemplate: summary-md
- if: parameters.file!='stdout'
to: stdout
value: |
Output written to ${parameters.file}
valueTemplates:
- name: summary-md
contents: |
# Fortify on Demand Release Summary
## [${r.applicationName}${#isNotBlank(r.microserviceNae)?'- '+r.microserviceName:''} - ${r.releaseName}](${#fod.releaseBrowserUrl(r)})
Summary generated on: ${#formatDateTime(dateFmt)}
### Security Policy
**Rating:** ${#repeat("&bigstar;", r.rating)}${#repeat("&star;", 5-r.rating)}
**Status:** ${r.isPassed?'Pass':'Fail'}
### Issue Counts
| Type | Last Scan Date | Critical | High | Medium | Low |
| ----------- | ---------------- | -------- | -------- | -------- | -------- |
${
#isNotBlank(r.staticScanDate)? '| **Static** | '+#formatDateTime(dateFmt, r.staticScanDate) +' | '+#fmt('%8s', r.staticCritical) +' | '+#fmt('%8s', r.staticHigh) +' | '+#fmt('%8s', r.staticMedium) +' | '+#fmt('%8s', r.staticLow) +' |\n':''
+#isNotBlank(r.dynamicScanDate)?'| **Dynamic** | '+#formatDateTime(dateFmt, r.dynamicScanDate)+' | '+#fmt('%8s', r.dynamicCritical)+' | '+#fmt('%8s', r.dynamicHigh)+' | '+#fmt('%8s', r.dynamicMedium)+' | '+#fmt('%8s', r.dynamicLow)+' |\n':''
+#isNotBlank(r.mobileScanDate)? '| **Mobile** | '+#formatDateTime(dateFmt, r.mobileScanDate) +' | '+#fmt('%8s', r.mobileCritical) +' | '+#fmt('%8s', r.mobileHigh) +' | '+#fmt('%8s', r.mobileMedium) +' | '+#fmt('%8s', r.mobileLow) +' |\n':''
}
Loading

0 comments on commit b6ab770

Please sign in to comment.