Skip to content

Commit

Permalink
issue-4
Browse files Browse the repository at this point in the history
  • Loading branch information
ethlo committed Apr 26, 2022
1 parent 9a1d4a0 commit 6000c29
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 49 deletions.
18 changes: 9 additions & 9 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -212,33 +212,33 @@
<groupId>org.jetbrains.kotlin</groupId>
<!--suppress KotlinMavenPluginPhase -->
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>1.5.30-M1</version>
<version>1.6.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.29</version>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.6.3</version>
<version>3.8.5</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.0</version>
<version>3.6.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.2.1</version>
<artifactId>maven-core</artifactId>
<version>3.8.5</version>
</dependency>
<dependency>
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
<version>4.8.115</version>
<version>4.8.146</version>
</dependency>

<!-- TEST -->
Expand All @@ -251,13 +251,13 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.20.2</version>
<version>3.22.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
106 changes: 80 additions & 26 deletions src/main/java/com/ethlo/zally/ExtractMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.LifecyclePhase;
Expand All @@ -47,6 +49,7 @@
import io.swagger.v3.core.filter.AbstractSpecFilter;
import io.swagger.v3.core.filter.SpecFilter;
import io.swagger.v3.core.model.ApiDescription;
import io.swagger.v3.core.util.Yaml;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
Expand All @@ -57,16 +60,22 @@ public class ExtractMojo extends AbstractMojo
@Parameter(required = true, defaultValue = "${project.basedir}/src/main/resources/api.yaml", property = "zally.source")
private String source;

@Parameter(property = "targetFile")
private File targetFile;
@Parameter(property = "outputFile")
private File outputFile;

@Parameter(property = "zally.skip", defaultValue = "false")
@Parameter(property = "configFile")
private File configFile;

@Parameter(property = "skip", defaultValue = "false")
private boolean skip;

@Parameter(property = "filters")
private List<String> filters;
private List<OperationFilter> filters;

@Parameter(property = "description")
private String description;

@Parameter(property = "name", required = true)
@Parameter(property = "name")
private String name;

@Parameter(property = "title")
Expand All @@ -75,21 +84,59 @@ public class ExtractMojo extends AbstractMojo
@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;

@Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
private MojoExecution mojoExecution;

private static final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()
.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)
.enable(YAMLGenerator.Feature.SPLIT_LINES)
.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS))
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
private static final ObjectMapper mapper = new ObjectMapper();

