org.opensearch.gradle.precommit.ValidateJsonAgainstSchemaTask Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of build-tools Show documentation
Show all versions of build-tools Show documentation
OpenSearch subproject :build-tools
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/
package org.opensearch.gradle.precommit;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaException;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.SchemaValidatorsConfig;
import com.networknt.schema.SpecVersion;
import com.networknt.schema.ValidationMessage;
import org.gradle.api.DefaultTask;
import org.gradle.api.UncheckedIOException;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.gradle.work.ChangeType;
import org.gradle.work.Incremental;
import org.gradle.work.InputChanges;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.StreamSupport;
/**
* Incremental task to validate a set of JSON files against against a schema.
*/
public class ValidateJsonAgainstSchemaTask extends DefaultTask {
private final ObjectMapper mapper = new ObjectMapper();
private File jsonSchema;
private File report;
private FileCollection inputFiles;
@Incremental
@InputFiles
public FileCollection getInputFiles() {
return inputFiles;
}
public void setInputFiles(FileCollection inputFiles) {
this.inputFiles = inputFiles;
}
@InputFile
public File getJsonSchema() {
return jsonSchema;
}
public void setJsonSchema(File jsonSchema) {
this.jsonSchema = jsonSchema;
}
public void setReport(File report) {
this.report = report;
}
@OutputFile
public File getReport() {
return this.report;
}
@TaskAction
public void validate(InputChanges inputChanges) throws IOException {
File jsonSchemaOnDisk = getJsonSchema();
getLogger().debug("JSON schema : [{}]", jsonSchemaOnDisk.getAbsolutePath());
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
config.setEcma262Validator(true);
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7);
JsonSchema jsonSchema = factory.getSchema(mapper.readTree(jsonSchemaOnDisk), config);
Map> errors = new LinkedHashMap<>();
// incrementally evaluate input files
StreamSupport.stream(inputChanges.getFileChanges(getInputFiles()).spliterator(), false)
.filter(f -> f.getChangeType() != ChangeType.REMOVED)
.forEach(fileChange -> {
File file = fileChange.getFile();
if (file.isDirectory() == false) {
// validate all files and hold on to errors for a complete report if there are failures
getLogger().debug("Validating JSON [{}]", file.getName());
try {
Set validationMessages = jsonSchema.validate(mapper.readTree(file));
maybeLogAndCollectError(validationMessages, errors, file);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
});
if (errors.isEmpty()) {
try (PrintWriter printWriter = new PrintWriter(getReport())) {
printWriter.println("Success! No validation errors found.");
}
} else {
try (PrintWriter printWriter = new PrintWriter(getReport())) {
printWriter.printf("Schema: %s%n", jsonSchemaOnDisk);
printWriter.println("----------Validation Errors-----------");
errors.values().stream().flatMap(Collection::stream).forEach(printWriter::println);
}
StringBuilder sb = new StringBuilder();
sb.append("Error validating JSON. See the report at: ");
sb.append(getReport().toURI().toASCIIString());
sb.append(System.lineSeparator());
sb.append(
String.format("JSON validation failed: %d files contained %d violations", errors.keySet().size(), errors.values().size())
);
throw new JsonSchemaException(sb.toString());
}
}
private void maybeLogAndCollectError(Set messages, Map> errors, File file) {
for (ValidationMessage message : messages) {
getLogger().error("[validate JSON][ERROR][{}][{}]", file.getName(), message.toString());
errors.computeIfAbsent(file, k -> new LinkedHashSet<>())
.add(String.format("%s: %s", file.getAbsolutePath(), message.toString()));
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy