Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .agents/skills/openfasttrace/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,28 @@ Multiple coverage:

## Tracing

## Syntax: Gherkin

Gherkin `.feature` files can define OFT scenario items. Put exactly one OFT ID
in the contiguous tag region immediately before a `Scenario` or `Scenario
Outline`. Optional `# Covers:` and `# Needs:` comments belong between the tags
and the scenario header. Multiple `Covers` comments accumulate IDs; `Needs`
may appear once.

```gherkin
@id:scn~user-login~1
# Covers: req~authentication~1
# Needs: dsn, itest
Scenario: User logs in
Given a registered user
When valid credentials are entered
Then access is granted
```

Legacy coverage tags are recognized only in Gherkin comments, for example
`# [impl~login~1 -> dsn~authentication~1]`. Executable Gherkin lines are not
evaluated for coverage tags.

Tracing can be performed via CLI, Maven, or Gradle.

### CLI Usage
Expand Down
1 change: 1 addition & 0 deletions doc/changes/changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Changes

* [4.7.0](changes_4.7.0.md)
* [4.6.0](changes_4.6.0.md)
* [4.5.0](changes_4.5.0.md)
* [4.4.0](changes_4.4.0.md)
Expand Down
14 changes: 14 additions & 0 deletions doc/changes/changes_4.7.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# OpenFastTrace 4.7.0, released 2026-07-??

Code name: Gherkin Importer

## Summary

OpenFastTrace can now import traced specifications directly from Gherkin
`.feature` files. Annotate scenarios or scenario outlines with an OFT ID and
optional `Covers` and `Needs` metadata; existing coverage tags remain supported
when written in Gherkin comments.

## New Features

* #563: Added Gherkin `.feature` specification import for annotated scenarios and scenario outlines.
75 changes: 58 additions & 17 deletions doc/spec/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,49 @@ The default priorities for standard importers are:
1. Markdown Importer: 1000
2. reStructuredText Importer: 2000
3. Specobject (ReqM2) Importer: 3000
4. Tag Importer: 10000
5. Zip Importer: 20000
4. Gherkin Importer: 9000
5. Tag Importer: 10000
6. Zip Importer: 20000

### Gherkin Import

#### Importer Selection
`dsn~gherkin.importer-selection~1`

The Gherkin importer selects `.feature` files with priority 9000, ahead of the Tag Importer. This gives Gherkin syntax ownership to the dedicated importer while retaining the Tag Importer as the fallback for other source files.

Covers:

* `req~gherkin-scenario-import~1`

Needs: impl, utest, itest

#### Streaming Import
`dsn~gherkin.streaming-import~1`

The Gherkin importer scans each input file once. It imports only scenarios and scenario outlines with exactly one immediately preceding `@id:` tag, maps header location and title to import events, and streams non-comment scenario steps into the description until a Gherkin block boundary.

Scoped `# Covers:` and `# Needs:` comments are validated between the tag region and header. Multiple `Covers` directives accumulate coverage IDs; `Needs` occurs at most once. The importer retains only active metadata and previously imported IDs.

Covers:

* `req~gherkin-scenario-import~1`
* `req~gherkin-metadata-validation~1`

Needs: impl, utest

#### Support Legacy Coverage Tags
`dsn~gherkin.comment-coverage-tags~1`

The Gherkin importer delegates only comment lines to the shared coverage-tag parser. This preserves legacy comment coverage tags without applying their regular expressions to executable Gherkin text.

When a comment tag occurs inside an imported scenario, its listener events are buffered until the scenario ends. The shared parser emits complete specification-item event sequences, so emitting them immediately would interleave them with the open scenario item and corrupt the listener state.

Covers:

* `req~gherkin-comment-coverage-tags~1`

Needs: impl, utest

### ReqM2 File Detection
`dsn~import.reqm2-file-detection~1`
Expand Down Expand Up @@ -558,7 +599,7 @@ Needs: impl, itest
#### HTML Reports Allows Configuring Details Display Status
`dsn~reporting.html.details-display~1`

OFT allows configuring the specification item detail section display status (expanded or collapsed). Default is collapsed.
OFT allows configuring the specification item detail section display status (expanded or collapsed). Default is collapsed.

Covers:

Expand Down Expand Up @@ -699,13 +740,13 @@ Needs: impl, utest
A requirement ID has the following format

requirement-id = type "~" id "~" revision

type = 1*ALPHA

id = id-fragment *("." id-fragment)

id-fragment = UNICODE_ALPHA *(UNICODE_ALPHA / DIGIT / "_" / "-")

revision = 1*DIGIT