@Override
public void execute() throws MojoFailureException
{
final Optional<OpenAPI> loaded = load(getLog(), skip, source);
final Optional<OpenAPI> loaded = load(getLog(), skip, source, false);

if (name == null)
{
name = mojoExecution.getExecutionId();
}

if (targetFile == null)
if (outputFile == null)
{
targetFile = Paths.get(project.getBuild().getOutputDirectory()).resolve(name + ".yaml").toFile();
outputFile = Paths.get(project.getBuild().getOutputDirectory()).resolve(name + ".yaml").toFile();
}

if (configFile != null)
{
try
{
final ExtractionDefinition extractionDefinition = yamlMapper.readValue(configFile, ExtractionDefinition.class);
if (this.title == null)
{
this.title = extractionDefinition.getTitle();
}

if (this.description == null)
{
this.description = extractionDefinition.getDescription();
}

this.filters = extractionDefinition.getFilters();
}
catch (IOException exc)
{
throw new UncheckedIOException(exc);
}
}

loaded.ifPresent(openAPI ->
{
getLog().info(String.format("Processing filter %s", name));
getLog().info(String.format("Processing extraction %s", name));
final AtomicInteger totalEvaluated = new AtomicInteger(0);
final AtomicInteger totalMatched = new AtomicInteger(0);
final OpenAPI filtered = new SpecFilter().filter(openAPI, new AbstractSpecFilter()
{
@Override
Expand All @@ -100,9 +147,18 @@ public Optional<Operation> filterOperation(final Operation operation, final ApiD
final Map<String, Object> extensionMap = new LinkedHashMap<>(Optional.ofNullable(pathItem.getExtensions()).orElse(Collections.emptyMap()));
extensionMap.putAll(operation.getExtensions());
final OperationData operationData = new OperationData(operation, api, extensionMap);
if (filters.stream().anyMatch(filter -> match(filter, operationData)))
if (filters.stream().anyMatch(filter ->
{
final boolean matched = match(filter, operationData);
if (matched)
{
totalMatched.incrementAndGet();
getLog().info(String.format("Including '%s' in '%s' because '%s'", operation.getOperationId(), name, filter.asString()));
}
totalEvaluated.incrementAndGet();
return matched;
}))
{
getLog().info(String.format("Including operation %s in %s", operation.getOperationId(), name));
return Optional.of(operation);
}
return Optional.empty();
Expand All @@ -116,16 +172,15 @@ public boolean isRemovingUnreferencedDefinitions()
}, null, null, null);


// Set title of document
Optional.ofNullable(title).ifPresent(t -> filtered.getInfo().setTitle(t));
Optional.ofNullable(description).ifPresent(t -> filtered.getInfo().setDescription(t));
getLog().info(String.format("Included %s/%s API operations in extract", totalMatched.get(), totalEvaluated.get()));

try
{
getLog().info("Writing extracted APIs to " + targetFile);
Files.createDirectories(targetFile.toPath().getParent());
new ObjectMapper(new YAMLFactory()
.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)).
setSerializationInclusion(JsonInclude.Include.NON_EMPTY).writeValue(targetFile, filtered);
getLog().info("Writing extracted APIs to " + outputFile);
Files.createDirectories(outputFile.toPath().getParent());
Yaml.mapper().writeValue(outputFile, filtered);
}
catch (IOException e)
{
Expand All @@ -134,11 +189,10 @@ public boolean isRemovingUnreferencedDefinitions()
});
}

public static boolean match(final String filter, final OperationData data)
public static boolean match(final OperationFilter filter, final OperationData data)
{
final String[] expression = filter.split("=");
final String path = expression[0].startsWith("/") ? expression[0] : "/" + expression[0];
final String regexp = expression[1];
final String path = filter.getPointer().startsWith("/") ? filter.getPointer() : "/" + filter.getPointer();
final String regexp = filter.getExpression();
try
{
final JsonNode jsonNode = mapper.readTree(mapper.writeValueAsString(data));
Expand All @@ -148,7 +202,7 @@ public static boolean match(final String filter, final OperationData data)
final Iterator<String> fieldNames = value.fieldNames();
while (fieldNames.hasNext())
{
if (fieldNames.next().matches(regexp))
if (filter.isMatch(fieldNames.next()))
{
return true;
}
Expand All @@ -159,15 +213,15 @@ else if (value.isArray())
final Iterator<JsonNode> elements = value.elements();
while (elements.hasNext())
{
if (elements.next().textValue().matches(regexp))
if (filter.isMatch(elements.next().textValue()))
{
return true;
}
}
}
else if (value.isTextual())
{
return value.textValue().matches(regexp);
return filter.isMatch(value.textValue());
}

return false;
Expand All @@ -178,7 +232,7 @@ else if (value.isTextual())
}
}

public static Optional<OpenAPI> load(final Log log, final boolean skip, final String source) throws MojoFailureException
public static Optional<OpenAPI> load(final Log log, final boolean skip, final String source, final boolean inlined) throws MojoFailureException
{
if (skip)
{
Expand All @@ -194,6 +248,6 @@ public static Optional<OpenAPI> load(final Log log, final boolean skip, final St
}

log.info("Reading file '" + source + "'");
return Optional.of(new OpenApiParser().parse(source));
return Optional.of(inlined ? new OpenApiParser().parseInlined(source) : new OpenApiParser().parse(source));
}
}
54 changes: 54 additions & 0 deletions src/main/java/com/ethlo/zally/ExtractionDefinition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.ethlo.zally;

/*-
* #%L
* zally-maven-plugin
* %%
* Copyright (C) 2021 - 2022 Morten Haraldsen (ethlo)
* %%
* Licensed 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.
* #L%
*/

import java.util.List;

import com.fasterxml.jackson.annotation.JsonProperty;

public class ExtractionDefinition
{
private final String title;
private final String description;
private final List<OperationFilter> filters;

public ExtractionDefinition(@JsonProperty("title") final String title, @JsonProperty("description") final String description, @JsonProperty("filters") final List<OperationFilter> filters)
{
this.title = title;
this.description = description;
this.filters = filters;
}

public String getTitle()
{
return title;
}

public List<OperationFilter> getFilters()
{
return filters;
}

public String getDescription()
{
return description;
}
}
11 changes: 10 additions & 1 deletion src/main/java/com/ethlo/zally/OpenApiParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,21 @@

public class OpenApiParser
{
public OpenAPI parse(String url)
public OpenAPI parseInlined(String url)
{
final ParseOptions parseOptions = new ParseOptions();
parseOptions.setResolve(true);
final OpenAPI parseResult = new OpenAPIV3Parser().read(url);
new ResolverFully(true).resolveFully(parseResult);
return parseResult;
}

public OpenAPI parse(final String url)
{
final ParseOptions parseOptions = new ParseOptions();
parseOptions.setResolve(true);
final OpenAPI parseResult = new OpenAPIV3Parser().read(url);
//new ResolverFully(true).resolveFully(parseResult);
return parseResult;
}
}
Loading

0 comments on commit 6000c29

Please sign in to comment.