Skip to content
Merged
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
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,44 @@ java -Dapis -DmodelTests=false {opts}

When using selective generation, _only_ the templates needed for the specific generation will be used.

### Ignore file format

Swagger codegen supports a `.swagger-codegen-ignore` file, similar to `.gitignore` or `.dockerignore` you're probably already familiar with.

The ignore file allows for better control over overwriting existing files than the `--skip-overwrite` flag. With the ignore file, you can specify individual files or directories can be ignored. This can be useful, for example if you only want a subset of the generated code.

Examples:

```
# Swagger Codegen Ignore
# Lines beginning with a # are comments

# This should match build.sh located anywhere.
build.sh

# Matches build.sh in the root
/build.sh

# Exclude all recursively
docs/**

# Explicitly allow files excluded by other rules
!docs/UserApi.md

# Recursively exclude directories named Api
# You can't negate files below this directory.
src/**/Api/

# When this file is nested under /Api (excluded above),
# this rule is ignored because parent directory is excluded by previous rule.
!src/**/PetApiTests.cs

# Exclude a single, nested file explicitly
src/IO.Swagger.Test/Model/AnimalFarmTests.cs
```

The `.swagger-codegen-ignore` file must exist in the root of the output directory.

### Customizing the generator

There are different aspects of customizing the code generator beyond just creating or modifying templates. Each language has a supporting configuration file to handle different type mappings, etc:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
package io.swagger.codegen.ignore.rules;

import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.nio.file.*;
import java.util.List;