Rationale:
Expand Down Expand Up @@ -750,9 +791,9 @@ Needs: impl, utest
In Markdown specification item references have the following format:

reference = (plain-reference / url-style-link)

plain-reference = requirement-id

url-style-link = "[" link-text "]" "(" "#" requirement-id ")"

Covers:
Expand All @@ -767,9 +808,9 @@ Needs: impl, utest
The Markdown Importer supports the following format for links that cover a different specification item.

covers-list = covers-header 1*(LINEBREAK covers-line)

covers-header = "Covers:" *WSP

covers-line = *WSP "*" *WSP reference

Only one traced reference per line is supported. Any optional text after the reference is ignored if it is separated by at least one whitespace character
Expand All @@ -790,9 +831,9 @@ Needs: impl, utest
The Markdown Importer supports the following format for links to a different specification item which the current depends on.

depends-list = depends-header 1*(LINEBREAK depends-line)

depends-header = "Depends:" *WSP

depends-line = *WSP "*" *WSP reference

Only one traced reference per line is supported. Any optional text after the reference is ignored if it is separated by at least one whitespace character
Expand Down Expand Up @@ -852,11 +893,11 @@ The Markdown Importer supports forwarding required coverage from one artifact ty

artifact-need-redirection = skipped-artifact-type *WSP "-->" *WSP target-artifact-list
*WSP ":" *WSP original-requirement-id

skipped-artifact-type = artifact-type

target-artifact-list = artifact-type *("," *WSP artifact-type)

original-requirement-id = requirement-id

The following example shows an architectural specification item that forwards the needed coverage directly to the detailed design and an integration test:
Expand Down Expand Up @@ -1234,7 +1275,7 @@ Needs: impl, utest

### Why is This Architecture Relevant?

Authors of importers need to be able to rely on these cleanups being done centrally, so that they don't have to implement them themselves.
Authors of importers need to be able to rely on these cleanups being done centrally, so that they don't have to implement them themselves.

### Alternatives Considered

Expand Down
11 changes: 6 additions & 5 deletions doc/spec/design/quality_requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,12 @@ The following rules are written for both human contributors and coding agents. T

### Java Test Rules

1. Use Hamcrest matchers for assertions.
2. Extract repeated complex assertions into dedicated matcher classes when that improves readability.
3. Declare only the specific checked exceptions that are directly thrown by the code under test. Do not use generic exceptions (e.g., Exception, Throwable) in test method signatures.
4. When asserting exceptions, the assertion should invoke exactly one method call—the method under test. Avoid nesting additional method calls inside the assertion. Prepare all inputs outside the assertion so the failure is attributable to a single call.
5. Prefer @ParameterizedTest for testing multiple input variations instead of generating or mutating test data within a single test method (e.g., loops or inline variations).
1. Test method names must start with `test` and describe the behavior under test.
2. Use Hamcrest matchers for assertions.
3. Extract repeated complex assertions into dedicated matcher classes when that improves readability.
4. Declare only the specific checked exceptions that are directly thrown by the code under test. Do not use generic exceptions (e.g., Exception, Throwable) in test method signatures.
5. When asserting exceptions, the assertion should invoke exactly one method call—the method under test. Avoid nesting additional method calls inside the assertion. Prepare all inputs outside the assertion so the failure is attributable to a single call.
6. Prefer @ParameterizedTest for testing multiple input variations instead of generating or mutating test data within a single test method (e.g., loops or inline variations).

## Dependency Policy

Expand Down
66 changes: 53 additions & 13 deletions doc/spec/system_requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,46 @@ Coverage tags indicate parts of the source code that implements a certain requir

Needs: req

### Gherkin Import
`feat~gherkin-import~1`

OFT imports specification items from annotated Gherkin scenarios and scenario outlines in `.feature` files.

Needs: req

#### Import Gherkin Scenarios
`req~gherkin-scenario-import~1`

OFT imports a Gherkin `Scenario` or `Scenario Outline` as a specification item when its immediately preceding contiguous tag region contains exactly one `@id:<specification-item-id>` tag. The scenario header supplies the title and location; scenario steps form the description.

Covers:

