|
4 | 4 | Changelog |
5 | 5 | ========= |
6 | 6 |
|
| 7 | +.. _`release:8.0.0`: |
| 8 | + |
| 9 | +8.0.0 |
| 10 | +----- |
| 11 | + |
| 12 | +:Released: Unreleased |
| 13 | +:Full Changelog: `v7.0.0...v8.0.0 <https://github.com/useblocks/sphinx-needs/compare/7.0.0...5b223fd71eeb7402d5b60c1a5832434d8fd05e31>`__ |
| 14 | + |
| 15 | +This release introduces **conditional link assessment** β the ability to attach |
| 16 | +:ref:`filter_string` conditions to links that are checked against the target need at build time. |
| 17 | +It also overhauls the internal link representation and fixes ``links_from_content`` to |
| 18 | +use the parsed doctree instead of fragile regex matching. |
| 19 | + |
| 20 | +Conditional link assessment |
| 21 | +........................... |
| 22 | + |
| 23 | +A major motivation for requirements-management tooling is ensuring traceability β |
| 24 | +not just *that* two needs are linked, but that the link is **valid in context**. |
| 25 | +For example, a specification should only link to requirements that are in an |
| 26 | +``"open"`` or ``"approved"`` state, or a test should only reference an implementation |
| 27 | +at a compatible version. |
| 28 | + |
| 29 | +Sphinx-Needs now supports this via **inline conditions** on link references |
| 30 | +(see :ref:`need_conditional_links`). |
| 31 | +Append a :ref:`filter_string` in square brackets after the target ID: |
| 32 | + |
| 33 | +.. code-block:: rst |
| 34 | +
|
| 35 | + .. spec:: My Specification |
| 36 | + :links: REQ_001[status=="open"], REQ_002[version>=3] |
| 37 | +
|
| 38 | +Each condition is evaluated against the **target** need's fields. |
| 39 | +If a condition evaluates to ``False``, a ``needs.link_condition_failed`` warning is emitted; |
| 40 | +if the condition syntax is invalid, a ``needs.link_condition_invalid`` warning is emitted. |
| 41 | +Links without conditions continue to work exactly as before. |
| 42 | + |
| 43 | +The condition is a standard :ref:`filter_string` expression, so you can use any Python-style |
| 44 | +comparison operators (``==``, ``!=``, ``>``, ``<``, ``>=``, ``<=``), membership checks |
| 45 | +(``in``, ``not in``), boolean connectives (``and``, ``or``, ``not``), and built-in helpers |
| 46 | +like ``search()``. |
| 47 | + |
| 48 | +This means conditions already work with **numeric fields** such as ``integer`` or ``number`` |
| 49 | +(decimal) types. For example, if you define a ``version`` field: |
| 50 | + |
| 51 | +.. code-block:: toml |
| 52 | +
|
| 53 | + [needs.fields.version] |
| 54 | + schema.type = "integer" |
| 55 | + nullable = false |
| 56 | +
|
| 57 | +You can then enforce version constraints on links: |
| 58 | + |
| 59 | +.. code-block:: rst |
| 60 | +
|
| 61 | + .. spec:: My Specification |
| 62 | + :links: REQ_001[version>=2] |
| 63 | +
|
| 64 | +When the condition contains square brackets (e.g. for list indexing), use multiple opening |
| 65 | +brackets β the parser matches N opening ``[`` with N closing ``]``: |
| 66 | +``REQ_001[[tags[0]=="important"]]``. |
| 67 | + |
| 68 | +- β¨ Add conditional need link assessment (:pr:`1675`) |
| 69 | +- β»οΈ Add ``_split_link_list`` parser with condition syntax support (:pr:`1674`) |
| 70 | +- π Parse link conditions from imported and external needs (:pr:`1680`) |
| 71 | +- π Add :ref:`needs_json_include_link_conditions` config option (:pr:`1681`) |
| 72 | + |
| 73 | + Controls whether conditions are included in ``needs.json`` output (default: ``True``). |
| 74 | + Backlink fields are never affected. |
| 75 | + |
| 76 | +- π Add ``parse_conditions`` configuration for link types (:pr:`1684`) |
| 77 | + |
| 78 | + Per-link-type control over whether ``[condition]`` brackets are parsed. |
| 79 | + Set ``parse_conditions = false`` on a link type to treat brackets as literal ID text. |
| 80 | + |
| 81 | + .. code-block:: toml |
| 82 | +
|
| 83 | + [needs.links.raw_links] |
| 84 | + parse_conditions = false |
| 85 | +
|
| 86 | +.. note:: |
| 87 | + |
| 88 | + **Potential future directions**: |
| 89 | + |
| 90 | + - **Hash-based checks**: combined with a ``hash`` field and a dynamic function that |
| 91 | + computes a content hash, conditions like ``REQ_001[hash=="abc123"]`` could detect |
| 92 | + when a linked need's content has changed since the link was authored. |
| 93 | + - **Semantic version comparisons**: a dedicated semver field type would enable |
| 94 | + conditions like ``REQ_001[version~=">=1.2.0"]`` with proper semver semantics. |
| 95 | + - **Terse constraint syntax**: a more compact notation (e.g. ``REQ_001[s=open,v>=2]`` |
| 96 | + with field shorthands) is under consideration for common cases, but would |
| 97 | + complement β not replace β the current filter-string syntax. |
| 98 | + |
| 99 | +``links_from_content`` rewrite |
| 100 | +.............................. |
| 101 | + |
| 102 | +The ``links_from_content`` dynamic function previously used a regex to |
| 103 | +extract ``:need:`ID``` references from raw RST source text. |
| 104 | +This was fragile and could not handle custom titles (e.g. ``:need:`My Title <REQ_001>```), |
| 105 | +nested content, or other edge cases. |
| 106 | + |
| 107 | +It now walks the **parsed doctree** for the source need, collecting ``NeedRef`` nodes |
| 108 | +directly. This is more robust and correctly handles all role syntax variants. |
| 109 | + |
| 110 | +**Limitations**: ``links_from_content`` requires a stored doctree node. |
| 111 | +It will emit a warning and return an empty list for: |
| 112 | + |
| 113 | +- **External needs** (loaded via ``needimport`` / ``needs_external_needs``) β they have no doctree. |
| 114 | +- **Need parts** β not supported; a warning is emitted. |
| 115 | + |
| 116 | +- β»οΈ Fix ``links_from_content`` to use parsed doctree nodes instead of regex (:pr:`1685`) |
| 117 | + |
| 118 | +Breaking changes |
| 119 | +................ |
| 120 | + |
| 121 | +- βΌοΈ ``ENV_DATA_VERSION`` bumped to 4 (:pr:`1683`) |
| 122 | + |
| 123 | + The internal format for storing link data in the Sphinx build environment has changed |
| 124 | + (links are now stored as structured ``NeedLink`` objects instead of plain strings). |
| 125 | + **Incremental builds from a previous version will trigger a full rebuild automatically.** |
| 126 | + |
| 127 | +- βΌοΈ ``need["links"]`` (and other link fields) now returns a fresh ``list[str]`` copy |
| 128 | + rather than a reference to the internal storage (:pr:`1670`) |
| 129 | + |
| 130 | + Previously, code like ``need["links"].append("NEW_ID")`` would mutate the internal list. |
| 131 | + This now **silently has no effect** β the returned list is a projection from the internal |
| 132 | + ``NeedLink`` representation. This should only affect exotic use cases such as dynamic |
| 133 | + functions or custom extensions that mutate link lists via ``__getitem__`` access. |
| 134 | + Use the ``NeedItem`` API (e.g. ``get_links(as_str=False)``) for direct access to the |
| 135 | + internal ``NeedLink`` objects. |
| 136 | + |
| 137 | +Internal changes |
| 138 | +................ |
| 139 | + |
| 140 | +These changes do not affect user-facing behaviour but improve link handling internals: |
| 141 | + |
| 142 | +- β»οΈ Introduce ``NeedLink`` structured internal representation for links (:pr:`1670`) |
| 143 | +- β»οΈ Store ``NeedLink`` instead of ``str`` in ``LinksLiteralValue`` and ``LinksFunctionArray`` (:pr:`1673`) |
| 144 | +- π§ Use ``NeedLink`` directly in ``update_back_links`` function (:pr:`1672`) |
| 145 | +- π§ Store ``NeedPartData.backlinks`` as ``NeedLink`` instead of ``str`` (:pr:`1679`) |
| 146 | +- π§ Use ``get_links(as_str=False)`` in needextend to avoid round-trip serialization (:pr:`1678`) |
| 147 | +- β»οΈ Store ``NeedLink`` on ``NeedRef`` node at parse time instead of re-parsing later (:pr:`1682`) |
| 148 | +- π§ͺ Add tests for variants in links (:pr:`1669`) |
| 149 | + |
| 150 | +Bug fixes |
| 151 | +......... |
| 152 | + |
| 153 | +- π Fix linkcheck CI job warnings (:pr:`1667`) |
| 154 | + |
| 155 | +Documentation |
| 156 | +............. |
| 157 | + |
| 158 | +- π Add sphinx-ai-index to Sphinx docs builder (:pr:`1671`) |
| 159 | + |
7 | 160 | .. _`release:7.0.0`: |
8 | 161 |
|
9 | 162 | 7.0.0 |
10 | 163 | ----- |
11 | 164 |
|
12 | 165 | :Released: 24.02.2026 |
13 | | -:Full Changelog: `v6.3.0...v7.0.0 <https://github.com/useblocks/sphinx-needs/compare/6.3.0...0aea09eda386880272205cbdc8a98fde3ff3566a>`__ |
| 166 | +:Full Changelog: `v6.3.0...v7.0.0 <https://github.com/useblocks/sphinx-needs/compare/6.3.0...7.0.0>`__ |
14 | 167 |
|
15 | 168 | This is a major release that consolidates field, link, and default configuration |
16 | 169 | into a single, composable schema system β inspired by |
@@ -264,7 +417,7 @@ Documentation fixes |
264 | 417 | ----- |
265 | 418 |
|
266 | 419 | :Released: 15.12.2025 |
267 | | -:Full Changelog: `v6.2.0...v6.3.0 <https://github.com/useblocks/sphinx-needs/compare/6.2.0...f567c1fafb4e1ba1a7dabb3bd6afc5f17ded84cd>`__ |
| 420 | +:Full Changelog: `v6.2.0...v6.3.0 <https://github.com/useblocks/sphinx-needs/compare/6.2.0...6.3.0>`__ |
268 | 421 |
|
269 | 422 | - β¬οΈ Support Python 3.14 (:pr:`1598`) |
270 | 423 | - β»οΈ Remove ``typeguard`` dependency (:pr:`1597`) |
|
0 commit comments