diff --git a/.github/workflows/broken_links_checker.yml b/.github/workflows/broken_links_checker.yml index 9c5b1e3..80a78d3 100644 --- a/.github/workflows/broken_links_checker.yml +++ b/.github/workflows/broken_links_checker.yml @@ -11,12 +11,14 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Configure broken links checker run: | mkdir -p ./target echo '{ "aliveStatusCodes": [429, 200] }' > ./target/broken_links_checker.json - - uses: gaurav-nelson/github-action-markdown-link-check@v1 + - uses: tcort/github-action-markdown-link-check@v1 with: use-quiet-mode: 'yes' use-verbose-mode: 'yes' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8c6415f..6425852 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,13 +12,15 @@ jobs: contents: read strategy: - fail-fast: true + fail-fast: false matrix: - java: [17] - os: [ubuntu-latest, macos-latest, windows-latest] + java: [17, 21, 25] + os: [ubuntu-latest] include: - - os: ubuntu-latest - java: 21 + - os: macos-latest + java: 17 + - os: windows-latest + java: 17 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-os-${{ matrix.os }}-java-${{ matrix.java }} @@ -35,21 +37,20 @@ jobs: steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 + persist-credentials: false - uses: actions/setup-java@v5 with: distribution: 'temurin' - java-version: | - 17 - 21 + java-version: ${{ matrix.java }} cache: 'maven' - name: Cache SonarQube packages if: ${{ env.DEFAULT_OS == matrix.os && env.DEFAULT_JAVA == matrix.java }} - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar @@ -58,12 +59,14 @@ jobs: - name: Build with Java ${{ matrix.java }} run: | mvn --batch-mode -T 1C clean org.jacoco:jacoco-maven-plugin:prepare-agent install \ + -DossindexSkip=true \ -Djava.version=${{ matrix.java }} - name: Sonar analysis if: ${{ env.DEFAULT_OS == matrix.os && env.DEFAULT_JAVA == matrix.java && env.SONAR_TOKEN != null }} run: | mvn --batch-mode org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \ + -DossindexSkip=true \ -Dsonar.token=$SONAR_TOKEN env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -72,10 +75,41 @@ jobs: - name: Verify reproducible build run: | mvn --batch-mode -T 1C clean verify artifact:compare -DskipTests \ + -DossindexSkip=true \ -Djava.version=${{ matrix.java }} - build: - needs: matrix-build + ossindex: runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - uses: actions/setup-java@v5 + with: + cache: maven + distribution: temurin + java-version: 17 + server-id: ossindex + server-username: OSSINDEX_USERNAME + server-password: OSSINDEX_TOKEN + - name: Ossindex + if: ${{ env.OSSINDEX_USERNAME != null && env.OSSINDEX_TOKEN != null }} + run: | + mvn --errors --batch-mode test-compile \ + org.sonatype.ossindex.maven:ossindex-maven-plugin:audit \ + org.sonatype.ossindex.maven:ossindex-maven-plugin:audit-aggregate + env: + OSSINDEX_USERNAME: ${{ secrets.OSSINDEX_USERNAME }} + OSSINDEX_TOKEN: ${{ secrets.OSSINDEX_TOKEN }} + + build: + needs: + - matrix-build + - ossindex + runs-on: ubuntu-slim + permissions: + contents: read steps: - run: echo "Build successful" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 522d768..7149f2e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -5,8 +5,6 @@ on: branches: [ main ] pull_request: branches: [ main ] - schedule: - - cron: '0 4 * * 3' jobs: analyze: @@ -22,7 +20,9 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 + with: + persist-credentials: false - uses: actions/setup-java@v5 with: @@ -35,8 +35,9 @@ jobs: with: languages: java - - name: Autobuild - uses: github/codeql-action/autobuild@v4 + - name: Build + # gitcommitid plugin requires a newer version of maven, so we skip it here + run: mvn --batch-mode --errors -Dmaven.gitcommitid.skip=true clean compile - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1ede7c9..d80b233 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,11 @@ on: required: true type: boolean default: false + maven-central-auto-publish: + description: "Automatically publish to Maven Central" + required: true + type: boolean + default: true jobs: release: @@ -22,7 +27,9 @@ jobs: contents: write # Required for creating GitHub release steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 + with: + persist-credentials: true - name: Fail if not running on main branch if: ${{ github.ref != 'refs/heads/main' }} @@ -37,25 +44,31 @@ jobs: distribution: "temurin" java-version: 17 cache: "maven" - server-id: ossrh + server-id: central server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD gpg-private-key: ${{ secrets.OSSRH_GPG_SECRET_KEY }} gpg-passphrase: MAVEN_GPG_PASSPHRASE - name: Build - run: mvn --batch-mode -T 1C clean install + run: mvn --batch-mode -T 1C clean install -DossindexSkip=true - name: List secret GPG keys run: gpg --list-secret-keys - name: Publish to Maven Central Repository if: ${{ !inputs.skip-deploy-maven-central }} - run: mvn --batch-mode deploy -DskipTests -Possrh -DstagingDescription="Deployed via GitHub workflow release.yml" + run: | + mvn --batch-mode deploy -DskipTests -PcentralPublishing + -DossindexSkip=true \ + -DcentralPublishingDeploymentName="Deployed OFT Asciidoc Plugin via release.yml" \ + -DcentralPublishingSkipPublishing=false \ + -DcentralPublishingAutoPublish=${AUTO_PUBLISH} env: - MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_PORTAL_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PORTAL_TOKEN }} MAVEN_GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} + AUTO_PUBLISH: ${{ inputs.maven-central-auto-publish }} - name: Create GitHub Release run: ./.github/workflows/github_release.sh diff --git a/.vscode/settings.json b/.vscode/settings.json index b1f2fae..4f07762 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,7 +6,6 @@ "source.generate.finalModifiers": "explicit", "source.fixAll": "explicit" }, - "java.saveActions.organizeImports": true, "java.sources.organizeImports.starThreshold": 3, "java.sources.organizeImports.staticStarThreshold": 3, "java.configuration.updateBuildConfiguration": "automatic", diff --git a/doc/changes/changelog.md b/doc/changes/changelog.md index 37d88fc..5cd0804 100644 --- a/doc/changes/changelog.md +++ b/doc/changes/changelog.md @@ -3,3 +3,4 @@ * [0.1.0](changes_0.1.0.md) * [0.2.0](changes_0.2.0.md) * [0.3.0](changes_0.3.0.md) +* [0.3.1](changes_0.3.1.md) diff --git a/doc/changes/changes_0.3.1.md b/doc/changes/changes_0.3.1.md new file mode 100644 index 0000000..dce6486 --- /dev/null +++ b/doc/changes/changes_0.3.1.md @@ -0,0 +1,11 @@ +# OpenFastTrace AsciiDoc Plugin 0.3.1, released 2026-05-15 + +Code name: Update Maven Central publishing + +## Summary + +This release updates dependencies and uses the new Maven Central Portal publishing process. The release also updates dependencies. + +## Bug Fixes + +* [PR #18](https://github.com/itsallcode/openfasttrace-asciidoc-plugin/pull/18): Updated dependencies diff --git a/pom.xml b/pom.xml index c220f80..7a691e3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.itsallcode openfasttrace-asciidoc-plugin - 0.3.0 + 0.3.1 jar OpenFastTrace AsciiDoc Importer @@ -15,13 +15,15 @@ UTF-8 17 - 4.1.0 - 5.11.4 - 0.8.12 + 4.4.0 + 6.0.3 + 0.8.14 + 3.0.0 itsallcode https://sonarcloud.io ${git.commit.time} + false @@ -62,17 +64,6 @@ https://github.com/itsallcode/openfasttrace-asciidoc-plugin - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - org.asciidoctor @@ -107,14 +98,14 @@ org.junit.jupiter - junit-jupiter-params + junit-jupiter ${junit.version} test org.mockito mockito-junit-jupiter - 5.12.0 + 5.23.0 test @@ -128,24 +119,31 @@ - ossrh + centralPublishing + + false + false + Manual deployment of OFT Asciidoc Plugin + - org.sonatype.plugins - nexus-staging-maven-plugin - 1.7.0 + org.sonatype.central + central-publishing-maven-plugin + 0.10.0 true - ossrh - https://oss.sonatype.org/ - true + central + ${centralPublishingSkipPublishing} + ${centralPublishingAutoPublish} + validated + ${centralPublishingDeploymentName} org.apache.maven.plugins maven-gpg-plugin - 3.2.4 + 3.2.8 sign-artifacts @@ -159,7 +157,7 @@ org.apache.maven.plugins maven-deploy-plugin - 3.1.2 + 3.1.4 @@ -171,7 +169,7 @@ io.github.git-commit-id git-commit-id-maven-plugin - 9.0.1 + 10.0.0 get-the-git-infos @@ -212,7 +210,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.5.0 + 3.6.2 enforce-maven @@ -232,12 +230,12 @@ org.apache.maven.plugins maven-clean-plugin - 3.4.0 + 3.5.0 org.apache.maven.plugins maven-compiler-plugin - 3.13.0 + 3.15.0 ${java.version} ${java.version} @@ -251,12 +249,12 @@ org.apache.maven.plugins maven-jar-plugin - 3.4.2 + 3.5.0 org.apache.maven.plugins maven-source-plugin - 3.3.1 + 3.4.0 attach-sources @@ -269,7 +267,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.8.0 + 3.12.0 attach-javadocs @@ -289,7 +287,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.2 package @@ -349,23 +347,39 @@ + + + org.apache.maven.plugins + maven-dependency-plugin + 3.10.0 + + + + properties + + + org.apache.maven.plugins maven-surefire-plugin - 3.5.2 + 3.5.5 src/test/resources/logging.properties - -XX:+EnableDynamicAgentLoading ${argLine} + @{argLine} -javaagent:${org.mockito:mockito-core:jar} org.sonatype.ossindex.maven ossindex-maven-plugin 3.2.0 + + ossindex + ${ossindexSkip} + audit @@ -404,7 +418,7 @@ org.apache.maven.plugins maven-artifact-plugin - 3.5.1 + 3.6.1 verify-reproducible-build @@ -416,6 +430,11 @@ true + + org.sonarsource.scanner.maven + sonar-maven-plugin + 5.6.0.6792 + diff --git a/src/test/java/org/itsallcode/openfasttrace/importer/asciidoc/AsciiDocImporterFactoryTest.java b/src/test/java/org/itsallcode/openfasttrace/importer/asciidoc/AsciiDocImporterFactoryTest.java index fa15a89..5827c68 100644 --- a/src/test/java/org/itsallcode/openfasttrace/importer/asciidoc/AsciiDocImporterFactoryTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/importer/asciidoc/AsciiDocImporterFactoryTest.java @@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public class AsciiDocImporterFactoryTest +class AsciiDocImporterFactoryTest { // [utest->dsn~asciidoc-file-extensions~1] @Test diff --git a/src/test/java/org/itsallcode/openfasttrace/importer/asciidoc/AsciiDocImporterTest.java b/src/test/java/org/itsallcode/openfasttrace/importer/asciidoc/AsciiDocImporterTest.java index 4e67fce..8400825 100644 --- a/src/test/java/org/itsallcode/openfasttrace/importer/asciidoc/AsciiDocImporterTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/importer/asciidoc/AsciiDocImporterTest.java @@ -2,7 +2,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.*; import org.itsallcode.openfasttrace.api.core.SpecificationItemId; import org.itsallcode.openfasttrace.api.importer.ImportEventListener; @@ -11,205 +11,200 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.*; +import org.mockito.InOrder; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class AsciiDocImporterTest +class AsciiDocImporterTest { - @Mock - private ImportEventListener listener; - private InOrder inOrder; - - @BeforeEach - void setup() - { - inOrder = inOrder(listener); - } - - @ParameterizedTest - @ValueSource(strings = - { - """ - # Spec - - [.specitem] - ## A Requirement - """, - """ - # Spec - - [.specitem] - ==== - ==== - """ - }) - void testImporterIgnoresSpecItemWithoutId(final String content) - { - final var importer = new AsciiDocImporter(content, listener); - importer.runImport(); - Mockito.verifyNoMoreInteractions(listener); - } - - // [utest->dsn~adoc-specification-item-markup~1] - // [utest->dsn~adoc-specification-item-id~1] - // [utest->dsn~adoc-specification-item-title~1] - // [utest->dsn~adoc-specification-item-description~1] - // [utest->dsn~adoc-specification-item-rationale~1] - // [utest->dsn~adoc-specification-item-comment~1] - // [utest->dsn~adoc-depends-list~1] - // [utest->dsn~adoc-covers-list~1] - // [utest->dsn~adoc-needs-coverage-list~1] - @ParameterizedTest - @ValueSource(strings = - { - """ - # Spec - - [.specitem, oft-sid="dsn~detail-design~1", oft-depends="dsn~grand-design~1, arch~general-constraints~1", oft-needs="impl, utest", oft-covers="req~first-requirement~1, req~second-requirement~1", oft-tags="Priority1, OtherComponent"] - ## A Requirement - - The description - - [.rationale] - The rationale - - [.comment] - A comment - """, - """ - # Spec - - [.specitem, oft-sid="dsn~detail-design~1", oft-depends="dsn~grand-design~1, arch~general-constraints~1", oft-needs="impl, utest", oft-covers="req~first-requirement~1, req~second-requirement~1", oft-tags="Priority1, OtherComponent"] - ## A Requirement - - [.rationale] - The rationale - - [.description] - The description - - [.comment] - A comment - """, - """ - # Spec - - .A Requirement - [.specitem, oft-sid="dsn~detail-design~1", oft-depends="dsn~grand-design~1, arch~general-constraints~1", oft-needs="impl, utest", oft-covers="req~first-requirement~1, req~second-requirement~1", oft-tags="Priority1, OtherComponent"] - ==== - - The description - - [.rationale] - The rationale - - [.comment] - A comment - ==== - """, - """ - # Spec - - .A Requirement - [.specitem, oft-sid="dsn~detail-design~1", oft-depends="dsn~grand-design~1, arch~general-constraints~1", oft-needs="impl, utest", oft-covers="req~first-requirement~1, req~second-requirement~1", oft-tags="Priority1, OtherComponent"] - ==== - - [.rationale] - The rationale - - [.description] - The description - - [.comment] - A comment - ==== - """ - }) - void testImporterReadsFullSpecItem(final String content) - { - final var importer = new AsciiDocImporter(content, listener); - importer.runImport(); - inOrder.verify(listener).beginSpecificationItem(); - Mockito.verify(listener).setId(new SpecificationItemId.Builder("dsn~detail-design~1").build()); - Mockito.verify(listener).setLocation(any()); - Mockito.verify(listener).setTitle("A Requirement"); - Mockito.verify(listener).addDependsOnId(new SpecificationItemId.Builder("dsn~grand-design~1").build()); - Mockito.verify(listener) - .addDependsOnId(new SpecificationItemId.Builder("arch~general-constraints~1").build()); - Mockito.verify(listener).addNeededArtifactType("impl"); - Mockito.verify(listener).addNeededArtifactType("utest"); - Mockito.verify(listener) - .addCoveredId(new SpecificationItemId.Builder("req~first-requirement~1").build()); - Mockito.verify(listener) - .addCoveredId(new SpecificationItemId.Builder("req~second-requirement~1").build()); - Mockito.verify(listener).addTag("Priority1"); - Mockito.verify(listener).addTag("OtherComponent"); - Mockito.verify(listener).appendDescription("The description"); - Mockito.verify(listener).appendRationale("The rationale"); - Mockito.verify(listener).appendComment("A comment"); - inOrder.verify(listener).endSpecificationItem(); - Mockito.verifyNoMoreInteractions(listener); - } - - // [utest->dsn~adoc-artifact-forwarding-notation~1] - @Test - void testImporterReadsForwardingSpecItem() - { - final var content = """ - # Spec - - ## Design - - [.specitem, oft-skipped="dsn", oft-needs="impl, utest", oft-covers="req~first-requirement~1"] - -- - -- - """; - final var importer = new AsciiDocImporter(content, listener); - importer.runImport(); - inOrder.verify(listener).beginSpecificationItem(); - Mockito.verify(listener) - .setId(new SpecificationItemId.Builder("dsn~first-requirement~1").build()); - Mockito.verify(listener).setLocation( - argThat(location -> "verbatim".equals(location.getPath()) && location.getLine() == 6)); - Mockito.verify(listener).addNeededArtifactType("impl"); - Mockito.verify(listener).addNeededArtifactType("utest"); - Mockito.verify(listener) - .addCoveredId(new SpecificationItemId.Builder("req~first-requirement~1").build()); - inOrder.verify(listener).endSpecificationItem(); - Mockito.verifyNoMoreInteractions(listener); - } - - @Test - void testImporterReadsSpecItemNestedInTableCell() - { - final var content = """ - .Test Table - [%autowidth] - |=== - |Column 1 |Column 2 - - |Default Style - a| - Asciidoc Style - - [.specitem, oft-sid="req~nested-in-table~1", oft-needs="dsn"] - -- - The description - -- - |=== - """; - final var importer = new AsciiDocImporter(content, listener); - importer.runImport(); - inOrder.verify(listener).beginSpecificationItem(); - Mockito.verify(listener) - .setId(new SpecificationItemId.Builder("req~nested-in-table~1").build()); - Mockito.verify(listener).setLocation( - argThat(location -> "verbatim".equals(location.getPath()))); - Mockito.verify(listener).addNeededArtifactType("dsn"); - Mockito.verify(listener).appendDescription("The description"); - inOrder.verify(listener).endSpecificationItem(); - Mockito.verifyNoMoreInteractions(listener); - } - + @Mock + private ImportEventListener listener; + private InOrder inOrder; + + @BeforeEach + void setup() + { + inOrder = inOrder(listener); + } + + @ParameterizedTest + @ValueSource(strings = + { + """ + # Spec + + [.specitem] + ## A Requirement + """, + """ + # Spec + + [.specitem] + ==== + ==== + """ + }) + void testImporterIgnoresSpecItemWithoutId(final String content) + { + final var importer = new AsciiDocImporter(content, listener); + importer.runImport(); + verifyNoMoreInteractions(listener); + } + + // [utest->dsn~adoc-specification-item-markup~1] + // [utest->dsn~adoc-specification-item-id~1] + // [utest->dsn~adoc-specification-item-title~1] + // [utest->dsn~adoc-specification-item-description~1] + // [utest->dsn~adoc-specification-item-rationale~1] + // [utest->dsn~adoc-specification-item-comment~1] + // [utest->dsn~adoc-depends-list~1] + // [utest->dsn~adoc-covers-list~1] + // [utest->dsn~adoc-needs-coverage-list~1] + @ParameterizedTest + @ValueSource(strings = + { + """ + # Spec + + [.specitem, oft-sid="dsn~detail-design~1", oft-depends="dsn~grand-design~1, arch~general-constraints~1", oft-needs="impl, utest", oft-covers="req~first-requirement~1, req~second-requirement~1", oft-tags="Priority1, OtherComponent"] + ## A Requirement + + The description + + [.rationale] + The rationale + + [.comment] + A comment + """, + """ + # Spec + + [.specitem, oft-sid="dsn~detail-design~1", oft-depends="dsn~grand-design~1, arch~general-constraints~1", oft-needs="impl, utest", oft-covers="req~first-requirement~1, req~second-requirement~1", oft-tags="Priority1, OtherComponent"] + ## A Requirement + + [.rationale] + The rationale + + [.description] + The description + + [.comment] + A comment + """, + """ + # Spec + + .A Requirement + [.specitem, oft-sid="dsn~detail-design~1", oft-depends="dsn~grand-design~1, arch~general-constraints~1", oft-needs="impl, utest", oft-covers="req~first-requirement~1, req~second-requirement~1", oft-tags="Priority1, OtherComponent"] + ==== + + The description + + [.rationale] + The rationale + + [.comment] + A comment + ==== + """, + """ + # Spec + + .A Requirement + [.specitem, oft-sid="dsn~detail-design~1", oft-depends="dsn~grand-design~1, arch~general-constraints~1", oft-needs="impl, utest", oft-covers="req~first-requirement~1, req~second-requirement~1", oft-tags="Priority1, OtherComponent"] + ==== + + [.rationale] + The rationale + + [.description] + The description + + [.comment] + A comment + ==== + """ + }) + void testImporterReadsFullSpecItem(final String content) + { + final var importer = new AsciiDocImporter(content, listener); + importer.runImport(); + inOrder.verify(listener).beginSpecificationItem(); + verify(listener).setId(new SpecificationItemId.Builder("dsn~detail-design~1").build()); + verify(listener).setLocation(any()); + verify(listener).setTitle("A Requirement"); + verify(listener).addDependsOnId(new SpecificationItemId.Builder("dsn~grand-design~1").build()); + verify(listener).addDependsOnId(new SpecificationItemId.Builder("arch~general-constraints~1").build()); + verify(listener).addNeededArtifactType("impl"); + verify(listener).addNeededArtifactType("utest"); + verify(listener).addCoveredId(new SpecificationItemId.Builder("req~first-requirement~1").build()); + verify(listener).addCoveredId(new SpecificationItemId.Builder("req~second-requirement~1").build()); + verify(listener).addTag("Priority1"); + verify(listener).addTag("OtherComponent"); + verify(listener).appendDescription("The description"); + verify(listener).appendRationale("The rationale"); + verify(listener).appendComment("A comment"); + inOrder.verify(listener).endSpecificationItem(); + verifyNoMoreInteractions(listener); + } + + // [utest->dsn~adoc-artifact-forwarding-notation~1] + @Test + void testImporterReadsForwardingSpecItem() + { + final var content = """ + # Spec + + ## Design + + [.specitem, oft-skipped="dsn", oft-needs="impl, utest", oft-covers="req~first-requirement~1"] + -- + -- + """; + final var importer = new AsciiDocImporter(content, listener); + importer.runImport(); + inOrder.verify(listener).beginSpecificationItem(); + verify(listener).setId(new SpecificationItemId.Builder("dsn~first-requirement~1").build()); + verify(listener).setLocation( + argThat(location -> "verbatim".equals(location.getPath()) && location.getLine() == 6)); + verify(listener).addNeededArtifactType("impl"); + verify(listener).addNeededArtifactType("utest"); + verify(listener).addCoveredId(new SpecificationItemId.Builder("req~first-requirement~1").build()); + inOrder.verify(listener).endSpecificationItem(); + verifyNoMoreInteractions(listener); + } + + @Test + void testImporterReadsSpecItemNestedInTableCell() + { + final var content = """ + .Test Table + [%autowidth] + |=== + |Column 1 |Column 2 + + |Default Style + a| + Asciidoc Style + + [.specitem, oft-sid="req~nested-in-table~1", oft-needs="dsn"] + -- + The description + -- + |=== + """; + final var importer = new AsciiDocImporter(content, listener); + importer.runImport(); + inOrder.verify(listener).beginSpecificationItem(); + verify(listener) + .setId(new SpecificationItemId.Builder("req~nested-in-table~1").build()); + verify(listener).setLocation( + argThat(location -> "verbatim".equals(location.getPath()))); + verify(listener).addNeededArtifactType("dsn"); + verify(listener).appendDescription("The description"); + inOrder.verify(listener).endSpecificationItem(); + verifyNoMoreInteractions(listener); + } }