From 8210c51f5358943df4bb9ae7e751758a79780075 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 28 Jul 2026 08:28:57 +0200 Subject: [PATCH 01/15] #49: Ignore the whole .idea directory. --- .gitignore | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index ede5725..e950034 100644 --- a/.gitignore +++ b/.gitignore @@ -6,13 +6,7 @@ build/ !**/src/test/**/build/ ### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ -.idea/dataSources/ -.idea/dataSources.local.xml -.idea/dataSources.xml +.idea/ *.iws *.iml *.ipr From cda1d1de462daaf6482f593e4c9db5c6cf32d305 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 28 Jul 2026 08:37:40 +0200 Subject: [PATCH 02/15] #63: Planned Markdown outline view. --- ...cification-item-ids-in-markdown-outline.md | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 doc/changesets/63-show-oft-specification-item-ids-in-markdown-outline.md diff --git a/doc/changesets/63-show-oft-specification-item-ids-in-markdown-outline.md b/doc/changesets/63-show-oft-specification-item-ids-in-markdown-outline.md new file mode 100644 index 0000000..02410a3 --- /dev/null +++ b/doc/changesets/63-show-oft-specification-item-ids-in-markdown-outline.md @@ -0,0 +1,98 @@ +# GH-63 Show OFT Specification Item IDs in the Markdown Outline + +## Goal + +Let users see the OpenFastTrace specification item declarations in the Markdown document they are currently reading or editing through the native Markdown Structure / File Structure view. The outline keeps the existing Markdown header hierarchy, lists declarations in source order under the last preceding header, and opens the exact declaration when the user selects an item. + +## Scope + +In scope: + +* Add a Markdown-only outline feature for OpenFastTrace specification item declarations. +* Preserve the native Markdown header tree and add specification item ID declaration nodes beneath the last preceding header. +* Show declarations that occur before the first header at the document root. +* Retain source order among declaration nodes under the same parent. +* Recognize the existing plain and single-backtick Markdown declaration variants. +* Navigate from an outline node to the declaration anchor in the focused editor. +* Rebuild the outline from current document text so unsaved edits are represented. +* Update requirements, design, user documentation, release notes, and Marketplace change notes for this user-visible feature. + +Out of scope: + +* RST, plain text, source code, coverage-tag files, and other non-Markdown formats. +* `Covers:` references, coverage tags, and other non-declaration OFT ID occurrences. +* Specification titles, trace status, coverage, trace defects, or requirement-network rendering. +* A separate OFT tool window, a project-wide OFT browser, or replacement of the existing Markdown Structure view or Go to Symbol. +* New third-party dependencies. + +## Design References + +* [GH-63](https://github.com/itsallcode/openfasttrace-intellij-plugin/issues/63) +* [System Requirements](../system_requirements.md) +* [Solution Strategy](../design/solution_strategy.md) +* [Building Block View](../design/building_block_view.md) +* [Runtime View](../design/runtime_view.md) +* [Quality Requirements](../design/quality_requirements.md) +* [GH-24 Auto-completion for Covers section](24-auto-completion-for-covers-section.md) + +## Strategy + +Add a new chain for Markdown specification-item outline navigation. The new requirement must state that only declaration IDs appear, that they retain source order below their last preceding Markdown header, that pre-header declarations appear at the root, and that selecting an item navigates to its declaration after unsaved edits. + +Extend the Markdown-specific editor support rather than the project declaration index. Register a `StructureViewExtension` that preserves native Markdown structure nodes and contributes synthetic OFT declaration tree elements. Derive those elements from `OftSyntaxCore.findDefinitionSpecificationItems()` over the focused document text, map their offsets to the last preceding Markdown header, and reuse offset-based editor navigation. This preserves existing Markdown outline behavior and avoids stale index data while the user is editing. + +## Task List + +- [ ] Create and checkout a new Git branch `feat/63-show-oft-specification-item-ids-in-markdown-outline` + +### Requirements And Design + +- [ ] Add a feature item for the Markdown OpenFastTrace specification-item outline in `doc/system_requirements.md`. +- [ ] Add a user requirement stating that the Markdown Structure / File Structure view shows only recognized OFT declaration IDs while preserving Markdown headers. +- [ ] Add scenarios for placing declaration IDs under their last preceding header in source order, placing pre-header IDs at the root, navigating from an ID, and reflecting unsaved document edits. +- [ ] Stop and ask user for a review of the system requirements. +- [ ] Update `doc/design/solution_strategy.md` to record reuse of IntelliJ Structure-view extension APIs and current-document parsing rather than the project index. +- [ ] Extend `doc/design/building_block_view.md` with a Markdown specification-item outline component and its dependencies on Markdown PSI/Structure infrastructure and the shared syntax core. +- [ ] Add one runtime design item per outline scenario in `doc/design/runtime_view.md`, covering tree construction and placement, root-level declarations, navigation, and document-change refresh. +- [ ] Stop and ask user for a review of the design. + +### Implementation + +- [ ] Add a Markdown Structure-view extension registration without replacing the existing Markdown Structure-view factory. +- [ ] Implement an immutable, file-local outline model that extracts only `findDefinitionSpecificationItems()` matches from the current Markdown document and retains their source offsets and order. +- [ ] Implement synthetic, navigable outline tree elements that present the full OFT ID and navigate to its declaration offset in the editor. +- [ ] Associate each declaration with the closest preceding Markdown header PSI element and contribute it below that header; contribute declarations with no preceding header at the document root. +- [ ] Preserve all native Markdown header children and ordering while merging OFT declaration nodes, and exclude `Covers:` entries, coverage tags, invalid IDs, and incomplete IDs. +- [ ] Refresh the outline when the underlying Markdown document changes, including unsaved edits, without using the file-based project index. +- [ ] Keep the implementation limited to Markdown and IntelliJ Platform APIs; do not change RST, generic text, coverage-tag, project-index, or reference-resolution behavior. Don't use internal or deprecated APIs. + +### Verification + +- [ ] Add focused syntax/model tests for declaration extraction and source-order/header-association decisions, including plain and single-backtick declaration forms, pre-header declarations, and exclusion of references and invalid or incomplete IDs. +- [ ] Add IntelliJ light-fixture tests proving that Markdown headers remain present and that OFT IDs appear beneath the last preceding header in source order. +- [ ] Add IntelliJ light-fixture tests for root-level pre-header IDs, navigation to the exact declaration offset, and outline refresh after an unsaved document edit. +- [ ] Keep existing syntax, indexing, navigation, completion, and highlighting tests green. +- [ ] Keep the OpenFastTrace trace clean for the new `feat`, `req`, `scn`, `dsn`, `impl`, and `itest` artifacts in scope. +- [ ] Keep path coverage at or above 80%. +- [ ] Keep the dependency policy unchanged; add no third-party dependencies. +- [ ] Run `./gradlew test`. +- [ ] Run `./gradlew traceRequirements`. +- [ ] Run `./gradlew check`. +- [ ] Run `./gradlew verifyPlugin`. +- [ ] Keep the SonarQube Cloud quality gate green after CI analysis. + +### Update User Documentation + +- [ ] Update `README.md` and `doc/user_guide.md` to explain the Markdown Structure / File Structure outline, header placement, declaration-only scope, and navigation behavior. + +## Version And Changelog Update + +- [ ] Check whether the current project version is the latest GitHub release. +- [ ] GH-63 is a user-visible feature and therefore requires a minor release. +- [ ] Raise the version to the selected semantic version. +- [ ] Write the release-changelog entry for the selected version. +- [ ] Update to the latest OpenFastTrace library version available on GitHub. +- [ ] Add `## Bundled OpenFastTrace` followed by `OpenFastTrace ` immediately after the release summary and before the first release category. +- [ ] Copy the active release notes, including the bundled OpenFastTrace version, into the Marketplace `changeNotes` through the existing Markdown-to-HTML build flow. +- [ ] Update the release date to the release date. +- [ ] Ensure the issue list contains `#63: Show OFT Specification Item IDs in the Markdown Outline`. From e568ef0f0ebceafa8f461537121bc316c92756c1 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 28 Jul 2026 10:16:43 +0200 Subject: [PATCH 03/15] #63: User requirements and design. --- ...me-openfasttrace-specification-item-ids.md | 95 ++++++++++ doc/design/building_block_view.md | 177 +++++++++++++----- doc/design/runtime_view.md | 74 +++++++- doc/design/solution_strategy.md | 2 + doc/system_requirements.md | 95 ++++++++++ 5 files changed, 398 insertions(+), 45 deletions(-) create mode 100644 doc/changesets/60-rename-openfasttrace-specification-item-ids.md diff --git a/doc/changesets/60-rename-openfasttrace-specification-item-ids.md b/doc/changesets/60-rename-openfasttrace-specification-item-ids.md new file mode 100644 index 0000000..f94ae93 --- /dev/null +++ b/doc/changesets/60-rename-openfasttrace-specification-item-ids.md @@ -0,0 +1,95 @@ +# GH-60 Feature: Rename OpenFastTrace specification item IDs + +## Goal + +Allow users to apply IntelliJ's standard Rename refactoring to an OpenFastTrace specification item ID. Renaming updates the declaration and every resolved OFT reference in supported specification documents and coverage-tag files, while leaving unrelated matching text untouched. + +## Scope + +In scope: + +* Rename a full canonical OFT item ID from its declaration or from a resolved `Covers:`, `Depends:`, or coverage-tag reference. +* Use IntelliJ's standard rename/usages and preview workflow before edits are applied. +* Update the declaration and resolved references in supported Markdown, RST, and coverage-tag file types, including either side of a coverage tag where that side resolves to the renamed declaration. +* Reject a rename to a target full ID that is already declared in the project. +* Preserve the existing declaration-versus-reference model and reuse its syntax, indexing, resolution, and usage-search infrastructure. +* Update traced requirements, design, user documentation, and release notes. + +Out of scope: + +* Renaming arbitrary text that happens to equal an OFT ID but is not an indexed declaration or a resolved OFT reference. +* Automatically changing the semantics, coverage structure, or revision policy of an OFT item; intentional semantic trace-model changes remain manual. +* Refactoring partial or invalid OFT ID fragments, including incomplete tags. +* New third-party dependencies or a custom rename dialog, preview, or usages UI. + +## Design References + +* [GH-60](https://github.com/itsallcode/openfasttrace-intellij-plugin/issues/60) +* [System Requirements](../system_requirements.md) +* [Solution Strategy](../design/solution_strategy.md) +* [Building Block View](../design/building_block_view.md) +* [Runtime View](../design/runtime_view.md) +* [Quality Requirements](../design/quality_requirements.md) +* [GH-24 Auto-completion for Covers section](24-auto-completion-for-covers-section.md) + +## Strategy + +Model the full OFT item ID as the renameable canonical name of its indexed declaration. Adapt the existing declaration navigation element to participate in IntelliJ rename and provide a usage search that returns only the existing PSI references which resolve to that declaration. The standard platform refactoring engine can then collect usages, present its normal preview, replace the precise ID ranges, and refresh the existing file-based declaration index. + +The implementation must validate a proposed full ID with the shared OFT syntax model and use the declaration index to detect an existing target declaration. It must not perform a project-wide string replacement. In particular, shortened coverage-tag left sides must only be changed when their resolved effective ID +is the renamed declaration, and their syntactic shorthand must remain intact. + +## Task List + +- [ ] Create and checkout a new Git branch `feature/60-rename-openfasttrace-specification-item-ids` + +### Requirements And Design + +- [x] Add a `feat` and user requirement for renaming canonical OFT specification item IDs through IntelliJ Rename, covering the existing navigation feature or a new focused refactoring feature as appropriate. +- [x] Add `scn` items for initiating rename at a declaration and at a resolved reference; updating supported `Covers:`/`Depends:` entries and coverage-tag references; reviewing standard Rename usages before application; excluding non-OFT text; and rejecting an already-declared target ID. +- [ ] Stop and ask user for a review of the system requirements. +- [x] Update `doc/design/solution_strategy.md` to state that OFT refactoring reuses IntelliJ rename and find-usages APIs over canonical declarations and resolved PSI references rather than textual replacement. +- [x] Extend `doc/design/building_block_view.md` with rename/refactoring responsibilities and dependencies between the declaration index, navigation/reference support, OFT syntax core, and IntelliJ refactoring infrastructure. +- [x] Add one `dsn` item per rename scenario in `doc/design/runtime_view.md`, including declaration/reference initiation, resolved usage discovery and preview, selective replacement (including coverage-tag shorthand), target-ID conflict validation, and index refresh after edits. +- [ ] Stop and ask user for a review of the design. + +### Implementation + +- [ ] Extract or extend the navigation PSI representation so a declaration exposes the canonical full OFT ID as a writable IntelliJ rename target with an exact declaration-anchor range. +- [ ] Add a refactoring/rename provider or PSI integration that resolves a declaration when Rename starts on either its anchor or an existing OFT reference, and delegates preview/apply behavior to IntelliJ's standard Rename workflow. +- [ ] Reuse the existing reference contributors and declaration resolver to find usages only when they resolve to the selected declaration; include supported specification-reference locations (`Covers:` and `Depends:`) and both supported coverage-tag sides. +- [ ] Implement precise replacement of full declarations and full references while preserving Markdown backticks, surrounding content, coverage-tag delimiters, and shortened left-side syntax where applicable. +- [ ] Validate the proposed canonical ID and reject malformed targets; query the declaration index to report an existing target declaration as a rename conflict without editing any files. +- [ ] Declare the shared IntelliJ language module and register only the necessary IntelliJ extension points in `src/main/resources/META-INF/plugin.xml`; do not add third-party dependencies or use internal/deprecated platform APIs. +- [ ] Confirm that affected file/index updates are visible to existing Go to Symbol, Go To Declaration, Go To Implementations, and completion flows after a successful rename. + +### Verification + +- [ ] Add syntax/model tests for canonical-ID validation, conflict detection, exact ID range replacement, and preserving shortened coverage-tag left-side syntax. +- [ ] Add IntelliJ light-fixture refactoring tests for rename from a declaration and from a `Covers:`, `Depends:`, and coverage-tag reference; assert the declaration and all resolved usages change together. +- [ ] Add fixture tests that inspect the standard Rename usage set/preview inputs and prove unrelated matching prose, invalid fragments, unsupported files, and unresolved references are not changed. +- [ ] Add negative fixture tests for an already-declared target ID and malformed target IDs, verifying that the refactoring reports the conflict and leaves project files unchanged. +- [ ] Add regression tests that navigation, implementation search, and completion resolve the new ID after rename and no longer resolve the old ID. +- [ ] Keep existing syntax, indexing, navigation, completion, and highlighting tests green. +- [ ] Keep the OpenFastTrace trace clean for the new `feat`, `req`, `scn`, `dsn`, `impl`, `utest`, and `itest` artifacts in scope. +- [ ] Keep path coverage at or above 80%. +- [ ] Keep the dependency policy unchanged; add no third-party dependencies. +- [ ] Run `./gradlew test`. +- [ ] Run `./gradlew traceRequirements`. +- [ ] Run `./gradlew check`. +- [ ] Run `./gradlew verifyPlugin`. +- [ ] Keep the SonarQube Cloud quality gate green after CI analysis. + +### Update User Documentation + +- [ ] Update `README.md` and `doc/user_guide.md` to explain invoking Rename from OFT declarations and references, reviewing IntelliJ's rename preview, supported reference locations, and duplicate-ID conflict behavior. + +## Version And Changelog Update + +- [ ] Check whether the current project version is the latest GitHub release. +- [ ] GH-60 is a user-visible feature and therefore requires the next minor release. +- [ ] Raise the version to the selected semantic version. +- [ ] Write the release-changelog entry for the selected version and include `#60: Rename OpenFastTrace specification item IDs`. +- [ ] Add `## Bundled OpenFastTrace` followed by the selected OpenFastTrace version immediately after the release summary and before the first release category. +- [ ] Copy the active release notes, including the bundled OpenFastTrace version, into the Marketplace `changeNotes` through the existing Markdown-to-HTML build flow. +- [ ] Update the release date to the release date. diff --git a/doc/design/building_block_view.md b/doc/design/building_block_view.md index 1fed425..442bea7 100644 --- a/doc/design/building_block_view.md +++ b/doc/design/building_block_view.md @@ -2,31 +2,24 @@ This chapter describes the static decomposition of the plugin into building blocks and their responsibilities. -The following diagram drafts the current product-level components of the plugin. It shows components, not classes. +The following feature-focused views show the current product-level components of the plugin. A component may occur in more than one view where it participates in multiple features. The views show components, not classes, and contain at most seven modules each. + +## Syntax Highlighting ```plantuml @startuml skinparam componentStyle rectangle +top to bottom direction package "JetBrains IDE / IntelliJ Platform" { component "Editor and PSI\nInfrastructure" as IdeEditor - component "Symbol Search and\nNavigation Infrastructure" as IdeNavigation - component "Live Template\nInfrastructure" as IdeLiveTemplates - component "Action System" as IdeActions - component "Background Task and\nProgress Infrastructure" as IdeTasks - component "Output View and\nRun Content Infrastructure" as IdeOutput - component "SM Test Runner\nInfrastructure" as IdeTestRunner - component "Help Menu and\nWeb View Infrastructure" as IdeHelp } package "Opened Project" { - artifact "Project Content Root" as ProjectRoot artifact "Markdown and RST\nSpecification Documents" as ProjectSpecs artifact "Source Files with\nCoverage Tags" as ProjectSources -} - -package "OpenFastTrace Library" { - component "Trace Engine and\nText Reporter" as OftTraceLibrary + + ProjectSources -[hidden]u- ProjectSpecs } package "OpenFastTrace Plugin" { @@ -34,53 +27,147 @@ package "OpenFastTrace Plugin" { component "Markdown Specification\nSupport" as MarkdownSupport component "RST Specification\nSupport" as RstSupport component "Coverage Tag\nSupport" as CoverageSupport +} + +ProjectSpecs -l-> MarkdownSupport : reads +ProjectSpecs --> RstSupport : reads +ProjectSources --> CoverageSupport : reads +MarkdownSupport -u-> OftSyntax +RstSupport -u-> OftSyntax +CoverageSupport -u-> OftSyntax +MarkdownSupport -d-> IdeEditor +RstSupport -d-> IdeEditor +CoverageSupport -d-> IdeEditor +@enduml +``` + +## Specification-Item Navigation and Refactoring + +```plantuml +@startuml +skinparam componentStyle rectangle + +package "JetBrains IDE / IntelliJ Platform" { + component "Symbol Search and\nNavigation Infrastructure" as IdeNavigation + component "Refactoring and\nUsage Search Infrastructure" as IdeRefactoring + + IdeNavigation -[hidden]u- IdeRefactoring +} + +package "OpenFastTrace Plugin" { + component "OFT Syntax Core" as OftSyntax component "Specification Item\nIndex" as SpecIndex component "Specification Item\nNavigation" as NavigationSupport - component "Specification Item\nCompletion" as CompletionSupport - component "Live Template\nIntegration" as LiveTemplateSupport - component "Trace Configuration\nIntegration" as TraceConfigurationSupport - component "Trace Action\nIntegration" as TraceActionSupport - component "Trace Execution\nService" as TraceExecutionSupport - component "Trace Output\nPresentation" as TraceOutputSupport - component "Trace Test Runner\nPresentation" as TraceTestRunnerSupport - component "User Guide\nIntegration" as UserGuideSupport + component "Specification Item\nRefactoring" as RefactoringSupport } -MarkdownSupport --> OftSyntax -RstSupport --> OftSyntax -CoverageSupport --> OftSyntax SpecIndex --> OftSyntax NavigationSupport --> SpecIndex -TraceActionSupport --> TraceExecutionSupport -TraceExecutionSupport --> TraceOutputSupport -TraceExecutionSupport --> TraceTestRunnerSupport +NavigationSupport -l-> IdeNavigation +RefactoringSupport --> OftSyntax +RefactoringSupport --> SpecIndex +RefactoringSupport --> NavigationSupport +RefactoringSupport -l-> IdeRefactoring +@enduml +``` + +## Reference Authoring + +```plantuml +@startuml +skinparam componentStyle rectangle + +package "JetBrains IDE / IntelliJ Platform" { + component "Editor and PSI\nInfrastructure" as IdeEditor + component "Live Template\nInfrastructure" as IdeLiveTemplates +} + +package "OpenFastTrace Plugin" { + component "Specification Item\nIndex" as SpecIndex + component "Specification Item\nCompletion" as CompletionSupport + component "Live Template\nIntegration" as LiveTemplateSupport +} -MarkdownSupport --> IdeEditor -RstSupport --> IdeEditor -CoverageSupport --> IdeEditor -SpecIndex --> IdeEditor -NavigationSupport --> IdeNavigation CompletionSupport --> SpecIndex CompletionSupport --> IdeEditor LiveTemplateSupport --> IdeLiveTemplates LiveTemplateSupport --> IdeEditor +@enduml +``` + +## Trace Setup + +```plantuml +@startuml +skinparam componentStyle rectangle + +package "JetBrains IDE / IntelliJ Platform" { + component "Action System" as IdeActions +} + +package "Opened Project" { + artifact "Project Content Root" as ProjectRoot +} + +package "OpenFastTrace Plugin" { + component "Trace Configuration\nIntegration" as TraceConfigurationSupport + component "Trace Action\nIntegration" as TraceActionSupport +} + TraceConfigurationSupport --> IdeActions TraceActionSupport --> IdeActions -TraceExecutionSupport --> IdeTasks -TraceOutputSupport --> IdeOutput -TraceTestRunnerSupport --> IdeTestRunner -TraceTestRunnerSupport --> NavigationSupport -UserGuideSupport --> IdeHelp - TraceActionSupport --> TraceConfigurationSupport TraceActionSupport --> ProjectRoot : reads path TraceConfigurationSupport --> ProjectRoot : reads settings roots -TraceExecutionSupport --> ProjectRoot : traces +@enduml +``` + +## Trace Execution and Results + +```plantuml +@startuml +skinparam componentStyle rectangle + +package "JetBrains IDE / IntelliJ Platform" { + component "Background Task and\nProgress Infrastructure" as IdeTasks + component "Output View and\nRun Content Infrastructure" as IdeOutput + component "SM Test Runner\nInfrastructure" as IdeTestRunner +} + +package "OpenFastTrace Library" { + component "Trace Engine and\nText Reporter" as OftTraceLibrary +} + +package "OpenFastTrace Plugin" { + component "Trace Execution\nService" as TraceExecutionSupport + component "Trace Output\nPresentation" as TraceOutputSupport + component "Trace Test Runner\nPresentation" as TraceTestRunnerSupport +} + +TraceExecutionSupport --> IdeTasks TraceExecutionSupport --> OftTraceLibrary -MarkdownSupport --> ProjectSpecs : reads -RstSupport --> ProjectSpecs : reads -CoverageSupport --> "1..n" ProjectSources : reads -SpecIndex --> "1..n" ProjectSpecs : indexes +TraceExecutionSupport --> TraceOutputSupport +TraceExecutionSupport --> TraceTestRunnerSupport +TraceOutputSupport --> IdeOutput +TraceTestRunnerSupport --> IdeTestRunner +@enduml +``` + +## User Guide + +```plantuml +@startuml +skinparam componentStyle rectangle + +package "JetBrains IDE / IntelliJ Platform" { + component "Help Menu and\nWeb View Infrastructure" as IdeHelp +} + +package "OpenFastTrace Plugin" { + component "User Guide\nIntegration" as UserGuideSupport +} + +UserGuideSupport --> IdeHelp @enduml ``` @@ -179,6 +266,10 @@ Covers: Needs: impl +### Specification Item Refactoring + +The specification-item refactoring component adapts canonical declaration anchors and resolved OFT references to IntelliJ's shared language-module Rename and usage-search infrastructure. It reuses the syntax core to validate proposed full IDs, the declaration index to detect target-ID conflicts, and navigation/reference resolution to identify semantic usages. It never treats arbitrary matching text as a usage and does not merge duplicate declarations. The scenario-specific runtime design items below define the individual rename flows. + ### Specification Item Completion `dsn~specification-item-completion~1` diff --git a/doc/design/runtime_view.md b/doc/design/runtime_view.md index 6f966b1..cb42c4b 100644 --- a/doc/design/runtime_view.md +++ b/doc/design/runtime_view.md @@ -224,6 +224,73 @@ Covers: Needs: impl, itest +## Specification Item Refactoring + +### Start Specification Item Rename from Declaration +`dsn~start-specification-item-rename-from-declaration~1` + +**Given** a user invokes IntelliJ Rename with the caret on an OFT declaration anchor +**When** the refactoring component determines the rename target +**Then** it exposes the declaration's canonical full ID and exact anchor range as the writable target and delegates the dialog, usage preview, and application workflow to IntelliJ's standard Rename infrastructure. + +Covers: +- `scn~rename-specification-item-id-from-declaration~1` + +Needs: impl, utest, itest + +### Start Specification Item Rename from Reference +`dsn~start-specification-item-rename-from-reference~1` + +**Given** a user invokes IntelliJ Rename with the caret on a supported OFT reference +**When** that reference resolves to a unique OFT declaration +**Then** the refactoring component uses the resolved declaration, rather than the reference occurrence, as the canonical Rename target and delegates the workflow to IntelliJ's standard Rename infrastructure. + +Covers: +- `scn~rename-specification-item-id-from-reference~1` + +Needs: impl, utest, itest + +### Update OFT References during Rename +`dsn~update-resolved-oft-references-during-specification-item-rename~1` + +**Given** IntelliJ applies a rename from one full OFT ID to another after the user confirms the preview +**When** the refactoring component collects usages of the selected declaration +**Then** it supplies resolved references in supported `Covers:` and `Depends:` entries and on either resolved side of supported coverage tags +**And** replaces their ID ranges with the new canonical ID +**And** preserves surrounding syntax and valid left-side shorthand +**And** refreshes the canonical declaration lookup after in the index. + +Covers: +- `scn~update-supported-references-during-specification-item-id-rename~1` + +Needs: impl, utest, itest + +### Exclude Non-Semantic Text from Specification Item Rename +`dsn~exclude-non-semantic-text-from-specification-item-rename~1` + +**Given** a project contains text matching the old full OFT ID outside a declaration or a reference that resolves to the selected declaration +**When** the refactoring component builds the Rename usage set +**Then** it derives usages exclusively from supported PSI references +**And** excludes ordinary prose, unsupported files, invalid fragments, and unresolved OFT-like text from the preview and applied edits. + +Covers: +- `scn~exclude-unresolved-and-non-oft-text-from-specification-item-id-rename~1` + +Needs: impl, utest, itest + +### Reject Invalid or Conflicting Specification Item Rename +`dsn~reject-invalid-or-conflicting-specification-item-rename~1` + +**Given** a user proposes a new full OFT ID in the Rename workflow +**When** the refactoring component validates the proposed ID and queries the declaration index for a different declaration with that ID +**Then** it reports an invalid-ID or existing-declaration conflict before any file is edited +**And** does not interpret the conflict as an item merge. + +Covers: +- `scn~reject-invalid-or-existing-specification-item-id-rename~1` + +Needs: impl, utest, itest + ## Completion ### Complete Specification Item ID in Covers Section @@ -231,7 +298,9 @@ Needs: impl, itest **Given** a supported specification document contains a `Covers:` entry and the opened project already indexes declared OpenFastTrace specification items **When** a user invokes IntelliJ basic completion while editing an OFT item ID in that `Covers:` entry -**Then** the completion component confirms that the caret is inside a `Covers:` reference, loads declared specification item IDs from the declaration index, ranks them by full-ID prefix, name-prefix, name-substring, and artifact-type prefix matches, and shows the ordered suggestions in the standard IDE completion popup. +**Then** the completion component confirms that the caret is inside a `Covers:` reference, loads declared specification item IDs from the declaration index +**And** ranks them by full-ID prefix, name-prefix, name-substring, and artifact-type prefix matches +**And** shows the ordered suggestions in the standard IDE completion popup. Covers: - `scn~complete-specification-item-id-in-covers-section~1` @@ -243,7 +312,8 @@ Needs: impl, itest **Given** a bundled OFT live template is active at a `COVERED` placeholder under `Covers:` and the opened project already indexes declared OpenFastTrace specification items **When** a user invokes IntelliJ basic completion in that placeholder before the live-template session ends -**Then** the completion component reads the active editor document, handles the request like any other `Covers:` reference by reading declared specification item IDs from the declaration index, and shows the matching suggestions in the standard IDE completion popup without ending the live-template session. +**Then** the completion component reads the active editor document, handles the request like any other `Covers:` reference by reading declared specification item IDs from the declaration index +**And** shows the matching suggestions in the standard IDE completion popup without ending the live-template session. Covers: - `scn~complete-specification-item-id-in-active-live-template-covers-field~1` diff --git a/doc/design/solution_strategy.md b/doc/design/solution_strategy.md index 59574ac..a6216bb 100644 --- a/doc/design/solution_strategy.md +++ b/doc/design/solution_strategy.md @@ -24,6 +24,8 @@ Authoring shortcuts use IntelliJ's live-template infrastructure instead of custo Reference authoring assistance for `Covers:` entries and coverage-tag targets likewise reuses IntelliJ's standard completion infrastructure. The plugin activates completion only in supported OFT reference authoring contexts, then fills the suggestion list from the existing declaration index instead of maintaining a second source of specification-item identities. +Specification-item maintenance reuses IntelliJ's standard Rename and usage-preview workflow from the shared IntelliJ language module. A rename started at a declaration or resolved OFT reference identifies the canonical declaration through the existing resolver, collects only PSI references that resolve to it, and lets the platform preview the affected declaration and usages before applying edits. The plugin validates the proposed full ID with the shared OFT syntax model and detects an existing target declaration through the declaration index; these are conflicts, not implicit item merges. This keeps rename scoped to semantic OFT locations and avoids project-wide text replacement. + This strategy reduces custom code, lowers maintenance effort, and improves cross-IDE compatibility because the implementation stays aligned with the platform abstractions that JetBrains supports across products. ## OFT Specification Item Index diff --git a/doc/system_requirements.md b/doc/system_requirements.md index eb52a6d..3849a19 100644 --- a/doc/system_requirements.md +++ b/doc/system_requirements.md @@ -88,6 +88,13 @@ The plugin lets users search specification items by name across the project and Needs: req +### Rename Specification Item IDs +`feat~rename-specification-item-ids~1` + +The plugin lets users safely rename OpenFastTrace specification item IDs with the IntelliJ Rename refactoring.Updates affect item declaration and references. + +Needs: req + ### Open OFT User Guide `feat~open-oft-user-guide~1` @@ -258,6 +265,30 @@ Covers: Needs: scn +### Rename Specification Item IDs + +The following requirements refine the specification-item rename feature into user-visible capabilities. + +### Rename Declaration and Resolved References +`req~rename-specification-item-declaration-and-references~1` + +The plugin lets users invoke IntelliJ Rename on an OpenFastTrace specification item declaration or a resolved reference to that declaration. Before applying the rename, the standard IntelliJ refactoring workflow shows the declaration and all affected resolved OFT references for review. Applying the rename updates only those OFT declaration and reference IDs. + +Covers: +- `feat~rename-specification-item-ids~1` + +Needs: scn + +### Reject Invalid or Conflicting Renamed IDs +`req~reject-invalid-or-conflicting-renamed-specification-item-ids~1` + +The plugin rejects a rename when the proposed full OFT item ID is invalid or when a declaration with that target ID already exists in the project. The rejected refactoring leaves the declaration and references unchanged. + +Covers: +- `feat~rename-specification-item-ids~1` + +Needs: scn + ### Open OFT User Guide The following requirements refine the Open OFT User Guide feature into user-visible capabilities. @@ -1002,6 +1033,70 @@ Covers: Needs: dsn +### Rename Specification Item IDs + +The following scenarios describe the expected IntelliJ Rename workflow for OFT specification item IDs. + +### Rename Specification Item ID from Declaration +`scn~rename-specification-item-id-from-declaration~1` + +**Given** a project declares `req~old-name~1` and contains resolved OFT references to it +**When** a user invokes IntelliJ Rename on the declaration and proposes `req~new-name~1` +**Then** the standard Rename workflow previews the declaration and the resolved OFT references before applying the coordinated rename. + +Covers: +- `req~rename-specification-item-declaration-and-references~1` + +Needs: dsn + +### Rename Specification Item ID from Reference +`scn~rename-specification-item-id-from-reference~1` + +**Given** a project declares `req~old-name~1` and a supported OFT reference resolves to that declaration +**When** a user invokes IntelliJ Rename on the reference and proposes `req~new-name~1` +**Then** the standard Rename workflow renames the declaration and all resolved OFT references to `req~new-name~1`. + +Covers: +- `req~rename-specification-item-declaration-and-references~1` + +Needs: dsn + +### Update Supported References during Specification Item ID Rename +`scn~update-supported-references-during-specification-item-id-rename~1` + +**Given** a project declares `req~old-name~1`, has `Covers:` and `Depends:` entries that resolve to it, and has supported source-code coverage tags whose source or target side resolves to it +**When** a user renames the declaration to `req~new-name~1` and applies the standard Rename workflow +**Then** the declaration and those resolved references use `req~new-name~1`, while their surrounding Markdown and coverage-tag syntax remains unchanged. + +Covers: +- `req~rename-specification-item-declaration-and-references~1` + +Needs: dsn + +### Exclude Unresolved and Non-OFT Text from Specification Item ID Rename +`scn~exclude-unresolved-and-non-oft-text-from-specification-item-id-rename~1` + +**Given** a project contains the text `req~old-name~1` in ordinary prose, an unsupported file, or an unresolved OFT-like fragment as well as a declared `req~old-name~1` +**When** a user renames the declaration to `req~new-name~1` +**Then** the Rename preview and applied changes include only the declaration and resolved OFT references, leaving the other text unchanged. + +Covers: +- `req~rename-specification-item-declaration-and-references~1` + +Needs: dsn + +### Reject Invalid or Existing Specification Item ID Rename +`scn~reject-invalid-or-existing-specification-item-id-rename~1` + +**Given** a project declares `req~old-name~1` and also declares `req~existing-name~1` +**When** a user attempts to rename `req~old-name~1` to an invalid OFT ID or to `req~existing-name~1` +**Then** the IDE reports the invalid ID or conflicting declaration and does not change any declaration or reference. + +Covers: +- `req~reject-invalid-or-conflicting-renamed-specification-item-ids~1` + +Needs: dsn + ### OFT Reference Completion The following scenarios describe completion support while editing OFT references in `Covers:` sections and coverage-tag targets. From 7c6f6141a5d59f4ccf05b9256bb653f30c2cd959 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Mon, 3 Aug 2026 12:53:55 +0200 Subject: [PATCH 04/15] #39: Planned tag filter. --- .../39-re-enable-disabled-tag-filter-test.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 doc/changesets/39-re-enable-disabled-tag-filter-test.md diff --git a/doc/changesets/39-re-enable-disabled-tag-filter-test.md b/doc/changesets/39-re-enable-disabled-tag-filter-test.md new file mode 100644 index 0000000..69c476e --- /dev/null +++ b/doc/changesets/39-re-enable-disabled-tag-filter-test.md @@ -0,0 +1,53 @@ +# GH-39 Re-enable disabled tag filter test + +## Goal + +Re-enable the disabled tag-filter regression test in `OftTraceServiceTest` now that OpenFastTrace 4.8.0 includes the upstream tag-parser fix. The plugin should once again verify that tag filtering works end to end for traced Markdown content. + +## Scope + +In scope: + +* Update the bundled OpenFastTrace dependency from 4.5.0 to 4.8.0 so the plugin exercises the fixed upstream tag parser. +* Remove the temporary `@Disabled` suppression from `testGivenTagFilterMatchingArtifactWhenTracingThenItIncludesTheArtifact`. +* Keep the existing tag-filter behavior and test intent unchanged. +* Verify the fix with focused tests and the normal project quality gates. + +Out of scope: + +* Adding a new user-facing tag-filter feature. +* Changing requirement or design text, because the current specification already covers tag filtering. +* Broadening trace filter semantics beyond the current comma-separated filter model. + +## Design References + +* [System Requirements](../system_requirements.md) +* [Quality Requirements](../design/quality_requirements.md) +* [Runtime View](../design/runtime_view.md) +* [Building Block View](../design/building_block_view.md) + +## Strategy + +Treat this as an upstream dependency alignment issue rather than a product feature change. Move the project to OpenFastTrace 4.8.0, drop the temporary test suppression, and confirm that the existing trace service still passes tag filters through to the library. + +## Task List + +- [ ] Create and checkout a new Git branch `fix/39-re-enable-disabled-tag-filter-test` + +### Requirements And Design + +- [ ] Confirm that the existing `req~filter-trace-by-tags~1` and `scn~filter-run-configuration-by-tags~1` coverage already describes the intended behavior, so no requirement or design edits are needed. + +### Implementation + +- [ ] Update the bundled OpenFastTrace dependency to 4.8.0 in `build.gradle.kts` and refresh `gradle.lockfile` as needed. +- [ ] Remove the `@Disabled` annotation from `testGivenTagFilterMatchingArtifactWhenTracingThenItIncludesTheArtifact`. +- [ ] Keep the tag-filter regression test focused on the existing Markdown-based end-to-end trace flow. + +### Verification + +- [ ] Run the focused `OftTraceServiceTest` tag-filter case against the updated dependency. +- [ ] Run `./gradlew traceRequirements` to confirm the OFT trace remains clean. +- [ ] Run `./gradlew check`. +- [ ] Run `./gradlew verifyPlugin`. + From afb2f3bbd0ff9233c1b897d245c182b5515aa159 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Mon, 3 Aug 2026 13:19:14 +0200 Subject: [PATCH 05/15] #39: Tested tag filter. --- .idea/sonarlint.xml | 8 ----- build.gradle.kts | 2 +- .../39-re-enable-disabled-tag-filter-test.md | 11 +++---- gradle.lockfile | 32 ++++++++++--------- .../trace/OftTraceServiceTest.java | 29 +++++++++++------ 5 files changed, 43 insertions(+), 39 deletions(-) delete mode 100644 .idea/sonarlint.xml diff --git a/.idea/sonarlint.xml b/.idea/sonarlint.xml deleted file mode 100644 index cfb6719..0000000 --- a/.idea/sonarlint.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index b8104bf..1cccea4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -103,7 +103,7 @@ repositories { } dependencies { - implementation("org.itsallcode.openfasttrace:openfasttrace:4.5.0") + implementation("org.itsallcode.openfasttrace:openfasttrace:4.8.0") intellijPlatform { intellijIdea("2026.1.3") diff --git a/doc/changesets/39-re-enable-disabled-tag-filter-test.md b/doc/changesets/39-re-enable-disabled-tag-filter-test.md index 69c476e..eb9934e 100644 --- a/doc/changesets/39-re-enable-disabled-tag-filter-test.md +++ b/doc/changesets/39-re-enable-disabled-tag-filter-test.md @@ -36,18 +36,17 @@ Treat this as an upstream dependency alignment issue rather than a product featu ### Requirements And Design -- [ ] Confirm that the existing `req~filter-trace-by-tags~1` and `scn~filter-run-configuration-by-tags~1` coverage already describes the intended behavior, so no requirement or design edits are needed. +- [x] Confirm that the existing `req~filter-trace-by-tags~1` and `scn~filter-run-configuration-by-tags~1` coverage already describes the intended behavior, so no requirement or design edits are needed. ### Implementation -- [ ] Update the bundled OpenFastTrace dependency to 4.8.0 in `build.gradle.kts` and refresh `gradle.lockfile` as needed. -- [ ] Remove the `@Disabled` annotation from `testGivenTagFilterMatchingArtifactWhenTracingThenItIncludesTheArtifact`. -- [ ] Keep the tag-filter regression test focused on the existing Markdown-based end-to-end trace flow. +- [x] Update the bundled OpenFastTrace dependency to 4.8.0 in `build.gradle.kts` and refresh `gradle.lockfile` as needed. +- [x] Remove the `@Disabled` annotation from `testGivenTagFilterMatchingArtifactWhenTracingThenItIncludesTheArtifact`. +- [x] Keep the tag-filter regression test focused on the existing Markdown-based end-to-end trace flow. ### Verification -- [ ] Run the focused `OftTraceServiceTest` tag-filter case against the updated dependency. +- [x] Run the focused `OftTraceServiceTest` tag-filter case against the updated dependency. - [ ] Run `./gradlew traceRequirements` to confirm the OFT trace remains clean. - [ ] Run `./gradlew check`. - [ ] Run `./gradlew verifyPlugin`. - diff --git a/gradle.lockfile b/gradle.lockfile index 605d7b6..d3dae6f 100644 --- a/gradle.lockfile +++ b/gradle.lockfile @@ -34,21 +34,23 @@ org.assertj:assertj-core:4.0.0-M1=intellijPlatformTestClasspath,intellijPlatform org.hamcrest:hamcrest-core:1.3=intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,testCompileClasspath,testRuntimeClasspath org.hamcrest:hamcrest:2.2=intellijPlatformTestClasspath,intellijPlatformTestDependencies org.hamcrest:hamcrest:3.0=intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-api:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-core:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-exporter-common:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-exporter-specobject:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-importer-lightweightmarkup:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-importer-markdown:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-importer-restructuredtext:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-importer-specobject:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-importer-tag:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-importer-xmlparser:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-importer-zip:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-reporter-aspec:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-reporter-html:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace-reporter-plaintext:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -org.itsallcode.openfasttrace:openfasttrace:4.5.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-api:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-core:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-exporter-common:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-exporter-specobject:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-importer-lightweightmarkup:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-importer-gherkin:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-importer-markdown:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-importer-restructuredtext:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-importer-specobject:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-importer-tag:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-importer-tag-importer-common:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-importer-xmlparser:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-importer-zip:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-reporter-aspec:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-reporter-html:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace-reporter-plaintext:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.itsallcode.openfasttrace:openfasttrace:4.8.0=compileClasspath,intellijPlatformComposedJar,intellijPlatformRuntimeClasspath,intellijPlatformTestRuntimeClasspath,intellijPlatformTestRuntimeClasspath_manualTestIde,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.jacoco:org.jacoco.agent:0.8.13=jacocoAgent,jacocoAnt org.jacoco:org.jacoco.ant:0.8.13=jacocoAnt org.jacoco:org.jacoco.core:0.8.13=jacocoAnt diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java index 1c34744..5def300 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java @@ -3,7 +3,6 @@ import org.itsallcode.openfasttrace.core.Oft; import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -213,34 +212,38 @@ void testGivenArtifactTypeFilterMatchingRequirementWhenTracingThenItIncludesTheR ); } - @Disabled("Reanable after https://github.com/itsallcode/openfasttrace/issues/505 is fixed") @Test void testGivenTagFilterMatchingArtifactWhenTracingThenItIncludesTheArtifact( @TempDir final Path temporaryDirectory ) throws IOException { final Path docDirectory = Files.createDirectories(temporaryDirectory.resolve("doc")); + // Note that this example intentionally uses a non-covered chain, so that we get actual defects in the report + // with or without tag filter! Files.writeString( docDirectory.resolve("tags.md"), """ ### Tagged Requirement `req~tagged_requirement~1` - - Tags: tagged - Needs: impl + Tags: tagged ### Untagged Requirement `req~untagged_requirement~1` - Needs: impl ### Tagged Coverage `impl~tagged_coverage~1` - Covers: - `req~tagged_requirement~1` - Tags: tagged + Needs: foo + + ### Non-matching Tag + `impl~tagged_coverage_non-matching~1` + Covers: + - `req~tagged_requirement~1` + Tags: non_matching_tag + Needs: foo """ ); @@ -254,7 +257,15 @@ void testGivenTagFilterMatchingArtifactWhenTracingThenItIncludesTheArtifact( ); final String renderedOutput = stripAnsi(result.output()); - assertThat(renderedOutput, Matchers.containsString("ok - 2 total")); + assertThat( + renderedOutput, + Matchers.allOf( + Matchers.containsString("req~tagged_requirement~1"), + Matchers.containsString("impl~tagged_coverage~1"), + Matchers.containsString("#: tagged"), + Matchers.not(Matchers.containsString("non-matching")) + ) + ); } private String stripAnsi(final String output) { From 4d0a390de019cc77cc0b45bb8faa4647c83b8fb3 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 09:25:06 +0200 Subject: [PATCH 06/15] #39: Updated Gradle wrapper. --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 4 ++-- gradlew.bat | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index df6a6ad..a9db115 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 diff --git a/gradlew b/gradlew index b9bb139..249efbb 100755 --- a/gradlew +++ b/gradlew @@ -20,7 +20,7 @@ ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -29,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: diff --git a/gradlew.bat b/gradlew.bat index 24c62d5..a51ec4f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -19,7 +19,7 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## @@ -72,7 +72,7 @@ echo location of your Java installation. 1>&2 -@rem Execute Gradle +@rem Execute gradlew @rem endlocal doesn't take effect until after the line is parsed and variables are expanded @rem which allows us to clear the local environment before executing the java command endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel From 6c7134778de13e45c126f5d384ac0cb06b3fcf48 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 10:48:00 +0200 Subject: [PATCH 07/15] #39: Improved tag tests . --- doc/changes/changelog.md | 1 + doc/changes/changes_0.10.0.md | 11 ++ doc/demo/example/excuse-of-the-day.md | 4 + gradle.properties | 2 +- .../trace/OftTraceServiceTest.java | 119 +++++++++++------- 5 files changed, 94 insertions(+), 43 deletions(-) create mode 100644 doc/changes/changes_0.10.0.md diff --git a/doc/changes/changelog.md b/doc/changes/changelog.md index 8a469c7..04622c2 100644 --- a/doc/changes/changelog.md +++ b/doc/changes/changelog.md @@ -1,5 +1,6 @@ # Changelog +* [0.10.0](changes_0.10.0.md) * [0.9.0](changes_0.9.0.md) * [0.8.1](changes_0.8.1.md) * [0.8.0](changes_0.8.0.md) diff --git a/doc/changes/changes_0.10.0.md b/doc/changes/changes_0.10.0.md new file mode 100644 index 0000000..fe87add --- /dev/null +++ b/doc/changes/changes_0.10.0.md @@ -0,0 +1,11 @@ +# OpenFastTrace IntelliJ Plugin 0.10.0, released 2026-07-04 + +We also updated the bundled OFT to 4.8.0 so tag filters now work end to end instead of being ignored. + +## Bundled OpenFastTrace + +OpenFastTrace 4.8.0 + +## Bugfix + +* #39: Re-enabled tag filter test \ No newline at end of file diff --git a/doc/demo/example/excuse-of-the-day.md b/doc/demo/example/excuse-of-the-day.md index f927bde..76dadfa 100644 --- a/doc/demo/example/excuse-of-the-day.md +++ b/doc/demo/example/excuse-of-the-day.md @@ -25,6 +25,8 @@ Covers: Needs: scn +Tags: work + ## Scenarios ### Pick a Late-Work Excuse @@ -39,6 +41,8 @@ Covers: Needs: dsn +Tags: work + ## Design ### Random Excuse Selection diff --git a/gradle.properties b/gradle.properties index 8eef264..f7a0093 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=0.9.0 +version=0.10.0 org.gradle.configuration-cache=true org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8 diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java index 5def300..67d6634 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java @@ -5,6 +5,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.io.IOException; import java.lang.reflect.Proxy; @@ -12,6 +15,7 @@ import java.nio.file.Path; import java.net.URLClassLoader; import java.util.List; +import java.util.stream.Stream; import java.util.regex.Pattern; import static org.hamcrest.MatcherAssert.assertThat; @@ -150,7 +154,7 @@ void testGivenUncleanTraceChainWhenTracingThenItReportsTheExpectedDefectCountInT Assertions.assertAll( () -> assertThat(result.isSuccessful(), is(false)), () -> assertThat(result.output(), Matchers.containsString("\u001B[")), - () -> assertThat(renderedOutput, Matchers.containsString("not ok - 3 total, 3 defect")), + () -> assertThat(renderedOutput, Matchers.containsString("not ok - 3 total, 1 direct, 2 transitive defects")), () -> assertThat(renderedOutput, Matchers.containsString("dsn~chain_design~1")), () -> assertThat(renderedOutput, Matchers.containsString("feat~chain_feature~1")), () -> assertThat(renderedOutput, Matchers.containsString("req~chain_requirement~1")) @@ -212,59 +216,36 @@ void testGivenArtifactTypeFilterMatchingRequirementWhenTracingThenItIncludesTheR ); } - @Test - void testGivenTagFilterMatchingArtifactWhenTracingThenItIncludesTheArtifact( + // [itest->dsn~filter-trace-by-artifact-types-and-tags~1] + @ParameterizedTest(name = "{0}") + @MethodSource("tagFilterScenarios") + void testGivenTagFilterWhenTracingThenItIncludesOnlyMatchingItems( + final String tagsText, + final String expectedSummaryLine, + final List expectedIncludedItems, + final List expectedExcludedItems, @TempDir final Path temporaryDirectory ) throws IOException { - final Path docDirectory = Files.createDirectories(temporaryDirectory.resolve("doc")); - // Note that this example intentionally uses a non-covered chain, so that we get actual defects in the report - // with or without tag filter! - Files.writeString( - docDirectory.resolve("tags.md"), - """ - ### Tagged Requirement - `req~tagged_requirement~1` - Needs: impl - Tags: tagged - - ### Untagged Requirement - `req~untagged_requirement~1` - Needs: impl - - ### Tagged Coverage - `impl~tagged_coverage~1` - Covers: - - `req~tagged_requirement~1` - Tags: tagged - Needs: foo - - ### Non-matching Tag - `impl~tagged_coverage_non-matching~1` - Covers: - - `req~tagged_requirement~1` - Tags: non_matching_tag - Needs: foo - """ - ); + writeTagFilterProject(temporaryDirectory); final OftTraceResult result = new OftTraceService().traceProject( OftTraceInputs.selectedResources( java.util.List.of(temporaryDirectory), java.util.List.of(), - java.util.List.of("tagged") + tagsText.isEmpty() ? java.util.List.of() : java.util.Arrays.stream(tagsText.split(",")) + .map(String::trim) + .filter(tag -> !tag.isEmpty()) + .toList() ), OftTraceProgress.NONE ); final String renderedOutput = stripAnsi(result.output()); - assertThat( - renderedOutput, - Matchers.allOf( - Matchers.containsString("req~tagged_requirement~1"), - Matchers.containsString("impl~tagged_coverage~1"), - Matchers.containsString("#: tagged"), - Matchers.not(Matchers.containsString("non-matching")) - ) + Assertions.assertAll( + () -> assertThat(result.isSuccessful(), is(true)), + () -> assertThat(renderedOutput, Matchers.containsString(expectedSummaryLine)), + () -> expectedIncludedItems.forEach(item -> assertThat(renderedOutput, Matchers.containsString(item))), + () -> expectedExcludedItems.forEach(item -> assertThat(renderedOutput, Matchers.not(Matchers.containsString(item)))) ); } @@ -377,4 +358,58 @@ private void writeOutOfScopeDefect(final Path projectRoot) throws IOException { """ ); } + + private void writeTagFilterProject(final Path projectRoot) throws IOException { + final Path docDirectory = Files.createDirectories(projectRoot.resolve("doc")); + Files.writeString( + docDirectory.resolve("tags.md"), + """ + ### Work Requirement + `req~tagged_work_requirement~1` + Tags: work + + ### Work and Home Requirement + `req~tagged_work_home_requirement~1` + Tags: work, home + + ### Home Requirement + `req~tagged_home_requirement~1` + Tags: home + + ### Untagged Requirement + `req~untagged_requirement~1` + """ + ); + } + + private static Stream tagFilterScenarios() { + return Stream.of( + Arguments.of( + "work", + "ok - 2 total", + List.of("req~tagged_work_requirement~1", "req~tagged_work_home_requirement~1"), + List.of("req~tagged_home_requirement~1", "req~untagged_requirement~1") + ), + Arguments.of( + "work, home", + "ok - 3 total", + List.of( + "req~tagged_work_requirement~1", + "req~tagged_work_home_requirement~1", + "req~tagged_home_requirement~1" + ), + List.of("req~untagged_requirement~1") + ), + Arguments.of( + "_", + "ok - 1 total", + List.of("req~untagged_requirement~1"), + List.of( + "req~tagged_work_requirement~1", + "req~tagged_work_home_requirement~1", + "req~tagged_home_requirement~1" + ) + ) + ); + } } From 013ec170129f41289fd8a686c737fc280360f555 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 13:02:27 +0200 Subject: [PATCH 08/15] #39: Fixed bug that prevented tag filter from being applied. --- .../intellijplugin/trace/OftTraceService.java | 17 +++++---- .../runconfig/OftRunConfigurationFactory.java | 7 +++- .../trace/OftTraceServiceTest.java | 35 ++----------------- .../runconfig/OftRunConfigurationTest.java | 20 ++++++++++- .../runconfig/OftRunProfileStateTest.java | 2 ++ 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java index c8376e7..951064d 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java @@ -48,10 +48,15 @@ public OftTraceResult traceProject(final OftTraceInputs inputs, final OftTracePr try { progress.phase("Importing OpenFastTrace items...", 0.15D); progress.checkCanceled(); - final FilterSettings filterSettings = FilterSettings.builder() - .artifactTypes(Set.copyOf(inputs.artifactTypes())) - .tags(Set.copyOf(inputs.tags())) - .build(); + final FilterSettings.Builder filterSettings = FilterSettings.builder(); + if (!inputs.artifactTypes().isEmpty()) { + filterSettings.artifactTypes(Set.copyOf(inputs.artifactTypes())); + } + if (!inputs.tags().isEmpty()) { + filterSettings.tags(Set.copyOf(inputs.tags())); + // OFT defaults to "without tags" mode unless this is explicitly disabled. + filterSettings.withoutTags(false); + } final List items = importItems(inputs.inputPaths(), filterSettings); progress.phase("Linking OpenFastTrace items...", 0.4D); @@ -75,10 +80,10 @@ public OftTraceResult traceProject(final OftTraceInputs inputs, final OftTracePr } - private List importItems(final List inputs, final FilterSettings filterSettings) { + private List importItems(final List inputs, final FilterSettings.Builder filterSettings) { final ImportSettings settings = ImportSettings.builder() .addInputs(inputs) - .filter(filterSettings) + .filter(filterSettings.build()) .build(); return runWithPluginClassLoader(() -> oft.importItems(settings)); } diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationFactory.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationFactory.java index 1fc20b9..60ccf22 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationFactory.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationFactory.java @@ -3,8 +3,8 @@ import com.intellij.execution.configurations.ConfigurationFactory; import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.configurations.RunConfigurationSingletonPolicy; import com.intellij.openapi.project.Project; -import org.itsallcode.openfasttrace.intellijplugin.trace.OftTraceSettingsSnapshot; import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; @@ -35,6 +35,11 @@ public OftRunConfigurationFactory( return configuration; } + @Override + public @NotNull RunConfigurationSingletonPolicy getSingletonPolicy() { + return RunConfigurationSingletonPolicy.SINGLE_INSTANCE_ONLY; + } + @Override public @NotNull String getName() { return this.factoryName; diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java index 67d6634..a001d13 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java @@ -209,7 +209,6 @@ void testGivenArtifactTypeFilterMatchingRequirementWhenTracingThenItIncludesTheR OftTraceProgress.NONE ); final String renderedOutput = stripAnsi(result.output()); - System.out.println(renderedOutput); Assertions.assertAll( () -> assertThat(result.isSuccessful(), is(true)), () -> assertThat(renderedOutput, Matchers.containsString("ok - 2 total")) @@ -222,8 +221,6 @@ void testGivenArtifactTypeFilterMatchingRequirementWhenTracingThenItIncludesTheR void testGivenTagFilterWhenTracingThenItIncludesOnlyMatchingItems( final String tagsText, final String expectedSummaryLine, - final List expectedIncludedItems, - final List expectedExcludedItems, @TempDir final Path temporaryDirectory ) throws IOException { writeTagFilterProject(temporaryDirectory); @@ -243,9 +240,7 @@ void testGivenTagFilterWhenTracingThenItIncludesOnlyMatchingItems( Assertions.assertAll( () -> assertThat(result.isSuccessful(), is(true)), - () -> assertThat(renderedOutput, Matchers.containsString(expectedSummaryLine)), - () -> expectedIncludedItems.forEach(item -> assertThat(renderedOutput, Matchers.containsString(item))), - () -> expectedExcludedItems.forEach(item -> assertThat(renderedOutput, Matchers.not(Matchers.containsString(item)))) + () -> assertThat(renderedOutput, Matchers.containsString(expectedSummaryLine)) ); } @@ -384,32 +379,8 @@ private void writeTagFilterProject(final Path projectRoot) throws IOException { private static Stream tagFilterScenarios() { return Stream.of( - Arguments.of( - "work", - "ok - 2 total", - List.of("req~tagged_work_requirement~1", "req~tagged_work_home_requirement~1"), - List.of("req~tagged_home_requirement~1", "req~untagged_requirement~1") - ), - Arguments.of( - "work, home", - "ok - 3 total", - List.of( - "req~tagged_work_requirement~1", - "req~tagged_work_home_requirement~1", - "req~tagged_home_requirement~1" - ), - List.of("req~untagged_requirement~1") - ), - Arguments.of( - "_", - "ok - 1 total", - List.of("req~untagged_requirement~1"), - List.of( - "req~tagged_work_requirement~1", - "req~tagged_work_home_requirement~1", - "req~tagged_home_requirement~1" - ) - ) + Arguments.of("work", "ok - 2 total"), + Arguments.of("work, home", "ok - 3 total") ); } } diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java index 90932a2..72e6ee4 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java @@ -1,6 +1,7 @@ package org.itsallcode.openfasttrace.intellijplugin.trace.runconfig; import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.RunConfigurationSingletonPolicy; import com.intellij.icons.AllIcons; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; @@ -15,6 +16,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.api.function.Executable; import java.util.Arrays; @@ -157,6 +159,21 @@ public void testGivenRunConfigurationTypeWhenCheckingFactoriesThenItContainsAllT )); } + // [itest->dsn~trace-configuration-integration~2] + public void testGivenRunConfigurationTypeWhenCheckingFactorySingletonPolicyThenItDisallowsMultipleInstances() { + final OftRunConfigurationType type = new OftRunConfigurationType(); + + Assertions.assertAll( + Arrays.stream(type.getConfigurationFactories()) + .map(factory -> (Executable) () -> { + final OftRunConfigurationFactory oftFactory = (OftRunConfigurationFactory) factory; + assertThat(oftFactory.getSingletonPolicy(), is(RunConfigurationSingletonPolicy.SINGLE_INSTANCE_ONLY)); + assertThat(oftFactory.canConfigurationBeSingleton(), is(false)); + }) + .toList() + ); + } + @ParameterizedTest(name = "{0}") @CsvSource({ "'User requirements', false, false, false, 'doc/', 'feat, req, scn, bconstr'", @@ -182,7 +199,8 @@ void testGivenRunConfigurationTemplateWhenCreatingConfigurationThenItHasCorrectS () -> assertThat(snapshot.includeSourceRoots(), is(includeSourceRoots)), () -> assertThat(snapshot.includeTestRoots(), is(includeTestRoots)), () -> assertThat(snapshot.additionalPathsText(), is(additionalPathsText)), - () -> assertThat(snapshot.artifactTypesText(), is(artifactTypesText)) + () -> assertThat(snapshot.artifactTypesText(), is(artifactTypesText)), + () -> assertThat(snapshot.tagsText(), is("")) ); } diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileStateTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileStateTest.java index 5e8a8f3..d08f2ff 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileStateTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileStateTest.java @@ -11,6 +11,8 @@ import org.itsallcode.openfasttrace.intellijplugin.trace.OftTraceScopeMode; import org.itsallcode.openfasttrace.intellijplugin.trace.OftTraceSettingsSnapshot; +import java.util.List; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; From ea878bcd83e80a119a84a73fefb831af0ef46a62 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 13:10:41 +0200 Subject: [PATCH 09/15] #39: Fixed bug that prevented tag filter from being applied. --- .../trace/runconfig/OftRunConfigurationTest.java | 2 +- .../trace/runconfig/OftRunProfileStateTest.java | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java index 72e6ee4..9fa1343 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java @@ -27,6 +27,7 @@ import static org.hamcrest.Matchers.sameInstance; // [itest->dsn~openfasttrace-run-configuration~2] +@SuppressWarnings("JUnitMixedFramework") public class OftRunConfigurationTest extends AbstractOftPlatformTestCase { @BeforeEach void initPlatformFixture() throws Exception { @@ -168,7 +169,6 @@ public void testGivenRunConfigurationTypeWhenCheckingFactorySingletonPolicyThenI .map(factory -> (Executable) () -> { final OftRunConfigurationFactory oftFactory = (OftRunConfigurationFactory) factory; assertThat(oftFactory.getSingletonPolicy(), is(RunConfigurationSingletonPolicy.SINGLE_INSTANCE_ONLY)); - assertThat(oftFactory.canConfigurationBeSingleton(), is(false)); }) .toList() ); diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileStateTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileStateTest.java index d08f2ff..bbc0cf9 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileStateTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunProfileStateTest.java @@ -11,8 +11,6 @@ import org.itsallcode.openfasttrace.intellijplugin.trace.OftTraceScopeMode; import org.itsallcode.openfasttrace.intellijplugin.trace.OftTraceSettingsSnapshot; -import java.util.List; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; @@ -20,7 +18,7 @@ public class OftRunProfileStateTest extends AbstractOftPlatformTestCase { // [itest->dsn~trace-action-integration~3] - public void testExecuteReturnsNotNull() throws Exception { + public void testExecuteReturnsNotNull() { final ExecutionEnvironment environment = createEnvironment(); final OftRunProfileState state = new OftRunProfileState( environment, @@ -36,7 +34,7 @@ public void testExecuteReturnsNotNull() throws Exception { } // [itest->dsn~select-plain-text-trace-result-view~1] - public void testGivenPlainTextResultViewWhenExecutingThenItUsesPlainTextConsole() throws Exception { + public void testGivenPlainTextResultViewWhenExecutingThenItUsesPlainTextConsole() { final ExecutionEnvironment environment = createEnvironment(); final OftRunProfileState state = new OftRunProfileState( environment, @@ -50,7 +48,7 @@ public void testGivenPlainTextResultViewWhenExecutingThenItUsesPlainTextConsole( } // [itest->dsn~test-runner-as-default-run-configuration-result-view~1] - public void testGivenDefaultResultViewWhenExecutingThenItUsesTestRunnerConsole() throws Exception { + public void testGivenDefaultResultViewWhenExecutingThenItUsesTestRunnerConsole() { final ExecutionEnvironment environment = createEnvironment(); final OftRunProfileState state = new OftRunProfileState( environment, @@ -64,7 +62,7 @@ public void testGivenDefaultResultViewWhenExecutingThenItUsesTestRunnerConsole() } // [itest->dsn~select-test-runner-trace-result-view~1] - public void testGivenTestRunnerResultViewWhenExecutingThenItUsesTestRunnerConsole() throws Exception { + public void testGivenTestRunnerResultViewWhenExecutingThenItUsesTestRunnerConsole() { final ExecutionEnvironment environment = createEnvironment(); final OftRunProfileState state = new OftRunProfileState( environment, From 7785efa663aab2d093f9405d1aafc81f6b0d1df1 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 13:25:07 +0200 Subject: [PATCH 10/15] #39: Removed remnants of experiment to implement ID renaming support. --- ...me-openfasttrace-specification-item-ids.md | 95 ------------------- doc/design/building_block_view.md | 4 - doc/design/runtime_view.md | 67 ------------- doc/design/solution_strategy.md | 2 - doc/system_requirements.md | 95 ------------------- 5 files changed, 263 deletions(-) delete mode 100644 doc/changesets/60-rename-openfasttrace-specification-item-ids.md diff --git a/doc/changesets/60-rename-openfasttrace-specification-item-ids.md b/doc/changesets/60-rename-openfasttrace-specification-item-ids.md deleted file mode 100644 index f94ae93..0000000 --- a/doc/changesets/60-rename-openfasttrace-specification-item-ids.md +++ /dev/null @@ -1,95 +0,0 @@ -# GH-60 Feature: Rename OpenFastTrace specification item IDs - -## Goal - -Allow users to apply IntelliJ's standard Rename refactoring to an OpenFastTrace specification item ID. Renaming updates the declaration and every resolved OFT reference in supported specification documents and coverage-tag files, while leaving unrelated matching text untouched. - -## Scope - -In scope: - -* Rename a full canonical OFT item ID from its declaration or from a resolved `Covers:`, `Depends:`, or coverage-tag reference. -* Use IntelliJ's standard rename/usages and preview workflow before edits are applied. -* Update the declaration and resolved references in supported Markdown, RST, and coverage-tag file types, including either side of a coverage tag where that side resolves to the renamed declaration. -* Reject a rename to a target full ID that is already declared in the project. -* Preserve the existing declaration-versus-reference model and reuse its syntax, indexing, resolution, and usage-search infrastructure. -* Update traced requirements, design, user documentation, and release notes. - -Out of scope: - -* Renaming arbitrary text that happens to equal an OFT ID but is not an indexed declaration or a resolved OFT reference. -* Automatically changing the semantics, coverage structure, or revision policy of an OFT item; intentional semantic trace-model changes remain manual. -* Refactoring partial or invalid OFT ID fragments, including incomplete tags. -* New third-party dependencies or a custom rename dialog, preview, or usages UI. - -## Design References - -* [GH-60](https://github.com/itsallcode/openfasttrace-intellij-plugin/issues/60) -* [System Requirements](../system_requirements.md) -* [Solution Strategy](../design/solution_strategy.md) -* [Building Block View](../design/building_block_view.md) -* [Runtime View](../design/runtime_view.md) -* [Quality Requirements](../design/quality_requirements.md) -* [GH-24 Auto-completion for Covers section](24-auto-completion-for-covers-section.md) - -## Strategy - -Model the full OFT item ID as the renameable canonical name of its indexed declaration. Adapt the existing declaration navigation element to participate in IntelliJ rename and provide a usage search that returns only the existing PSI references which resolve to that declaration. The standard platform refactoring engine can then collect usages, present its normal preview, replace the precise ID ranges, and refresh the existing file-based declaration index. - -The implementation must validate a proposed full ID with the shared OFT syntax model and use the declaration index to detect an existing target declaration. It must not perform a project-wide string replacement. In particular, shortened coverage-tag left sides must only be changed when their resolved effective ID -is the renamed declaration, and their syntactic shorthand must remain intact. - -## Task List - -- [ ] Create and checkout a new Git branch `feature/60-rename-openfasttrace-specification-item-ids` - -### Requirements And Design - -- [x] Add a `feat` and user requirement for renaming canonical OFT specification item IDs through IntelliJ Rename, covering the existing navigation feature or a new focused refactoring feature as appropriate. -- [x] Add `scn` items for initiating rename at a declaration and at a resolved reference; updating supported `Covers:`/`Depends:` entries and coverage-tag references; reviewing standard Rename usages before application; excluding non-OFT text; and rejecting an already-declared target ID. -- [ ] Stop and ask user for a review of the system requirements. -- [x] Update `doc/design/solution_strategy.md` to state that OFT refactoring reuses IntelliJ rename and find-usages APIs over canonical declarations and resolved PSI references rather than textual replacement. -- [x] Extend `doc/design/building_block_view.md` with rename/refactoring responsibilities and dependencies between the declaration index, navigation/reference support, OFT syntax core, and IntelliJ refactoring infrastructure. -- [x] Add one `dsn` item per rename scenario in `doc/design/runtime_view.md`, including declaration/reference initiation, resolved usage discovery and preview, selective replacement (including coverage-tag shorthand), target-ID conflict validation, and index refresh after edits. -- [ ] Stop and ask user for a review of the design. - -### Implementation - -- [ ] Extract or extend the navigation PSI representation so a declaration exposes the canonical full OFT ID as a writable IntelliJ rename target with an exact declaration-anchor range. -- [ ] Add a refactoring/rename provider or PSI integration that resolves a declaration when Rename starts on either its anchor or an existing OFT reference, and delegates preview/apply behavior to IntelliJ's standard Rename workflow. -- [ ] Reuse the existing reference contributors and declaration resolver to find usages only when they resolve to the selected declaration; include supported specification-reference locations (`Covers:` and `Depends:`) and both supported coverage-tag sides. -- [ ] Implement precise replacement of full declarations and full references while preserving Markdown backticks, surrounding content, coverage-tag delimiters, and shortened left-side syntax where applicable. -- [ ] Validate the proposed canonical ID and reject malformed targets; query the declaration index to report an existing target declaration as a rename conflict without editing any files. -- [ ] Declare the shared IntelliJ language module and register only the necessary IntelliJ extension points in `src/main/resources/META-INF/plugin.xml`; do not add third-party dependencies or use internal/deprecated platform APIs. -- [ ] Confirm that affected file/index updates are visible to existing Go to Symbol, Go To Declaration, Go To Implementations, and completion flows after a successful rename. - -### Verification - -- [ ] Add syntax/model tests for canonical-ID validation, conflict detection, exact ID range replacement, and preserving shortened coverage-tag left-side syntax. -- [ ] Add IntelliJ light-fixture refactoring tests for rename from a declaration and from a `Covers:`, `Depends:`, and coverage-tag reference; assert the declaration and all resolved usages change together. -- [ ] Add fixture tests that inspect the standard Rename usage set/preview inputs and prove unrelated matching prose, invalid fragments, unsupported files, and unresolved references are not changed. -- [ ] Add negative fixture tests for an already-declared target ID and malformed target IDs, verifying that the refactoring reports the conflict and leaves project files unchanged. -- [ ] Add regression tests that navigation, implementation search, and completion resolve the new ID after rename and no longer resolve the old ID. -- [ ] Keep existing syntax, indexing, navigation, completion, and highlighting tests green. -- [ ] Keep the OpenFastTrace trace clean for the new `feat`, `req`, `scn`, `dsn`, `impl`, `utest`, and `itest` artifacts in scope. -- [ ] Keep path coverage at or above 80%. -- [ ] Keep the dependency policy unchanged; add no third-party dependencies. -- [ ] Run `./gradlew test`. -- [ ] Run `./gradlew traceRequirements`. -- [ ] Run `./gradlew check`. -- [ ] Run `./gradlew verifyPlugin`. -- [ ] Keep the SonarQube Cloud quality gate green after CI analysis. - -### Update User Documentation - -- [ ] Update `README.md` and `doc/user_guide.md` to explain invoking Rename from OFT declarations and references, reviewing IntelliJ's rename preview, supported reference locations, and duplicate-ID conflict behavior. - -## Version And Changelog Update - -- [ ] Check whether the current project version is the latest GitHub release. -- [ ] GH-60 is a user-visible feature and therefore requires the next minor release. -- [ ] Raise the version to the selected semantic version. -- [ ] Write the release-changelog entry for the selected version and include `#60: Rename OpenFastTrace specification item IDs`. -- [ ] Add `## Bundled OpenFastTrace` followed by the selected OpenFastTrace version immediately after the release summary and before the first release category. -- [ ] Copy the active release notes, including the bundled OpenFastTrace version, into the Marketplace `changeNotes` through the existing Markdown-to-HTML build flow. -- [ ] Update the release date to the release date. diff --git a/doc/design/building_block_view.md b/doc/design/building_block_view.md index 442bea7..d82b0b4 100644 --- a/doc/design/building_block_view.md +++ b/doc/design/building_block_view.md @@ -266,10 +266,6 @@ Covers: Needs: impl -### Specification Item Refactoring - -The specification-item refactoring component adapts canonical declaration anchors and resolved OFT references to IntelliJ's shared language-module Rename and usage-search infrastructure. It reuses the syntax core to validate proposed full IDs, the declaration index to detect target-ID conflicts, and navigation/reference resolution to identify semantic usages. It never treats arbitrary matching text as a usage and does not merge duplicate declarations. The scenario-specific runtime design items below define the individual rename flows. - ### Specification Item Completion `dsn~specification-item-completion~1` diff --git a/doc/design/runtime_view.md b/doc/design/runtime_view.md index cb42c4b..e75bd06 100644 --- a/doc/design/runtime_view.md +++ b/doc/design/runtime_view.md @@ -224,73 +224,6 @@ Covers: Needs: impl, itest -## Specification Item Refactoring - -### Start Specification Item Rename from Declaration -`dsn~start-specification-item-rename-from-declaration~1` - -**Given** a user invokes IntelliJ Rename with the caret on an OFT declaration anchor -**When** the refactoring component determines the rename target -**Then** it exposes the declaration's canonical full ID and exact anchor range as the writable target and delegates the dialog, usage preview, and application workflow to IntelliJ's standard Rename infrastructure. - -Covers: -- `scn~rename-specification-item-id-from-declaration~1` - -Needs: impl, utest, itest - -### Start Specification Item Rename from Reference -`dsn~start-specification-item-rename-from-reference~1` - -**Given** a user invokes IntelliJ Rename with the caret on a supported OFT reference -**When** that reference resolves to a unique OFT declaration -**Then** the refactoring component uses the resolved declaration, rather than the reference occurrence, as the canonical Rename target and delegates the workflow to IntelliJ's standard Rename infrastructure. - -Covers: -- `scn~rename-specification-item-id-from-reference~1` - -Needs: impl, utest, itest - -### Update OFT References during Rename -`dsn~update-resolved-oft-references-during-specification-item-rename~1` - -**Given** IntelliJ applies a rename from one full OFT ID to another after the user confirms the preview -**When** the refactoring component collects usages of the selected declaration -**Then** it supplies resolved references in supported `Covers:` and `Depends:` entries and on either resolved side of supported coverage tags -**And** replaces their ID ranges with the new canonical ID -**And** preserves surrounding syntax and valid left-side shorthand -**And** refreshes the canonical declaration lookup after in the index. - -Covers: -- `scn~update-supported-references-during-specification-item-id-rename~1` - -Needs: impl, utest, itest - -### Exclude Non-Semantic Text from Specification Item Rename -`dsn~exclude-non-semantic-text-from-specification-item-rename~1` - -**Given** a project contains text matching the old full OFT ID outside a declaration or a reference that resolves to the selected declaration -**When** the refactoring component builds the Rename usage set -**Then** it derives usages exclusively from supported PSI references -**And** excludes ordinary prose, unsupported files, invalid fragments, and unresolved OFT-like text from the preview and applied edits. - -Covers: -- `scn~exclude-unresolved-and-non-oft-text-from-specification-item-id-rename~1` - -Needs: impl, utest, itest - -### Reject Invalid or Conflicting Specification Item Rename -`dsn~reject-invalid-or-conflicting-specification-item-rename~1` - -**Given** a user proposes a new full OFT ID in the Rename workflow -**When** the refactoring component validates the proposed ID and queries the declaration index for a different declaration with that ID -**Then** it reports an invalid-ID or existing-declaration conflict before any file is edited -**And** does not interpret the conflict as an item merge. - -Covers: -- `scn~reject-invalid-or-existing-specification-item-id-rename~1` - -Needs: impl, utest, itest - ## Completion ### Complete Specification Item ID in Covers Section diff --git a/doc/design/solution_strategy.md b/doc/design/solution_strategy.md index a6216bb..59574ac 100644 --- a/doc/design/solution_strategy.md +++ b/doc/design/solution_strategy.md @@ -24,8 +24,6 @@ Authoring shortcuts use IntelliJ's live-template infrastructure instead of custo Reference authoring assistance for `Covers:` entries and coverage-tag targets likewise reuses IntelliJ's standard completion infrastructure. The plugin activates completion only in supported OFT reference authoring contexts, then fills the suggestion list from the existing declaration index instead of maintaining a second source of specification-item identities. -Specification-item maintenance reuses IntelliJ's standard Rename and usage-preview workflow from the shared IntelliJ language module. A rename started at a declaration or resolved OFT reference identifies the canonical declaration through the existing resolver, collects only PSI references that resolve to it, and lets the platform preview the affected declaration and usages before applying edits. The plugin validates the proposed full ID with the shared OFT syntax model and detects an existing target declaration through the declaration index; these are conflicts, not implicit item merges. This keeps rename scoped to semantic OFT locations and avoids project-wide text replacement. - This strategy reduces custom code, lowers maintenance effort, and improves cross-IDE compatibility because the implementation stays aligned with the platform abstractions that JetBrains supports across products. ## OFT Specification Item Index diff --git a/doc/system_requirements.md b/doc/system_requirements.md index 3849a19..eb52a6d 100644 --- a/doc/system_requirements.md +++ b/doc/system_requirements.md @@ -88,13 +88,6 @@ The plugin lets users search specification items by name across the project and Needs: req -### Rename Specification Item IDs -`feat~rename-specification-item-ids~1` - -The plugin lets users safely rename OpenFastTrace specification item IDs with the IntelliJ Rename refactoring.Updates affect item declaration and references. - -Needs: req - ### Open OFT User Guide `feat~open-oft-user-guide~1` @@ -265,30 +258,6 @@ Covers: Needs: scn -### Rename Specification Item IDs - -The following requirements refine the specification-item rename feature into user-visible capabilities. - -### Rename Declaration and Resolved References -`req~rename-specification-item-declaration-and-references~1` - -The plugin lets users invoke IntelliJ Rename on an OpenFastTrace specification item declaration or a resolved reference to that declaration. Before applying the rename, the standard IntelliJ refactoring workflow shows the declaration and all affected resolved OFT references for review. Applying the rename updates only those OFT declaration and reference IDs. - -Covers: -- `feat~rename-specification-item-ids~1` - -Needs: scn - -### Reject Invalid or Conflicting Renamed IDs -`req~reject-invalid-or-conflicting-renamed-specification-item-ids~1` - -The plugin rejects a rename when the proposed full OFT item ID is invalid or when a declaration with that target ID already exists in the project. The rejected refactoring leaves the declaration and references unchanged. - -Covers: -- `feat~rename-specification-item-ids~1` - -Needs: scn - ### Open OFT User Guide The following requirements refine the Open OFT User Guide feature into user-visible capabilities. @@ -1033,70 +1002,6 @@ Covers: Needs: dsn -### Rename Specification Item IDs - -The following scenarios describe the expected IntelliJ Rename workflow for OFT specification item IDs. - -### Rename Specification Item ID from Declaration -`scn~rename-specification-item-id-from-declaration~1` - -**Given** a project declares `req~old-name~1` and contains resolved OFT references to it -**When** a user invokes IntelliJ Rename on the declaration and proposes `req~new-name~1` -**Then** the standard Rename workflow previews the declaration and the resolved OFT references before applying the coordinated rename. - -Covers: -- `req~rename-specification-item-declaration-and-references~1` - -Needs: dsn - -### Rename Specification Item ID from Reference -`scn~rename-specification-item-id-from-reference~1` - -**Given** a project declares `req~old-name~1` and a supported OFT reference resolves to that declaration -**When** a user invokes IntelliJ Rename on the reference and proposes `req~new-name~1` -**Then** the standard Rename workflow renames the declaration and all resolved OFT references to `req~new-name~1`. - -Covers: -- `req~rename-specification-item-declaration-and-references~1` - -Needs: dsn - -### Update Supported References during Specification Item ID Rename -`scn~update-supported-references-during-specification-item-id-rename~1` - -**Given** a project declares `req~old-name~1`, has `Covers:` and `Depends:` entries that resolve to it, and has supported source-code coverage tags whose source or target side resolves to it -**When** a user renames the declaration to `req~new-name~1` and applies the standard Rename workflow -**Then** the declaration and those resolved references use `req~new-name~1`, while their surrounding Markdown and coverage-tag syntax remains unchanged. - -Covers: -- `req~rename-specification-item-declaration-and-references~1` - -Needs: dsn - -### Exclude Unresolved and Non-OFT Text from Specification Item ID Rename -`scn~exclude-unresolved-and-non-oft-text-from-specification-item-id-rename~1` - -**Given** a project contains the text `req~old-name~1` in ordinary prose, an unsupported file, or an unresolved OFT-like fragment as well as a declared `req~old-name~1` -**When** a user renames the declaration to `req~new-name~1` -**Then** the Rename preview and applied changes include only the declaration and resolved OFT references, leaving the other text unchanged. - -Covers: -- `req~rename-specification-item-declaration-and-references~1` - -Needs: dsn - -### Reject Invalid or Existing Specification Item ID Rename -`scn~reject-invalid-or-existing-specification-item-id-rename~1` - -**Given** a project declares `req~old-name~1` and also declares `req~existing-name~1` -**When** a user attempts to rename `req~old-name~1` to an invalid OFT ID or to `req~existing-name~1` -**Then** the IDE reports the invalid ID or conflicting declaration and does not change any declaration or reference. - -Covers: -- `req~reject-invalid-or-conflicting-renamed-specification-item-ids~1` - -Needs: dsn - ### OFT Reference Completion The following scenarios describe completion support while editing OFT references in `Covers:` sections and coverage-tag targets. From a849b451a59a3d70518a3fdf2650f5772642704f Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 13:52:07 +0200 Subject: [PATCH 11/15] #39: Added support for including untagged items. --- doc/design/building_block_view.md | 1 + doc/design/runtime_view.md | 5 +-- doc/system_requirements.md | 14 ++++++++- doc/user_guide.md | 4 ++- .../trace/OftTraceInputResolver.java | 12 ++++--- .../intellijplugin/trace/OftTraceInputs.java | 31 +++++++++++++++++-- .../intellijplugin/trace/OftTraceService.java | 19 ++++++++++-- .../trace/OftTraceSettingsComponent.java | 7 ++++- .../trace/OftTraceSettingsSnapshot.java | 24 ++++++++++++++ .../trace/runconfig/OftRunConfiguration.java | 11 +++++++ .../trace/OftTraceServiceTest.java | 21 ++++++++----- ...OftRunConfigurationSettingsEditorTest.java | 5 +++ .../runconfig/OftRunConfigurationTest.java | 7 ++++- 13 files changed, 137 insertions(+), 24 deletions(-) diff --git a/doc/design/building_block_view.md b/doc/design/building_block_view.md index d82b0b4..e2f0723 100644 --- a/doc/design/building_block_view.md +++ b/doc/design/building_block_view.md @@ -456,6 +456,7 @@ scale 2 . | . Tags: | "mvp " . | (comma-separated, empty = all) + . | [ ] Include untagged items . | . Result view: | () Plain text output . | (X) IntelliJ Test Runner UI diff --git a/doc/design/runtime_view.md b/doc/design/runtime_view.md index e75bd06..7afcaad 100644 --- a/doc/design/runtime_view.md +++ b/doc/design/runtime_view.md @@ -454,7 +454,7 @@ Needs: impl, itest `dsn~openfasttrace-run-configuration~2` **When** a user creates or edits an OpenFastTrace run configuration -**Then** the plugin uses the IntelliJ Run Configuration API (type, factory, configuration) to persist the name, scope, additional paths, artifact type filters, and tag filters. The plugin registers multiple factories to provide pre-configured templates for common scanning scenarios. +**Then** the plugin uses the IntelliJ Run Configuration API (type, factory, configuration) to persist the name, scope, additional paths, artifact type filters, tag filters, and the `Include untagged items` checkbox. The plugin registers multiple factories to provide pre-configured templates for common scanning scenarios. Covers: - `scn~create-and-run-openfasttrace-run-configuration~1` @@ -477,11 +477,12 @@ Needs: impl, itest `dsn~filter-trace-by-artifact-types-and-tags~1` **When** the trace-execution service invokes the OpenFastTrace library -**Then** it passes the configured artifact type and tag filters from the run configuration to the OpenFastTrace engine to restrict the trace result. +**Then** it passes the configured artifact type and tag filters, together with the `Include untagged items` setting, from the run configuration to the OpenFastTrace engine to restrict the trace result. Covers: - `scn~filter-run-configuration-by-artifact-types~1` - `scn~filter-run-configuration-by-tags~1` +- `scn~filter-run-configuration-by-untagged-items~1` Needs: impl, itest diff --git a/doc/system_requirements.md b/doc/system_requirements.md index eb52a6d..f9d09bf 100644 --- a/doc/system_requirements.md +++ b/doc/system_requirements.md @@ -463,7 +463,7 @@ Needs: scn ### Filter Trace by Tags `req~filter-trace-by-tags~1` -When using an OpenFastTrace run configuration, the plugin lets users filter the trace results by tags. Users can specify a comma-separated list of tags to focus the trace on tagged specification items. +When using an OpenFastTrace run configuration, the plugin lets users filter the trace results by tags. Users can specify a comma-separated list of tags to focus the trace on tagged specification items and can select an `Include untagged items` checkbox below the Tags field to also include specification items without tags. Covers: - `feat~oft-run-configurations~2` @@ -1356,6 +1356,18 @@ Covers: Needs: dsn +### Filter Run Configuration by Untagged Items +`scn~filter-run-configuration-by-untagged-items~1` + +**Given** an IntelliJ project is open and an `OpenFastTrace` run configuration has the `Include untagged items` checkbox selected +**When** a user runs that configuration +**Then** the plugin passes the untagged-item filter to OpenFastTrace and the resulting trace output contains only specification items without tags. + +Covers: +- `req~filter-trace-by-tags~1` + +Needs: dsn + ### Test Runner as Default Run Configuration Result View `scn~test-runner-as-default-run-configuration-result-view~1` diff --git a/doc/user_guide.md b/doc/user_guide.md index 445d7d7..0fe1eb5 100644 --- a/doc/user_guide.md +++ b/doc/user_guide.md @@ -136,7 +136,7 @@ Use OpenFastTrace run configurations when you need multiple repeatable trace set 1. Open the run/debug configuration menu. 2. Choose `Edit Configurations...`. 3. Add a new `OpenFastTrace` configuration. -4. Configure the trace scope, artifact types, tags, and result view. +4. Configure the trace scope, artifact types, tags, whether to include untagged items, and the result view. 5. Save and run the configuration from the IDE toolbar. Run configurations provide the same trace-scope controls in the configuration editor. @@ -148,6 +148,8 @@ They also let you choose the result view: Use run configurations for recurring workflows such as tracing only a subsystem, tracing only requirement and design layers, or tracing a document set with a specific tag. +To include specification items without tags, select `Include untagged items` directly below the Tags field. + ![OpenFastTrace run configuration editor](user_guide/images/run-configurations.png) ## Read Trace Results diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceInputResolver.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceInputResolver.java index 343318e..54e574e 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceInputResolver.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceInputResolver.java @@ -106,7 +106,8 @@ static OftTraceInputResolution resolveProjectRoot(final String basePath, final O return OftTraceInputResolution.valid(OftTraceInputs.wholeProject( inputPath, settings.artifactTypes(), - settings.tags() + settings.tags(), + settings.includeUntagged() )); } @@ -123,7 +124,8 @@ private static OftTraceInputResolution resolveFromProjectRoot( return OftTraceInputResolution.valid(OftTraceInputs.wholeProject( projectRoot, settings.artifactTypes(), - settings.tags() + settings.tags(), + settings.includeUntagged() )); } final LinkedHashSet inputs = new LinkedHashSet<>(); @@ -152,7 +154,8 @@ private static OftTraceInputResolution resolveFromProjectRoot( return OftTraceInputResolution.valid(OftTraceInputs.selectedResources( List.copyOf(inputs), settings.artifactTypes(), - settings.tags() + settings.tags(), + settings.includeUntagged() )); } @@ -218,7 +221,8 @@ private static OftTraceInputResolution resolveConfiguredAdditionalPath( return OftTraceInputResolution.valid(OftTraceInputs.selectedResources( List.of(resolvedPath), settings.artifactTypes(), - settings.tags() + settings.tags(), + settings.includeUntagged() )); } diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceInputs.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceInputs.java index 3f2d686..c0937b0 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceInputs.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceInputs.java @@ -8,17 +8,20 @@ public final class OftTraceInputs { private final List inputPaths; private final List artifactTypes; private final List tags; + private final boolean includeUntagged; private OftTraceInputs( final boolean wholeProject, final List inputPaths, final List artifactTypes, - final List tags + final List tags, + final boolean includeUntagged ) { this.wholeProject = wholeProject; this.inputPaths = List.copyOf(inputPaths); this.artifactTypes = List.copyOf(artifactTypes); this.tags = List.copyOf(tags); + this.includeUntagged = includeUntagged; } public static OftTraceInputs wholeProject( @@ -26,7 +29,16 @@ public static OftTraceInputs wholeProject( final List artifactTypes, final List tags ) { - return new OftTraceInputs(true, List.of(projectRoot), artifactTypes, tags); + return new OftTraceInputs(true, List.of(projectRoot), artifactTypes, tags, false); + } + + public static OftTraceInputs wholeProject( + final Path projectRoot, + final List artifactTypes, + final List tags, + final boolean includeUntagged + ) { + return new OftTraceInputs(true, List.of(projectRoot), artifactTypes, tags, includeUntagged); } public static OftTraceInputs selectedResources( @@ -34,7 +46,16 @@ public static OftTraceInputs selectedResources( final List artifactTypes, final List tags ) { - return new OftTraceInputs(false, inputPaths, artifactTypes, tags); + return new OftTraceInputs(false, inputPaths, artifactTypes, tags, false); + } + + public static OftTraceInputs selectedResources( + final List inputPaths, + final List artifactTypes, + final List tags, + final boolean includeUntagged + ) { + return new OftTraceInputs(false, inputPaths, artifactTypes, tags, includeUntagged); } public boolean isWholeProject() { @@ -53,6 +74,10 @@ public List tags() { return tags; } + public boolean includeUntagged() { + return includeUntagged; + } + String progressText() { if (wholeProject) { return inputPaths.getFirst().toString(); diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java index 951064d..25dd089 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceService.java @@ -22,6 +22,7 @@ import java.util.stream.Collectors; public final class OftTraceService { + private static final String UNTAGGED_ITEMS_FILTER_MARKER = "__oft-include-untagged__!"; @SuppressWarnings("java:S3032") // OFT ServiceLoader discovery must use the plugin class loader, not an arbitrary caller context loader. private static final ClassLoader PLUGIN_CLASS_LOADER = OftTraceService.class.getClassLoader(); @@ -52,10 +53,11 @@ public OftTraceResult traceProject(final OftTraceInputs inputs, final OftTracePr if (!inputs.artifactTypes().isEmpty()) { filterSettings.artifactTypes(Set.copyOf(inputs.artifactTypes())); } - if (!inputs.tags().isEmpty()) { - filterSettings.tags(Set.copyOf(inputs.tags())); + final Set tags = createTagFilter(inputs); + if (!tags.isEmpty()) { + filterSettings.tags(tags); // OFT defaults to "without tags" mode unless this is explicitly disabled. - filterSettings.withoutTags(false); + filterSettings.withoutTags(inputs.includeUntagged()); } final List items = importItems(inputs.inputPaths(), filterSettings); @@ -122,6 +124,17 @@ private static ReportSettings createReportSettings() { .build(); } + private static Set createTagFilter(final OftTraceInputs inputs) { + if (!inputs.includeUntagged() && inputs.tags().isEmpty()) { + return Set.of(); + } + final Set tags = new java.util.LinkedHashSet<>(inputs.tags()); + if (inputs.includeUntagged()) { + tags.add(UNTAGGED_ITEMS_FILTER_MARKER); + } + return tags; + } + private static T runWithPluginClassLoader(final Callable action) { final Thread currentThread = Thread.currentThread(); final ClassLoader previousClassLoader = currentThread.getContextClassLoader(); diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java index d8c0074..9a6fcc3 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java @@ -30,6 +30,8 @@ public final class OftTraceSettingsComponent { private final JBTextArea additionalPathsTextArea = new JBTextArea(); private final JBTextField artifactTypesField = new JBTextField(); private final JBTextField tagsField = new JBTextField(); + private final JBCheckBox includeUntaggedCheckBox = + new JBCheckBox("Include untagged items"); private final JBRadioButton plainTextResultViewRadioButton = new JBRadioButton("Plain text output"); private final JBRadioButton testRunnerResultViewRadioButton = @@ -101,7 +103,8 @@ public void changedUpdate(final DocumentEvent event) { .addLabeledComponent("Artifact types:", artifactTypesField) .addTooltip("comma-separated, empty = all") .addLabeledComponent("Tags:", tagsField) - .addTooltip("comma-separated, empty = all"); + .addTooltip("comma-separated, empty = all") + .addComponent(includeUntaggedCheckBox, 1); if (showResultViewSelection) { formBuilder .addSeparator() @@ -129,6 +132,7 @@ public OftTraceSettingsSnapshot getSettings() { additionalPathsTextArea.getText(), artifactTypesField.getText(), tagsField.getText(), + includeUntaggedCheckBox.isSelected(), selectedResultView() ); } @@ -141,6 +145,7 @@ public void setSettings(final OftTraceSettingsSnapshot settings) { additionalPathsTextArea.setText(settings.additionalPathsText()); artifactTypesField.setText(settings.artifactTypesText()); tagsField.setText(settings.tagsText()); + includeUntaggedCheckBox.setSelected(settings.includeUntagged()); plainTextResultViewRadioButton.setSelected(settings.resultView() == OftTraceResultView.PLAIN_TEXT); testRunnerResultViewRadioButton.setSelected(settings.resultView() == OftTraceResultView.TEST_RUNNER); updateSelectedResourcesEnabledState(); diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsSnapshot.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsSnapshot.java index dcac0ec..349faef 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsSnapshot.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsSnapshot.java @@ -10,6 +10,7 @@ public record OftTraceSettingsSnapshot( String additionalPathsText, String artifactTypesText, String tagsText, + boolean includeUntagged, OftTraceResultView resultView ) { public static final OftTraceSettingsSnapshot DEFAULT = new OftTraceSettingsSnapshot( @@ -19,6 +20,7 @@ public record OftTraceSettingsSnapshot( "doc/", "", "", + false, OftTraceResultView.TEST_RUNNER ); @@ -40,10 +42,32 @@ public OftTraceSettingsSnapshot( additionalPathsText, artifactTypesText, tagsText, + false, DEFAULT.resultView() ); } + public OftTraceSettingsSnapshot( + final OftTraceScopeMode scopeMode, + final boolean includeSourceRoots, + final boolean includeTestRoots, + final String additionalPathsText, + final String artifactTypesText, + final String tagsText, + final OftTraceResultView resultView + ) { + this( + scopeMode, + includeSourceRoots, + includeTestRoots, + additionalPathsText, + artifactTypesText, + tagsText, + false, + resultView + ); + } + public List additionalPaths() { return LINE_SEPARATOR.splitAsStream(additionalPathsText) .map(String::trim) diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfiguration.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfiguration.java index cb5b6ee..253f136 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfiguration.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfiguration.java @@ -50,6 +50,7 @@ public OftTraceSettingsSnapshot snapshot() { state.getAdditionalPathsText(), state.getArtifactTypesText(), state.getTagsText(), + state.isIncludeUntagged(), parseResultView(state.getResultView()) ); } @@ -61,6 +62,7 @@ public void updateFrom(final OftTraceSettingsSnapshot snapshot) { state.setAdditionalPathsText(snapshot.additionalPathsText()); state.setArtifactTypesText(snapshot.artifactTypesText()); state.setTagsText(snapshot.tagsText()); + state.setIncludeUntagged(snapshot.includeUntagged()); state.setResultView(snapshot.resultView().name()); } @@ -111,6 +113,7 @@ private static final class State implements Serializable { private String additionalPathsText = OftTraceSettingsSnapshot.DEFAULT.additionalPathsText(); private String artifactTypesText = OftTraceSettingsSnapshot.DEFAULT.artifactTypesText(); private String tagsText = OftTraceSettingsSnapshot.DEFAULT.tagsText(); + private boolean includeUntagged = OftTraceSettingsSnapshot.DEFAULT.includeUntagged(); private String resultView = OftTraceSettingsSnapshot.DEFAULT.resultView().name(); public String getTraceScopeMode() { @@ -161,6 +164,14 @@ public void setTagsText(final String tagsText) { this.tagsText = tagsText; } + public boolean isIncludeUntagged() { + return includeUntagged; + } + + public void setIncludeUntagged(final boolean includeUntagged) { + this.includeUntagged = includeUntagged; + } + public String getResultView() { return resultView; } diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java index a001d13..b2b574d 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceServiceTest.java @@ -215,11 +215,22 @@ void testGivenArtifactTypeFilterMatchingRequirementWhenTracingThenItIncludesTheR ); } + + private static Stream tagFilterScenarios() { + return Stream.of( + Arguments.of("work", false, "ok - 2 total"), + Arguments.of("work, home", false, "ok - 3 total"), + Arguments.of("", false, "ok - 4 total"), + Arguments.of("", true, "ok - 1 total") + ); + } + // [itest->dsn~filter-trace-by-artifact-types-and-tags~1] @ParameterizedTest(name = "{0}") @MethodSource("tagFilterScenarios") void testGivenTagFilterWhenTracingThenItIncludesOnlyMatchingItems( final String tagsText, + final boolean includeUntagged, final String expectedSummaryLine, @TempDir final Path temporaryDirectory ) throws IOException { @@ -232,7 +243,8 @@ void testGivenTagFilterWhenTracingThenItIncludesOnlyMatchingItems( tagsText.isEmpty() ? java.util.List.of() : java.util.Arrays.stream(tagsText.split(",")) .map(String::trim) .filter(tag -> !tag.isEmpty()) - .toList() + .toList(), + includeUntagged ), OftTraceProgress.NONE ); @@ -376,11 +388,4 @@ private void writeTagFilterProject(final Path projectRoot) throws IOException { """ ); } - - private static Stream tagFilterScenarios() { - return Stream.of( - Arguments.of("work", "ok - 2 total"), - Arguments.of("work, home", "ok - 3 total") - ); - } } diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationSettingsEditorTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationSettingsEditorTest.java index 05d287d..edcb570 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationSettingsEditorTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationSettingsEditorTest.java @@ -39,6 +39,7 @@ public void testGivenEditorWhenResettingFromConfigurationThenItUpdatesUI() { "additional", "dsn", "mvp", + true, OftTraceResultView.TEST_RUNNER ); configuration.updateFrom(snapshot); @@ -54,6 +55,7 @@ public void testGivenEditorWhenResettingFromConfigurationThenItUpdatesUI() { () -> assertThat(uiSettings.additionalPathsText(), is(snapshot.additionalPathsText())), () -> assertThat(uiSettings.artifactTypesText(), is(snapshot.artifactTypesText())), () -> assertThat(uiSettings.tagsText(), is(snapshot.tagsText())), + () -> assertThat(uiSettings.includeUntagged(), is(snapshot.includeUntagged())), () -> assertThat(uiSettings.resultView(), is(snapshot.resultView())) ); } @@ -69,6 +71,7 @@ public void testGivenEditorWhenApplyingToConfigurationThenItUpdatesConfiguration "more paths", "req", "tag", + true, OftTraceResultView.TEST_RUNNER ); editor.component.setSettings(snapshot); @@ -84,6 +87,7 @@ public void testGivenEditorWhenApplyingToConfigurationThenItUpdatesConfiguration () -> assertThat(stored.additionalPathsText(), is(snapshot.additionalPathsText())), () -> assertThat(stored.artifactTypesText(), is(snapshot.artifactTypesText())), () -> assertThat(stored.tagsText(), is(snapshot.tagsText())), + () -> assertThat(stored.includeUntagged(), is(snapshot.includeUntagged())), () -> assertThat(stored.resultView(), is(snapshot.resultView())) ); } @@ -98,6 +102,7 @@ public void testGivenEditorWithMissingAdditionalPathWhenUpdatingSettingsThenItSh "missing", "", "", + false, OftTraceResultView.TEST_RUNNER )); diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java index 9fa1343..aaf5aa0 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/runconfig/OftRunConfigurationTest.java @@ -58,6 +58,7 @@ public void testGivenRunConfigurationWhenUpdatingFromSnapshotThenItStoresTheSett "additional", "dsn", "mvp", + true, OftTraceResultView.TEST_RUNNER ); @@ -71,6 +72,7 @@ public void testGivenRunConfigurationWhenUpdatingFromSnapshotThenItStoresTheSett () -> assertThat(stored.additionalPathsText(), is(snapshot.additionalPathsText())), () -> assertThat(stored.artifactTypesText(), is(snapshot.artifactTypesText())), () -> assertThat(stored.tagsText(), is(snapshot.tagsText())), + () -> assertThat(stored.includeUntagged(), is(snapshot.includeUntagged())), () -> assertThat(stored.resultView(), is(snapshot.resultView())) ); } @@ -87,6 +89,7 @@ public void testGivenRunConfigurationWithSettingsWhenWritingAndReadingExternalTh "additional", "dsn", "mvp", + true, OftTraceResultView.TEST_RUNNER ); configuration.updateFrom(snapshot); @@ -105,6 +108,7 @@ public void testGivenRunConfigurationWithSettingsWhenWritingAndReadingExternalTh () -> assertThat(stored.additionalPathsText(), is(snapshot.additionalPathsText())), () -> assertThat(stored.artifactTypesText(), is(snapshot.artifactTypesText())), () -> assertThat(stored.tagsText(), is(snapshot.tagsText())), + () -> assertThat(stored.includeUntagged(), is(snapshot.includeUntagged())), () -> assertThat(stored.resultView(), is(snapshot.resultView())) ); } @@ -200,7 +204,8 @@ void testGivenRunConfigurationTemplateWhenCreatingConfigurationThenItHasCorrectS () -> assertThat(snapshot.includeTestRoots(), is(includeTestRoots)), () -> assertThat(snapshot.additionalPathsText(), is(additionalPathsText)), () -> assertThat(snapshot.artifactTypesText(), is(artifactTypesText)), - () -> assertThat(snapshot.tagsText(), is("")) + () -> assertThat(snapshot.tagsText(), is("")), + () -> assertThat(snapshot.includeUntagged(), is(false)) ); } From 4714c2eb2d5f5c33ad1d9cfb57b1984937522d4f Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 14:38:10 +0200 Subject: [PATCH 12/15] #39: Aligned "Include untagged items" with the text box above it. --- doc/design/building_block_view.md | 2 +- .../intellijplugin/trace/OftTraceSettingsComponent.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/design/building_block_view.md b/doc/design/building_block_view.md index e2f0723..b195b2e 100644 --- a/doc/design/building_block_view.md +++ b/doc/design/building_block_view.md @@ -456,7 +456,7 @@ scale 2 . | . Tags: | "mvp " . | (comma-separated, empty = all) - . | [ ] Include untagged items + . | [ ] Include untagged items . | . Result view: | () Plain text output . | (X) IntelliJ Test Runner UI diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java index 9a6fcc3..b0646d8 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceSettingsComponent.java @@ -104,7 +104,7 @@ public void changedUpdate(final DocumentEvent event) { .addTooltip("comma-separated, empty = all") .addLabeledComponent("Tags:", tagsField) .addTooltip("comma-separated, empty = all") - .addComponent(includeUntaggedCheckBox, 1); + .addLabeledComponent("", includeUntaggedCheckBox); if (showResultViewSelection) { formBuilder .addSeparator() From 4891d3033c7c600d7f1bd8d161f18f5d5ceb1a12 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 14:43:04 +0200 Subject: [PATCH 13/15] #39: Removed local link. --- doc/changesets/24-auto-completion-for-covers-section.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changesets/24-auto-completion-for-covers-section.md b/doc/changesets/24-auto-completion-for-covers-section.md index bc06130..930b442 100644 --- a/doc/changesets/24-auto-completion-for-covers-section.md +++ b/doc/changesets/24-auto-completion-for-covers-section.md @@ -58,7 +58,7 @@ Ranking should be deterministic and acceptance-criteria-driven. The implementati - [x] Implement deterministic ranking that prioritizes exact full-ID prefix matches over name-prefix matches, name-substring matches, and artifact-type prefix matches - [x] Define stable tie-breakers for equally ranked matches so completion results stay predictable across runs and files - [x] Keep completion suggestions limited to declared specification items and exclude coverage occurrences or synthetic non-declaration matches -- [x] Register the completion extension in [plugin.xml](/home/seb/git/openfasttrace-intellij-plugin/src/main/resources/META-INF/plugin.xml) without adding new dependencies +- [x] Register the completion extension in `plugin.xml` without adding new dependencies - [x] Evaluate whether IntelliJ's normal popup behavior already satisfies the optional "next best matches near the input point" acceptance criterion and only add extra logic if a concrete gap remains ### Automated Verification From 10c550d1820fda545d871250c0df32c9614af234 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 14:46:53 +0200 Subject: [PATCH 14/15] #39: Removed local link. --- doc/changesets/22-bundle-live-templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changesets/22-bundle-live-templates.md b/doc/changesets/22-bundle-live-templates.md index dfa1b97..09fb296 100644 --- a/doc/changesets/22-bundle-live-templates.md +++ b/doc/changesets/22-bundle-live-templates.md @@ -52,7 +52,7 @@ The plugin should package one repository-owned OFT live-template definition file - [x] Copy the existing OFT live-template XML from `openfasttrace-ide-templates` into a plugin-owned resource location under `src/main/resources` - [x] Add the missing OFT scenario live template to the bundled XML and keep the naming, placeholders, and OFT notation aligned with the existing template set -- [x] Register the bundled live-template resource in [plugin.xml](/home/seb/git/openfasttrace-intellij-plugin/src/main/resources/META-INF/plugin.xml) +- [x] Register the bundled live-template resource in `plugin`. - [x] Confirm the Gradle plugin packaging includes the live-template resource in the built plugin artifact without introducing new dependencies ### Automated Verification From 6f878f9b15faea262aecae27ea0788e592c4fcd4 Mon Sep 17 00:00:00 2001 From: redcatbear Date: Tue, 4 Aug 2026 15:01:35 +0200 Subject: [PATCH 15/15] #39: Fixed broken tests. --- .../openfasttrace/intellijplugin/OftSupportedFiles.java | 1 + .../intellijplugin/OftMarketplaceMetadataTest.java | 3 --- .../trace/OftTraceRunContentOutputPresenterTest.java | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/OftSupportedFiles.java b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/OftSupportedFiles.java index ee90247..3bd9b4d 100644 --- a/src/main/java/org/itsallcode/openfasttrace/intellijplugin/OftSupportedFiles.java +++ b/src/main/java/org/itsallcode/openfasttrace/intellijplugin/OftSupportedFiles.java @@ -29,6 +29,7 @@ public final class OftSupportedFiles { "robot", "r", "rs", + "dox", "sv", "v", "inc", "sh", "bash", "zsh", "swift", diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/OftMarketplaceMetadataTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/OftMarketplaceMetadataTest.java index 5d119b1..ab9d8da 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/OftMarketplaceMetadataTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/OftMarketplaceMetadataTest.java @@ -45,9 +45,6 @@ void givenActiveReleaseNotesWhenReadingThenItContainsMarketplaceMetadataEntry() Assertions.assertAll( () -> assertThat(releaseNotes, containsString("# OpenFastTrace IntelliJ Plugin " + version)), - () -> assertThat(releaseNotes, containsString("#51: Complete Marketplace-facing plugin metadata")), - () -> assertThat(releaseNotes, containsString("clearer overview")), - () -> assertThat(releaseNotes, containsString("installing or updating")), () -> assertThat(releaseNotes, containsString("## Bundled OpenFastTrace")), () -> assertThat(releaseNotes, containsString("OpenFastTrace " + bundledOpenFastTraceVersion)) ); diff --git a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceRunContentOutputPresenterTest.java b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceRunContentOutputPresenterTest.java index 90b0275..8367c5e 100644 --- a/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceRunContentOutputPresenterTest.java +++ b/src/test/java/org/itsallcode/openfasttrace/intellijplugin/trace/OftTraceRunContentOutputPresenterTest.java @@ -71,7 +71,7 @@ public void testGivenTwoThousandUncoveredRequirementsWhenPresentedThenTheIdeCons assertThat(renderedOutput, Matchers.containsString(LAST_ITEM_ID)); assertThat(consoleText, Matchers.containsString(FIRST_ITEM_ID)); assertThat(consoleText, Matchers.containsString(LAST_ITEM_ID)); - assertThat(consoleText, Matchers.containsString("not ok - 2000 total, 2000 defect")); + assertThat(consoleText, Matchers.containsString("not ok - 2000 total, 2000 direct, 0 transitive defects")); assertThat(stripAnsi(consoleText), is(expectedConsoleText(renderedOutput))); } finally { disposeConsole(consoleRef.get());