diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml
index 348d600..8627b21 100644
--- a/.github/workflows/check-links.yml
+++ b/.github/workflows/check-links.yml
@@ -34,7 +34,7 @@ jobs:
- name: Check links
id: lychee
- uses: lycheeverse/lychee-action@v1.9.3
+ uses: lycheeverse/lychee-action@v1.10.0
with:
fail: true
args: --max-concurrency 1 --cache --no-progress --exclude-all-private './**/*.md'
diff --git a/.github/workflows/heylogs.yml b/.github/workflows/heylogs.yml
new file mode 100644
index 0000000..c0e0bf5
--- /dev/null
+++ b/.github/workflows/heylogs.yml
@@ -0,0 +1,33 @@
+name: Heylogs
+
+on: [ push ]
+
+jobs:
+ badge-job:
+ if: startsWith(github.repository, 'nbbrd/') && startsWith(github.ref, 'refs/heads/develop')
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Setup Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin'
+ java-version: 21
+ cache: 'maven'
+
+ - name: Scan changelog
+ run: mvn -B -ntp -U com.github.nbbrd.heylogs:heylogs-maven-plugin::scan -Dheylogs.output.file=scan.json -Dheylogs.format.id=json
+
+ - name: Create badges endpoint json
+ run: |
+ mkdir heylogs
+ jq '{schemaVersion: 1, label: "unreleased changes", message: "#\(.[0].summary.unreleasedChanges)", color: "E05735", logoColor: "white", namedLogo: "keepachangelog"}' scan.json > heylogs/unreleased-changes.json
+
+ - name: Deploy badges endpoint json
+ uses: peaceiris/actions-gh-pages@v4
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_branch: badges
+ publish_dir: ./heylogs
diff --git a/.github/workflows/java-ea-maven.yml b/.github/workflows/java-ea-maven.yml
index e331b7b..a690e85 100644
--- a/.github/workflows/java-ea-maven.yml
+++ b/.github/workflows/java-ea-maven.yml
@@ -12,7 +12,7 @@ jobs:
fail-fast: false
matrix:
java: [ 21 ]
- os: [ ubuntu-latest ]
+ os: [ ubuntu-latest, macos-latest ]
name: JDK${{ matrix.java }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/java8-maven.yml b/.github/workflows/java8-maven.yml
index 77f5183..d0683de 100644
--- a/.github/workflows/java8-maven.yml
+++ b/.github/workflows/java8-maven.yml
@@ -9,7 +9,7 @@ jobs:
fail-fast: false
matrix:
java: [ 8, 21 ]
- os: [ ubuntu-latest, macOS-latest, windows-latest ]
+ os: [ ubuntu-latest, macos-13, windows-latest ]
name: JDK${{ matrix.java }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 34efa8b..ba00ee8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,19 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
+## [0.9.0] - 2024-08-28
+
+This release adds a release command that greatly improves the use of heylogs in automations.
+It also brings some code refactoring to split the code into more manageable parts.
+
+### Added
+
+- Add release command to promote the Unreleased section into a new release version section [#10](https://github.com/nbbrd/heylogs/issues/10)
+
+### Changed
+
+- Improve code modularization
+
## [0.8.1] - 2024-04-18
### Fixed
@@ -154,7 +167,8 @@ This release improves extension points and also aligns features of Maven plugin
- Initial release
-[Unreleased]: https://github.com/nbbrd/heylogs/compare/v0.8.1...HEAD
+[Unreleased]: https://github.com/nbbrd/heylogs/compare/v0.9.0...HEAD
+[0.9.0]: https://github.com/nbbrd/heylogs/compare/v0.8.1...v0.9.0
[0.8.1]: https://github.com/nbbrd/heylogs/compare/v0.8.0...v0.8.1
[0.8.0]: https://github.com/nbbrd/heylogs/compare/v0.7.2...v0.8.0
[0.7.2]: https://github.com/nbbrd/heylogs/compare/v0.7.1...v0.7.2
diff --git a/README.md b/README.md
index 0f94ff6..6ba9d33 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# heylogs
[![Download](https://img.shields.io/github/release/nbbrd/heylogs.svg)](https://github.com/nbbrd/heylogs/releases/latest)
+[![Changes](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fnbbrd%2Fheylogs%2Fbadges%2Funreleased-changes.json)](https://github.com/nbbrd/heylogs/blob/develop/CHANGELOG.md)
`heylogs` is a set of tools to deal with the [keep-a-changelog format](https://keepachangelog.com),
a changelog format designed to be human-readable.
@@ -16,11 +17,40 @@ Features:
- Checks format
- Summarizes content
- Extracts versions
+- Modify content
-[ [Library](#library) | [Command-line tool](#command-line-tool) | [Maven plugin](#maven-plugin) | [Developing](#developing) | [Contributing](#contributing) | [Licensing](#licensing) | [Related work](#related-work)]
+[ [Library](#library) | [Command-line tool](#command-line-tool) | [Maven plugin](#maven-plugin) | [Badges](#badges) | [Developing](#developing) | [Contributing](#contributing) | [Licensing](#licensing) | [Related work](#related-work)]
## Library
+Heylogs is available as a Java library.
+_Note that the API is currently in beta and might change frequently._
+
+```xml
+
+
+ com.github.nbbrd.heylogs
+ heylogs-api
+ _VERSION_
+
+
+ com.github.nbbrd.heylogs
+ heylogs-ext-github
+ _VERSION_
+ runtime
+
+ ...
+
+```
+
+The API is straightforward and has a single point of entry:
+```java
+Heylogs heylogs = Heylogs.ofServiceLoader();
+Document flexmarkDocument = parseFileWithFlexmark(file);
+List problems = heylogs.checkFormat(flexmarkDocument);
+...
+```
+
`WIP`
## Command-line tool
@@ -31,12 +61,13 @@ It requires a Java SE Runtime Environment (JRE) version 8 or later to run on suc
It provides the following commands:
-| Name | Description |
-|-----------|---------------------------------|
-| `scan` | Summarize changelog content |
-| `check` | Check changelog format |
-| `extract` | Extract versions from changelog |
-| `list` | List available resources |
+| Name | Description |
+|-----------|-------------------|
+| `check` | Check format |
+| `scan` | Summarize content |
+| `extract` | Extract versions |
+| `release` | Release changes |
+| `list` | List resources |
It follows the Unix philosophy of [“Do one thing and do it well“](https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well) by performing a single function and beeing composable.
@@ -140,12 +171,13 @@ To use the CLI without installing it:
It provides the following goals:
-| Name | Description |
-|-----------|---------------------------------|
-| `scan` | Summarize changelog content |
-| `check` | Check changelog format |
-| `extract` | Extract versions from changelog |
-| `list` | List available resources |
+| Name | Description |
+|-----------|-------------------|
+| `check` | Check format |
+| `scan` | Summarize content |
+| `extract` | Extract versions |
+| `release` | Release changes |
+| `list` | List resources |
### Examples
@@ -196,6 +228,16 @@ Extract the latest version from the changelog during a release:
```
+## Badges
+
+Heylogs make it possible to generate nice badges using a [GitHub workflow](https://github.com/nbbrd/heylogs/blob/develop/.github/workflows/heylogs.yml) and the [shields.io API](https://shields.io/badges/endpoint-badge).
+Here are some examples:
+
+![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fnbbrd%2Fheylogs%2Fbadges%2Funreleased-changes.json)
+![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fnbbrd%2Fheylogs%2Fbadges%2Funreleased-changes.json&label=changelog)
+![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fnbbrd%2Fheylogs%2Fbadges%2Funreleased-changes.json&label=changelog&logo=none)
+![Endpoint Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fnbbrd%2Fheylogs%2Fbadges%2Funreleased-changes.json&label=%20)
+
## Developing
This project is written in Java and uses [Apache Maven](https://maven.apache.org/) as a build tool.
diff --git a/heylogs-api/pom.xml b/heylogs-api/pom.xml
index d1adc01..abf74fc 100644
--- a/heylogs-api/pom.xml
+++ b/heylogs-api/pom.xml
@@ -7,7 +7,7 @@
com.github.nbbrd.heylogs
heylogs-parent
- 0.8.1
+ 0.9.0
heylogs-api
@@ -22,7 +22,7 @@
com.github.nbbrd.java-io-util
java-io-bom
- 0.0.28
+ 0.0.30
pom
import
@@ -65,17 +65,6 @@
-
- org.semver4j
- semver4j
- 5.2.3
-
-
- org.jetbrains
- annotations
-
-
-
com.github.nbbrd.java-io-util
java-io-base
@@ -84,11 +73,6 @@
com.github.nbbrd.java-io-util
java-io-http
-
- com.google.code.gson
- gson
- 2.10.1
-
@@ -102,4 +86,25 @@
test
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ test-jar
+
+
+
+ tests/**
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/heylogs-api/src/main/java/internal/heylogs/ChangelogNodes.java b/heylogs-api/src/main/java/internal/heylogs/ChangelogNodes.java
index 0129a7d..c89ba0a 100644
--- a/heylogs-api/src/main/java/internal/heylogs/ChangelogNodes.java
+++ b/heylogs-api/src/main/java/internal/heylogs/ChangelogNodes.java
@@ -3,11 +3,14 @@
import com.vladsch.flexmark.ast.BulletList;
import com.vladsch.flexmark.ast.BulletListItem;
import com.vladsch.flexmark.ast.Heading;
+import com.vladsch.flexmark.ast.Reference;
import com.vladsch.flexmark.util.ast.Node;
+import com.vladsch.flexmark.util.sequence.BasedSequence;
import nbbrd.heylogs.Nodes;
import nbbrd.heylogs.TypeOfChange;
import nbbrd.heylogs.Version;
+import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -64,4 +67,8 @@ private static List collect(Heading typeOfChange) {
.flatMap(Nodes.of(BulletListItem.class)::descendants)
.collect(toList());
}
+
+ public static Reference newReference(Version newVersion, URL newURL) {
+ return new Reference(BasedSequence.of("[" + newVersion.getRef() + "]: " + newURL), null, null);
+ }
}
diff --git a/heylogs-api/src/main/java/internal/heylogs/RuleSupport.java b/heylogs-api/src/main/java/internal/heylogs/RuleSupport.java
index 044d932..7e59747 100644
--- a/heylogs-api/src/main/java/internal/heylogs/RuleSupport.java
+++ b/heylogs-api/src/main/java/internal/heylogs/RuleSupport.java
@@ -1,12 +1,21 @@
package internal.heylogs;
import com.vladsch.flexmark.ast.LinkNodeBase;
+import com.vladsch.flexmark.util.ast.Document;
+import com.vladsch.flexmark.util.ast.Node;
import lombok.NonNull;
+import nbbrd.heylogs.Nodes;
+import nbbrd.heylogs.Problem;
+import nbbrd.heylogs.spi.Rule;
+import nbbrd.heylogs.spi.RuleIssue;
import nbbrd.io.text.Parser;
import java.net.URL;
+import java.util.List;
import java.util.Locale;
+import java.util.Objects;
import java.util.Optional;
+import java.util.stream.Stream;
public final class RuleSupport {
@@ -21,4 +30,14 @@ private RuleSupport() {
public static @NonNull Optional linkToURL(@NonNull LinkNodeBase link) {
return Parser.onURL().parseValue(link.getUrl());
}
+
+ public static @NonNull Stream problemStreamOf(@NonNull Document root, @NonNull List rules) {
+ return Nodes.walk(root)
+ .flatMap(node -> rules.stream().map(rule -> getProblemOrNull(node, rule)).filter(Objects::nonNull));
+ }
+
+ private static Problem getProblemOrNull(Node node, Rule rule) {
+ RuleIssue ruleIssueOrNull = rule.getRuleIssueOrNull(node);
+ return ruleIssueOrNull != null ? Problem.builder().rule(rule).issue(ruleIssueOrNull).build() : null;
+ }
}
diff --git a/heylogs-api/src/main/java/internal/heylogs/VersionNode.java b/heylogs-api/src/main/java/internal/heylogs/VersionNode.java
new file mode 100644
index 0000000..50b90f8
--- /dev/null
+++ b/heylogs-api/src/main/java/internal/heylogs/VersionNode.java
@@ -0,0 +1,61 @@
+package internal.heylogs;
+
+import com.vladsch.flexmark.ast.Heading;
+import com.vladsch.flexmark.ast.Reference;
+import com.vladsch.flexmark.ast.util.ReferenceRepository;
+import com.vladsch.flexmark.util.ast.Document;
+import lombok.NonNull;
+import nbbrd.heylogs.Nodes;
+import nbbrd.heylogs.Version;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static java.util.stream.Collectors.toList;
+
+@lombok.Value
+public class VersionNode {
+
+ @NonNull
+ Heading heading;
+
+ @NonNull
+ Version version;
+
+ @NonNull
+ Reference reference;
+
+ public static VersionNode of(Version version, URL url) {
+ return new VersionNode(
+ version.toHeading(), version,
+ ChangelogNodes.newReference(version, url));
+ }
+
+ public static List allOf(Document document, ReferenceRepository repository) {
+ return Nodes.of(Heading.class)
+ .descendants(document)
+ .filter(Version::isVersionLevel)
+ .map(heading -> {
+ try {
+ Version version = Version.parse(heading);
+ return new VersionNode(heading, version, Objects.requireNonNull(repository.getFromRaw(version.getRef())));
+ } catch (RuntimeException ex) {
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .collect(toList());
+ }
+
+ public static Optional findUnreleased(List list) {
+ return list.stream()
+ .filter(versionNode -> versionNode.getVersion().isUnreleased())
+ .findFirst();
+ }
+
+ public URL getURL() {
+ return URLExtractor.urlOf(getReference().getUrl());
+ }
+}
diff --git a/heylogs-api/src/main/java/internal/heylogs/VersioningSupport.java b/heylogs-api/src/main/java/internal/heylogs/VersioningSupport.java
new file mode 100644
index 0000000..85277c4
--- /dev/null
+++ b/heylogs-api/src/main/java/internal/heylogs/VersioningSupport.java
@@ -0,0 +1,19 @@
+package internal.heylogs;
+
+import nbbrd.heylogs.Version;
+import nbbrd.heylogs.spi.Versioning;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+public final class VersioningSupport {
+
+ private VersioningSupport() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+
+ public static Stream versioningStreamOf(List list, List releases) {
+ return list.stream()
+ .filter(versioning -> releases.stream().allMatch(release -> versioning.isValidVersion(release.getRef())));
+ }
+}
diff --git a/heylogs-api/src/main/java/internal/heylogs/github/GitHub.java b/heylogs-api/src/main/java/internal/heylogs/github/GitHub.java
deleted file mode 100644
index f86d19d..0000000
--- a/heylogs-api/src/main/java/internal/heylogs/github/GitHub.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package internal.heylogs.github;
-
-import lombok.NonNull;
-import nbbrd.design.DirectImpl;
-import nbbrd.heylogs.spi.Forge;
-import nbbrd.io.http.URLQueryBuilder;
-import nbbrd.io.text.Parser;
-import nbbrd.service.ServiceProvider;
-
-import java.io.UncheckedIOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-@DirectImpl
-@ServiceProvider
-public final class GitHub implements Forge {
-
- @Override
- public @NonNull String getForgeId() {
- return "github";
- }
-
- @Override
- public @NonNull String getForgeName() {
- return "GitHub";
- }
-
- @Override
- public boolean isCompareLink(@NonNull CharSequence text) {
- return Parser.of(GitHubCompareLink::parse).parseValue(text).isPresent();
- }
-
- @Override
- public @NonNull URL getBaseURL(@NonNull CharSequence text) {
- GitHubCompareLink compareLink = GitHubCompareLink.parse(text);
- try {
- return URLQueryBuilder
- .of(compareLink.getBase())
- .path(compareLink.getOwner())
- .path(compareLink.getRepo())
- .build();
- } catch (MalformedURLException ex) {
- throw new UncheckedIOException(ex);
- }
- }
-}
diff --git a/heylogs-api/src/main/java/nbbrd/heylogs/Extractor.java b/heylogs-api/src/main/java/nbbrd/heylogs/Extractor.java
deleted file mode 100644
index 13fcd2b..0000000
--- a/heylogs-api/src/main/java/nbbrd/heylogs/Extractor.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package nbbrd.heylogs;
-
-import com.vladsch.flexmark.ast.Heading;
-import com.vladsch.flexmark.ast.RefNode;
-import com.vladsch.flexmark.ast.Reference;
-import com.vladsch.flexmark.util.ast.Document;
-import com.vladsch.flexmark.util.ast.Node;
-import internal.heylogs.GuidingPrinciples;
-import lombok.NonNull;
-
-import java.time.LocalDate;
-import java.time.Year;
-import java.time.YearMonth;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import static java.util.Arrays.asList;
-
-@lombok.Value
-@lombok.Builder(toBuilder = true)
-public class Extractor {
-
- public static final Extractor DEFAULT = Extractor.builder().build();
-
- @lombok.NonNull
- @lombok.Builder.Default
- String ref = "";
-
- @lombok.NonNull
- @lombok.Builder.Default
- Pattern unreleasedPattern = Pattern.compile("^.*-SNAPSHOT$");
-
- @lombok.NonNull
- @lombok.Builder.Default
- TimeRange timeRange = TimeRange.ALL;
-
- @lombok.Builder.Default
- int limit = Integer.MAX_VALUE;
-
- @lombok.Builder.Default
- boolean ignoreContent = false;
-
- private boolean isUnreleasedPattern() {
- return unreleasedPattern.asPredicate().test(ref);
- }
-
- private boolean containsRef(@NonNull Version version) {
- return (isUnreleasedPattern() && version.isUnreleased()) || version.getRef().contains(ref);
- }
-
- public boolean contains(@NonNull Version version) {
- return containsRef(version) && timeRange.contains(version.getDate());
- }
-
- public boolean contains(@NonNull Heading heading) {
- return contains(Version.parse(heading));
- }
-
- public void extract(@NonNull Document root) throws IllegalArgumentException {
- if (Heylogs.getProblemStream(root, asList(GuidingPrinciples.values())).findFirst().isPresent()) {
- throw new IllegalArgumentException("Invalid changelog");
- }
-
- int found = 0;
- boolean keep = false;
-
- List refNodes = new ArrayList<>();
- List references = new ArrayList<>();
-
- for (Node current : root.getChildren()) {
-
- boolean versionHeading = current instanceof Heading
- && Version.isVersionLevel((Heading) current);
-
- if (versionHeading) {
- if (found >= getLimit() || !contains((Heading) current)) {
- keep = false;
- } else {
- found++;
- keep = true;
- }
- }
-
- if (keep) {
- Nodes.of(RefNode.class)
- .descendants(current)
- .map(node -> node.getReference().toString())
- .forEach(refNodes::add);
- if (versionHeading && ignoreContent) {
- keep = false;
- }
- } else {
- if (current instanceof Reference) {
- references.add((Reference) current);
- } else {
- current.unlink();
- }
- }
- }
-
- references
- .stream()
- .filter(reference -> !refNodes.contains(reference.getReference().toString()))
- .forEach(Node::unlink);
- }
-
- public static LocalDate parseLocalDate(CharSequence input) {
- try {
- return Year.parse(input).atDay(1);
- } catch (Exception ex1) {
- try {
- return YearMonth.parse(input).atDay(1);
- } catch (Exception ex2) {
- return LocalDate.parse(input);
- }
- }
- }
-}
diff --git a/heylogs-api/src/main/java/nbbrd/heylogs/Filter.java b/heylogs-api/src/main/java/nbbrd/heylogs/Filter.java
new file mode 100644
index 0000000..e9c393a
--- /dev/null
+++ b/heylogs-api/src/main/java/nbbrd/heylogs/Filter.java
@@ -0,0 +1,57 @@
+package nbbrd.heylogs;
+
+import lombok.NonNull;
+
+import java.time.LocalDate;
+import java.time.Year;
+import java.time.YearMonth;
+import java.util.regex.Pattern;
+
+@lombok.Value
+@lombok.Builder(toBuilder = true)
+public class Filter {
+
+ public static final Filter DEFAULT = Filter.builder().build();
+
+ @lombok.NonNull
+ @lombok.Builder.Default
+ String ref = "";
+
+ @lombok.NonNull
+ @lombok.Builder.Default
+ Pattern unreleasedPattern = Pattern.compile("^.*-SNAPSHOT$");
+
+ @lombok.NonNull
+ @lombok.Builder.Default
+ TimeRange timeRange = TimeRange.ALL;
+
+ @lombok.Builder.Default
+ int limit = Integer.MAX_VALUE;
+
+ @lombok.Builder.Default
+ boolean ignoreContent = false;
+
+ private boolean isUnreleasedPattern() {
+ return unreleasedPattern.asPredicate().test(ref);
+ }
+
+ private boolean containsRef(@NonNull Version version) {
+ return (isUnreleasedPattern() && version.isUnreleased()) || version.getRef().contains(ref);
+ }
+
+ public boolean contains(@NonNull Version version) {
+ return containsRef(version) && timeRange.contains(version.getDate());
+ }
+
+ public static @NonNull LocalDate parseLocalDate(@NonNull CharSequence input) {
+ try {
+ return Year.parse(input).atDay(1);
+ } catch (Exception ex1) {
+ try {
+ return YearMonth.parse(input).atDay(1);
+ } catch (Exception ex2) {
+ return LocalDate.parse(input);
+ }
+ }
+ }
+}
diff --git a/heylogs-api/src/main/java/nbbrd/heylogs/Heylogs.java b/heylogs-api/src/main/java/nbbrd/heylogs/Heylogs.java
index ef794ae..9a01972 100644
--- a/heylogs-api/src/main/java/nbbrd/heylogs/Heylogs.java
+++ b/heylogs-api/src/main/java/nbbrd/heylogs/Heylogs.java
@@ -1,6 +1,8 @@
package nbbrd.heylogs;
import com.vladsch.flexmark.ast.Heading;
+import com.vladsch.flexmark.ast.RefNode;
+import com.vladsch.flexmark.ast.Reference;
import com.vladsch.flexmark.ast.util.ReferenceRepository;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Document;
@@ -8,24 +10,24 @@
import internal.heylogs.ChangelogNodes;
import internal.heylogs.GuidingPrinciples;
import internal.heylogs.URLExtractor;
+import internal.heylogs.VersionNode;
import lombok.NonNull;
import nbbrd.design.MightBePromoted;
import nbbrd.design.StaticFactoryMethod;
-import nbbrd.design.VisibleForTesting;
import nbbrd.heylogs.spi.*;
import java.io.IOException;
import java.net.URL;
+import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
+import static internal.heylogs.RuleSupport.problemStreamOf;
+import static internal.heylogs.VersioningSupport.versioningStreamOf;
import static java.util.Arrays.asList;
-import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
import static nbbrd.heylogs.TimeRange.toTimeRange;
-import static nbbrd.heylogs.Util.illegalArgumentToNull;
@lombok.Value
@lombok.Builder(toBuilder = true)
@@ -58,130 +60,155 @@ public class Heylogs {
@lombok.Singular
List forges;
- public @NonNull List validate(@NonNull Document doc) {
- return getProblemStream(doc, rules).collect(toList());
+ public @NonNull List checkFormat(@NonNull Document document) {
+ return problemStreamOf(document, rules).collect(toList());
}
- public @NonNull List getResources() {
- return concat(
- rules.stream().map(Heylogs::asResource),
- formats.stream().map(Heylogs::asResource),
- versionings.stream().map(Heylogs::asResource),
- forges.stream().map(Heylogs::asResource)
- )
- .sorted(comparing(Resource::getType).thenComparing(Resource::getCategory).thenComparing(Resource::getId))
- .collect(toList());
- }
+ public void extractVersions(@NonNull Document document, @NonNull Filter filter) {
+ if (isNotValidAgainstGuidingPrinciples(document)) {
+ throw new IllegalArgumentException("Invalid changelog");
+ }
- private static Resource asResource(Rule rule) {
- return Resource
- .builder()
- .type("rule")
- .category(rule.getRuleCategory())
- .id(rule.getRuleId())
- .name(rule.getRuleName())
- .build();
- }
+ int found = 0;
+ boolean keep = false;
+
+ List refNodes = new ArrayList<>();
+ List references = new ArrayList<>();
+
+ for (Node current : document.getChildren()) {
+
+ boolean versionHeading = current instanceof Heading
+ && Version.isVersionLevel((Heading) current);
+
+ if (versionHeading) {
+ if (found >= filter.getLimit() || !filter.contains(Version.parse((Heading) current))) {
+ keep = false;
+ } else {
+ found++;
+ keep = true;
+ }
+ }
+
+ if (keep) {
+ Nodes.of(RefNode.class)
+ .descendants(current)
+ .map(node -> node.getReference().toString())
+ .forEach(refNodes::add);
+ if (versionHeading && filter.isIgnoreContent()) {
+ keep = false;
+ }
+ } else {
+ if (current instanceof Reference) {
+ references.add((Reference) current);
+ } else {
+ current.unlink();
+ }
+ }
+ }
- private static Resource asResource(Format format) {
- return Resource
- .builder()
- .type("format")
- .category(format.getFormatCategory())
- .id(format.getFormatId())
- .name(format.getFormatName())
- .build();
+ references
+ .stream()
+ .filter(reference -> !refNodes.contains(reference.getReference().toString()))
+ .forEach(Node::unlink);
}
- private static Resource asResource(Versioning versioning) {
- return Resource
- .builder()
- .type("versioning")
- .category("main")
- .id(versioning.getVersioningId())
- .name(versioning.getVersioningName())
- .build();
+ public @NonNull List listResources() {
+ return concat(
+ rules.stream().map(Resource::of),
+ formats.stream().map(Resource::of),
+ versionings.stream().map(Resource::of),
+ forges.stream().map(Resource::of)
+ ).sorted(Resource.DEFAULT_COMPARATOR).collect(toList());
}
- private static Resource asResource(Forge forge) {
- return Resource
- .builder()
- .type("forge")
- .category("main")
- .id(forge.getForgeId())
- .name(forge.getForgeName())
- .build();
- }
+ public void releaseChanges(@NonNull Document document, @NonNull Version newVersion, @NonNull String versionTagPrefix) {
+ if (isNotValidAgainstGuidingPrinciples(document)) {
+ throw new IllegalArgumentException("Invalid changelog");
+ }
- public void formatProblems(@NonNull String formatId, @NonNull Appendable appendable, @NonNull List list) throws IOException {
- getFormatById(formatId).formatProblems(appendable, list);
- }
+ ReferenceRepository repository = Parser.REFERENCES.get(document);
+ List versions = VersionNode.allOf(document, repository);
- public void formatStatus(@NonNull String formatId, @NonNull Appendable appendable, @NonNull List list) throws IOException {
- getFormatById(formatId).formatStatus(appendable, list);
- }
+ VersionNode unreleased = VersionNode.findUnreleased(versions)
+ .orElseThrow(() -> new IllegalArgumentException("Cannot locate unreleased header"));
- public void formatResources(@NonNull String formatId, @NonNull Appendable appendable, @NonNull List list) throws IOException {
- getFormatById(formatId).formatResources(appendable, list);
+ Forge forge = findForge(unreleased)
+ .orElseThrow(() -> new IllegalArgumentException("Cannot determine forge"));
+
+ URL releaseURL = forge.deriveCompareLink(unreleased.getURL(), versionTagPrefix + newVersion.getRef());
+ VersionNode release = VersionNode.of(newVersion, releaseURL);
+
+ URL updatedURL = forge.deriveCompareLink(releaseURL, "HEAD");
+ VersionNode updated = VersionNode.of(unreleased.getVersion(), updatedURL);
+
+ repository.putRawKey(release.getReference().getReference(), release.getReference());
+ repository.putRawKey(updated.getReference().getReference(), updated.getReference());
+
+ unreleased.getHeading().appendChild(release.getHeading());
+ unreleased.getReference().insertAfter(release.getReference());
+ unreleased.getReference().insertBefore(updated.getReference());
+ unreleased.getReference().unlink();
}
- public @NonNull Summary scan(@NonNull Node document) {
- if (getProblemStream(document, asList(GuidingPrinciples.values())).findFirst().isPresent())
- return Summary.builder().valid(false).build();
+ public @NonNull Summary scanContent(@NonNull Document document) {
+ if (isNotValidAgainstGuidingPrinciples(document)) {
+ return Summary.INVALID;
+ }
+
+ ReferenceRepository repository = Parser.REFERENCES.get(document);
+ List versions = VersionNode.allOf(document, repository);
+
+ if (versions.isEmpty()) {
+ return Summary.EMPTY;
+ }
- List releases = Nodes.of(Heading.class)
- .descendants(document)
- .filter(Version::isVersionLevel)
- .map(illegalArgumentToNull(Version::parse))
- .filter(Objects::nonNull)
+ List releases = versions
+ .stream()
+ .map(VersionNode::getVersion)
.filter(version -> !version.isUnreleased())
.collect(toList());
- long unreleasedChanges = ChangelogNodes.getUnreleasedHeading(document)
+ long unreleasedChanges = VersionNode.findUnreleased(versions)
+ .map(VersionNode::getHeading)
.map(ChangelogNodes::getBulletListsByTypeOfChange)
.map(o -> o.values().stream().mapToLong(List::size).sum())
.orElse(0L);
- Optional forgeURL = getLatestVersionURL(document);
- Forge forgeOrNull = forgeURL.flatMap(this::getForge).orElse(null);
+ VersionNode first = versions.get(0);
+ Forge forgeOrNull = findForge(first).orElse(null);
return Summary
.builder()
.valid(true)
.releaseCount(releases.size())
.timeRange(releases.stream().map(Version::getDate).collect(toTimeRange()).orElse(TimeRange.ALL))
- .compatibilities(getCompatibilities(releases))
+ .compatibilities(versioningStreamOf(versionings, releases).map(Versioning::getVersioningName).collect(toList()))
.unreleasedChanges((int) unreleasedChanges)
.forgeName(forgeOrNull != null ? forgeOrNull.getForgeName() : null)
- .forgeURL(forgeURL.map(x -> getBaseURL(forgeOrNull, x)).orElse(null))
+ .forgeURL(getBaseURL(forgeOrNull, first.getURL()))
.build();
}
- private URL getBaseURL(Forge forgeOrNull, CharSequence url) {
- return forgeOrNull != null ? forgeOrNull.getBaseURL(url) : URLExtractor.baseOf(URLExtractor.urlOf(url));
+ public void formatProblems(@NonNull String formatId, @NonNull Appendable appendable, @NonNull List list) throws IOException {
+ getFormatById(formatId).formatProblems(appendable, list);
+ }
+
+ public void formatStatus(@NonNull String formatId, @NonNull Appendable appendable, @NonNull List list) throws IOException {
+ getFormatById(formatId).formatStatus(appendable, list);
}
- private Optional getForge(String url) {
- return forges.stream().filter(forge -> forge.isCompareLink(url)).findFirst();
+ public void formatResources(@NonNull String formatId, @NonNull Appendable appendable, @NonNull List list) throws IOException {
+ getFormatById(formatId).formatResources(appendable, list);
}
- private static Optional getLatestVersionURL(Node document) {
- return Nodes.of(Heading.class)
- .descendants(document)
- .filter(Version::isVersionLevel)
- .map(heading -> {
- ReferenceRepository repository = Parser.REFERENCES.get(heading.getDocument());
- String normalizeRef = repository.normalizeKey(Version.parse(heading).getRef());
- return Objects.requireNonNull(repository.get(normalizeRef)).getUrl().toString();
- })
- .findFirst();
+ private URL getBaseURL(Forge forgeOrNull, URL url) {
+ return forgeOrNull != null ? forgeOrNull.getProjectURL(url) : URLExtractor.baseOf(url);
}
- private List getCompatibilities(List releases) {
- return versionings.stream()
- .filter(versioning -> releases.stream().allMatch(release -> versioning.isValidVersion(release.getRef())))
- .map(Versioning::getVersioningName)
- .collect(toList());
+ private Optional findForge(VersionNode node) {
+ return forges.stream()
+ .filter(forge -> forge.isCompareLink(node.getURL()))
+ .findFirst();
}
private Format getFormatById(String formatId) throws IOException {
@@ -191,19 +218,12 @@ private Format getFormatById(String formatId) throws IOException {
.orElseThrow(() -> new IOException("Cannot find format '" + formatId + "'"));
}
- @VisibleForTesting
- static Stream getProblemStream(Node root, List rules) {
- return Nodes.walk(root)
- .flatMap(node -> rules.stream().map(rule -> getProblemOrNull(node, rule)).filter(Objects::nonNull));
- }
+ public static final String FIRST_FORMAT_AVAILABLE = "";
- private static Problem getProblemOrNull(Node node, Rule rule) {
- RuleIssue ruleIssueOrNull = rule.getRuleIssueOrNull(node);
- return ruleIssueOrNull != null ? Problem.builder().rule(rule).issue(ruleIssueOrNull).build() : null;
+ private static boolean isNotValidAgainstGuidingPrinciples(Document document) {
+ return problemStreamOf(document, asList(GuidingPrinciples.values())).findFirst().isPresent();
}
- public static final String FIRST_FORMAT_AVAILABLE = "";
-
@MightBePromoted
@SafeVarargs
private static Stream concat(Stream first, Stream... rest) {
diff --git a/heylogs-api/src/main/java/nbbrd/heylogs/Resource.java b/heylogs-api/src/main/java/nbbrd/heylogs/Resource.java
index fce76cc..6387478 100644
--- a/heylogs-api/src/main/java/nbbrd/heylogs/Resource.java
+++ b/heylogs-api/src/main/java/nbbrd/heylogs/Resource.java
@@ -1,13 +1,70 @@
package nbbrd.heylogs;
import lombok.NonNull;
+import nbbrd.heylogs.spi.Forge;
+import nbbrd.heylogs.spi.Format;
+import nbbrd.heylogs.spi.Rule;
+import nbbrd.heylogs.spi.Versioning;
+
+import java.util.Comparator;
+
+import static java.util.Comparator.comparing;
@lombok.Value
@lombok.Builder
public class Resource {
- @NonNull String type;
- @NonNull String category;
- @NonNull String id;
- @NonNull String name;
+ @NonNull
+ String type;
+ @NonNull
+ String category;
+ @NonNull
+ String id;
+ @NonNull
+ String name;
+
+ static Resource of(Rule rule) {
+ return Resource
+ .builder()
+ .type("rule")
+ .category(rule.getRuleCategory())
+ .id(rule.getRuleId())
+ .name(rule.getRuleName())
+ .build();
+ }
+
+ static Resource of(Format format) {
+ return Resource
+ .builder()
+ .type("format")
+ .category(format.getFormatCategory())
+ .id(format.getFormatId())
+ .name(format.getFormatName())
+ .build();
+ }
+
+ static Resource of(Versioning versioning) {
+ return Resource
+ .builder()
+ .type("versioning")
+ .category("main")
+ .id(versioning.getVersioningId())
+ .name(versioning.getVersioningName())
+ .build();
+ }
+
+ static Resource of(Forge forge) {
+ return Resource
+ .builder()
+ .type("forge")
+ .category("main")
+ .id(forge.getForgeId())
+ .name(forge.getForgeName())
+ .build();
+ }
+
+ static final Comparator DEFAULT_COMPARATOR
+ = comparing(Resource::getType)
+ .thenComparing(Resource::getCategory)
+ .thenComparing(Resource::getId);
}
diff --git a/heylogs-api/src/main/java/nbbrd/heylogs/Summary.java b/heylogs-api/src/main/java/nbbrd/heylogs/Summary.java
index e36b5a2..e57308f 100644
--- a/heylogs-api/src/main/java/nbbrd/heylogs/Summary.java
+++ b/heylogs-api/src/main/java/nbbrd/heylogs/Summary.java
@@ -7,6 +7,9 @@
@lombok.Builder
public class Summary {
+ public static final Summary INVALID = Summary.builder().valid(false).build();
+ public static final Summary EMPTY = Summary.builder().valid(true).build();
+
boolean valid;
@lombok.Builder.Default
diff --git a/heylogs-api/src/main/java/nbbrd/heylogs/spi/Forge.java b/heylogs-api/src/main/java/nbbrd/heylogs/spi/Forge.java
index cb912d1..ea57ec3 100644
--- a/heylogs-api/src/main/java/nbbrd/heylogs/spi/Forge.java
+++ b/heylogs-api/src/main/java/nbbrd/heylogs/spi/Forge.java
@@ -19,8 +19,11 @@ public interface Forge {
@NonNull
String getForgeName();
- boolean isCompareLink(@NonNull CharSequence text);
+ boolean isCompareLink(@NonNull URL url);
@NonNull
- URL getBaseURL(@NonNull CharSequence text);
+ URL getProjectURL(@NonNull URL url);
+
+ @NonNull
+ URL deriveCompareLink(@NonNull URL latest, @NonNull String nextTag);
}
diff --git a/heylogs-api/src/test/java/internal/heylogs/ChangelogNodesTest.java b/heylogs-api/src/test/java/internal/heylogs/ChangelogNodesTest.java
index 4c10aba..ea5e683 100644
--- a/heylogs-api/src/test/java/internal/heylogs/ChangelogNodesTest.java
+++ b/heylogs-api/src/test/java/internal/heylogs/ChangelogNodesTest.java
@@ -8,8 +8,8 @@
import java.util.List;
import java.util.Map;
-import static _test.Sample.asHeading;
-import static _test.Sample.using;
+import static tests.heylogs.api.Sample.asHeading;
+import static tests.heylogs.api.Sample.using;
import static internal.heylogs.ChangelogNodes.*;
import static org.assertj.core.api.Assertions.assertThat;
diff --git a/heylogs-api/src/test/java/internal/heylogs/ExtendedRulesTest.java b/heylogs-api/src/test/java/internal/heylogs/ExtendedRulesTest.java
index e99c17d..9268d7b 100644
--- a/heylogs-api/src/test/java/internal/heylogs/ExtendedRulesTest.java
+++ b/heylogs-api/src/test/java/internal/heylogs/ExtendedRulesTest.java
@@ -1,31 +1,28 @@
package internal.heylogs;
-import _test.Sample;
import com.vladsch.flexmark.ast.LinkNodeBase;
import com.vladsch.flexmark.util.ast.Node;
import nbbrd.heylogs.Nodes;
-import nbbrd.heylogs.spi.Rule;
import nbbrd.heylogs.spi.RuleIssue;
-import nbbrd.heylogs.spi.RuleLoader;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
+import tests.heylogs.api.Sample;
import java.util.Objects;
-import static _test.Sample.using;
import static internal.heylogs.ExtendedRules.NO_RULE_ISSUE;
import static internal.heylogs.ExtendedRules.validateConsistentSeparator;
import static nbbrd.heylogs.Nodes.of;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Index.atIndex;
+import static tests.heylogs.api.Sample.using;
+import static tests.heylogs.spi.RuleAssert.assertRuleCompliance;
public class ExtendedRulesTest {
@Test
- public void testIdPattern() {
- assertThat(ExtendedRules.values())
- .extracting(Rule::getRuleId)
- .allMatch(RuleLoader.ID_PATTERN.asPredicate());
+ public void testCompliance() {
+ assertRuleCompliance(new ExtendedRules.Batch());
}
@Test
diff --git a/heylogs-api/src/test/java/internal/heylogs/GuidingPrinciplesTest.java b/heylogs-api/src/test/java/internal/heylogs/GuidingPrinciplesTest.java
index 69e08c5..73a2967 100644
--- a/heylogs-api/src/test/java/internal/heylogs/GuidingPrinciplesTest.java
+++ b/heylogs-api/src/test/java/internal/heylogs/GuidingPrinciplesTest.java
@@ -2,28 +2,25 @@
import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.util.ast.Node;
-import nbbrd.heylogs.spi.Rule;
import nbbrd.heylogs.spi.RuleIssue;
-import nbbrd.heylogs.spi.RuleLoader;
import org.junit.jupiter.api.Test;
import java.util.Objects;
-import static _test.Sample.using;
import static internal.heylogs.GuidingPrinciples.validateForHumans;
import static internal.heylogs.GuidingPrinciples.validateLatestVersionFirst;
import static nbbrd.heylogs.Nodes.of;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Index.atIndex;
+import static tests.heylogs.api.Sample.using;
+import static tests.heylogs.spi.RuleAssert.assertRuleCompliance;
public class
GuidingPrinciplesTest {
@Test
- public void testIdPattern() {
- assertThat(GuidingPrinciples.values())
- .extracting(Rule::getRuleId)
- .allMatch(RuleLoader.ID_PATTERN.asPredicate());
+ public void testCompliance() {
+ assertRuleCompliance(new GuidingPrinciples.Batch());
}
@Test
diff --git a/heylogs-api/src/test/java/internal/heylogs/StylishFormatTest.java b/heylogs-api/src/test/java/internal/heylogs/StylishFormatTest.java
index 2f6f252..5bd3c1d 100644
--- a/heylogs-api/src/test/java/internal/heylogs/StylishFormatTest.java
+++ b/heylogs-api/src/test/java/internal/heylogs/StylishFormatTest.java
@@ -5,14 +5,20 @@
import nbbrd.heylogs.spi.FormatType;
import org.junit.jupiter.api.Test;
-import static _test.Sample.*;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
+import static tests.heylogs.api.Sample.*;
+import static tests.heylogs.spi.FormatAssert.assertFormatCompliance;
class StylishFormatTest {
+ @Test
+ public void testCompliance() {
+ assertFormatCompliance(new StylishFormat());
+ }
+
@Test
public void testIdPattern() {
assertThat(new StylishFormat().getFormatId())
diff --git a/heylogs-api/src/test/java/internal/heylogs/github/GitHubTest.java b/heylogs-api/src/test/java/internal/heylogs/github/GitHubTest.java
deleted file mode 100644
index 7c10290..0000000
--- a/heylogs-api/src/test/java/internal/heylogs/github/GitHubTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package internal.heylogs.github;
-
-import internal.heylogs.URLExtractor;
-import nbbrd.heylogs.spi.Forge;
-import nbbrd.heylogs.spi.ForgeLoader;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-
-class GitHubTest {
-
- @Test
- void testGetForgeId() {
- assertThat(new GitHub().getForgeId())
- .matches(ForgeLoader.ID_PATTERN);
- }
-
- @Test
- void testGetForgeName() {
- assertThat(new GitHub().getForgeName())
- .isNotBlank();
- }
-
- @Test
- void testIsCompareLink() {
- Forge x = new GitHub();
- assertThat(x.isCompareLink("")).isFalse();
- assertThat(x.isCompareLink("https://github.com/nbbrd/heylogs/compare/v0.7.2...HEAD")).isTrue();
- }
-
- @Test
- void testGetBaseURL() {
- Forge x = new GitHub();
-
- assertThatIllegalArgumentException()
- .isThrownBy(() -> x.getBaseURL(""));
-
- assertThat(x.getBaseURL("https://github.com/nbbrd/heylogs/compare/v0.7.2...HEAD"))
- .isEqualTo(URLExtractor.urlOf("https://github.com/nbbrd/heylogs"));
- }
-}
\ No newline at end of file
diff --git a/heylogs-api/src/test/java/internal/heylogs/semver/SemVerTest.java b/heylogs-api/src/test/java/internal/heylogs/semver/SemVerTest.java
deleted file mode 100644
index af8239e..0000000
--- a/heylogs-api/src/test/java/internal/heylogs/semver/SemVerTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package internal.heylogs.semver;
-
-import nbbrd.heylogs.spi.VersioningLoader;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-class SemVerTest {
-
- @Test
- void getVersioningId() {
- assertThat(new SemVer().getVersioningId())
- .matches(VersioningLoader.ID_PATTERN);
- }
-
- @Test
- void getVersioningName() {
- assertThat(new SemVer().getVersioningName())
- .isNotBlank();
- }
-
- @Test
- void isValidVersion() {
- SemVer x = new SemVer();
- assertThat(x.isValidVersion("1.1.0")).isTrue();
- assertThat(x.isValidVersion(".1.0")).isFalse();
- }
-}
\ No newline at end of file
diff --git a/heylogs-api/src/test/java/nbbrd/heylogs/ChangelogTest.java b/heylogs-api/src/test/java/nbbrd/heylogs/ChangelogTest.java
index edd41f3..675f902 100644
--- a/heylogs-api/src/test/java/nbbrd/heylogs/ChangelogTest.java
+++ b/heylogs-api/src/test/java/nbbrd/heylogs/ChangelogTest.java
@@ -1,12 +1,12 @@
package nbbrd.heylogs;
-import _test.Sample;
+import tests.heylogs.api.Sample;
import com.vladsch.flexmark.ast.Heading;
import org.junit.jupiter.api.Test;
-import static _test.Sample.using;
+import static tests.heylogs.api.Sample.using;
import static nbbrd.heylogs.Changelog.parse;
-import static _test.Sample.asHeading;
+import static tests.heylogs.api.Sample.asHeading;
import static org.assertj.core.api.Assertions.*;
public class ChangelogTest {
diff --git a/heylogs-api/src/test/java/nbbrd/heylogs/ExtractorTest.java b/heylogs-api/src/test/java/nbbrd/heylogs/FilterTest.java
similarity index 63%
rename from heylogs-api/src/test/java/nbbrd/heylogs/ExtractorTest.java
rename to heylogs-api/src/test/java/nbbrd/heylogs/FilterTest.java
index 5755aae..95f1565 100644
--- a/heylogs-api/src/test/java/nbbrd/heylogs/ExtractorTest.java
+++ b/heylogs-api/src/test/java/nbbrd/heylogs/FilterTest.java
@@ -1,21 +1,17 @@
package nbbrd.heylogs;
-import _test.Sample;
-import com.vladsch.flexmark.util.ast.Document;
import org.assertj.core.api.Condition;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.util.function.Function;
-import static _test.Sample.using;
-import static nbbrd.heylogs.Extractor.builder;
-import static nbbrd.heylogs.Extractor.parseLocalDate;
+import static nbbrd.heylogs.Filter.builder;
+import static nbbrd.heylogs.Filter.parseLocalDate;
import static nbbrd.heylogs.Version.HYPHEN;
import static org.assertj.core.api.Assertions.*;
-import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
-public class ExtractorTest {
+public class FilterTest {
@Test
public void testRef() {
@@ -64,7 +60,7 @@ public void testRef() {
@Test
public void testTimeRange() {
- Function onTimeRange = o -> builder().timeRange(o).build();
+ Function onTimeRange = o -> builder().timeRange(o).build();
assertThat(TimeRange.ALL)
.extracting(onTimeRange)
@@ -103,47 +99,6 @@ public void testTimeRange() {
.isNot(containing(v1_0_0));
}
-
- @Test
- public void testExtract() {
- Function usingMain = extractor -> {
- Document doc = using("/Main.md");
- extractor.extract(doc);
- return Sample.FORMATTER.render(doc);
- };
-
- assertThat(builder().ref("1.1.0").build())
- .extracting(usingMain, STRING)
- .isEqualTo(
- "## [1.1.0] - 2019-02-15\n" +
- "\n" +
- "### Added\n" +
- "\n" +
- "- Danish translation from [@frederikspang](https://github.com/frederikspang).\n" +
- "- Georgian translation from [@tatocaster](https://github.com/tatocaster).\n" +
- "- Changelog inconsistency section in Bad Practices\n" +
- "\n" +
- "### Changed\n" +
- "\n" +
- "- Fixed typos in Italian translation from [@lorenzo-arena](https://github.com/lorenzo-arena).\n" +
- "- Fixed typos in Indonesian translation from [@ekojs](https://github.com/ekojs).\n" +
- "\n" +
- "[1.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0\n" +
- "\n");
-
- assertThat(builder().ref("1.1.0").ignoreContent(true).build())
- .extracting(usingMain, STRING)
- .isEqualTo(
- "## [1.1.0] - 2019-02-15\n" +
- "\n" +
- "[1.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0\n" +
- "\n");
-
- assertThat(builder().ref("zzz").build())
- .extracting(usingMain, STRING)
- .isEmpty();
- }
-
@Test
public void testParseLocalDate() {
assertThatNullPointerException()
@@ -162,7 +117,7 @@ public void testParseLocalDate() {
.isEqualTo("2010-02-03");
}
- private static Condition containing(Version version) {
+ private static Condition containing(Version version) {
return new Condition<>(parent -> parent.contains(version), "Must contain %s", version);
}
diff --git a/heylogs-api/src/test/java/nbbrd/heylogs/HeylogsTest.java b/heylogs-api/src/test/java/nbbrd/heylogs/HeylogsTest.java
index dcb1e19..95840f4 100644
--- a/heylogs-api/src/test/java/nbbrd/heylogs/HeylogsTest.java
+++ b/heylogs-api/src/test/java/nbbrd/heylogs/HeylogsTest.java
@@ -1,23 +1,32 @@
package nbbrd.heylogs;
+import com.vladsch.flexmark.util.ast.Document;
+import com.vladsch.flexmark.util.ast.Node;
import internal.heylogs.StylishFormat;
-import internal.heylogs.semver.SemVerRule;
+import lombok.NonNull;
+import nbbrd.design.MightBePromoted;
+import nbbrd.heylogs.spi.Forge;
import nbbrd.heylogs.spi.Rule;
import nbbrd.heylogs.spi.RuleIssue;
+import nbbrd.heylogs.spi.RuleSeverity;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.junit.jupiter.api.Test;
+import tests.heylogs.api.Sample;
import java.io.IOException;
+import java.net.URL;
import java.time.LocalDate;
import java.util.List;
+import java.util.function.Function;
-import static _test.Sample.using;
import static internal.heylogs.URLExtractor.urlOf;
import static java.util.Collections.singletonList;
+import static nbbrd.heylogs.Filter.builder;
import static nbbrd.heylogs.Heylogs.FIRST_FORMAT_AVAILABLE;
import static nbbrd.heylogs.spi.RuleSeverity.ERROR;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIOException;
+import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.InstanceOfAssertFactories.list;
+import static tests.heylogs.api.Sample.using;
public class HeylogsTest {
@@ -33,48 +42,118 @@ public void testFactories() {
.map(Rule::getRuleId)
.doesNotContain("semver");
- assertThat(Heylogs.ofServiceLoader().toBuilder().rule(new SemVerRule()).build())
+ assertThat(Heylogs.ofServiceLoader().toBuilder().rule(new MockedRule()).build())
.extracting(Heylogs::getRules, list(Rule.class))
.hasSizeGreaterThan(1)
.map(Rule::getRuleId)
- .contains("semver");
+ .contains("mocked");
}
@Test
- public void testValidate() {
- assertThat(Heylogs.builder().build().validate(using("/InvalidVersion.md")))
+ public void testCheckFormat() {
+ assertThat(Heylogs.builder().build().checkFormat(using("/InvalidVersion.md")))
.isEmpty();
- assertThat(Heylogs.ofServiceLoader().validate(using("/InvalidVersion.md")))
+ assertThat(Heylogs.ofServiceLoader().checkFormat(using("/InvalidVersion.md")))
.isNotEmpty();
}
@Test
- public void testFormatProblems() throws IOException {
- List checks = singletonList(Check.builder().source("file1").problem(Problem.builder().id("rule1").severity(ERROR).issue(RuleIssue.builder().message("some message").line(10).column(20).build()).build()).build());
+ public void testExtractVersions() {
+ Heylogs x = Heylogs.ofServiceLoader();
- assertThatIOException()
- .isThrownBy(() -> Heylogs.builder().build().formatProblems(FIRST_FORMAT_AVAILABLE, new StringBuilder(), checks));
+ Function usingMain = extractor -> {
+ Document doc = using("/Main.md");
+ x.extractVersions(doc, extractor);
+ return Sample.FORMATTER.render(doc);
+ };
- assertThatIOException()
- .isThrownBy(() -> Heylogs.ofServiceLoader().formatProblems("other", new StringBuilder(), checks));
+ assertThat(builder().ref("1.1.0").build())
+ .extracting(usingMain, STRING)
+ .isEqualTo(
+ "## [1.1.0] - 2019-02-15\n" +
+ "\n" +
+ "### Added\n" +
+ "\n" +
+ "- Danish translation from [@frederikspang](https://github.com/frederikspang).\n" +
+ "- Georgian translation from [@tatocaster](https://github.com/tatocaster).\n" +
+ "- Changelog inconsistency section in Bad Practices\n" +
+ "\n" +
+ "### Changed\n" +
+ "\n" +
+ "- Fixed typos in Italian translation from [@lorenzo-arena](https://github.com/lorenzo-arena).\n" +
+ "- Fixed typos in Indonesian translation from [@ekojs](https://github.com/ekojs).\n" +
+ "\n" +
+ "[1.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0\n" +
+ "\n");
- StringBuilder output = new StringBuilder();
- Heylogs.ofServiceLoader().formatProblems(StylishFormat.ID, output, checks);
- assertThat(output.toString())
- .isEqualToIgnoringNewLines(
- "file1\n" +
- " 10:20 error some message rule1\n" +
- " \n" +
- " 1 problem\n"
- );
+ assertThat(builder().ref("1.1.0").ignoreContent(true).build())
+ .extracting(usingMain, STRING)
+ .isEqualTo(
+ "## [1.1.0] - 2019-02-15\n" +
+ "\n" +
+ "[1.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0\n" +
+ "\n");
+
+ assertThat(builder().ref("zzz").build())
+ .extracting(usingMain, STRING)
+ .isEmpty();
}
@Test
- void testScan() {
- Heylogs x = Heylogs.ofServiceLoader();
+ public void testListResources() {
+ assertThat(Heylogs.builder().build().listResources())
+ .isEmpty();
- assertThat(x.scan(using("/Empty.md")))
+ assertThat(Heylogs.ofServiceLoader().listResources())
+ .isNotEmpty();
+ }
+
+ @Test
+ public void testReleaseChanges() {
+ Heylogs x = Heylogs.ofServiceLoader()
+ .toBuilder()
+ .forge(new MockedForge())
+ .build();
+
+ Version v123 = Version.of("1.2.3", Version.HYPHEN, LocalDate.of(2010, 1, 1));
+
+ assertThatIllegalArgumentException().isThrownBy(() -> releaseChangesToString(x, using("/Empty.md"), v123))
+ .withMessageContaining("Invalid changelog");
+
+ assertThat(releaseChangesToString(x, using("/Main.md"), v123))
+ .contains(
+ "## [Unreleased]",
+ "## [1.2.3] - 2010-01-01",
+ "[Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.2.3...HEAD",
+ "[1.2.3]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.1.0...v1.2.3")
+ .doesNotContain("[unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.1.0...HEAD");
+
+ assertThat(releaseChangesToString(x, using("/UnreleasedChanges.md"), v123))
+ .contains(
+ "## [Unreleased]",
+ "## [1.2.3] - 2010-01-01",
+ "[Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.2.3...HEAD",
+ "[1.2.3]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.1.0...v1.2.3")
+ .doesNotContain("[unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.1.0...HEAD");
+
+ assertThat(releaseChangesToString(x, using("/FirstRelease.md"), v123))
+ .contains(
+ "## [Unreleased]",
+ "## [1.2.3] - 2010-01-01",
+ "[Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.2.3...HEAD",
+ "[1.2.3]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.2.3...v1.2.3")
+ .doesNotContain("[unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/HEAD...HEAD");
+ }
+
+ @Test
+ public void testScanContent() {
+ Heylogs x = Heylogs.ofServiceLoader()
+ .toBuilder()
+ .forge(new MockedForge())
+ .build();
+
+ assertThat(x.scanContent(using("/Empty.md")))
.isEqualTo(Summary
.builder()
.valid(false)
@@ -84,20 +163,20 @@ void testScan() {
.build()
);
- assertThat(x.scan(using("/Main.md")))
+ assertThat(x.scanContent(using("/Main.md")))
.isEqualTo(Summary
- .builder()
- .valid(true)
- .releaseCount(13)
- .timeRange(TimeRange.of(LocalDate.of(2014, 5, 31), LocalDate.of(2019, 2, 15)))
- .compatibility("Semantic Versioning")
- .unreleasedChanges(2)
- .forgeName("GitHub")
- .forgeURL(urlOf("https://github.com/olivierlacan/keep-a-changelog"))
- .build()
+ .builder()
+ .valid(true)
+ .releaseCount(13)
+ .timeRange(TimeRange.of(LocalDate.of(2014, 5, 31), LocalDate.of(2019, 2, 15)))
+// .compatibility("Semantic Versioning")
+ .unreleasedChanges(2)
+ .forgeName("GitHub")
+ .forgeURL(urlOf("https://github.com/olivierlacan/keep-a-changelog"))
+ .build()
);
- assertThat(x.scan(using("/InvalidSemver.md")))
+ assertThat(x.scanContent(using("/InvalidSemver.md")))
.isEqualTo(Summary
.builder()
.valid(true)
@@ -109,7 +188,7 @@ void testScan() {
.build()
);
- assertThat(x.scan(using("/InvalidVersion.md")))
+ assertThat(x.scanContent(using("/InvalidVersion.md")))
.isEqualTo(Summary
.builder()
.valid(false)
@@ -120,6 +199,27 @@ void testScan() {
);
}
+ @Test
+ public void testFormatProblems() throws IOException {
+ List checks = singletonList(Check.builder().source("file1").problem(Problem.builder().id("rule1").severity(ERROR).issue(RuleIssue.builder().message("some message").line(10).column(20).build()).build()).build());
+
+ assertThatIOException()
+ .isThrownBy(() -> Heylogs.builder().build().formatProblems(FIRST_FORMAT_AVAILABLE, new StringBuilder(), checks));
+
+ assertThatIOException()
+ .isThrownBy(() -> Heylogs.ofServiceLoader().formatProblems("other", new StringBuilder(), checks));
+
+ StringBuilder output = new StringBuilder();
+ Heylogs.ofServiceLoader().formatProblems(StylishFormat.ID, output, checks);
+ assertThat(output.toString())
+ .isEqualToIgnoringNewLines(
+ "file1\n" +
+ " 10:20 error some message rule1\n" +
+ " \n" +
+ " 1 problem\n"
+ );
+ }
+
@Test
public void testFormatStatus() throws IOException {
List scans = singletonList(
@@ -158,4 +258,79 @@ public void testFormatStatus() throws IOException {
" Has 3 unreleased changes \n"
);
}
+
+ private static String releaseChangesToString(Heylogs heylogs, Document doc, Version version) {
+ heylogs.releaseChanges(doc, version, "v");
+ return Sample.FORMATTER.render(doc);
+ }
+
+ private static final class MockedRule implements Rule {
+
+ @Override
+ public @NonNull String getRuleId() {
+ return "mocked";
+ }
+
+ @Override
+ public @NonNull String getRuleName() {
+ return "";
+ }
+
+ @Override
+ public @NonNull String getRuleCategory() {
+ return "";
+ }
+
+ @Override
+ public boolean isRuleAvailable() {
+ return false;
+ }
+
+ @Override
+ public @NonNull RuleSeverity getRuleSeverity() {
+ return RuleSeverity.OFF;
+ }
+
+ @Override
+ public @Nullable RuleIssue getRuleIssueOrNull(@NonNull Node node) {
+ return null;
+ }
+ }
+
+ private static final class MockedForge implements Forge {
+
+ @Override
+ public @NonNull String getForgeId() {
+ return "github";
+ }
+
+ @Override
+ public @NonNull String getForgeName() {
+ return "GitHub";
+ }
+
+ @Override
+ public boolean isCompareLink(@NonNull URL url) {
+ return true;
+ }
+
+ @Override
+ public @NonNull URL getProjectURL(@NonNull URL url) {
+ return urlOf("https://github.com/olivierlacan/keep-a-changelog");
+ }
+
+ @Override
+ public @NonNull URL deriveCompareLink(@NonNull URL latest, @NonNull String nextTag) {
+ String urlAsString = latest.toString();
+ int oidIndex = urlAsString.lastIndexOf("/") + 1;
+ return urlOf(urlAsString.substring(0, oidIndex) + deriveOID(nextTag, urlAsString.substring(oidIndex)));
+ }
+
+ @MightBePromoted
+ private static String deriveOID(String nextTag, String oid) {
+ return oid.endsWith("...HEAD")
+ ? oid.startsWith("HEAD...") ? (nextTag + "..." + nextTag) : (oid.substring(0, oid.length() - 4) + nextTag)
+ : (oid.substring(oid.indexOf("...") + 3) + "..." + nextTag);
+ }
+ }
}
diff --git a/heylogs-api/src/test/java/nbbrd/heylogs/NodesTest.java b/heylogs-api/src/test/java/nbbrd/heylogs/NodesTest.java
index 694b77b..0820c69 100644
--- a/heylogs-api/src/test/java/nbbrd/heylogs/NodesTest.java
+++ b/heylogs-api/src/test/java/nbbrd/heylogs/NodesTest.java
@@ -4,7 +4,7 @@
import internal.heylogs.ChangelogNodes;
import org.junit.jupiter.api.Test;
-import static _test.Sample.using;
+import static tests.heylogs.api.Sample.using;
import static org.assertj.core.api.Assertions.assertThat;
class NodesTest {
diff --git a/heylogs-api/src/test/java/nbbrd/heylogs/TypeOfChangeTest.java b/heylogs-api/src/test/java/nbbrd/heylogs/TypeOfChangeTest.java
index ebd732c..0ff8f53 100644
--- a/heylogs-api/src/test/java/nbbrd/heylogs/TypeOfChangeTest.java
+++ b/heylogs-api/src/test/java/nbbrd/heylogs/TypeOfChangeTest.java
@@ -1,11 +1,11 @@
package nbbrd.heylogs;
-import _test.Sample;
+import tests.heylogs.api.Sample;
import com.vladsch.flexmark.ast.Heading;
import org.junit.jupiter.api.Test;
-import static _test.Sample.asHeading;
-import static _test.Sample.using;
+import static tests.heylogs.api.Sample.asHeading;
+import static tests.heylogs.api.Sample.using;
import static nbbrd.heylogs.TypeOfChange.parse;
import static org.assertj.core.api.Assertions.*;
diff --git a/heylogs-api/src/test/java/nbbrd/heylogs/VersionTest.java b/heylogs-api/src/test/java/nbbrd/heylogs/VersionTest.java
index 8a4282e..d9f2a55 100644
--- a/heylogs-api/src/test/java/nbbrd/heylogs/VersionTest.java
+++ b/heylogs-api/src/test/java/nbbrd/heylogs/VersionTest.java
@@ -1,13 +1,13 @@
package nbbrd.heylogs;
-import _test.Sample;
+import tests.heylogs.api.Sample;
import com.vladsch.flexmark.ast.Heading;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
-import static _test.Sample.asHeading;
-import static _test.Sample.using;
+import static tests.heylogs.api.Sample.asHeading;
+import static tests.heylogs.api.Sample.using;
import static nbbrd.heylogs.Version.*;
import static org.assertj.core.api.Assertions.*;
diff --git a/heylogs-api/src/test/java/_test/Sample.java b/heylogs-api/src/test/java/tests/heylogs/api/Sample.java
similarity index 99%
rename from heylogs-api/src/test/java/_test/Sample.java
rename to heylogs-api/src/test/java/tests/heylogs/api/Sample.java
index 8ef758d..e623310 100644
--- a/heylogs-api/src/test/java/_test/Sample.java
+++ b/heylogs-api/src/test/java/tests/heylogs/api/Sample.java
@@ -1,4 +1,4 @@
-package _test;
+package tests.heylogs.api;
import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.formatter.Formatter;
diff --git a/heylogs-api/src/test/java/tests/heylogs/spi/ForgeAssert.java b/heylogs-api/src/test/java/tests/heylogs/spi/ForgeAssert.java
new file mode 100644
index 0000000..cb8bcb5
--- /dev/null
+++ b/heylogs-api/src/test/java/tests/heylogs/spi/ForgeAssert.java
@@ -0,0 +1,37 @@
+package tests.heylogs.spi;
+
+import lombok.NonNull;
+import nbbrd.heylogs.spi.Forge;
+
+import static internal.heylogs.URLExtractor.urlOf;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+public final class ForgeAssert {
+
+ private ForgeAssert() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+
+ @SuppressWarnings("DataFlowIssue")
+ public static void assertForgeCompliance(@NonNull Forge x) {
+ assertThat(x.getForgeId())
+ .matches(nbbrd.heylogs.spi.ForgeLoader.ID_PATTERN);
+
+ assertThat(x.getForgeName())
+ .isNotEmpty()
+ .isNotNull();
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.isCompareLink(null));
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.getProjectURL(null));
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.deriveCompareLink(null, ""));
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.deriveCompareLink(urlOf("http://localhost"), null));
+ }
+}
diff --git a/heylogs-api/src/test/java/tests/heylogs/spi/ForgeLinkAssert.java b/heylogs-api/src/test/java/tests/heylogs/spi/ForgeLinkAssert.java
new file mode 100644
index 0000000..f86b5b4
--- /dev/null
+++ b/heylogs-api/src/test/java/tests/heylogs/spi/ForgeLinkAssert.java
@@ -0,0 +1,18 @@
+package tests.heylogs.spi;
+
+import lombok.NonNull;
+import nbbrd.heylogs.spi.ForgeLink;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public final class ForgeLinkAssert {
+
+ private ForgeLinkAssert() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+
+ public static void assertForgeLinkCompliance(@NonNull ForgeLink x) {
+ assertThat(x.getBase())
+ .isNotNull();
+ }
+}
diff --git a/heylogs-api/src/test/java/tests/heylogs/spi/ForgeRefAssert.java b/heylogs-api/src/test/java/tests/heylogs/spi/ForgeRefAssert.java
new file mode 100644
index 0000000..3a1d86a
--- /dev/null
+++ b/heylogs-api/src/test/java/tests/heylogs/spi/ForgeRefAssert.java
@@ -0,0 +1,20 @@
+package tests.heylogs.spi;
+
+import lombok.NonNull;
+import nbbrd.heylogs.spi.ForgeRef;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+public final class ForgeRefAssert {
+
+ private ForgeRefAssert() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+
+ @SuppressWarnings("DataFlowIssue")
+ public static void assertForgeRefCompliance(@NonNull ForgeRef> x) {
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.isCompatibleWith(null));
+ }
+}
diff --git a/heylogs-api/src/test/java/tests/heylogs/spi/FormatAssert.java b/heylogs-api/src/test/java/tests/heylogs/spi/FormatAssert.java
new file mode 100644
index 0000000..c8ae999
--- /dev/null
+++ b/heylogs-api/src/test/java/tests/heylogs/spi/FormatAssert.java
@@ -0,0 +1,50 @@
+package tests.heylogs.spi;
+
+import lombok.NonNull;
+import nbbrd.heylogs.spi.Format;
+
+import static java.util.Collections.emptyList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+public final class FormatAssert {
+
+ private FormatAssert() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+
+ @SuppressWarnings("DataFlowIssue")
+ public static void assertFormatCompliance(@NonNull Format x) {
+ assertThat(x.getFormatId())
+ .matches(nbbrd.heylogs.spi.FormatLoader.ID_PATTERN);
+
+ assertThat(x.getFormatName())
+ .isNotEmpty()
+ .isNotNull();
+
+ assertThat(x.getFormatCategory())
+ .isNotEmpty()
+ .isNotNull();
+
+ assertThat(x.getSupportedFormatTypes())
+ .isNotNull();
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.formatStatus(null, emptyList()));
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.formatStatus(new StringBuilder(), null));
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.formatResources(null, emptyList()));
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.formatResources(new StringBuilder(), null));
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.formatProblems(null, emptyList()));
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.formatProblems(new StringBuilder(), null));
+ }
+}
diff --git a/heylogs-api/src/test/java/tests/heylogs/spi/RuleAssert.java b/heylogs-api/src/test/java/tests/heylogs/spi/RuleAssert.java
new file mode 100644
index 0000000..c40e901
--- /dev/null
+++ b/heylogs-api/src/test/java/tests/heylogs/spi/RuleAssert.java
@@ -0,0 +1,39 @@
+package tests.heylogs.spi;
+
+import lombok.NonNull;
+import nbbrd.heylogs.spi.Rule;
+import nbbrd.heylogs.spi.RuleBatch;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+public final class RuleAssert {
+
+ private RuleAssert() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+
+ public static void assertRuleCompliance(@NonNull RuleBatch x) {
+ x.getProviders().forEach(RuleAssert::assertRuleCompliance);
+ }
+
+ @SuppressWarnings("DataFlowIssue")
+ public static void assertRuleCompliance(@NonNull Rule x) {
+ assertThat(x.getRuleId())
+ .matches(nbbrd.heylogs.spi.RuleLoader.ID_PATTERN);
+
+ assertThat(x.getRuleName())
+ .isNotEmpty()
+ .isNotNull();
+
+ assertThat(x.getRuleCategory())
+ .isNotEmpty()
+ .isNotNull();
+
+ assertThat(x.getRuleSeverity())
+ .isNotNull();
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.getRuleIssueOrNull(null));
+ }
+}
diff --git a/heylogs-api/src/test/java/tests/heylogs/spi/VersioningAssert.java b/heylogs-api/src/test/java/tests/heylogs/spi/VersioningAssert.java
new file mode 100644
index 0000000..5835905
--- /dev/null
+++ b/heylogs-api/src/test/java/tests/heylogs/spi/VersioningAssert.java
@@ -0,0 +1,27 @@
+package tests.heylogs.spi;
+
+import lombok.NonNull;
+import nbbrd.heylogs.spi.Versioning;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
+
+public final class VersioningAssert {
+
+ private VersioningAssert() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+
+ @SuppressWarnings("DataFlowIssue")
+ public static void assertVersioningCompliance(@NonNull Versioning x) {
+ assertThat(x.getVersioningId())
+ .matches(nbbrd.heylogs.spi.VersioningLoader.ID_PATTERN);
+
+ assertThat(x.getVersioningName())
+ .isNotEmpty()
+ .isNotNull();
+
+ assertThatNullPointerException()
+ .isThrownBy(() -> x.isValidVersion(null));
+ }
+}
diff --git a/heylogs-api/src/test/resources/FirstRelease.md b/heylogs-api/src/test/resources/FirstRelease.md
new file mode 100644
index 0000000..05c03a5
--- /dev/null
+++ b/heylogs-api/src/test/resources/FirstRelease.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## [Unreleased]
+
+[unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/HEAD...HEAD
diff --git a/heylogs-bom/pom.xml b/heylogs-bom/pom.xml
index 1ab5efa..230cb7a 100644
--- a/heylogs-bom/pom.xml
+++ b/heylogs-bom/pom.xml
@@ -7,7 +7,7 @@
com.github.nbbrd.heylogs
heylogs-parent
- 0.8.1
+ 0.9.0
heylogs-bom
@@ -24,11 +24,33 @@
${project.groupId}
${project.version}
+
+ heylogs-api
+ ${project.groupId}
+ ${project.version}
+ tests
+ test-jar
+
heylogs-cli
${project.groupId}
${project.version}
+
+ heylogs-ext-github
+ ${project.groupId}
+ ${project.version}
+
+
+ heylogs-ext-json
+ ${project.groupId}
+ ${project.version}
+
+
+ heylogs-ext-semver
+ ${project.groupId}
+ ${project.version}
+
heylogs-maven-plugin
${project.groupId}
diff --git a/heylogs-cli/pom.xml b/heylogs-cli/pom.xml
index c57bb9a..4f5f0dd 100644
--- a/heylogs-cli/pom.xml
+++ b/heylogs-cli/pom.xml
@@ -7,7 +7,7 @@
com.github.nbbrd.heylogs
heylogs-parent
- 0.8.1
+ 0.9.0
heylogs-cli
@@ -46,6 +46,21 @@
${project.groupId}
${project.version}
+
+ heylogs-ext-github
+ ${project.groupId}
+ ${project.version}
+
+
+ heylogs-ext-json
+ ${project.groupId}
+ ${project.version}
+
+
+ heylogs-ext-semver
+ ${project.groupId}
+ ${project.version}
+
info.picocli
picocli
@@ -79,7 +94,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.5.2
+ 3.6.0
package
diff --git a/heylogs-cli/src/main/java/internal/heylogs/cli/HeylogsOptions.java b/heylogs-cli/src/main/java/internal/heylogs/cli/HeylogsOptions.java
index 019e4a4..78e12f5 100644
--- a/heylogs-cli/src/main/java/internal/heylogs/cli/HeylogsOptions.java
+++ b/heylogs-cli/src/main/java/internal/heylogs/cli/HeylogsOptions.java
@@ -1,7 +1,7 @@
package internal.heylogs.cli;
-import internal.heylogs.semver.SemVerRule;
import nbbrd.heylogs.Heylogs;
+import nbbrd.heylogs.ext.semver.SemVerRule;
import picocli.CommandLine;
@lombok.Getter
diff --git a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/CheckCommand.java b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/CheckCommand.java
index b14a2d2..918c0b4 100644
--- a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/CheckCommand.java
+++ b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/CheckCommand.java
@@ -16,7 +16,7 @@
import static internal.heylogs.cli.MarkdownInputSupport.newMarkdownInputSupport;
import static nbbrd.console.picocli.text.TextOutputSupport.newTextOutputSupport;
-@Command(name = "check", description = "Check changelog format.")
+@Command(name = "check", description = "Check format.")
public final class CheckCommand implements Callable {
@CommandLine.Mixin
@@ -50,7 +50,7 @@ public Integer call() throws Exception {
list.add(Check
.builder()
.source(markdown.getName(file))
- .problems(heylogs.validate(markdown.readDocument(file)))
+ .problems(heylogs.checkFormat(markdown.readDocument(file)))
.build());
}
heylogs.formatProblems(formatOptions.getFormatId(), writer, list);
diff --git a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ExtractCommand.java b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ExtractCommand.java
index ae54dc1..5fce4ac 100644
--- a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ExtractCommand.java
+++ b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ExtractCommand.java
@@ -2,10 +2,10 @@
import com.vladsch.flexmark.util.ast.Document;
import internal.heylogs.cli.ChangelogInputParameters;
+import internal.heylogs.cli.HeylogsOptions;
import internal.heylogs.cli.SpecialProperties;
-import nbbrd.console.picocli.FileInputParameters;
import nbbrd.console.picocli.FileOutputOptions;
-import nbbrd.heylogs.Extractor;
+import nbbrd.heylogs.Filter;
import nbbrd.heylogs.TimeRange;
import picocli.CommandLine;
import picocli.CommandLine.Command;
@@ -18,7 +18,7 @@
import static internal.heylogs.cli.MarkdownInputSupport.newMarkdownInputSupport;
import static internal.heylogs.cli.MarkdownOutputSupport.newMarkdownOutputSupport;
-@Command(name = "extract", description = "Extract versions from changelog.")
+@Command(name = "extract", description = "Extract versions.")
public final class ExtractCommand implements Callable {
@CommandLine.Mixin
@@ -32,14 +32,14 @@ public final class ExtractCommand implements Callable {
paramLabel = "[",
description = "Filter versions by name."
)
- private String ref = Extractor.DEFAULT.getRef();
+ private String ref = Filter.DEFAULT.getRef();
@CommandLine.Option(
names = {"-u", "--unreleased"},
paramLabel = "",
description = "Assume that versions that match this pattern are unreleased."
)
- private Pattern unreleasedPattern = Extractor.DEFAULT.getUnreleasedPattern();
+ private Pattern unreleasedPattern = Filter.DEFAULT.getUnreleasedPattern();
@CommandLine.Option(
names = {"-f", "--from"},
@@ -47,7 +47,7 @@ public final class ExtractCommand implements Callable {
description = "Filter versions by min date (included).",
converter = LenientDateConverter.class
)
- private LocalDate from = Extractor.DEFAULT.getTimeRange().getFrom();
+ private LocalDate from = Filter.DEFAULT.getTimeRange().getFrom();
@CommandLine.Option(
names = {"-t", "--to"},
@@ -55,13 +55,13 @@ public final class ExtractCommand implements Callable {
description = "Filter versions by max date (included).",
converter = LenientDateConverter.class
)
- private LocalDate to = Extractor.DEFAULT.getTimeRange().getTo();
+ private LocalDate to = Filter.DEFAULT.getTimeRange().getTo();
@CommandLine.Option(
names = {"-l", "--limit"},
description = "Limit the number of versions."
)
- private int limit = Extractor.DEFAULT.getLimit();
+ private int limit = Filter.DEFAULT.getLimit();
@CommandLine.Option(
names = "--ignore-content",
@@ -69,6 +69,9 @@ public final class ExtractCommand implements Callable {
)
private boolean ignoreContent = false;
+ @CommandLine.Mixin
+ private HeylogsOptions heylogsOptions;
+
@CommandLine.Option(
names = {SpecialProperties.DEBUG_OPTION},
defaultValue = "false",
@@ -87,7 +90,7 @@ private Document load() throws IOException {
}
private Document extract(Document document) {
- getExtractor().extract(document);
+ heylogsOptions.initHeylogs().extractVersions(document, getFilter());
return document;
}
@@ -95,8 +98,8 @@ private void store(Document document) throws IOException {
newMarkdownOutputSupport().writeDocument(output.getFile(), document);
}
- public Extractor getExtractor() {
- return Extractor
+ public Filter getFilter() {
+ return Filter
.builder()
.ref(ref)
.unreleasedPattern(unreleasedPattern)
@@ -110,7 +113,7 @@ private static final class LenientDateConverter implements CommandLine.ITypeConv
@Override
public LocalDate convert(String value) {
- return Extractor.parseLocalDate(value);
+ return Filter.parseLocalDate(value);
}
}
}
diff --git a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ListCommand.java b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ListCommand.java
index 649ab16..2729762 100644
--- a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ListCommand.java
+++ b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ListCommand.java
@@ -14,7 +14,7 @@
import static nbbrd.console.picocli.text.TextOutputSupport.newTextOutputSupport;
-@Command(name = "list", description = "List available resources.")
+@Command(name = "list", description = "List resources.")
public final class ListCommand implements Callable {
@CommandLine.Mixin
@@ -37,7 +37,7 @@ public final class ListCommand implements Callable {
public Void call() throws IOException {
try (Writer writer = newTextOutputSupport().newBufferedWriter(output.getFile())) {
Heylogs heylogs = heylogsOptions.initHeylogs();
- heylogs.formatResources(formatOptions.getFormatId(), writer, heylogs.getResources());
+ heylogs.formatResources(formatOptions.getFormatId(), writer, heylogs.listResources());
}
return null;
}
diff --git a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/MainCommand.java b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/MainCommand.java
index 40f3421..69aaa3f 100644
--- a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/MainCommand.java
+++ b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/MainCommand.java
@@ -24,9 +24,10 @@
commandListHeading = "%nCommands:%n",
headerHeading = "%n",
subcommands = {
- ScanCommand.class,
CheckCommand.class,
+ ScanCommand.class,
ExtractCommand.class,
+ ReleaseCommand.class,
ListCommand.class
},
description = {
diff --git a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ReleaseCommand.java b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ReleaseCommand.java
new file mode 100644
index 0000000..f0f591d
--- /dev/null
+++ b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ReleaseCommand.java
@@ -0,0 +1,81 @@
+package nbbrd.heylogs.cli;
+
+import com.vladsch.flexmark.util.ast.Document;
+import internal.heylogs.cli.ChangelogInputParameters;
+import internal.heylogs.cli.HeylogsOptions;
+import internal.heylogs.cli.SpecialProperties;
+import nbbrd.console.picocli.FileOutputOptions;
+import nbbrd.heylogs.Version;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.concurrent.Callable;
+
+import static internal.heylogs.cli.MarkdownInputSupport.newMarkdownInputSupport;
+import static internal.heylogs.cli.MarkdownOutputSupport.newMarkdownOutputSupport;
+
+@Command(name = "release", description = "Release changes.")
+public final class ReleaseCommand implements Callable {
+
+ @CommandLine.Mixin
+ private ChangelogInputParameters input;
+
+ @CommandLine.Mixin
+ private FileOutputOptions output;
+
+ @CommandLine.Option(
+ names = {"-r", "--ref"},
+ paramLabel = "][",
+ description = "Version reference.",
+ required = true
+ )
+ private String ref;
+
+ @CommandLine.Option(
+ names = {"-t", "--tag-prefix"},
+ paramLabel = "",
+ description = "Version tag prefix.",
+ required = false
+ )
+ private String tagPrefix = "";
+
+ @CommandLine.Option(
+ names = {"-d", "--date"},
+ paramLabel = "",
+ description = "Release date (default : today).",
+ required = false
+ )
+ private LocalDate date = LocalDate.now(ZoneId.systemDefault());
+
+ @CommandLine.Mixin
+ private HeylogsOptions heylogsOptions;
+
+ @CommandLine.Option(
+ names = {SpecialProperties.DEBUG_OPTION},
+ defaultValue = "false",
+ hidden = true
+ )
+ private boolean debug;
+
+ @Override
+ public Void call() throws Exception {
+ store(release(load()));
+ return null;
+ }
+
+ private Document load() throws IOException {
+ return newMarkdownInputSupport().readDocument(input.getFile());
+ }
+
+ private Document release(Document document) {
+ heylogsOptions.initHeylogs().releaseChanges(document, Version.of(ref, '-', date), tagPrefix);
+ return document;
+ }
+
+ private void store(Document document) throws IOException {
+ newMarkdownOutputSupport().writeDocument(output.getFile(), document);
+ }
+}
diff --git a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ScanCommand.java b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ScanCommand.java
index 71e3647..45cf47b 100644
--- a/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ScanCommand.java
+++ b/heylogs-cli/src/main/java/nbbrd/heylogs/cli/ScanCommand.java
@@ -16,7 +16,7 @@
import static internal.heylogs.cli.MarkdownInputSupport.newMarkdownInputSupport;
import static nbbrd.console.picocli.text.TextOutputSupport.newTextOutputSupport;
-@Command(name = "scan", description = "Summarize changelog content.")
+@Command(name = "scan", description = "Summarize content.")
public final class ScanCommand implements Callable {
@CommandLine.Mixin
@@ -50,7 +50,7 @@ public Void call() throws Exception {
list.add(Scan
.builder()
.source(markdown.getName(file))
- .summary(heylogs.scan(markdown.readDocument(file)))
+ .summary(heylogs.scanContent(markdown.readDocument(file)))
.build());
}
heylogs.formatStatus(formatOptions.getFormatId(), writer, list);
diff --git a/heylogs-ext-github/pom.xml b/heylogs-ext-github/pom.xml
new file mode 100644
index 0000000..ffaaae1
--- /dev/null
+++ b/heylogs-ext-github/pom.xml
@@ -0,0 +1,66 @@
+
+
+ 4.0.0
+
+
+ com.github.nbbrd.heylogs
+ heylogs-parent
+ 0.9.0
+
+
+ heylogs-ext-github
+ jar
+
+
+
+
+ org.checkerframework
+ checker-qual
+ provided
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+ com.github.nbbrd.java-design-util
+ java-design-processor
+ provided
+
+
+ com.github.nbbrd.java-service-util
+ java-service-processor
+ provided
+
+
+
+
+ heylogs-api
+ ${project.groupId}
+ ${project.version}
+
+
+
+
+ heylogs-api
+ ${project.groupId}
+ ${project.version}
+ tests
+ test-jar
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
\ No newline at end of file
diff --git a/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHub.java b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHub.java
new file mode 100644
index 0000000..7df12f7
--- /dev/null
+++ b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHub.java
@@ -0,0 +1,43 @@
+package nbbrd.heylogs.ext.github;
+
+import lombok.NonNull;
+import nbbrd.design.DirectImpl;
+import nbbrd.heylogs.spi.Forge;
+import nbbrd.service.ServiceProvider;
+
+import java.net.URL;
+
+@DirectImpl
+@ServiceProvider
+public final class GitHub implements Forge {
+
+ @Override
+ public @NonNull String getForgeId() {
+ return "github";
+ }
+
+ @Override
+ public @NonNull String getForgeName() {
+ return "GitHub";
+ }
+
+ @Override
+ public boolean isCompareLink(@NonNull URL url) {
+ try {
+ GitHubCompareLink.parse(url);
+ return true;
+ } catch (IllegalArgumentException ex) {
+ return false;
+ }
+ }
+
+ @Override
+ public @NonNull URL getProjectURL(@NonNull URL url) {
+ return GitHubCompareLink.parse(url).getProjectURL();
+ }
+
+ @Override
+ public @NonNull URL deriveCompareLink(@NonNull URL latest, @NonNull String nextTag) {
+ return GitHubCompareLink.parse(latest).derive(nextTag).toURL();
+ }
+}
diff --git a/heylogs-api/src/main/java/internal/heylogs/github/GitHubCommitSHALink.java b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubCommitSHALink.java
similarity index 98%
rename from heylogs-api/src/main/java/internal/heylogs/github/GitHubCommitSHALink.java
rename to heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubCommitSHALink.java
index 9c59b2c..36f9f12 100644
--- a/heylogs-api/src/main/java/internal/heylogs/github/GitHubCommitSHALink.java
+++ b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubCommitSHALink.java
@@ -1,4 +1,4 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import nbbrd.heylogs.spi.ForgeLink;
import lombok.AccessLevel;
diff --git a/heylogs-api/src/main/java/internal/heylogs/github/GitHubCommitSHARef.java b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubCommitSHARef.java
similarity index 98%
rename from heylogs-api/src/main/java/internal/heylogs/github/GitHubCommitSHARef.java
rename to heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubCommitSHARef.java
index ac3f2a4..0e91128 100644
--- a/heylogs-api/src/main/java/internal/heylogs/github/GitHubCommitSHARef.java
+++ b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubCommitSHARef.java
@@ -1,4 +1,4 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import nbbrd.heylogs.spi.ForgeRef;
import lombok.AccessLevel;
diff --git a/heylogs-api/src/main/java/internal/heylogs/github/GitHubCompareLink.java b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubCompareLink.java
similarity index 61%
rename from heylogs-api/src/main/java/internal/heylogs/github/GitHubCompareLink.java
rename to heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubCompareLink.java
index a9211e9..25354e9 100644
--- a/heylogs-api/src/main/java/internal/heylogs/github/GitHubCompareLink.java
+++ b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubCompareLink.java
@@ -1,7 +1,8 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import lombok.AccessLevel;
import lombok.NonNull;
+import nbbrd.design.RepresentableAs;
import nbbrd.design.RepresentableAsString;
import nbbrd.design.StaticFactoryMethod;
import nbbrd.heylogs.spi.ForgeLink;
@@ -14,16 +15,18 @@
// https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-comparing-branches-in-pull-requests#three-dot-and-two-dot-git-diff-comparisons
@RepresentableAsString
+@RepresentableAs(URL.class)
@lombok.Value
@lombok.AllArgsConstructor(access = AccessLevel.PRIVATE)
class GitHubCompareLink implements ForgeLink {
@StaticFactoryMethod
public static @NonNull GitHubCompareLink parse(@NonNull CharSequence text) {
- return parseURL(urlOf(text));
+ return parse(urlOf(text));
}
- private static @NonNull GitHubCompareLink parseURL(@NonNull URL url) {
+ @StaticFactoryMethod
+ public static @NonNull GitHubCompareLink parse(@NonNull URL url) {
String[] pathArray = getPathArray(url);
checkPathLength(pathArray, 4);
@@ -35,18 +38,41 @@ class GitHubCompareLink implements ForgeLink {
return new GitHubCompareLink(baseOf(url), pathArray[0], pathArray[1], pathArray[2], pathArray[3]);
}
- @NonNull URL base;
- @NonNull String owner;
- @NonNull String repo;
- @NonNull String type;
- @NonNull String oid;
+ @NonNull
+ URL base;
+ @NonNull
+ String owner;
+ @NonNull
+ String repo;
+ @NonNull
+ String type;
+ @NonNull
+ String oid;
@Override
public String toString() {
return URLQueryBuilder.of(base).path(owner).path(repo).path(type).path(oid).toString();
}
+ public URL toURL() {
+ return urlOf(toString());
+ }
+
private static final Pattern OWNER = Pattern.compile("[a-z\\d](?:[a-z\\d]|-(?=[a-z\\d])){0,38}");
private static final Pattern REPO = Pattern.compile("[a-z\\d._-]{1,100}");
private static final Pattern OID = Pattern.compile(".+\\.{3}.+");
+
+ public GitHubCompareLink derive(String tag) {
+ return new GitHubCompareLink(base, owner, repo, type, getOid(tag));
+ }
+
+ public URL getProjectURL() {
+ return urlOf(URLQueryBuilder.of(base).path(owner).path(repo).toString());
+ }
+
+ private String getOid(String tag) {
+ return oid.endsWith("...HEAD")
+ ? oid.startsWith("HEAD...") ? (tag + "..." + tag) : (oid.substring(0, oid.length() - 4) + tag)
+ : (oid.substring(oid.indexOf("...") + 3) + "..." + tag);
+ }
}
diff --git a/heylogs-api/src/main/java/internal/heylogs/github/GitHubIssueLink.java b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubIssueLink.java
similarity index 98%
rename from heylogs-api/src/main/java/internal/heylogs/github/GitHubIssueLink.java
rename to heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubIssueLink.java
index c000a84..82abfab 100644
--- a/heylogs-api/src/main/java/internal/heylogs/github/GitHubIssueLink.java
+++ b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubIssueLink.java
@@ -1,4 +1,4 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import nbbrd.heylogs.spi.ForgeLink;
import lombok.AccessLevel;
diff --git a/heylogs-api/src/main/java/internal/heylogs/github/GitHubIssueRef.java b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubIssueRef.java
similarity index 98%
rename from heylogs-api/src/main/java/internal/heylogs/github/GitHubIssueRef.java
rename to heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubIssueRef.java
index a737b95..3a27e92 100644
--- a/heylogs-api/src/main/java/internal/heylogs/github/GitHubIssueRef.java
+++ b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubIssueRef.java
@@ -1,4 +1,4 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import nbbrd.heylogs.spi.ForgeRef;
import lombok.AccessLevel;
diff --git a/heylogs-api/src/main/java/internal/heylogs/github/GitHubMentionLink.java b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubMentionLink.java
similarity index 98%
rename from heylogs-api/src/main/java/internal/heylogs/github/GitHubMentionLink.java
rename to heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubMentionLink.java
index 9c0b2f5..28adf61 100644
--- a/heylogs-api/src/main/java/internal/heylogs/github/GitHubMentionLink.java
+++ b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubMentionLink.java
@@ -1,4 +1,4 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import nbbrd.heylogs.spi.ForgeLink;
import lombok.AccessLevel;
diff --git a/heylogs-api/src/main/java/internal/heylogs/github/GitHubMentionRef.java b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubMentionRef.java
similarity index 98%
rename from heylogs-api/src/main/java/internal/heylogs/github/GitHubMentionRef.java
rename to heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubMentionRef.java
index 7568d14..722747b 100644
--- a/heylogs-api/src/main/java/internal/heylogs/github/GitHubMentionRef.java
+++ b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubMentionRef.java
@@ -1,4 +1,4 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import nbbrd.heylogs.spi.ForgeRef;
import lombok.AccessLevel;
diff --git a/heylogs-api/src/main/java/internal/heylogs/github/GitHubRules.java b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubRules.java
similarity index 98%
rename from heylogs-api/src/main/java/internal/heylogs/github/GitHubRules.java
rename to heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubRules.java
index 9309e81..a3f2a61 100644
--- a/heylogs-api/src/main/java/internal/heylogs/github/GitHubRules.java
+++ b/heylogs-ext-github/src/main/java/nbbrd/heylogs/ext/github/GitHubRules.java
@@ -1,4 +1,4 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import nbbrd.heylogs.spi.ForgeLink;
import nbbrd.heylogs.spi.ForgeRef;
diff --git a/heylogs-api/src/test/java/internal/heylogs/github/GitHubCommitSHALinkTest.java b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubCommitSHALinkTest.java
similarity index 91%
rename from heylogs-api/src/test/java/internal/heylogs/github/GitHubCommitSHALinkTest.java
rename to heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubCommitSHALinkTest.java
index af93d50..d0b28e2 100644
--- a/heylogs-api/src/test/java/internal/heylogs/github/GitHubCommitSHALinkTest.java
+++ b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubCommitSHALinkTest.java
@@ -1,14 +1,20 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import org.junit.jupiter.api.Test;
import static internal.heylogs.URLExtractor.urlOf;
-import static internal.heylogs.github.GitHubCommitSHALink.parse;
+import static nbbrd.heylogs.ext.github.GitHubCommitSHALink.parse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static tests.heylogs.spi.ForgeLinkAssert.assertForgeLinkCompliance;
class GitHubCommitSHALinkTest {
+ @Test
+ public void testCompliance() {
+ assertForgeLinkCompliance(parse("https://github.com/nbbrd/heylogs/commit/862157d164a8afa1fdd3295c89ceb394efbcb82d"));
+ }
+
@Test
public void testRepresentableAsString() {
assertThatIllegalArgumentException()
diff --git a/heylogs-api/src/test/java/internal/heylogs/github/GitHubCommitSHARefTest.java b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubCommitSHARefTest.java
similarity index 90%
rename from heylogs-api/src/test/java/internal/heylogs/github/GitHubCommitSHARefTest.java
rename to heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubCommitSHARefTest.java
index 52339fc..0b47b4b 100644
--- a/heylogs-api/src/test/java/internal/heylogs/github/GitHubCommitSHARefTest.java
+++ b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubCommitSHARefTest.java
@@ -1,13 +1,19 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import org.junit.jupiter.api.Test;
-import static internal.heylogs.github.GitHubCommitSHARef.of;
-import static internal.heylogs.github.GitHubCommitSHARef.parse;
+import static nbbrd.heylogs.ext.github.GitHubCommitSHARef.of;
+import static nbbrd.heylogs.ext.github.GitHubCommitSHARef.parse;
import static org.assertj.core.api.Assertions.*;
+import static tests.heylogs.spi.ForgeRefAssert.assertForgeRefCompliance;
class GitHubCommitSHARefTest {
+ @Test
+ public void testCompliance() {
+ assertForgeRefCompliance(parse("862157d"));
+ }
+
@Test
public void testRepresentableAsString() {
assertThatIllegalArgumentException()
diff --git a/heylogs-api/src/test/java/internal/heylogs/github/GitHubCompareLinkTest.java b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubCompareLinkTest.java
similarity index 91%
rename from heylogs-api/src/test/java/internal/heylogs/github/GitHubCompareLinkTest.java
rename to heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubCompareLinkTest.java
index 942438e..8a02507 100644
--- a/heylogs-api/src/test/java/internal/heylogs/github/GitHubCompareLinkTest.java
+++ b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubCompareLinkTest.java
@@ -1,14 +1,20 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import org.junit.jupiter.api.Test;
import static internal.heylogs.URLExtractor.urlOf;
-import static internal.heylogs.github.GitHubCompareLink.parse;
+import static nbbrd.heylogs.ext.github.GitHubCompareLink.parse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static tests.heylogs.spi.ForgeLinkAssert.assertForgeLinkCompliance;
class GitHubCompareLinkTest {
+ @Test
+ public void testCompliance() {
+ assertForgeLinkCompliance(parse("https://github.com/nbbrd/heylogs/compare/v0.7.2...HEAD"));
+ }
+
@Test
public void testRepresentableAsString() {
assertThatIllegalArgumentException()
diff --git a/heylogs-api/src/test/java/internal/heylogs/github/GitHubIssueLinkTest.java b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubIssueLinkTest.java
similarity index 92%
rename from heylogs-api/src/test/java/internal/heylogs/github/GitHubIssueLinkTest.java
rename to heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubIssueLinkTest.java
index 406f8b0..8f55472 100644
--- a/heylogs-api/src/test/java/internal/heylogs/github/GitHubIssueLinkTest.java
+++ b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubIssueLinkTest.java
@@ -1,14 +1,20 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import internal.heylogs.URLExtractor;
import org.junit.jupiter.api.Test;
-import static internal.heylogs.github.GitHubIssueLink.parse;
+import static nbbrd.heylogs.ext.github.GitHubIssueLink.parse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static tests.heylogs.spi.ForgeLinkAssert.assertForgeLinkCompliance;
class GitHubIssueLinkTest {
+ @Test
+ public void testCompliance() {
+ assertForgeLinkCompliance(parse("https://github.com/nbbrd/heylogs/issues/173"));
+ }
+
@Test
public void testRepresentableAsString() {
assertThatIllegalArgumentException()
diff --git a/heylogs-api/src/test/java/internal/heylogs/github/GitHubIssueRefTest.java b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubIssueRefTest.java
similarity index 91%
rename from heylogs-api/src/test/java/internal/heylogs/github/GitHubIssueRefTest.java
rename to heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubIssueRefTest.java
index 47af56e..1853af8 100644
--- a/heylogs-api/src/test/java/internal/heylogs/github/GitHubIssueRefTest.java
+++ b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubIssueRefTest.java
@@ -1,12 +1,18 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import org.junit.jupiter.api.Test;
-import static internal.heylogs.github.GitHubIssueRef.*;
+import static nbbrd.heylogs.ext.github.GitHubIssueRef.*;
import static org.assertj.core.api.Assertions.*;
+import static tests.heylogs.spi.ForgeRefAssert.assertForgeRefCompliance;
class GitHubIssueRefTest {
+ @Test
+ public void testCompliance() {
+ assertForgeRefCompliance(parse("#173"));
+ }
+
@Test
public void testRepresentableAsString() {
assertThatIllegalArgumentException()
diff --git a/heylogs-api/src/test/java/internal/heylogs/github/GitHubMentionLinkTest.java b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubMentionLinkTest.java
similarity index 84%
rename from heylogs-api/src/test/java/internal/heylogs/github/GitHubMentionLinkTest.java
rename to heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubMentionLinkTest.java
index ca20447..c41e8a0 100644
--- a/heylogs-api/src/test/java/internal/heylogs/github/GitHubMentionLinkTest.java
+++ b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubMentionLinkTest.java
@@ -1,14 +1,20 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import internal.heylogs.URLExtractor;
import org.junit.jupiter.api.Test;
-import static internal.heylogs.github.GitHubMentionLink.parse;
+import static nbbrd.heylogs.ext.github.GitHubMentionLink.parse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static tests.heylogs.spi.ForgeLinkAssert.assertForgeLinkCompliance;
class GitHubMentionLinkTest {
+ @Test
+ public void testCompliance() {
+ assertForgeLinkCompliance(parse("https://github.com/orgs/nbbrd/teams/devs"));
+ }
+
@Test
public void testRepresentableAsString() {
assertThatIllegalArgumentException()
diff --git a/heylogs-api/src/test/java/internal/heylogs/github/GitHubMentionRefTest.java b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubMentionRefTest.java
similarity index 88%
rename from heylogs-api/src/test/java/internal/heylogs/github/GitHubMentionRefTest.java
rename to heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubMentionRefTest.java
index 6c5b7bf..e2fa9c8 100644
--- a/heylogs-api/src/test/java/internal/heylogs/github/GitHubMentionRefTest.java
+++ b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubMentionRefTest.java
@@ -1,13 +1,19 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
import org.junit.jupiter.api.Test;
-import static internal.heylogs.github.GitHubMentionRef.of;
-import static internal.heylogs.github.GitHubMentionRef.parse;
+import static nbbrd.heylogs.ext.github.GitHubMentionRef.of;
+import static nbbrd.heylogs.ext.github.GitHubMentionRef.parse;
import static org.assertj.core.api.Assertions.*;
+import static tests.heylogs.spi.ForgeRefAssert.assertForgeRefCompliance;
class GitHubMentionRefTest {
+ @Test
+ public void testCompliance() {
+ assertForgeRefCompliance(parse("@charphi"));
+ }
+
@Test
public void testRepresentableAsString() {
assertThatIllegalArgumentException()
diff --git a/heylogs-api/src/test/java/internal/heylogs/github/GitHubRulesTest.java b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubRulesTest.java
similarity index 92%
rename from heylogs-api/src/test/java/internal/heylogs/github/GitHubRulesTest.java
rename to heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubRulesTest.java
index 7c5e256..39b8d83 100644
--- a/heylogs-api/src/test/java/internal/heylogs/github/GitHubRulesTest.java
+++ b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubRulesTest.java
@@ -1,30 +1,28 @@
-package internal.heylogs.github;
+package nbbrd.heylogs.ext.github;
-import _test.Sample;
import com.vladsch.flexmark.ast.Link;
import com.vladsch.flexmark.util.ast.Node;
import nbbrd.heylogs.Nodes;
import nbbrd.heylogs.spi.Rule;
import nbbrd.heylogs.spi.RuleIssue;
-import nbbrd.heylogs.spi.RuleLoader;
import org.junit.jupiter.api.Test;
+import tests.heylogs.api.Sample;
import java.util.Objects;
-import static _test.Sample.using;
-import static internal.heylogs.github.GitHubRules.*;
import static java.util.stream.Collectors.toList;
import static nbbrd.heylogs.Nodes.of;
+import static nbbrd.heylogs.ext.github.GitHubRules.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Index.atIndex;
+import static tests.heylogs.api.Sample.using;
+import static tests.heylogs.spi.RuleAssert.assertRuleCompliance;
public class GitHubRulesTest {
@Test
- public void testIdPattern() {
- assertThat(new GitHubRules().getProviders())
- .extracting(Rule::getRuleId)
- .allMatch(RuleLoader.ID_PATTERN.asPredicate());
+ public void testCompliance() {
+ assertRuleCompliance(new GitHubRules());
}
@Test
diff --git a/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubTest.java b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubTest.java
new file mode 100644
index 0000000..42735c1
--- /dev/null
+++ b/heylogs-ext-github/src/test/java/nbbrd/heylogs/ext/github/GitHubTest.java
@@ -0,0 +1,35 @@
+package nbbrd.heylogs.ext.github;
+
+import nbbrd.heylogs.spi.Forge;
+import org.junit.jupiter.api.Test;
+
+import static internal.heylogs.URLExtractor.urlOf;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static tests.heylogs.spi.ForgeAssert.assertForgeCompliance;
+
+class GitHubTest {
+
+ @Test
+ void testCompliance() {
+ assertForgeCompliance(new GitHub());
+ }
+
+ @Test
+ void testIsCompareLink() {
+ Forge x = new GitHub();
+ assertThat(x.isCompareLink(urlOf("https://nbb.be"))).isFalse();
+ assertThat(x.isCompareLink(urlOf("https://github.com/nbbrd/heylogs/compare/v0.7.2...HEAD"))).isTrue();
+ }
+
+ @Test
+ void testGetProjectURL() {
+ Forge x = new GitHub();
+
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> x.getProjectURL(urlOf("https://nbb.be")));
+
+ assertThat(x.getProjectURL(urlOf("https://github.com/nbbrd/heylogs/compare/v0.7.2...HEAD")))
+ .isEqualTo(urlOf("https://github.com/nbbrd/heylogs"));
+ }
+}
\ No newline at end of file
diff --git a/heylogs-api/src/test/resources/InvalidGitHubCommitSHARef.md b/heylogs-ext-github/src/test/resources/InvalidGitHubCommitSHARef.md
similarity index 100%
rename from heylogs-api/src/test/resources/InvalidGitHubCommitSHARef.md
rename to heylogs-ext-github/src/test/resources/InvalidGitHubCommitSHARef.md
diff --git a/heylogs-api/src/test/resources/InvalidGitHubIssueRef.md b/heylogs-ext-github/src/test/resources/InvalidGitHubIssueRef.md
similarity index 100%
rename from heylogs-api/src/test/resources/InvalidGitHubIssueRef.md
rename to heylogs-ext-github/src/test/resources/InvalidGitHubIssueRef.md
diff --git a/heylogs-api/src/test/resources/InvalidGitHubMentionRef.md b/heylogs-ext-github/src/test/resources/InvalidGitHubMentionRef.md
similarity index 100%
rename from heylogs-api/src/test/resources/InvalidGitHubMentionRef.md
rename to heylogs-ext-github/src/test/resources/InvalidGitHubMentionRef.md
diff --git a/heylogs-api/src/test/resources/InvalidGitHubPullRequestRef.md b/heylogs-ext-github/src/test/resources/InvalidGitHubPullRequestRef.md
similarity index 100%
rename from heylogs-api/src/test/resources/InvalidGitHubPullRequestRef.md
rename to heylogs-ext-github/src/test/resources/InvalidGitHubPullRequestRef.md
diff --git a/heylogs-ext-github/src/test/resources/Main.md b/heylogs-ext-github/src/test/resources/Main.md
new file mode 100644
index 0000000..145e79f
--- /dev/null
+++ b/heylogs-ext-github/src/test/resources/Main.md
@@ -0,0 +1,206 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+### Added
+
+- Added Dutch translation
+
+### Fixed
+
+- Fixed foldouts in Dutch translation
+
+## [1.1.0] - 2019-02-15
+
+### Added
+
+- Danish translation from [@frederikspang](https://github.com/frederikspang).
+- Georgian translation from [@tatocaster](https://github.com/tatocaster).
+- Changelog inconsistency section in Bad Practices
+
+### Changed
+
+- Fixed typos in Italian translation from [@lorenzo-arena](https://github.com/lorenzo-arena).
+- Fixed typos in Indonesian translation from [@ekojs](https://github.com/ekojs).
+
+## [1.0.0] - 2017-06-20
+
+### Added
+
+- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
+- Version navigation.
+- Links to latest released version in previous versions.
+- "Why keep a changelog?" section.
+- "Who needs a changelog?" section.
+- "How do I make a changelog?" section.
+- "Frequently Asked Questions" section.
+- New "Guiding Principles" sub-section to "How do I make a changelog?".
+- Simplified and Traditional Chinese translations from [@tianshuo](https://github.com/tianshuo).
+- German translation from [@mpbzh](https://github.com/mpbzh) & [@Art4](https://github.com/Art4).
+- Italian translation from [@azkidenz](https://github.com/azkidenz).
+- Swedish translation from [@magol](https://github.com/magol).
+- Turkish translation from [@emreerkan](https://github.com/emreerkan).
+- French translation from [@zapashcanon](https://github.com/zapashcanon).
+- Brazilian Portuguese translation from [@Webysther](https://github.com/Webysther).
+- Polish translation from [@amielucha](https://github.com/amielucha) & [@m-aciek](https://github.com/m-aciek).
+- Russian translation from [@aishek](https://github.com/aishek).
+- Czech translation from [@h4vry](https://github.com/h4vry).
+- Slovak translation from [@jkostolansky](https://github.com/jkostolansky).
+- Korean translation from [@pierceh89](https://github.com/pierceh89).
+- Croatian translation from [@porx](https://github.com/porx).
+- Persian translation from [@Hameds](https://github.com/Hameds).
+- Ukrainian translation from [@osadchyi-s](https://github.com/osadchyi-s).
+
+### Changed
+
+- Start using "changelog" over "change log" since it's the common usage.
+- Start versioning based on the current English version at 0.3.0 to help
+ translation authors keep things up-to-date.
+- Rewrite "What makes unicorns cry?" section.
+- Rewrite "Ignoring Deprecations" sub-section to clarify the ideal
+ scenario.
+- Improve "Commit log diffs" sub-section to further argument against
+ them.
+- Merge "Why can’t people just use a git log diff?" with "Commit log
+ diffs"
+- Fix typos in Simplified Chinese and Traditional Chinese translations.
+- Fix typos in Brazilian Portuguese translation.
+- Fix typos in Turkish translation.
+- Fix typos in Czech translation.
+- Fix typos in Swedish translation.
+- Improve phrasing in French translation.
+- Fix phrasing and spelling in German translation.
+
+### Removed
+
+- Section about "changelog" vs "CHANGELOG".
+
+## [0.3.0] - 2015-12-03
+
+### Added
+
+- RU translation from [@aishek](https://github.com/aishek).
+- pt-BR translation from [@tallesl](https://github.com/tallesl).
+- es-ES translation from [@ZeliosAriex](https://github.com/ZeliosAriex).
+
+## [0.2.0] - 2015-10-06
+
+### Changed
+
+- Remove exclusionary mentions of "open source" since this project can
+ benefit both "open" and "closed" source projects equally.
+
+## [0.1.0] - 2015-10-06
+
+### Added
+
+- Answer "Should you ever rewrite a change log?".
+
+### Changed
+
+- Improve argument against commit logs.
+- Start following [SemVer](https://semver.org) properly.
+
+## [0.0.8] - 2015-02-17
+
+### Changed
+
+- Update year to match in every README example.
+- Reluctantly stop making fun of Brits only, since most of the world
+ writes dates in a strange way.
+
+### Fixed
+
+- Fix typos in recent README changes.
+- Update outdated unreleased diff link.
+
+## [0.0.7] - 2015-02-16
+
+### Added
+
+- Link, and make it obvious that date format is ISO 8601.
+
+### Changed
+
+- Clarified the section on "Is there a standard change log format?".
+
+### Fixed
+
+- Fix Markdown links to tag comparison URL with footnote-style links.
+
+## [0.0.6] - 2014-12-12
+
+### Added
+
+- README section on "yanked" releases.
+
+## [0.0.5] - 2014-08-09
+
+### Added
+
+- Markdown links to version tags on release headings.
+- Unreleased section to gather unreleased changes and encourage note
+ keeping prior to releases.
+
+## [0.0.4] - 2014-08-09
+
+### Added
+
+- Better explanation of the difference between the file ("CHANGELOG")
+ and its function "the change log".
+
+### Changed
+
+- Refer to a "change log" instead of a "CHANGELOG" throughout the site
+ to differentiate between the file and the purpose of the file — the
+ logging of changes.
+
+### Removed
+
+- Remove empty sections from CHANGELOG, they occupy too much space and
+ create too much noise in the file. People will have to assume that the
+ missing sections were intentionally left out because they contained no
+ notable changes.
+
+## [0.0.3] - 2014-08-09
+
+### Added
+
+- "Why should I care?" section mentioning The Changelog podcast.
+
+## [0.0.2] - 2014-07-10
+
+### Added
+
+- Explanation of the recommended reverse chronological release ordering.
+
+## [0.0.1] - 2014-05-31
+
+### Added
+
+- This CHANGELOG file to hopefully serve as an evolving example of a
+ standardized open source project CHANGELOG.
+- CNAME file to enable GitHub Pages custom domain
+- README now contains answers to common questions about CHANGELOGs
+- Good examples and basic guidelines, including proper date formatting.
+- Counter-examples: "What makes unicorns cry?"
+
+[unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.1.0...HEAD
+[1.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0
+[1.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.3.0...v1.0.0
+[0.3.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.2.0...v0.3.0
+[0.2.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.1.0...v0.2.0
+[0.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.8...v0.1.0
+[0.0.8]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.7...v0.0.8
+[0.0.7]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.6...v0.0.7
+[0.0.6]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.5...v0.0.6
+[0.0.5]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.4...v0.0.5
+[0.0.4]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.3...v0.0.4
+[0.0.3]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.2...v0.0.3
+[0.0.2]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.1...v0.0.2
+[0.0.1]: https://github.com/olivierlacan/keep-a-changelog/releases/tag/v0.0.1
\ No newline at end of file
diff --git a/heylogs-ext-json/pom.xml b/heylogs-ext-json/pom.xml
new file mode 100644
index 0000000..530805a
--- /dev/null
+++ b/heylogs-ext-json/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+
+
+ com.github.nbbrd.heylogs
+ heylogs-parent
+ 0.9.0
+
+
+ heylogs-ext-json
+ jar
+
+
+
+
+ org.checkerframework
+ checker-qual
+ provided
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+ com.github.nbbrd.java-design-util
+ java-design-processor
+ provided
+
+
+ com.github.nbbrd.java-service-util
+ java-service-processor
+ provided
+
+
+
+
+ heylogs-api
+ ${project.groupId}
+ ${project.version}
+
+
+ com.google.code.gson
+ gson
+ 2.11.0
+
+
+
+
+ heylogs-api
+ ${project.groupId}
+ ${project.version}
+ tests
+ test-jar
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
\ No newline at end of file
diff --git a/heylogs-api/src/main/java/internal/heylogs/JsonFormat.java b/heylogs-ext-json/src/main/java/nbbrd/heylogs/ext/json/JsonFormat.java
similarity index 99%
rename from heylogs-api/src/main/java/internal/heylogs/JsonFormat.java
rename to heylogs-ext-json/src/main/java/nbbrd/heylogs/ext/json/JsonFormat.java
index e4c2448..b16130b 100644
--- a/heylogs-api/src/main/java/internal/heylogs/JsonFormat.java
+++ b/heylogs-ext-json/src/main/java/nbbrd/heylogs/ext/json/JsonFormat.java
@@ -1,4 +1,4 @@
-package internal.heylogs;
+package nbbrd.heylogs.ext.json;
import com.google.gson.*;
import lombok.NonNull;
diff --git a/heylogs-api/src/test/java/internal/heylogs/JsonFormatTest.java b/heylogs-ext-json/src/test/java/nbbrd/heylogs/ext/json/JsonFormatTest.java
similarity index 79%
rename from heylogs-api/src/test/java/internal/heylogs/JsonFormatTest.java
rename to heylogs-ext-json/src/test/java/nbbrd/heylogs/ext/json/JsonFormatTest.java
index e28d629..6e16a1d 100644
--- a/heylogs-api/src/test/java/internal/heylogs/JsonFormatTest.java
+++ b/heylogs-ext-json/src/test/java/nbbrd/heylogs/ext/json/JsonFormatTest.java
@@ -1,21 +1,20 @@
-package internal.heylogs;
+package nbbrd.heylogs.ext.json;
import nbbrd.heylogs.spi.Format;
-import nbbrd.heylogs.spi.FormatLoader;
import org.junit.jupiter.api.Test;
-import static _test.Sample.*;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
+import static tests.heylogs.api.Sample.*;
+import static tests.heylogs.spi.FormatAssert.assertFormatCompliance;
class JsonFormatTest {
@Test
- public void testIdPattern() {
- assertThat(new JsonFormat().getFormatId())
- .matches(FormatLoader.ID_PATTERN);
+ public void testCompliance() {
+ assertFormatCompliance(new JsonFormat());
}
@Test
@@ -23,13 +22,13 @@ public void testFormatProblems() {
Format x = new JsonFormat();
assertThat(writing(appendable -> x.formatProblems(appendable, singletonList(CHECK1))))
- .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "check1.json"));
+ .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "/check1.json"));
assertThat(writing(appendable -> x.formatProblems(appendable, singletonList(CHECK2))))
- .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "check2.json"));
+ .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "/check2.json"));
assertThat(writing(appendable -> x.formatProblems(appendable, singletonList(CHECK3))))
- .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "check3.json"));
+ .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "/check3.json"));
}
@Test
@@ -37,10 +36,10 @@ public void testFormatStatus() {
Format x = new JsonFormat();
assertThat(writing(appendable -> x.formatStatus(appendable, singletonList(SCAN1))))
- .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "scan1.json"));
+ .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "/scan1.json"));
assertThat(writing(appendable -> x.formatStatus(appendable, singletonList(SCAN2))))
- .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "scan2.json"));
+ .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "/scan2.json"));
}
@Test
@@ -48,13 +47,13 @@ public void testFormatResource() {
Format x = new JsonFormat();
assertThat(writing(appendable -> x.formatResources(appendable, emptyList())))
- .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "resource1.json"));
+ .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "/resource1.json"));
assertThat(writing(appendable -> x.formatResources(appendable, singletonList(RESOURCE1))))
- .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "resource2.json"));
+ .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "/resource2.json"));
assertThat(writing(appendable -> x.formatResources(appendable, asList(RESOURCE1, RESOURCE2))))
- .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "resource3.json"));
+ .isEqualToNormalizingNewlines(contentOf(JsonFormatTest.class, "/resource3.json"));
}
}
\ No newline at end of file
diff --git a/heylogs-api/src/test/resources/internal/heylogs/check1.json b/heylogs-ext-json/src/test/resources/check1.json
similarity index 100%
rename from heylogs-api/src/test/resources/internal/heylogs/check1.json
rename to heylogs-ext-json/src/test/resources/check1.json
diff --git a/heylogs-api/src/test/resources/internal/heylogs/check2.json b/heylogs-ext-json/src/test/resources/check2.json
similarity index 100%
rename from heylogs-api/src/test/resources/internal/heylogs/check2.json
rename to heylogs-ext-json/src/test/resources/check2.json
diff --git a/heylogs-api/src/test/resources/internal/heylogs/check3.json b/heylogs-ext-json/src/test/resources/check3.json
similarity index 100%
rename from heylogs-api/src/test/resources/internal/heylogs/check3.json
rename to heylogs-ext-json/src/test/resources/check3.json
diff --git a/heylogs-api/src/test/resources/internal/heylogs/resource1.json b/heylogs-ext-json/src/test/resources/resource1.json
similarity index 100%
rename from heylogs-api/src/test/resources/internal/heylogs/resource1.json
rename to heylogs-ext-json/src/test/resources/resource1.json
diff --git a/heylogs-api/src/test/resources/internal/heylogs/resource2.json b/heylogs-ext-json/src/test/resources/resource2.json
similarity index 100%
rename from heylogs-api/src/test/resources/internal/heylogs/resource2.json
rename to heylogs-ext-json/src/test/resources/resource2.json
diff --git a/heylogs-api/src/test/resources/internal/heylogs/resource3.json b/heylogs-ext-json/src/test/resources/resource3.json
similarity index 100%
rename from heylogs-api/src/test/resources/internal/heylogs/resource3.json
rename to heylogs-ext-json/src/test/resources/resource3.json
diff --git a/heylogs-api/src/test/resources/internal/heylogs/scan1.json b/heylogs-ext-json/src/test/resources/scan1.json
similarity index 100%
rename from heylogs-api/src/test/resources/internal/heylogs/scan1.json
rename to heylogs-ext-json/src/test/resources/scan1.json
diff --git a/heylogs-api/src/test/resources/internal/heylogs/scan2.json b/heylogs-ext-json/src/test/resources/scan2.json
similarity index 100%
rename from heylogs-api/src/test/resources/internal/heylogs/scan2.json
rename to heylogs-ext-json/src/test/resources/scan2.json
diff --git a/heylogs-ext-semver/pom.xml b/heylogs-ext-semver/pom.xml
new file mode 100644
index 0000000..40be88f
--- /dev/null
+++ b/heylogs-ext-semver/pom.xml
@@ -0,0 +1,77 @@
+
+
+ 4.0.0
+
+
+ com.github.nbbrd.heylogs
+ heylogs-parent
+ 0.9.0
+
+
+ heylogs-ext-semver
+ jar
+
+
+
+
+ org.checkerframework
+ checker-qual
+ provided
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+ com.github.nbbrd.java-design-util
+ java-design-processor
+ provided
+
+
+ com.github.nbbrd.java-service-util
+ java-service-processor
+ provided
+
+
+
+
+ heylogs-api
+ ${project.groupId}
+ ${project.version}
+
+
+ org.semver4j
+ semver4j
+ 5.3.0
+
+
+ org.jetbrains
+ annotations
+
+
+
+
+
+
+ heylogs-api
+ ${project.groupId}
+ ${project.version}
+ tests
+ test-jar
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
\ No newline at end of file
diff --git a/heylogs-api/src/main/java/internal/heylogs/semver/SemVer.java b/heylogs-ext-semver/src/main/java/nbbrd/heylogs/ext/semver/SemVer.java
similarity index 94%
rename from heylogs-api/src/main/java/internal/heylogs/semver/SemVer.java
rename to heylogs-ext-semver/src/main/java/nbbrd/heylogs/ext/semver/SemVer.java
index 1eb2947..1a4d719 100644
--- a/heylogs-api/src/main/java/internal/heylogs/semver/SemVer.java
+++ b/heylogs-ext-semver/src/main/java/nbbrd/heylogs/ext/semver/SemVer.java
@@ -1,4 +1,4 @@
-package internal.heylogs.semver;
+package nbbrd.heylogs.ext.semver;
import lombok.NonNull;
import nbbrd.design.DirectImpl;
diff --git a/heylogs-api/src/main/java/internal/heylogs/semver/SemVerRule.java b/heylogs-ext-semver/src/main/java/nbbrd/heylogs/ext/semver/SemVerRule.java
similarity index 98%
rename from heylogs-api/src/main/java/internal/heylogs/semver/SemVerRule.java
rename to heylogs-ext-semver/src/main/java/nbbrd/heylogs/ext/semver/SemVerRule.java
index 6190ef4..3411678 100644
--- a/heylogs-api/src/main/java/internal/heylogs/semver/SemVerRule.java
+++ b/heylogs-ext-semver/src/main/java/nbbrd/heylogs/ext/semver/SemVerRule.java
@@ -1,4 +1,4 @@
-package internal.heylogs.semver;
+package nbbrd.heylogs.ext.semver;
import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.util.ast.Node;
diff --git a/heylogs-api/src/test/java/internal/heylogs/semver/SemVerRuleTest.java b/heylogs-ext-semver/src/test/java/nbbrd/heylogs/ext/semver/SemVerRuleTest.java
similarity index 85%
rename from heylogs-api/src/test/java/internal/heylogs/semver/SemVerRuleTest.java
rename to heylogs-ext-semver/src/test/java/nbbrd/heylogs/ext/semver/SemVerRuleTest.java
index 1809a66..5cff839 100644
--- a/heylogs-api/src/test/java/internal/heylogs/semver/SemVerRuleTest.java
+++ b/heylogs-ext-semver/src/test/java/nbbrd/heylogs/ext/semver/SemVerRuleTest.java
@@ -1,23 +1,22 @@
-package internal.heylogs.semver;
+package nbbrd.heylogs.ext.semver;
import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.util.ast.Node;
import nbbrd.heylogs.spi.RuleIssue;
-import nbbrd.heylogs.spi.RuleLoader;
import org.junit.jupiter.api.Test;
import java.util.Objects;
-import static _test.Sample.using;
import static nbbrd.heylogs.Nodes.of;
import static org.assertj.core.api.Assertions.assertThat;
+import static tests.heylogs.api.Sample.using;
+import static tests.heylogs.spi.RuleAssert.assertRuleCompliance;
public class SemVerRuleTest {
@Test
- public void testIdPattern() {
- assertThat(new SemVerRule().getRuleId())
- .matches(RuleLoader.ID_PATTERN);
+ public void testCompliance() {
+ assertRuleCompliance(new SemVerRule());
}
@Test
diff --git a/heylogs-ext-semver/src/test/java/nbbrd/heylogs/ext/semver/SemVerTest.java b/heylogs-ext-semver/src/test/java/nbbrd/heylogs/ext/semver/SemVerTest.java
new file mode 100644
index 0000000..423fb5d
--- /dev/null
+++ b/heylogs-ext-semver/src/test/java/nbbrd/heylogs/ext/semver/SemVerTest.java
@@ -0,0 +1,21 @@
+package nbbrd.heylogs.ext.semver;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static tests.heylogs.spi.VersioningAssert.assertVersioningCompliance;
+
+class SemVerTest {
+
+ @Test
+ public void testCompliance() {
+ assertVersioningCompliance(new SemVer());
+ }
+
+ @Test
+ void isValidVersion() {
+ SemVer x = new SemVer();
+ assertThat(x.isValidVersion("1.1.0")).isTrue();
+ assertThat(x.isValidVersion(".1.0")).isFalse();
+ }
+}
\ No newline at end of file
diff --git a/heylogs-ext-semver/src/test/resources/Empty.md b/heylogs-ext-semver/src/test/resources/Empty.md
new file mode 100644
index 0000000..e69de29
diff --git a/heylogs-ext-semver/src/test/resources/InvalidSemver.md b/heylogs-ext-semver/src/test/resources/InvalidSemver.md
new file mode 100644
index 0000000..886858b
--- /dev/null
+++ b/heylogs-ext-semver/src/test/resources/InvalidSemver.md
@@ -0,0 +1,7 @@
+# Changelog
+
+## [1.1.0] - 2019-02-15
+## [.1.0] - 2019-02-15
+
+[1.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0
+[.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0
diff --git a/heylogs-ext-semver/src/test/resources/Main.md b/heylogs-ext-semver/src/test/resources/Main.md
new file mode 100644
index 0000000..145e79f
--- /dev/null
+++ b/heylogs-ext-semver/src/test/resources/Main.md
@@ -0,0 +1,206 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+### Added
+
+- Added Dutch translation
+
+### Fixed
+
+- Fixed foldouts in Dutch translation
+
+## [1.1.0] - 2019-02-15
+
+### Added
+
+- Danish translation from [@frederikspang](https://github.com/frederikspang).
+- Georgian translation from [@tatocaster](https://github.com/tatocaster).
+- Changelog inconsistency section in Bad Practices
+
+### Changed
+
+- Fixed typos in Italian translation from [@lorenzo-arena](https://github.com/lorenzo-arena).
+- Fixed typos in Indonesian translation from [@ekojs](https://github.com/ekojs).
+
+## [1.0.0] - 2017-06-20
+
+### Added
+
+- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
+- Version navigation.
+- Links to latest released version in previous versions.
+- "Why keep a changelog?" section.
+- "Who needs a changelog?" section.
+- "How do I make a changelog?" section.
+- "Frequently Asked Questions" section.
+- New "Guiding Principles" sub-section to "How do I make a changelog?".
+- Simplified and Traditional Chinese translations from [@tianshuo](https://github.com/tianshuo).
+- German translation from [@mpbzh](https://github.com/mpbzh) & [@Art4](https://github.com/Art4).
+- Italian translation from [@azkidenz](https://github.com/azkidenz).
+- Swedish translation from [@magol](https://github.com/magol).
+- Turkish translation from [@emreerkan](https://github.com/emreerkan).
+- French translation from [@zapashcanon](https://github.com/zapashcanon).
+- Brazilian Portuguese translation from [@Webysther](https://github.com/Webysther).
+- Polish translation from [@amielucha](https://github.com/amielucha) & [@m-aciek](https://github.com/m-aciek).
+- Russian translation from [@aishek](https://github.com/aishek).
+- Czech translation from [@h4vry](https://github.com/h4vry).
+- Slovak translation from [@jkostolansky](https://github.com/jkostolansky).
+- Korean translation from [@pierceh89](https://github.com/pierceh89).
+- Croatian translation from [@porx](https://github.com/porx).
+- Persian translation from [@Hameds](https://github.com/Hameds).
+- Ukrainian translation from [@osadchyi-s](https://github.com/osadchyi-s).
+
+### Changed
+
+- Start using "changelog" over "change log" since it's the common usage.
+- Start versioning based on the current English version at 0.3.0 to help
+ translation authors keep things up-to-date.
+- Rewrite "What makes unicorns cry?" section.
+- Rewrite "Ignoring Deprecations" sub-section to clarify the ideal
+ scenario.
+- Improve "Commit log diffs" sub-section to further argument against
+ them.
+- Merge "Why can’t people just use a git log diff?" with "Commit log
+ diffs"
+- Fix typos in Simplified Chinese and Traditional Chinese translations.
+- Fix typos in Brazilian Portuguese translation.
+- Fix typos in Turkish translation.
+- Fix typos in Czech translation.
+- Fix typos in Swedish translation.
+- Improve phrasing in French translation.
+- Fix phrasing and spelling in German translation.
+
+### Removed
+
+- Section about "changelog" vs "CHANGELOG".
+
+## [0.3.0] - 2015-12-03
+
+### Added
+
+- RU translation from [@aishek](https://github.com/aishek).
+- pt-BR translation from [@tallesl](https://github.com/tallesl).
+- es-ES translation from [@ZeliosAriex](https://github.com/ZeliosAriex).
+
+## [0.2.0] - 2015-10-06
+
+### Changed
+
+- Remove exclusionary mentions of "open source" since this project can
+ benefit both "open" and "closed" source projects equally.
+
+## [0.1.0] - 2015-10-06
+
+### Added
+
+- Answer "Should you ever rewrite a change log?".
+
+### Changed
+
+- Improve argument against commit logs.
+- Start following [SemVer](https://semver.org) properly.
+
+## [0.0.8] - 2015-02-17
+
+### Changed
+
+- Update year to match in every README example.
+- Reluctantly stop making fun of Brits only, since most of the world
+ writes dates in a strange way.
+
+### Fixed
+
+- Fix typos in recent README changes.
+- Update outdated unreleased diff link.
+
+## [0.0.7] - 2015-02-16
+
+### Added
+
+- Link, and make it obvious that date format is ISO 8601.
+
+### Changed
+
+- Clarified the section on "Is there a standard change log format?".
+
+### Fixed
+
+- Fix Markdown links to tag comparison URL with footnote-style links.
+
+## [0.0.6] - 2014-12-12
+
+### Added
+
+- README section on "yanked" releases.
+
+## [0.0.5] - 2014-08-09
+
+### Added
+
+- Markdown links to version tags on release headings.
+- Unreleased section to gather unreleased changes and encourage note
+ keeping prior to releases.
+
+## [0.0.4] - 2014-08-09
+
+### Added
+
+- Better explanation of the difference between the file ("CHANGELOG")
+ and its function "the change log".
+
+### Changed
+
+- Refer to a "change log" instead of a "CHANGELOG" throughout the site
+ to differentiate between the file and the purpose of the file — the
+ logging of changes.
+
+### Removed
+
+- Remove empty sections from CHANGELOG, they occupy too much space and
+ create too much noise in the file. People will have to assume that the
+ missing sections were intentionally left out because they contained no
+ notable changes.
+
+## [0.0.3] - 2014-08-09
+
+### Added
+
+- "Why should I care?" section mentioning The Changelog podcast.
+
+## [0.0.2] - 2014-07-10
+
+### Added
+
+- Explanation of the recommended reverse chronological release ordering.
+
+## [0.0.1] - 2014-05-31
+
+### Added
+
+- This CHANGELOG file to hopefully serve as an evolving example of a
+ standardized open source project CHANGELOG.
+- CNAME file to enable GitHub Pages custom domain
+- README now contains answers to common questions about CHANGELOGs
+- Good examples and basic guidelines, including proper date formatting.
+- Counter-examples: "What makes unicorns cry?"
+
+[unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.1.0...HEAD
+[1.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...v1.1.0
+[1.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.3.0...v1.0.0
+[0.3.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.2.0...v0.3.0
+[0.2.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.1.0...v0.2.0
+[0.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.8...v0.1.0
+[0.0.8]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.7...v0.0.8
+[0.0.7]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.6...v0.0.7
+[0.0.6]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.5...v0.0.6
+[0.0.5]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.4...v0.0.5
+[0.0.4]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.3...v0.0.4
+[0.0.3]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.2...v0.0.3
+[0.0.2]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.1...v0.0.2
+[0.0.1]: https://github.com/olivierlacan/keep-a-changelog/releases/tag/v0.0.1
\ No newline at end of file
diff --git a/heylogs-maven-plugin/pom.xml b/heylogs-maven-plugin/pom.xml
index e2a2e32..7889503 100644
--- a/heylogs-maven-plugin/pom.xml
+++ b/heylogs-maven-plugin/pom.xml
@@ -7,7 +7,7 @@
com.github.nbbrd.heylogs
heylogs-parent
- 0.8.1
+ 0.9.0
heylogs-maven-plugin
@@ -49,7 +49,7 @@
org.apache.maven.plugin-tools
maven-plugin-annotations
- 3.12.0
+ 3.14.0
provided
@@ -59,6 +59,21 @@
${project.groupId}
${project.version}
]
+
+ heylogs-ext-github
+ ${project.groupId}
+ ${project.version}
+
+
+ heylogs-ext-json
+ ${project.groupId}
+ ${project.version}
+
+
+ heylogs-ext-semver
+ ${project.groupId}
+ ${project.version}
+
com.github.nbbrd.java-console-properties
java-console-properties
@@ -71,7 +86,7 @@
org.apache.maven.plugins
maven-plugin-plugin
- 3.12.0
+ 3.14.0
diff --git a/heylogs-maven-plugin/src/main/java/internal/heylogs/maven/plugin/MojoFunction.java b/heylogs-maven-plugin/src/main/java/internal/heylogs/maven/plugin/MojoFunction.java
index 98cad4c..c50a76e 100644
--- a/heylogs-maven-plugin/src/main/java/internal/heylogs/maven/plugin/MojoFunction.java
+++ b/heylogs-maven-plugin/src/main/java/internal/heylogs/maven/plugin/MojoFunction.java
@@ -1,13 +1,9 @@
package internal.heylogs.maven.plugin;
import lombok.NonNull;
-import nbbrd.design.StaticFactoryMethod;
-import nbbrd.heylogs.Extractor;
import org.apache.maven.plugin.MojoExecutionException;
-import java.time.LocalDate;
import java.util.function.Function;
-import java.util.regex.Pattern;
@FunctionalInterface
public interface MojoFunction {
@@ -23,14 +19,4 @@ public interface MojoFunction {
}
};
}
-
- @StaticFactoryMethod
- static @NonNull MojoFunction onPattern(@NonNull String errorMessage) {
- return of(Pattern::compile, errorMessage);
- }
-
- @StaticFactoryMethod
- static @NonNull MojoFunction onLocalDate(@NonNull String errorMessage) {
- return of(Extractor::parseLocalDate, errorMessage);
- }
}
diff --git a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/CheckMojo.java b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/CheckMojo.java
index e9d2b2f..7ce1f88 100644
--- a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/CheckMojo.java
+++ b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/CheckMojo.java
@@ -1,9 +1,9 @@
package nbbrd.heylogs.maven.plugin;
import internal.heylogs.StylishFormat;
-import internal.heylogs.semver.SemVer;
import nbbrd.heylogs.Check;
import nbbrd.heylogs.Heylogs;
+import nbbrd.heylogs.ext.semver.SemVer;
import nbbrd.heylogs.spi.Versioning;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
@@ -73,7 +73,7 @@ private void check() throws MojoExecutionException {
Check check = Check
.builder()
.source(inputFile.toString())
- .problems(heylogs.validate(readChangelog(inputFile)))
+ .problems(heylogs.checkFormat(readChangelog(inputFile)))
.build();
try (Writer writer = newWriter(outputFile, check.hasErrors() ? getLog()::error : getLog()::info)) {
diff --git a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ExtractMojo.java b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ExtractMojo.java
index b50dc05..70766f6 100644
--- a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ExtractMojo.java
+++ b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ExtractMojo.java
@@ -1,7 +1,9 @@
package nbbrd.heylogs.maven.plugin;
import com.vladsch.flexmark.util.ast.Document;
-import nbbrd.heylogs.Extractor;
+import internal.heylogs.maven.plugin.MojoFunction;
+import nbbrd.heylogs.Filter;
+import nbbrd.heylogs.Heylogs;
import nbbrd.heylogs.TimeRange;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
@@ -9,11 +11,12 @@
import org.apache.maven.plugins.annotations.Parameter;
import java.io.File;
+import java.time.LocalDate;
import java.util.Objects;
+import java.util.regex.Pattern;
import static internal.heylogs.maven.plugin.HeylogsParameters.*;
-import static internal.heylogs.maven.plugin.MojoFunction.onLocalDate;
-import static internal.heylogs.maven.plugin.MojoFunction.onPattern;
+import static internal.heylogs.maven.plugin.MojoFunction.of;
@Mojo(name = "extract", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, threadSafe = true, requiresProject = false)
public final class ExtractMojo extends HeylogsMojo {
@@ -54,29 +57,32 @@ public void execute() throws MojoExecutionException {
throw new MojoExecutionException("Changelog not found");
}
- extract(loadExtractor());
+ extract(loadFilter());
}
- private Extractor loadExtractor() throws MojoExecutionException {
- return Extractor
+ private Filter loadFilter() throws MojoExecutionException {
+ return Filter
.builder()
.ref(Objects.toString(ref, ""))
- .unreleasedPattern(onPattern("Invalid unreleased pattern").applyWithMojo(unreleasedPattern))
- .timeRange(TimeRange.of(
- onLocalDate("Invalid format for 'from' parameter").applyWithMojo(from),
- onLocalDate("Invalid format for 'to' parameter").applyWithMojo(to))
- )
+ .unreleasedPattern(UNRELEASED_PATTERN_PARSER.applyWithMojo(unreleasedPattern))
+ .timeRange(TimeRange.of(FROM_PARSER.applyWithMojo(from), TO_PARSER.applyWithMojo(to)))
.limit(limit)
.ignoreContent(ignoreContent)
.build();
}
- private void extract(Extractor extractor) throws MojoExecutionException {
+ private void extract(Filter filter) throws MojoExecutionException {
+ Heylogs heylogs = initHeylogs(false);
+
Document changelog = readChangelog(inputFile);
- getLog().info("Extracting with " + extractor);
- extractor.extract(changelog);
+ getLog().info("Extracting with " + filter);
+ heylogs.extractVersions(changelog, filter);
writeChangelog(changelog, outputFile);
}
+
+ private static final MojoFunction UNRELEASED_PATTERN_PARSER = of(Pattern::compile, "Invalid unreleased pattern");
+ private static final MojoFunction FROM_PARSER = of(Filter::parseLocalDate, "Invalid format for 'from' parameter");
+ private static final MojoFunction TO_PARSER = of(Filter::parseLocalDate, "Invalid format for 'to' parameter");
}
diff --git a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/HeylogsMojo.java b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/HeylogsMojo.java
index 0cce37e..1ea666e 100644
--- a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/HeylogsMojo.java
+++ b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/HeylogsMojo.java
@@ -3,9 +3,9 @@
import com.vladsch.flexmark.formatter.Formatter;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Document;
-import internal.heylogs.semver.SemVerRule;
import nbbrd.design.MightBePromoted;
import nbbrd.heylogs.Heylogs;
+import nbbrd.heylogs.ext.semver.SemVerRule;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Parameter;
diff --git a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ListMojo.java b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ListMojo.java
index 1a1d4d6..cf42473 100644
--- a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ListMojo.java
+++ b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ListMojo.java
@@ -39,7 +39,7 @@ private void list() throws MojoExecutionException {
Heylogs heylogs = initHeylogs(semver);
try (Writer writer = newWriter(outputFile, getLog()::info)) {
- heylogs.formatResources(formatId, writer, heylogs.getResources());
+ heylogs.formatResources(formatId, writer, heylogs.listResources());
} catch (IOException ex) {
throw new MojoExecutionException("Error while writing", ex);
}
diff --git a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ReleaseMojo.java b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ReleaseMojo.java
new file mode 100644
index 0000000..d361b14
--- /dev/null
+++ b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ReleaseMojo.java
@@ -0,0 +1,85 @@
+package nbbrd.heylogs.maven.plugin;
+
+import com.vladsch.flexmark.util.ast.Document;
+import internal.heylogs.maven.plugin.MojoFunction;
+import nbbrd.design.MightBePromoted;
+import nbbrd.heylogs.Heylogs;
+import nbbrd.heylogs.Version;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+
+import java.io.File;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Objects;
+
+import static internal.heylogs.maven.plugin.HeylogsParameters.*;
+import static internal.heylogs.maven.plugin.MojoFunction.of;
+
+@Mojo(name = "release", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, threadSafe = true, requiresProject = false)
+public final class ReleaseMojo extends HeylogsMojo {
+
+ @Parameter(defaultValue = WORKING_DIR_CHANGELOG, property = INPUT_FILE_PROPERTY)
+ private File inputFile;
+
+ @Parameter(defaultValue = "${project.build.directory}/CHANGELOG.md", property = OUTPUT_FILE_PROPERTY)
+ private File outputFile;
+
+ @Parameter(defaultValue = "${project.version}", property = "heylogs.ref")
+ private String ref;
+
+ @Parameter(defaultValue = "", property = "heylogs.tag.prefix")
+ private String tagPrefix;
+
+ @Parameter(defaultValue = "", property = "heylogs.date")
+ private String date;
+
+ @Override
+ public void execute() throws MojoExecutionException {
+ if (skip) {
+ getLog().info("Release has been skipped.");
+ return;
+ }
+
+ if (!inputFile.exists()) {
+ getLog().error("Changelog not found");
+ throw new MojoExecutionException("Changelog not found");
+ }
+
+ release(loadVersion(), loadTagPrefix());
+ }
+
+ private Version loadVersion() throws MojoExecutionException {
+ return Version.of(ref, '-', DATE_PARSER.applyWithMojo(date));
+ }
+
+ private String loadTagPrefix() throws MojoExecutionException {
+ return TAG_PREFIX_PARSER.applyWithMojo(tagPrefix);
+ }
+
+ private void release(Version version, String tagPrefix) throws MojoExecutionException {
+ Heylogs heylogs = initHeylogs(false);
+
+ Document changelog = readChangelog(inputFile);
+
+ getLog().info("Releasing " + version + " with tag prefix '" + tagPrefix + "'");
+ heylogs.releaseChanges(changelog, version, tagPrefix);
+
+ writeChangelog(changelog, outputFile);
+ }
+
+ @MightBePromoted
+ private static String parseTagPrefix(String tagPrefix) {
+ return Objects.toString(tagPrefix, "");
+ }
+
+ @MightBePromoted
+ private static LocalDate parseDate(String date) {
+ return date == null ? LocalDate.now(ZoneId.systemDefault()) : LocalDate.parse(date);
+ }
+
+ private static final MojoFunction TAG_PREFIX_PARSER = of(ReleaseMojo::parseTagPrefix, "Invalid format for 'tagPrefix' parameter");
+ private static final MojoFunction DATE_PARSER = of(ReleaseMojo::parseDate, "Invalid format for 'date' parameter");
+}
diff --git a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ScanMojo.java b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ScanMojo.java
index acf4081..9d7881d 100644
--- a/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ScanMojo.java
+++ b/heylogs-maven-plugin/src/main/java/nbbrd/heylogs/maven/plugin/ScanMojo.java
@@ -51,7 +51,7 @@ private void scan() throws MojoExecutionException {
Scan scan = Scan
.builder()
.source(inputFile.toString())
- .summary(heylogs.scan(readChangelog(inputFile)))
+ .summary(heylogs.scanContent(readChangelog(inputFile)))
.build();
try (Writer writer = newWriter(outputFile, getLog()::info)) {
diff --git a/lychee.toml b/lychee.toml
index 7690982..bcb4aea 100644
--- a/lychee.toml
+++ b/lychee.toml
@@ -1 +1 @@
-exclude_path = ["heylogs-api/src/test/resources/Main.md"]
\ No newline at end of file
+exclude_path = ["heylogs-api/src/test/resources/Main.md","heylogs-ext-github/src/test/resources/Main.md","heylogs-ext-semver/src/test/resources/Main.md"]
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 3c5907d..4615da8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.github.nbbrd.heylogs
heylogs-parent
- 0.8.1
+ 0.9.0
pom
heylogs
@@ -39,7 +39,7 @@
UTF-8
- 2024-04-18T14:11:44Z
+ 2024-08-28T13:40:35Z
1.8
1.8
@@ -54,21 +54,21 @@
org.checkerframework
checker-qual
- 3.42.0
+ 3.46.0
org.junit
junit-bom
- 5.10.2
+ 5.11.0
pom
import
org.assertj
assertj-core
- 3.25.3
+ 3.26.3
@@ -93,7 +93,7 @@
org.apache.maven.plugins
maven-clean-plugin
- 3.3.2
+ 3.4.0
org.apache.maven.plugins
@@ -103,17 +103,17 @@
org.apache.maven.plugins
maven-deploy-plugin
- 3.1.1
+ 3.1.3
org.apache.maven.plugins
maven-install-plugin
- 3.1.1
+ 3.1.3
org.apache.maven.plugins
maven-jar-plugin
- 3.4.0
+ 3.4.2
org.apache.maven.plugins
@@ -123,17 +123,17 @@
org.apache.maven.plugins
maven-site-plugin
- 3.12.1
+ 3.20.0
org.apache.maven.plugins
maven-surefire-plugin
- 3.2.5
+ 3.4.0
org.apache.maven.surefire
surefire-junit-platform
- 3.2.5
+ 3.4.0
@@ -141,17 +141,17 @@
org.apache.maven.plugins
maven-dependency-plugin
- 3.6.1
+ 3.8.0
org.apache.maven.plugins
maven-enforcer-plugin
- 3.4.1
+ 3.5.0
org.gaul
modernizer-maven-plugin
- 2.7.0
+ 2.9.0
de.thetaphi
@@ -171,7 +171,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.6.3
+ 3.8.0
org.simplify4u.plugins
@@ -181,7 +181,7 @@
org.sonatype.plugins
nexus-staging-maven-plugin
- 1.6.13
+ 1.7.0
org.jacoco
@@ -191,7 +191,7 @@
org.jreleaser
jreleaser-maven-plugin
- 1.11.0
+ 1.13.1
@@ -243,6 +243,9 @@
heylogs-cli
heylogs-maven-plugin
heylogs-bom
+ heylogs-ext-github
+ heylogs-ext-json
+ heylogs-ext-semver
@@ -276,10 +279,10 @@
- 1.18.32
+ 1.18.34
1.9.0
1.5.1
- 4.7.5
+ 4.7.6
@@ -476,7 +479,7 @@
true
-
+
true
@@ -658,6 +661,7 @@
ossrh
https://s01.oss.sonatype.org/
true
+ 10
@@ -683,6 +687,7 @@
ossrh
https://s01.oss.sonatype.org/
true
+ 10