Skip to content

Add excel provider and improve csv #432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@
<artifactId>jackson-dataformat-csv</artifactId>
<version>${jackson-dataformat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.4.0</version>
</dependency>

<!-- Workflow dependencies -->
<dependency>
Expand Down
162 changes: 25 additions & 137 deletions src/main/java/io/jenkins/plugins/reporter/provider/Csv.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@

import hudson.Extension;
import io.jenkins.plugins.reporter.Messages;
import io.jenkins.plugins.reporter.model.Item;
import io.jenkins.plugins.reporter.model.Provider;
import io.jenkins.plugins.reporter.model.ReportDto;
import io.jenkins.plugins.reporter.model.ReportParser;
import io.jenkins.plugins.reporter.util.TabularData;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

Expand All @@ -24,18 +23,23 @@
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
* Provider for CSV files
*/
public class Csv extends Provider {

private static final long serialVersionUID = 9141170397250309265L;

private static final String ID = "csv";

/** Default constructor */
@DataBoundConstructor
public Csv() {
super();
// empty constructor required for stapler
}

/** Creates a CSV parser */
@Override
public ReportParser createParser() {
if (getActualId().equals(getDescriptor().getId())) {
Expand All @@ -45,41 +49,45 @@
return new CsvCustomParser(getActualId());
}

/** Descriptor for this provider. */
/** Descriptor for this provider */
@Symbol("csv")
@Extension
public static class Descriptor extends Provider.ProviderDescriptor {
/** Creates the descriptor instance. */
public static class Descriptor extends ProviderDescriptor {
/** Creates a descriptor instance */
public Descriptor() {
super(ID);
}
}

/**
* Parser for CSV files
*/
public static class CsvCustomParser extends ReportParser {

private static final long serialVersionUID = -8689695008930386640L;

private final String id;

private List<String> parserMessages;

/** Constructor */
public CsvCustomParser(String id) {
super();
this.id = id;
this.parserMessages = new ArrayList<String>();
}

/** Returns the parser identifier */
public String getId() {
return id;
}


/** Detects the delimiter used in the CSV file */
private char detectDelimiter(File file) throws IOException {
// List of possible delimiters
char[] delimiters = { ',', ';', '\t', '|' };
int[] delimiterCounts = new int[delimiters.length];

// Read the lines of the file to detect the delimiter
// Read the file lines to detect the delimiter
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
int linesToCheck = 5; // Number of lines to check
int linesChecked = 0;
Expand All @@ -105,13 +113,14 @@

return detectedDelimiter;
}


/** Parses a CSV file and creates a ReportDto */
@Override
public ReportDto parse(File file) throws IOException {
// Get delimiter
// Delimiter detection
char delimiter = detectDelimiter(file);

// CSV parser configuration
final CsvMapper mapper = new CsvMapper();
final CsvSchema schema = mapper.schemaFor(String[].class).withColumnSeparator(delimiter);

Expand All @@ -121,139 +130,18 @@
mapper.enable(CsvParser.Feature.INSERT_NULLS_FOR_MISSING_COLUMNS);
mapper.enable(CsvParser.Feature.TRIM_SPACES);

// Read CSV data
final MappingIterator<List<String>> it = mapper.readerForListOf(String.class)
.with(schema)
.readValues(file);

ReportDto report = new ReportDto();
report.setId(getId());
report.setItems(new ArrayList<>());

// Extract headers and rows
final List<String> header = it.next();
final List<List<String>> rows = it.readAll();

int rowCount = 0;
final int headerColumnCount = header.size();
int colIdxValueStart = 0;

if (headerColumnCount >= 2) {
rowCount = rows.size();
} else {
parserMessages.add(String.format("skipped file - First line has %d elements", headerColumnCount + 1));
}

/** Parse all data rows */
for (int rowIdx = 0; rowIdx < rowCount; rowIdx++) {
String parentId = "report";
List<String> row = rows.get(rowIdx);
Item last = null;
boolean lastItemAdded = false;
LinkedHashMap<String, Integer> result = new LinkedHashMap<>();
boolean emptyFieldFound = false;
int rowSize = row.size();

/** Parse untill first data line is found to get data and value field */
if (colIdxValueStart == 0) {
/** Col 0 is assumed to be string */
for (int colIdx = rowSize - 1; colIdx > 1; colIdx--) {
String value = row.get(colIdx);

if (NumberUtils.isCreatable(value)) {
colIdxValueStart = colIdx;
} else {
if (colIdxValueStart > 0) {
parserMessages
.add(String.format("Found data - fields number = %d - numeric fields = %d",
colIdxValueStart, rowSize - colIdxValueStart));
}
break;
}
}
}

String valueId = "";
/** Parse line if first data line is OK and line has more element than header */
if ((colIdxValueStart > 0) && (rowSize >= headerColumnCount)) {
/** Check line and header size matching */
for (int colIdx = 0; colIdx < headerColumnCount; colIdx++) {
String id = header.get(colIdx);
String value = row.get(colIdx);

/** Check value fields */
if ((colIdx < colIdxValueStart)) {
/** Test if text item is a value or empty */
if ((NumberUtils.isCreatable(value)) || (StringUtils.isBlank(value))) {
/** Empty field found - message */
if (colIdx == 0) {
parserMessages
.add(String.format("skipped line %d - First column item empty - col = %d ",
rowIdx + 2, colIdx + 1));
break;
} else {
emptyFieldFound = true;
/** Continue next column parsing */
continue;
}
} else {
/** Check if field values are present after empty cells */
if (emptyFieldFound) {
parserMessages.add(String.format("skipped line %d Empty field in col = %d ",
rowIdx + 2, colIdx + 1));
break;
}
}
valueId += value;
Optional<Item> parent = report.findItem(parentId, report.getItems());
Item item = new Item();
lastItemAdded = false;
item.setId(valueId);
item.setName(value);
String finalValueId = valueId;
if (parent.isPresent()) {
Item p = parent.get();
if (!p.hasItems()) {
p.setItems(new ArrayList<>());
}
if (p.getItems().stream().noneMatch(i -> i.getId().equals(finalValueId))) {
p.addItem(item);
lastItemAdded = true;
}
} else {
if (report.getItems().stream().noneMatch(i -> i.getId().equals(finalValueId))) {
report.getItems().add(item);
lastItemAdded = true;
}
}
parentId = valueId;
last = item;
} else {
Number val = 0;
if (NumberUtils.isCreatable(value)) {
val = NumberUtils.createNumber(value);
}
result.put(id, val.intValue());
}
}
} else {
/** Skip file if first data line has no value field */
if (colIdxValueStart == 0) {
parserMessages.add(String.format("skipped line %d - First data row not found", rowIdx + 2));
continue;
} else {
parserMessages
.add(String.format("skipped line %d - line has fewer element than title", rowIdx + 2));
continue;
}
}
/** If last item was created, it will be added to report */
if (lastItemAdded) {
last.setResult(result);
} else {
parserMessages.add(String.format("ignored line %d - Same fields already exists", rowIdx + 2));
}
}
// report.setParserLog(parserMessages);
return report;
// Create TabularData object and process it
TabularData tabularData = new TabularData(id, header, rows);
return tabularData.processData(parserMessages);

Check warning on line 144 in src/main/java/io/jenkins/plugins/reporter/provider/Csv.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 143-144 are not covered by tests
}
}
}
}
Loading
Loading