public class DirectoryRule extends FileRule {

private PathMatcher matcher = null;
private PathMatcher directoryMatcher = null;
private PathMatcher contentsMatcher = null;

DirectoryRule(List<Part> syntax, String definition) {
super(syntax, definition);
matcher = FileSystems.getDefault().getPathMatcher("glob:**/"+this.getPattern());
String pattern = this.getPattern();
StringBuilder sb = new StringBuilder();
sb.append("glob:");
sb.append(pattern);
if(!pattern.endsWith("/")) sb.append("/");
directoryMatcher = FileSystems.getDefault().getPathMatcher(sb.toString());
sb.append("**");
contentsMatcher = FileSystems.getDefault().getPathMatcher(sb.toString());
}

@Override
public Boolean matches(String relativePath) {
return matcher.matches(FileSystems.getDefault().getPath(relativePath));
return contentsMatcher.matches(FileSystems.getDefault().getPath(relativePath)) || directoryMatcher.matches(FileSystems.getDefault().getPath(relativePath));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ static List<Part> parse(String text) throws ParserException {
i++;
continue;
} else {

if (sb.length() > 0) {
// A MATCH_ANY may commonly follow a filename or some other character. Dump that to results before the MATCH_ANY.
parts.add(new Part(Token.TEXT, sb.toString()));
sb.delete(0, sb.length());
}

parts.add(new Part(Token.MATCH_ANY));
continue;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,141 @@
package io.swagger.codegen.ignore;

import org.testng.annotations.Test;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.*;
import static org.testng.Assert.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class CodegenIgnoreProcessorTest {
@Test
public void loadCodegenRules() throws Exception {

private static final Logger LOGGER = LoggerFactory.getLogger(CodegenIgnoreProcessorTest.class);

private Boolean allowed;
private final String filename;
private final String ignoreDefinition;
private final String description;
private String outputDir;
private File target;
private Path temp;

private CodegenIgnoreProcessorTest(String filename, String ignoreDefinition, String description) throws IOException {
this.filename = filename;
this.ignoreDefinition = ignoreDefinition;
this.description = description;
}

@Test
public void getInclusionRules() throws Exception {
CodegenIgnoreProcessorTest allowed() {
this.allowed = true;
return this;
}

CodegenIgnoreProcessorTest ignored() {
this.allowed = false;
return this;
}

private void prepareTestFiles() throws IOException {
// NOTE: Each test needs its own directory because .swagger-codegen-ignore needs to exist at the root.
temp = Files.createTempDirectory(getClass().getSimpleName());
this.outputDir = temp.toFile().getAbsolutePath();

target = new File(this.outputDir, this.filename);

boolean mkdirs = target.getParentFile().mkdirs();
if(!mkdirs) {
LOGGER.warn("Failed to create directories for CodegenIgnoreProcessorTest test file. Directory may already exist.");
}

Path created = Files.createFile(target.toPath());
if(!created.toFile().exists()) {
throw new IOException("Failed to write CodegenIgnoreProcessorTest test file.");
}

// System.out.print(String.format("Created codegen ignore processor test file: %s\n", created.toAbsolutePath()));
File ignoreFile = new File(this.outputDir, ".swagger-codegen-ignore");
try (FileOutputStream stream = new FileOutputStream(ignoreFile)) {
stream.write(this.ignoreDefinition.getBytes());
}
}

@AfterTest
public void afterTest() throws IOException {
if(temp != null && temp.toFile().exists() && temp.toFile().isDirectory()) {
FileUtils.deleteDirectory(temp.toFile());
}
}

@Test
public void getExclusionRules() throws Exception {
public void evaluate() {
// Arrange
try {
// Lazily setup files to avoid conflicts and creation when these tests may not even run.
prepareTestFiles();
} catch (IOException e) {
e.printStackTrace();
fail("Failed to prepare test files. " + e.getMessage());
}
CodegenIgnoreProcessor processor = new CodegenIgnoreProcessor(outputDir);
Boolean actual = null;

// Act
actual = processor.allowsFile(target);

// Assert
assertEquals(actual, this.allowed, this.description);
}

@Factory
public static Object[] factoryMethod() throws IOException {
return new Object[] {
// Matching filenames
new CodegenIgnoreProcessorTest("build.sh", "build.sh", "A file when matching should ignore.").ignored(),
new CodegenIgnoreProcessorTest("src/build.sh", "**/build.sh", "A file when matching nested files should ignore.").ignored(),
new CodegenIgnoreProcessorTest("Build.sh", "build.sh", "A file when non-matching should allow.").allowed(),
new CodegenIgnoreProcessorTest("build.sh", "/build.sh", "A rooted file when matching should ignore.").ignored(),
new CodegenIgnoreProcessorTest("nested/build.sh", "/build.sh", "A rooted file definition when non-matching should allow.").allowed(),
new CodegenIgnoreProcessorTest("src/IO.Swagger.Test/Model/AnimalFarmTests.cs", "src/IO.Swagger.Test/Model/AnimalFarmTests.cs", "A file when matching exactly should ignore.").ignored(),

// Matching spaces in filenames
new CodegenIgnoreProcessorTest("src/properly escaped.txt", "**/properly escaped.txt", "A file when matching nested files with spaces in the name should ignore.").ignored(),
new CodegenIgnoreProcessorTest("src/improperly escaped.txt", "**/improperly\\ escaped.txt", "A file when matching nested files with spaces in the name (improperly escaped rule) should allow.").allowed(),

// Match All
new CodegenIgnoreProcessorTest("docs/somefile.md", "docs/**", "A recursive file (0 level) when matching should ignore.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/somefile.md", "docs/**", "A recursive file (1 level) when matching should ignore.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/2/3/somefile.md", "docs/**", "A recursive file (n level) when matching should ignore.").ignored(),

// Match Any
new CodegenIgnoreProcessorTest("docs/1/2/3/somefile.md", "docs/**/somefile.*", "A recursive file with match-any extension when matching should ignore.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/2/3/somefile.java", "docs/**/*.java", "A recursive file with match-any file name when matching should ignore.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/2/3/4/somefile.md", "docs/**/*", "A recursive file with match-any file name when matching should ignore.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/2/3/4/5/somefile.md", "docs/**/anyfile.*", "A recursive file with match-any extension when non-matching should allow.").allowed(),

// Directory matches
new CodegenIgnoreProcessorTest("docs/1/Users/a", "docs/**/Users/", "A directory rule when matching should be ignored.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/Users1/a", "docs/**/Users/", "A directory rule when non-matching should be allowed.").allowed(),

// Negation of excluded recursive files
new CodegenIgnoreProcessorTest("docs/UserApi.md", "docs/**\n!docs/UserApi.md", "A pattern negating a previous ignore FILE rule should be allowed.").allowed(),

// Negation of excluded directories
new CodegenIgnoreProcessorTest("docs/1/Users/UserApi.md", "docs/**/Users/\n!docs/1/Users/UserApi.md", "A pattern negating a previous ignore DIRECTORY rule should be ignored.").ignored(),

// Other matches which may not be parsed for correctness, but are free because of PathMatcher
new CodegenIgnoreProcessorTest("docs/1/2/3/Some99File.md", "**/*[0-9]*", "A file when matching against simple regex patterns when matching should be ignored.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/2/3/SomeFile.md", "**/*.{java,md}", "A file when matching against grouped subpatterns for extension when matching (md) should be ignored.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/2/3/SomeFile.java", "**/*.{java,md}", "A file when matching against grouped subpatterns for extension when matching (java) should be ignored.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/2/3/SomeFile.txt", "**/*.{java,md}", "A file when matching against grouped subpatterns for extension when non-matching should be allowed.").allowed(),

new CodegenIgnoreProcessorTest("docs/1/2/3/foo.c", "**/*.?", "A file when matching against required single-character extension when matching should be ignored.").ignored(),
new CodegenIgnoreProcessorTest("docs/1/2/3/foo.cc", "**/*.?", "A file when matching against required single-character extension when non-matching should be allowed.").allowed()

};
}
}