mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
4 Commits
sschroever
...
sschroever
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e94846ff67 | ||
|
|
19121d647f | ||
|
|
379b4d603f | ||
|
|
66c485e14d |
17
.github/workflows/deploy-website.yml
vendored
17
.github/workflows/deploy-website.yml
vendored
@@ -38,26 +38,29 @@ jobs:
|
||||
www.bestpractices.dev:443
|
||||
www.youtube.com:443
|
||||
youtrack.jetbrains.com:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
java-version: 17.0.10
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
|
||||
with:
|
||||
working-directory: ./website
|
||||
bundler-cache: true
|
||||
- name: Configure Github Pages
|
||||
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
|
||||
- name: Compile project and extract data
|
||||
run: mvn -T1C clean install -DskipTests -Dverification.skip
|
||||
- name: Generate documentation
|
||||
run: ./generate-docs.sh
|
||||
run: mvn exec:java@generate-docs -pl documentation-support
|
||||
- name: Build website with Jekyll
|
||||
working-directory: ./website
|
||||
run: bundle exec jekyll build
|
||||
- name: Validate HTML output
|
||||
working-directory: ./website
|
||||
# XXX: Drop `--disable_external true` once we fully adopted the
|
||||
# "Refaster rules" terminology on our website and in the code.
|
||||
run: bundle exec htmlproofer --disable_external true --check-external-hash false ./_site
|
||||
# XXX: StackOverflow returns a 403 when run on GHA.
|
||||
run: bundle exec htmlproofer --no-check-external-hash --swap-url 'https\://error-prone.picnic.tech:' --ignore-urls '/^https:\/\/stackoverflow.com\/.*/' ./_site
|
||||
- name: Upload website as artifact
|
||||
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
|
||||
with:
|
||||
|
||||
@@ -46,10 +46,18 @@
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-guava</artifactId>
|
||||
@@ -76,6 +84,10 @@
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.java-diff-utils</groupId>
|
||||
<artifactId>java-diff-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
@@ -104,4 +116,29 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-docs</id>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<mainClass>tech.picnic.errorprone.documentation.JekyllCollectionGenerator</mainClass>
|
||||
<arguments>
|
||||
<argument>${maven.multiModuleProjectDirectory}</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableListMultimap.flatteningToImmutableListMultimap;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableTable.toImmutableTable;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
|
||||
import com.github.difflib.DiffUtils;
|
||||
import com.github.difflib.UnifiedDiffUtils;
|
||||
import com.github.difflib.patch.Patch;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.errorprone.BugPattern.SeverityLevel;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.documentation.BugPatternExtractor.BugPatternDocumentation;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.BugPatternTestCase;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.BugPatternTestCases;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.IdentificationTestEntry;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.ReplacementTestEntry;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestEntry;
|
||||
import tech.picnic.errorprone.documentation.RefasterRuleCollectionTestExtractor.RefasterTestCase;
|
||||
import tech.picnic.errorprone.documentation.RefasterRuleCollectionTestExtractor.RefasterTestCases;
|
||||
|
||||
/**
|
||||
* A command line utility that produces configuration files for the Jekyll-based Error Prone Support
|
||||
* website.
|
||||
*/
|
||||
// XXX: Expand the class documentation.
|
||||
// XXX: Rename this class. Then also update the reference in `website/.gitignore`.
|
||||
// XXX: Now that we have bug checkers in multiple Maven modules, we should
|
||||
// likely document the source of each check on the website, perhaps even
|
||||
// grouping them by module.
|
||||
public final class JekyllCollectionGenerator {
|
||||
// XXX: Find a bette name. Also, externalize this.
|
||||
private static final PathMatcher PATH_MATCHER =
|
||||
FileSystems.getDefault().getPathMatcher("glob:**/target/docs/*.json");
|
||||
|
||||
// XXX: Review class setup.
|
||||
private JekyllCollectionGenerator() {}
|
||||
|
||||
/**
|
||||
* Runs the application.
|
||||
*
|
||||
* @param args Arguments to the application; must specify the path to the Error Prone Support
|
||||
* project root, and nothing else.
|
||||
* @throws IOException If any file could not be read or written.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
checkArgument(args.length == 1, "Precisely one project root path must be provided");
|
||||
Path projectRoot = Path.of(args[0]).toAbsolutePath();
|
||||
|
||||
generateIndex(projectRoot);
|
||||
PageGenerator.apply(projectRoot);
|
||||
}
|
||||
|
||||
private static void generateIndex(Path projectRoot) throws IOException {
|
||||
try (BufferedWriter writer =
|
||||
Files.newBufferedWriter(projectRoot.resolve("website").resolve("index.md"), UTF_8)) {
|
||||
writer.write("---");
|
||||
writer.newLine();
|
||||
writer.write("layout: default");
|
||||
writer.newLine();
|
||||
writer.write("title: Home");
|
||||
writer.newLine();
|
||||
writer.write("nav_order: 1");
|
||||
writer.newLine();
|
||||
writer.write("---");
|
||||
writer.newLine();
|
||||
writer.write(
|
||||
Files.readString(projectRoot.resolve("README.md")).replace("=\"website/", "=\""));
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Review this class should be split in two: one for bug patterns and one for Refaster rules.
|
||||
private static final class PageGenerator extends SimpleFileVisitor<Path> {
|
||||
private static final Splitter LINE_SPLITTER = Splitter.on(System.lineSeparator());
|
||||
private static final YAMLMapper YAML_MAPPER =
|
||||
YAMLMapper.builder()
|
||||
.visibility(PropertyAccessor.FIELD, Visibility.ANY)
|
||||
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
|
||||
.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)
|
||||
.enable(YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS)
|
||||
.build();
|
||||
|
||||
private final List<BugPatternDocumentation> bugPatterns = new ArrayList<>();
|
||||
private final List<BugPatternTestCases> bugPatternTests = new ArrayList<>();
|
||||
private final List<RefasterTestCases> refasterRuleCollectionTests = new ArrayList<>();
|
||||
|
||||
static void apply(Path projectRoot) throws IOException {
|
||||
PageGenerator pageGenerator = new PageGenerator();
|
||||
Files.walkFileTree(projectRoot, pageGenerator);
|
||||
pageGenerator.writePages(projectRoot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
if (!PATH_MATCHER.matches(file)) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
// XXX: If we use a consistent ID separator, then this can become a switch statement. Now we
|
||||
// depend on evaluation order.
|
||||
// XXX: Alternatively, use polymorphism and let Jackson figure it out.
|
||||
// XXX: If we stick with an ID-based approach, then deduplicate the ID references here and in
|
||||
// the `Extractor` implementations.
|
||||
String fileName = file.getFileName().toString();
|
||||
if (fileName.startsWith("bugpattern-test")) {
|
||||
bugPatternTests.add(Json.read(file, BugPatternTestCases.class));
|
||||
} else if (fileName.startsWith("bugpattern")) {
|
||||
bugPatterns.add(Json.read(file, BugPatternDocumentation.class));
|
||||
} else if (fileName.startsWith("refaster-rule-collection-test")) {
|
||||
refasterRuleCollectionTests.add(Json.read(file, RefasterTestCases.class));
|
||||
} else {
|
||||
// XXX: Handle differently?
|
||||
throw new IllegalStateException("Unexpected file: " + fileName);
|
||||
}
|
||||
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
private void writePages(Path projectRoot) throws IOException {
|
||||
Path website = projectRoot.resolve("website");
|
||||
writePages(
|
||||
website.resolve("_bugpatterns"),
|
||||
getJekyllBugPatternDescriptions(projectRoot),
|
||||
JekyllBugPatternDescription::name);
|
||||
writePages(
|
||||
website.resolve("_refasterrules"),
|
||||
getJekyllRefasterRuleCollectionDescription(),
|
||||
JekyllRefasterRuleCollectionDescription::name);
|
||||
}
|
||||
|
||||
private static <T> void writePages(
|
||||
Path directory, ImmutableList<T> documents, Function<T, String> nameExtractor)
|
||||
throws IOException {
|
||||
for (T document : documents) {
|
||||
Files.createDirectories(directory);
|
||||
try (BufferedWriter writer =
|
||||
Files.newBufferedWriter(
|
||||
directory.resolve(nameExtractor.apply(document) + ".md"), UTF_8)) {
|
||||
YAML_MAPPER.writeValue(writer, document);
|
||||
writer.write("---");
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ImmutableList<JekyllBugPatternDescription> getJekyllBugPatternDescriptions(
|
||||
Path projectRoot) {
|
||||
ImmutableListMultimap<String, TestEntry> bugPatternTestCases =
|
||||
bugPatternTests.stream()
|
||||
.flatMap(testCases -> testCases.testCases().stream())
|
||||
.collect(
|
||||
flatteningToImmutableListMultimap(
|
||||
BugPatternTestCase::classUnderTest, t -> t.entries().stream()));
|
||||
|
||||
return bugPatterns.stream()
|
||||
.map(
|
||||
b ->
|
||||
new AutoValue_JekyllCollectionGenerator_JekyllBugPatternDescription(
|
||||
b.name(),
|
||||
b.name(),
|
||||
b.summary(),
|
||||
b.severityLevel(),
|
||||
b.tags(),
|
||||
// XXX: Derive `Path` from filesytem.
|
||||
Path.of(b.source()).relativize(projectRoot).toString(),
|
||||
bugPatternTestCases.get(b.fullyQualifiedName()).stream()
|
||||
.filter(t -> t.type() == TestEntry.TestType.IDENTIFICATION)
|
||||
.map(t -> ((IdentificationTestEntry) t).code())
|
||||
.collect(toImmutableList()),
|
||||
bugPatternTestCases.get(b.fullyQualifiedName()).stream()
|
||||
.filter(t -> t.type() == TestEntry.TestType.REPLACEMENT)
|
||||
.map(t -> generateDiff((ReplacementTestEntry) t))
|
||||
.collect(toImmutableList())))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
private ImmutableList<JekyllRefasterRuleCollectionDescription>
|
||||
getJekyllRefasterRuleCollectionDescription() {
|
||||
ImmutableTable<String, Boolean, List<RefasterTestCase>> refasterTests =
|
||||
refasterRuleCollectionTests.stream()
|
||||
.collect(
|
||||
toImmutableTable(
|
||||
RefasterTestCases::ruleCollection,
|
||||
RefasterTestCases::isInput,
|
||||
RefasterTestCases::testCases));
|
||||
|
||||
return refasterTests.rowMap().entrySet().stream()
|
||||
.map(
|
||||
c ->
|
||||
new AutoValue_JekyllCollectionGenerator_JekyllRefasterRuleCollectionDescription(
|
||||
c.getKey(),
|
||||
c.getKey(),
|
||||
// XXX: Derive severity from input.
|
||||
SUGGESTION,
|
||||
// XXX: Derive tags from input (or drop this feature).
|
||||
ImmutableList.of("Simplification"),
|
||||
// XXX: Derive source location from input.
|
||||
String.format(
|
||||
"error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/%s.java",
|
||||
c.getKey()),
|
||||
getRules(c.getValue().get(true), c.getValue().get(false))))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
private static ImmutableList<JekyllRefasterRuleCollectionDescription.Rule> getRules(
|
||||
@Nullable List<RefasterTestCase> inputTests, @Nullable List<RefasterTestCase> outputTests) {
|
||||
ImmutableMap<String, String> inputs = indexRefasterTestData(inputTests);
|
||||
ImmutableMap<String, String> outputs = indexRefasterTestData(outputTests);
|
||||
|
||||
return Sets.intersection(inputs.keySet(), outputs.keySet()).stream()
|
||||
.map(
|
||||
name ->
|
||||
new AutoValue_JekyllCollectionGenerator_JekyllRefasterRuleCollectionDescription_Rule(
|
||||
name,
|
||||
// XXX: Derive severity from input.
|
||||
SUGGESTION,
|
||||
// XXX: Derive tags from input (or drop this feature).
|
||||
ImmutableList.of("Simplification"),
|
||||
generateDiff(
|
||||
requireNonNull(inputs.get(name), "Input"),
|
||||
requireNonNull(outputs.get(name), "Output"))))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
private static ImmutableMap<String, String> indexRefasterTestData(
|
||||
@Nullable List<RefasterTestCase> data) {
|
||||
return data == null
|
||||
? ImmutableMap.of()
|
||||
: data.stream()
|
||||
.collect(toImmutableMap(RefasterTestCase::name, RefasterTestCase::content));
|
||||
}
|
||||
|
||||
private static String generateDiff(ReplacementTestEntry testEntry) {
|
||||
return generateDiff(testEntry.input(), testEntry.output());
|
||||
}
|
||||
|
||||
private static String generateDiff(String before, String after) {
|
||||
// XXX: Extract splitter.
|
||||
List<String> originalLines = LINE_SPLITTER.splitToList(before);
|
||||
List<String> replacementLines = LINE_SPLITTER.splitToList(after);
|
||||
|
||||
Patch<String> diff = DiffUtils.diff(originalLines, replacementLines);
|
||||
|
||||
return UnifiedDiffUtils.generateUnifiedDiff(
|
||||
"", "", originalLines, diff, Integer.MAX_VALUE / 2)
|
||||
.stream()
|
||||
.skip(3)
|
||||
.collect(joining(System.lineSeparator()));
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class JekyllBugPatternDescription {
|
||||
// XXX: Make this a derived property?
|
||||
abstract String title();
|
||||
|
||||
abstract String name();
|
||||
|
||||
abstract String summary();
|
||||
|
||||
abstract SeverityLevel severity();
|
||||
|
||||
abstract ImmutableList<String> tags();
|
||||
|
||||
// XXX: The documentation could link to the original test code. Perhaps even with the correct
|
||||
// line numbers.
|
||||
abstract String source();
|
||||
|
||||
// XXX: The `identification` and `replacement` fields have odd names.
|
||||
abstract ImmutableList<String> identification();
|
||||
|
||||
abstract ImmutableList<String> replacement();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class JekyllRefasterRuleCollectionDescription {
|
||||
// XXX: Make this a derived property?
|
||||
abstract String title();
|
||||
|
||||
abstract String name();
|
||||
|
||||
abstract SeverityLevel severity();
|
||||
|
||||
abstract ImmutableList<String> tags();
|
||||
|
||||
// XXX: The documentation could link to the original test code. Perhaps even with the correct
|
||||
// line numbers. If we do this, we should do the same for individual rules.
|
||||
abstract String source();
|
||||
|
||||
abstract ImmutableList<Rule> rules();
|
||||
|
||||
@AutoValue
|
||||
abstract static class Rule {
|
||||
abstract String name();
|
||||
|
||||
abstract SeverityLevel severity();
|
||||
|
||||
abstract ImmutableList<String> tags();
|
||||
|
||||
abstract String diff();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package tech.picnic.errorprone.documentation.models;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Object containing all data related to a Refaster template collection. This is solely used for
|
||||
* serialization.
|
||||
*/
|
||||
// XXX: This class is not yet used.
|
||||
@AutoValue
|
||||
@JsonDeserialize(as = AutoValue_RefasterTemplateCollectionData.class)
|
||||
abstract class RefasterTemplateCollectionData {
|
||||
static RefasterTemplateCollectionData create(
|
||||
String name, String description, String link, ImmutableList<RefasterTemplateData> templates) {
|
||||
return new AutoValue_RefasterTemplateCollectionData(name, description, link, templates);
|
||||
}
|
||||
|
||||
abstract String name();
|
||||
|
||||
abstract String description();
|
||||
|
||||
abstract String link();
|
||||
|
||||
abstract ImmutableList<RefasterTemplateData> templates();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package tech.picnic.errorprone.documentation.models;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.errorprone.BugPattern.SeverityLevel;
|
||||
|
||||
// XXX: This class is not yet used.
|
||||
@AutoValue
|
||||
@JsonDeserialize(as = AutoValue_RefasterTemplateData.class)
|
||||
abstract class RefasterTemplateData {
|
||||
static RefasterTemplateData create(
|
||||
String name, String description, String link, SeverityLevel severityLevel) {
|
||||
return new AutoValue_RefasterTemplateData(name, description, link, severityLevel);
|
||||
}
|
||||
|
||||
abstract String name();
|
||||
|
||||
abstract String description();
|
||||
|
||||
abstract String link();
|
||||
|
||||
abstract SeverityLevel severityLevel();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
// XXX: Implement tests.
|
||||
final class JekyllCollectionGeneratorTest {
|
||||
@Test
|
||||
void foo() throws IOException {
|
||||
JekyllCollectionGenerator.main(
|
||||
new String[] {"/home/sschroevers/workspace/picnic/error-prone-support"});
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e -u -o pipefail
|
||||
|
||||
REPOSITORY_ROOT="$(git rev-parse --show-toplevel)"
|
||||
WEBSITE_ROOT="${REPOSITORY_ROOT}/website"
|
||||
|
||||
generate_homepage() {
|
||||
local homepage="${WEBSITE_ROOT}/index.md"
|
||||
|
||||
echo "Generating ${homepage}..."
|
||||
cat - "${REPOSITORY_ROOT}/README.md" > "${homepage}" << EOF
|
||||
---
|
||||
layout: default
|
||||
title: Home
|
||||
nav_order: 1
|
||||
---
|
||||
EOF
|
||||
|
||||
local macos_compat=""
|
||||
[[ "${OSTYPE}" == "darwin"* ]] && macos_compat="yes"
|
||||
sed -i ${macos_compat:+".bak"} 's/src="website\//src="/g' "${homepage}"
|
||||
sed -i ${macos_compat:+".bak"} 's/srcset="website\//srcset="/g' "${homepage}"
|
||||
}
|
||||
|
||||
# Generate the website.
|
||||
generate_homepage
|
||||
10
pom.xml
10
pom.xml
@@ -362,6 +362,11 @@
|
||||
<artifactId>nullaway</artifactId>
|
||||
<version>${version.nullaway}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.java-diff-utils</groupId>
|
||||
<artifactId>java-diff-utils</artifactId>
|
||||
<version>4.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-bom</artifactId>
|
||||
@@ -1823,6 +1828,11 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
|
||||
7
website/.gitignore
vendored
7
website/.gitignore
vendored
@@ -1,12 +1,13 @@
|
||||
# Generated by Bundler and Jekyll.
|
||||
.bundle/
|
||||
Gemfile.lock
|
||||
.jekyll-cache/
|
||||
.jekyll-metadata
|
||||
.sass-cache/
|
||||
_site/
|
||||
vendor/
|
||||
|
||||
# Generated by `../generate-docs.sh`.
|
||||
*.bak
|
||||
# XXX: Update generator name when it's renamed.
|
||||
# Generated by `JekyllCollectionGenerator`.
|
||||
index.md
|
||||
_bugpatterns/
|
||||
_refasterrules/
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
ruby File.read(".ruby-version").strip
|
||||
|
||||
source "https://rubygems.org"
|
||||
gem "html-proofer", "4.4.1"
|
||||
gem "jekyll", "4.2.2"
|
||||
gem "jekyll-sitemap", "1.4"
|
||||
gem "just-the-docs", "0.4.0.rc2"
|
||||
gem "webrick", "1.7"
|
||||
|
||||
group :jekyll_site_dependencies do
|
||||
gem "jekyll", "4.3.2"
|
||||
gem "jekyll-sitemap", "1.4.0"
|
||||
gem "just-the-docs", "0.6.2"
|
||||
gem "rake", "13.0.6"
|
||||
gem "webrick", "1.8.1"
|
||||
end
|
||||
|
||||
group :website_validation_dependencies do
|
||||
gem "html-proofer", "5.0.8"
|
||||
end
|
||||
|
||||
133
website/Gemfile.lock
Normal file
133
website/Gemfile.lock
Normal file
@@ -0,0 +1,133 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
Ascii85 (1.1.0)
|
||||
addressable (2.8.5)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
afm (0.2.2)
|
||||
async (2.6.4)
|
||||
console (~> 1.10)
|
||||
fiber-annotation
|
||||
io-event (~> 1.1)
|
||||
timers (~> 4.1)
|
||||
colorator (1.1.0)
|
||||
concurrent-ruby (1.2.2)
|
||||
console (1.23.2)
|
||||
fiber-annotation
|
||||
fiber-local
|
||||
em-websocket (0.5.3)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0)
|
||||
ethon (0.16.0)
|
||||
ffi (>= 1.15.0)
|
||||
eventmachine (1.2.7)
|
||||
ffi (1.16.3)
|
||||
fiber-annotation (0.2.0)
|
||||
fiber-local (1.0.0)
|
||||
forwardable-extended (2.6.0)
|
||||
google-protobuf (3.24.4-x86_64-linux)
|
||||
hashery (2.1.2)
|
||||
html-proofer (5.0.8)
|
||||
addressable (~> 2.3)
|
||||
async (~> 2.1)
|
||||
nokogiri (~> 1.13)
|
||||
pdf-reader (~> 2.11)
|
||||
rainbow (~> 3.0)
|
||||
typhoeus (~> 1.3)
|
||||
yell (~> 2.0)
|
||||
zeitwerk (~> 2.5)
|
||||
http_parser.rb (0.8.0)
|
||||
i18n (1.14.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
io-event (1.3.2)
|
||||
jekyll (4.3.2)
|
||||
addressable (~> 2.4)
|
||||
colorator (~> 1.0)
|
||||
em-websocket (~> 0.5)
|
||||
i18n (~> 1.0)
|
||||
jekyll-sass-converter (>= 2.0, < 4.0)
|
||||
jekyll-watch (~> 2.0)
|
||||
kramdown (~> 2.3, >= 2.3.1)
|
||||
kramdown-parser-gfm (~> 1.0)
|
||||
liquid (~> 4.0)
|
||||
mercenary (>= 0.3.6, < 0.5)
|
||||
pathutil (~> 0.9)
|
||||
rouge (>= 3.0, < 5.0)
|
||||
safe_yaml (~> 1.0)
|
||||
terminal-table (>= 1.8, < 4.0)
|
||||
webrick (~> 1.7)
|
||||
jekyll-include-cache (0.2.1)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-sass-converter (3.0.0)
|
||||
sass-embedded (~> 1.54)
|
||||
jekyll-seo-tag (2.8.0)
|
||||
jekyll (>= 3.8, < 5.0)
|
||||
jekyll-sitemap (1.4.0)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-watch (2.2.1)
|
||||
listen (~> 3.0)
|
||||
just-the-docs (0.6.2)
|
||||
jekyll (>= 3.8.5)
|
||||
jekyll-include-cache
|
||||
jekyll-seo-tag (>= 2.0)
|
||||
rake (>= 12.3.1)
|
||||
kramdown (2.4.0)
|
||||
rexml
|
||||
kramdown-parser-gfm (1.1.0)
|
||||
kramdown (~> 2.0)
|
||||
liquid (4.0.4)
|
||||
listen (3.8.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.4.0)
|
||||
nokogiri (1.15.4-x86_64-linux)
|
||||
racc (~> 1.4)
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
pdf-reader (2.11.0)
|
||||
Ascii85 (~> 1.0)
|
||||
afm (~> 0.2.1)
|
||||
hashery (~> 2.0)
|
||||
ruby-rc4
|
||||
ttfunk
|
||||
public_suffix (5.0.3)
|
||||
racc (1.7.1)
|
||||
rainbow (3.1.1)
|
||||
rake (13.0.6)
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.2.6)
|
||||
rouge (4.1.3)
|
||||
ruby-rc4 (0.1.5)
|
||||
safe_yaml (1.0.5)
|
||||
sass-embedded (1.69.4)
|
||||
google-protobuf (~> 3.23)
|
||||
rake (>= 13.0.0)
|
||||
terminal-table (3.0.2)
|
||||
unicode-display_width (>= 1.1.1, < 3)
|
||||
timers (4.3.5)
|
||||
ttfunk (1.7.0)
|
||||
typhoeus (1.4.0)
|
||||
ethon (>= 0.9.0)
|
||||
unicode-display_width (2.5.0)
|
||||
webrick (1.8.1)
|
||||
yell (2.2.2)
|
||||
zeitwerk (2.6.12)
|
||||
|
||||
PLATFORMS
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
html-proofer (= 5.0.8)
|
||||
jekyll (= 4.3.2)
|
||||
jekyll-sitemap (= 1.4.0)
|
||||
just-the-docs (= 0.6.2)
|
||||
rake (= 13.0.6)
|
||||
webrick (= 1.8.1)
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.1.2p20
|
||||
|
||||
BUNDLED WITH
|
||||
2.3.7
|
||||
@@ -7,18 +7,30 @@ statically generated using [Jekyll][jekyll].
|
||||
# Local development
|
||||
|
||||
To view the website on `localhost`, first follow the [Jekyll installation
|
||||
instructions][jekyll-docs-installation]. Once done, in this directory execute:
|
||||
instructions][jekyll-docs-installation]. Once done, run the following Maven
|
||||
commands in the root of the repository to extract the (test) data from the bug
|
||||
patterns and Refaster rule collections and to transform this data into a
|
||||
Jekyll-digestible format. Unless and relevant Java code has been changed, these
|
||||
commands needs to be executed once.
|
||||
|
||||
```sh
|
||||
mvn -T1C clean install -DskipTests -Dverification.skip
|
||||
mvn exec:java@generate-docs -pl documentation-support
|
||||
```
|
||||
|
||||
Then to build the website for local development, execute in this directory:
|
||||
|
||||
```sh
|
||||
bundle install
|
||||
../generate-docs.sh && bundle exec jekyll serve --livereload
|
||||
bundle exec jekyll serve --livereload
|
||||
```
|
||||
|
||||
The website will now be [available][localhost-port-4000] on port 4000. Source
|
||||
code modifications (including the result of rerunning `../generate-docs.sh`)
|
||||
will automatically be reflected. (An exception is `_config.yml`: changes to
|
||||
this file require a server restart.) Subsequent server restarts do not require
|
||||
running `bundle install`, unless `Gemfile` has been updated in the interim.
|
||||
code modifications (including the result of rerunning `mvn
|
||||
exec:java@generate-docs -pl documentation-support`) will automatically be
|
||||
reflected. (An exception is `_config.yml`: changes to this file require a
|
||||
server restart.) Subsequent server restarts do not require running `bundle
|
||||
install`, unless `Gemfile` has been updated in the interim.
|
||||
|
||||
If you are not familiar with Jekyll, be sure to check out its
|
||||
[documentation][jekyll-docs]. It is recommended to follow the provided
|
||||
|
||||
@@ -8,15 +8,40 @@ description: >-
|
||||
|
||||
theme: just-the-docs
|
||||
plugins:
|
||||
- jekyll-sitemap
|
||||
- jekyll-sitemap
|
||||
|
||||
# Files and directories not to be deployed through GitHub pages.
|
||||
exclude:
|
||||
- Gemfile
|
||||
- Gemfile.lock
|
||||
- generate-version-compatibility-overview.sh
|
||||
- README.md
|
||||
- vendor
|
||||
- Gemfile
|
||||
- Gemfile.lock
|
||||
- generate-version-compatibility-overview.sh
|
||||
- README.md
|
||||
- vendor
|
||||
|
||||
collections:
|
||||
bugpatterns:
|
||||
output: true
|
||||
refasterrules:
|
||||
output: true
|
||||
|
||||
defaults:
|
||||
- scope:
|
||||
type: "bugpatterns"
|
||||
values:
|
||||
layout: "bugpattern"
|
||||
- scope:
|
||||
type: "refasterrules"
|
||||
values:
|
||||
layout: "refasterrule"
|
||||
|
||||
just_the_docs:
|
||||
collections:
|
||||
bugpatterns:
|
||||
name: Bug Patterns
|
||||
nav_fold: true
|
||||
refasterrules:
|
||||
name: Refaster Rules
|
||||
nav_fold: true
|
||||
|
||||
# See https://jekyllrb.com/docs/permalinks/#built-in-formats.
|
||||
permalink: pretty
|
||||
@@ -25,9 +50,9 @@ permalink: pretty
|
||||
# See
|
||||
# https://just-the-docs.github.io/just-the-docs/docs/navigation-structure/#external-navigation-links.
|
||||
nav_external_links:
|
||||
- title: Error Prone Support on GitHub
|
||||
url: https://github.com/PicnicSupermarket/error-prone-support
|
||||
hide_icon: false
|
||||
- title: Error Prone Support on GitHub
|
||||
url: https://github.com/PicnicSupermarket/error-prone-support
|
||||
hide_icon: false
|
||||
|
||||
callouts:
|
||||
summary:
|
||||
@@ -40,9 +65,9 @@ callouts:
|
||||
social:
|
||||
name: Picnic
|
||||
links:
|
||||
- https://github.com/PicnicSupermarket
|
||||
- https://twitter.com/picnic
|
||||
- https://www.linkedin.com/company/picnictechnologies
|
||||
- https://github.com/PicnicSupermarket
|
||||
- https://twitter.com/picnic
|
||||
- https://www.linkedin.com/company/picnictechnologies
|
||||
twitter:
|
||||
username: picnic
|
||||
card: summary
|
||||
|
||||
6
website/_data/severities.yml
Normal file
6
website/_data/severities.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
ERROR:
|
||||
color: red
|
||||
WARNING:
|
||||
color: yellow
|
||||
SUGGESTION:
|
||||
color: green
|
||||
94
website/_layouts/bugpattern.md
Normal file
94
website/_layouts/bugpattern.md
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
# XXX: To be implemented:
|
||||
# - Support for alt names.
|
||||
# - Support for explanations.
|
||||
# - Support for "can disable".
|
||||
# - Support for custom suppression annotations.
|
||||
layout: default
|
||||
---
|
||||
|
||||
{% capture markdown_layout %}
|
||||
|
||||
# {{ page.name }}
|
||||
|
||||
{{ page.severity }}
|
||||
{: .label .label-{{ site.data.severities[page.severity].color }} }
|
||||
|
||||
{% for tag in page.tags %}
|
||||
{{ tag }}
|
||||
{: .label }
|
||||
{% endfor %}
|
||||
|
||||
<a href="https://github.com/PicnicSupermarket/error-prone-support/blob/master/{{ page.source }}" class="fs-3 btn external" target="_blank">
|
||||
View source code on GitHub
|
||||
<svg viewBox="0 0 24 24" aria-labelledby="svg-external-link-title">
|
||||
<use xlink:href="#svg-external-link"></use>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
{: .summary-title }
|
||||
> Summary
|
||||
>
|
||||
> {{ page.summary }}
|
||||
|
||||
{% comment %}
|
||||
# XXX: Here, include a more elaborate explantion, if available.
|
||||
{% endcomment %}
|
||||
|
||||
{: .note-title }
|
||||
> Suppression
|
||||
>
|
||||
> Suppress false positives by adding the suppression annotation `@SuppressWarnings("{{ page.name }}")` to
|
||||
> the enclosing element.
|
||||
>
|
||||
> Disable this pattern completely by adding `-Xep:{{ page.name }}:OFF` as compiler argument.
|
||||
> [Learn more][error-prone-flags].
|
||||
{% comment %}
|
||||
# XXX: Create an internal page on documenting the usage of compiler flags.
|
||||
{% endcomment %}
|
||||
|
||||
{% if page.replacement or page.identification %}
|
||||
|
||||
## Samples
|
||||
|
||||
{% comment %}
|
||||
# XXX: Either make this "Samples" header useful, or drop it. (In which case
|
||||
# the wrapping conjunctive guard should also go.)
|
||||
{% endcomment %}
|
||||
|
||||
{% if page.replacement %}
|
||||
|
||||
### Replacement
|
||||
|
||||
Shows the difference in example code before and after the bug pattern is
|
||||
applied.
|
||||
|
||||
{% for diff in page.replacement %}
|
||||
{% highlight diff %}
|
||||
{{ diff }}
|
||||
{% endhighlight %}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if page.identification %}
|
||||
|
||||
### Identification
|
||||
|
||||
Shows code lines which will (not) be flagged by this bug pattern. \
|
||||
A `//BUG: Diagnostic contains:` comment is placed above any violating line.
|
||||
|
||||
{% for source in page.identification %}
|
||||
{% highlight java %}
|
||||
{{ source }}
|
||||
{% endhighlight %}
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
[error-prone-flags]: https://errorprone.info/docs/flags
|
||||
|
||||
{% endcapture %}
|
||||
{{ markdown_layout | markdownify }}
|
||||
78
website/_layouts/refasterrule.md
Normal file
78
website/_layouts/refasterrule.md
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
{% capture markdown_layout %}
|
||||
|
||||
# {{ page.name }}
|
||||
{: .no_toc }
|
||||
|
||||
{{ page.severity }}
|
||||
{: .label .label-{{ site.data.severities[page.severity].color }} }
|
||||
|
||||
{% for tag in page.tags %}
|
||||
{{ tag }}
|
||||
{: .label }
|
||||
{% endfor %}
|
||||
|
||||
<a href="https://github.com/PicnicSupermarket/error-prone-support/blob/master/{{ page.source }}" class="fs-3 btn external" target="_blank">
|
||||
View source code on GitHub
|
||||
<svg viewBox="0 0 24 24" aria-labelledby="svg-external-link-title">
|
||||
<use xlink:href="#svg-external-link"></use>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
{: .note-title }
|
||||
> Suppression
|
||||
>
|
||||
> Disable all rules by adding `-XepOpt:Refaster:NamePattern=^(?!{{page.name}}\$).*` as
|
||||
> compiler argument.
|
||||
{% comment %}
|
||||
# XXX: Create an internal page on documenting the usage of compiler flags.
|
||||
{% endcomment %}
|
||||
|
||||
<details open markdown="block">
|
||||
<summary>
|
||||
Table of contents
|
||||
</summary>
|
||||
{: .text-delta }
|
||||
1. TOC
|
||||
{:toc}
|
||||
</details>
|
||||
|
||||
{% for rule in page.rules %}
|
||||
## {{rule.name}}
|
||||
|
||||
{{ page.severity }}
|
||||
{: .label .label-{{ site.data.severities[rule.severity].color }} }
|
||||
|
||||
{% for tag in rule.tags %}
|
||||
{{ tag }}
|
||||
{: .label }
|
||||
{% endfor %}
|
||||
|
||||
{: .note-title }
|
||||
> Suppression
|
||||
>
|
||||
> Suppress false positives by adding the suppression annotation `@SuppressWarnings("{{rule.name}}")` to
|
||||
> the enclosing element.
|
||||
>
|
||||
> Disable this rule by adding `-XepOpt:Refaster:NamePattern=^(?!{{page.name}}\${{rule.name}}).*`
|
||||
> as compiler argument.
|
||||
{% comment %}
|
||||
# XXX: Create an internal page on documenting the usage of compiler flags.
|
||||
{% endcomment %}
|
||||
|
||||
### Samples
|
||||
{: .no_toc .text-delta }
|
||||
|
||||
Shows the difference in example code before and after the Refaster rule is
|
||||
applied.
|
||||
|
||||
{% highlight diff %}
|
||||
{{ rule.diff }}
|
||||
{% endhighlight %}
|
||||
{% endfor %}
|
||||
|
||||
{% endcapture %}
|
||||
{{ markdown_layout | markdownify }}
|
||||
@@ -2,4 +2,4 @@
|
||||
// https://github.com/just-the-docs/just-the-docs/blob/main/_sass/support/_variables.scss.
|
||||
|
||||
// Grid system.
|
||||
$nav-width: 400px;
|
||||
$nav-width: 25rem;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
layout: default
|
||||
title: Bug Patterns
|
||||
nav_order: 2
|
||||
has_children: true
|
||||
---
|
||||
|
||||
# Bug Patterns
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
layout: default
|
||||
title: Refaster Rules
|
||||
nav_order: 2
|
||||
has_children: true
|
||||
---
|
||||
|
||||
# Refaster Rules
|
||||
Reference in New Issue
Block a user