* [feat~gherkin-import~1](#gherkin-import)

Needs: dsn

#### Validate Gherkin Metadata
`req~gherkin-metadata-validation~1`

OFT accepts optional, scoped `# Covers:` and `# Needs:` comments between an ID tag region and its scenario header. `Covers` may occur multiple times; `Needs` may occur once. Each directive must contain a non-empty, valid, duplicate-free list. Invalid IDs, artifact types, repeated IDs, duplicate scenario IDs, and orphan directives cause an import error that identifies the file and line.

Covers:

* [feat~gherkin-import~1](#gherkin-import)

Needs: dsn

#### Preserve Gherkin Comment Coverage Tags
`req~gherkin-comment-coverage-tags~1`

OFT imports legacy coverage tags from comments in `.feature` files, but does not evaluate coverage tags in executable Gherkin lines.

Covers:

* [feat~gherkin-import~1](#gherkin-import)

Needs: dsn

### ReqM2 Export
`feat~reqm2-export~1`

Expand Down Expand Up @@ -526,7 +566,7 @@ Covers:

Needs: dsn

#### Include Items That Don't Have Tags Or Where at Least One Tag Matches
#### Include Items That Don't Have Tags Or Where at Least One Tag Matches
`req~include-items-that-do-not-have-tags-or-where-at-least-one-tag-matches~1`

OFT gives users the option to include only specification items that either do not have tags or have at least one tag from a configurable set of tags during processing.
Expand All @@ -548,7 +588,7 @@ Reports are the main way to find out if a projects requirements are covered prop
Users can choose to display the requirement origin (e.g. file and line number) in reports:

* In the body of a specification item
* For each link to a specification item
* For each link to a specification item

Rationale:

Expand Down Expand Up @@ -806,29 +846,29 @@ Covers:
Needs: dsn

#### Common

##### CLI Help
`req~cli.help~1`

`help`, `-h` and `--help` show a short help text with command line usage.

Covers:

* [feat~command-line-interface~1](#command-line-interface)

Needs: dsn

##### CLI Version
`req~cli.version~1`

`help`, `-h` and `--help` show the version of OFT.

Covers:

* [feat~command-line-interface~1](#command-line-interface)

Needs: dsn

##### Input Selection
`req~cli.input-selection~1`

Expand Down
19 changes: 19 additions & 0 deletions doc/user_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,25 @@ Note that XML is at the moment not yet supported by the Tag Importer, because it
**Test Specification languages**

* [Gherkin](https://cucumber.io/docs/gherkin/) (`.feature`)

#### Gherkin

OFT imports Gherkin `Scenario` and `Scenario Outline` blocks in `.feature` files when the immediately preceding tag region contains one OFT ID tag. Place optional `Covers` and `Needs` comments after the tags and before the scenario header:

```gherkin
@smoke
@id:scn~user-can-log-in~1
# Covers: req~authentication~1
# Needs: dsn, itest
Scenario: A registered user logs in
Given a registered user
When they enter valid credentials
Then access is granted
```

The scenario header becomes the item title and location; its executable steps become the description. `Covers` and `Needs` are case-sensitive and optional. Multiple `Covers` comments accumulate coverage IDs, while `Needs` may appear once; all lists must be non-empty and comma-separated. Invalid or duplicate IDs, types, or directives cause an import error.

Existing full coverage tags remain supported in Gherkin comments, for example `# [impl~login~1 -> dsn~authentication~1]`. OFT deliberately ignores coverage-tag-shaped text in executable Gherkin lines.

#### Markdown

Expand Down
31 changes: 31 additions & 0 deletions importer/gherkin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>openfasttrace-importer-gherkin</artifactId>
<name>OpenFastTrace Gherkin Importer</name>
<parent>
<relativePath>../../openfasttrace-mc-deployable-parent/pom.xml</relativePath>
<groupId>org.itsallcode.openfasttrace</groupId>
<artifactId>openfasttrace-mc-deployable-parent</artifactId>
<version>${revision}</version>
</parent>
<properties>
<project.build.outputTimestamp>${reproducible.build.timestamp}</project.build.outputTimestamp>
</properties>
<dependencies>
<dependency>
<groupId>org.itsallcode.openfasttrace</groupId>
<artifactId>openfasttrace-api</artifactId>
</dependency>
<dependency>
<groupId>org.itsallcode.openfasttrace</groupId>
<artifactId>openfasttrace-importer-tag-importer-common</artifactId>
</dependency>
<dependency>
<groupId>org.itsallcode.openfasttrace</groupId>
<artifactId>openfasttrace-testutil</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
10 changes: 10 additions & 0 deletions importer/gherkin/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import org.itsallcode.openfasttrace.importer.gherkin.GherkinImporterFactory;

/** Provides an importer for Gherkin {@code .feature} files. */
module org.itsallcode.openfasttrace.importer.gherkin {
requires transitive org.itsallcode.openfasttrace.api;
requires org.itsallcode.openfasttrace.importer.tag.common;

provides org.itsallcode.openfasttrace.api.importer.ImporterFactory
with GherkinImporterFactory;
}
Loading
Loading