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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ repos:
rev: v6.0.0
hooks:
- id: trailing-whitespace
exclude: ^doc/static/uml/styles/plantuml-c4/
exclude: ^doc/static/
- id: end-of-file-fixer
exclude: ^doc/static/uml/styles/plantuml-c4/
exclude: ^doc/static/
Comment on lines +8 to +10
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: List files under doc/static/ to identify vendored vs project-authored content

echo "=== Files under doc/static/ ==="
fd . doc/static/ --type f --max-depth 3

echo ""
echo "=== Checking for project-authored files (CSS, HTML, JS, templates) ==="
fd '\.(css|html|js|jinja|j2)$' doc/static/ --type f

Repository: dfetch-org/dfetch

Length of output: 1934


🏁 Script executed:

cat -n .pre-commit-config.yaml | head -30

Repository: dfetch-org/dfetch

Length of output: 1066


Exclusion pattern is overly broad and should target only vendored assets.

The change broadens the exclusion from ^doc/static/uml/styles/plantuml-c4/ to the entire ^doc/static/ tree, which excludes project-authored files like doc/static/css/custom.css and doc/static/js/diataxis.js from whitespace and newline checks.

Use a more targeted pattern that excludes only vendored fonts:

exclude: ^doc/static/fonts/

This preserves checks on project-authored CSS, JavaScript, and PlantUML diagrams while excluding the vendored font packages (inter, jetbrains-mono, font-awesome).

🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 9-9: too many spaces after hyphen

(hyphens)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.pre-commit-config.yaml around lines 8 - 10, The pre-commit exclusion was
widened to exclude the entire ^doc/static/ tree, which unintentionally skips
project-authored assets; update the exclude pattern for the end-of-file-fixer
hook (id: end-of-file-fixer) to target only vendored fonts by replacing the
exclude value ^doc/static/ with a narrower pattern such as ^doc/static/fonts/ so
CSS/JS/PlantUML files remain checked while vendored font packages are ignored.

- id: check-yaml
- id: check-added-large-files
- repo: local
Expand Down
11 changes: 11 additions & 0 deletions dfetch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,14 @@
- JetBrainsMono-Semi*
- JetBrainsMono-Thin*
- JetBrainsMono-*Italic*

- name: font-awesome

Check warning

Code scanning / DFetch

Project was locally changed Warning

font-awesome : font-awesome has local changes, please create a patch file or upstream the changes.
remote: github
dst: doc/static/fonts/font-awesome
repo-path: FortAwesome/Font-Awesome/releases/download/7.2.0/fontawesome-free-7.2.0-web.zip
ignore:
- scss*
- sprites*
- svg*
- js
- metadata
63 changes: 63 additions & 0 deletions doc/_ext/colordot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Sphinx role ``colordot`` for inline colour swatches.

Renders an inline ``<span class="dg-dot" style="background:<color>;"></span>``
so RST tables can show a filled colour circle next to a hex value without
resorting to raw HTML blocks.

Usage in .rst files::

:colordot:`#c2620a` ``#c2620a`` (``--primary``)

Register in conf.py::

extensions = [..., "colordot"]
"""

import html
from typing import Any

from docutils import nodes
from docutils.nodes import Node, system_message
from sphinx.application import Sphinx


def colordot_role( # pylint: disable=too-many-arguments,too-many-positional-arguments
name: str, # pylint: disable=unused-argument
rawtext: str, # pylint: disable=unused-argument
text: str,
lineno: int, # pylint: disable=unused-argument
inliner: Any, # pylint: disable=unused-argument
options: dict[str, Any] | None = None, # pylint: disable=unused-argument
content: list[str] | None = None, # pylint: disable=unused-argument
) -> tuple[list[Node], list[system_message]]:
"""Render a filled colour circle as an inline HTML ``<span>``.

Args:
name: The role name (``colordot``).
rawtext: The raw markup including role and argument.
text: The interpreted text (a CSS colour value, e.g. ``#c2620a``).
lineno: The line number in the source document.
inliner: The inliner instance.
options: Directive options mapping.
content: The directive content lines.

Returns:
A two-tuple of (node list, system message list) as required by Sphinx.
"""
color = html.escape(text.strip(), quote=True)
markup = f'<span class="dg-dot" style="background:{color};"></span>'
node = nodes.raw("", markup, format="html")
return [node], []


def setup(app: Sphinx) -> dict[str, Any]:
"""Register the ``colordot`` role with Sphinx.

Args:
app: The Sphinx application object.

Returns:
Extension metadata dictionary.
"""
app.add_role("colordot", colordot_role)
return {"version": "0.1", "parallel_read_safe": True, "parallel_write_safe": True}
122 changes: 122 additions & 0 deletions doc/_ext/designguide.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""Sphinx directives ``palette`` and ``swatch`` for design-guide colour palettes.

Renders design-guide colour palette HTML without raw HTML blocks.

Usage::

.. palette::

.. swatch:: #c2620a
:token: --primary
:label: Amber Orange
:usage: CTAs, active borders, diagram start nodes, section pips

.. palette::
:columns: 4

.. swatch:: #c2620a
:token: --dxt-tutorial
:label: Tutorials
:usage: Same as ``--primary``; warm amber for learning-oriented pages

Register in conf.py::

extensions = [..., "designguide"]
"""

import html
from typing import Any

from docutils import nodes
from docutils.nodes import Node
from docutils.parsers.rst import Directive, directives
from sphinx.application import Sphinx


class SwatchDirective(Directive):
"""Render a single colour swatch card as ``.. swatch:: #hexcolor``."""

required_arguments = 1
optional_arguments = 0
option_spec = {
"token": directives.unchanged,
"label": directives.unchanged,
"usage": directives.unchanged,
"border": directives.unchanged,
}
has_content = False

def run(self) -> list[Node]:
"""Emit a ``dg-swatch`` HTML block for the given colour.

Returns:
A list containing a single raw HTML node.
"""
color = html.escape(self.arguments[0].strip(), quote=True)
token = html.escape(self.options.get("token", ""))
label = html.escape(self.options.get("label", ""))
usage = html.escape(self.options.get("usage", ""))
border = html.escape(self.options.get("border", ""), quote=True)

color_style = f"background:{color};"
if border:
color_style += f" border-bottom:1px solid {border};"
Comment on lines +55 to +63
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Validate the swatch argument instead of accepting arbitrary strings.

Lines 55-63 accept any string even though the directive is documented as .. swatch:: #hexcolor``. A typo just renders a blank chip and silently ships bad docs; fail fast with self.error(...) when the value is not a supported colour token.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@doc/_ext/designguide.py` around lines 55 - 63, The directive currently
accepts any string for the swatch (variable color) and silently produces invalid
output; update the handler that reads self.arguments[0] (the color variable
assigned to color and used to build color_style) to validate the value and call
self.error(...) on invalid input. Specifically, check that the argument matches
an allowed colour token or a hex color (e.g., regex for
^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$) or is present in your canonical token set
(e.g., COLOR_TOKENS or SUPPORTED_COLORS), and if not, raise self.error("Invalid
swatch value: ...") instead of proceeding; keep using the same variables (color,
color_style) once validated. Ensure the validation happens before
html.escape(...) and before any use of color_style so bad values fail fast.


markup = (
f'<div class="dg-swatch">'
f'<div class="dg-swatch-color" style="{color_style}"></div>'
f'<div class="dg-swatch-body">'
f'<div class="dg-swatch-token">{token}</div>'
f'<div class="dg-swatch-hex">{color}</div>'
f'<div class="dg-swatch-label">{label}</div>'
f'<div class="dg-swatch-usage">{usage}</div>'
f"</div>"
f"</div>"
)
return [nodes.raw("", markup, format="html")]


class PaletteDirective(Directive):
"""Render a grid of ``.. swatch::`` directives as ``.. palette::``."""

required_arguments = 0
optional_arguments = 0
option_spec = {
"columns": directives.positive_int,
}
has_content = True

def run(self) -> list[Node]:
"""Emit a ``dg-palette`` wrapper div containing parsed swatch children.

Returns:
A list of nodes: opening div, swatch children, closing div.
"""
columns: int | None = self.options.get("columns", None)

style = ""
if columns:
style = f' style="grid-template-columns:repeat({columns},1fr);"'

open_div = nodes.raw("", f'<div class="dg-palette"{style}>\n', format="html")
Comment on lines +95 to +101
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

:columns: currently breaks the responsive palette grid.

Line 99 overwrites the repeat(auto-fill, minmax(160px, 1fr)) tracks from doc/static/css/custom.css with fixed repeat({columns}, 1fr). The new :columns: 4 example will therefore squeeze swatches into four tiny columns on narrow screens instead of wrapping.

close_div = nodes.raw("", "</div>\n", format="html")

container = nodes.section()
container.document = self.state.document
self.state.nested_parse(self.content, self.content_offset, container)

return [open_div, *container.children, close_div]


def setup(app: Sphinx) -> dict[str, Any]:
"""Register the ``palette`` and ``swatch`` directives with Sphinx.

Args:
app: The Sphinx application object.

Returns:
Extension metadata dictionary.
"""
app.add_directive("palette", PaletteDirective)
app.add_directive("swatch", SwatchDirective)
return {"version": "0.1", "parallel_read_safe": True, "parallel_write_safe": True}
11 changes: 11 additions & 0 deletions doc/_templates/about.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<nav class="sidebar-quicklinks" aria-label="Quick links">
<a href="{{ pathto(master_doc) }}" title="Documentation home" aria-label="Documentation home">
<i class="fa-solid fa-house" aria-hidden="true"></i>
</a>
<a href="https://dfetch-org.github.io/" title="Dfetch website" aria-label="Dfetch website" target="_blank" rel="noopener noreferrer">
<i class="fa-solid fa-globe" aria-hidden="true"></i>
</a>
<a href="https://github.com/dfetch-org/dfetch" title="Source on GitHub" aria-label="Source on GitHub" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-github" aria-hidden="true"></i>
</a>
</nav>
14 changes: 12 additions & 2 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
import os
import sys

from dfetch import __version__

# Prevent ANSI color codes in command output captured by sphinxcontrib.programoutput.
# Python 3.13+ argparse emits colors when FORCE_COLOR is set; NO_COLOR suppresses
# that regardless of FORCE_COLOR, and dfetch's own Rich console respects it too.
os.environ["NO_COLOR"] = "1"

from dfetch import __version__

# -- General configuration ------------------------------------------------

ext_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext"))
Expand Down Expand Up @@ -47,8 +47,15 @@
"sphinxcontrib.programoutput",
"sphinx_tabs.tabs",
"sphinx_autoissues",
"sphinx_copybutton",
"colordot",
"designguide",
]

# Strip shell prompts and Python REPL prompts from copied text
copybutton_prompt_text = r"\$ |>>> |\.\.\. "
copybutton_prompt_is_regexp = True

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

Expand Down Expand Up @@ -123,6 +130,9 @@
html_extra_path = ["robots.txt"]

html_css_files = [
"fonts/font-awesome/css/fontawesome.min.css",
"fonts/font-awesome/css/solid.min.css",
"fonts/font-awesome/css/brands.min.css",
"css/custom.css",
Comment on lines 132 to 136
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for Font Awesome regular icon usage in documentation

echo "=== Searching for .far or .fa-regular classes in doc files ==="
rg -n '\bfa-regular\b|\bfar\b' doc/ --type=rst --type=html --type=md

echo ""
echo "=== Checking if regular.css should be in html_css_files ==="
cat doc/static/fonts/font-awesome/css/regular.css | head -20

Repository: dfetch-org/dfetch

Length of output: 841


Remove the unused doc/static/fonts/font-awesome/css/regular.css file.

The regular Font Awesome CSS file is not loaded in html_css_files and a search for .far or .fa-regular icon classes in the documentation found no usage. The file should be removed from the repository as it serves no purpose.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@doc/conf.py` around lines 132 - 136, The repository contains an unused Font
Awesome CSS file (regular.css) that is not referenced in the html_css_files list
in conf.py (variable html_css_files) and no `.far`/`.fa-regular` classes are
used; delete the regular.css file from the repository and remove any related
unused references or assets to keep static files in sync with the html_css_files
configuration.

]

Expand Down
36 changes: 3 additions & 33 deletions doc/explanation/internal.rst → doc/explanation/architecture.rst
Original file line number Diff line number Diff line change
@@ -1,38 +1,8 @@
.. Dfetch documentation internal

Internal
========
*DFetch* is becoming larger everyday. To give it some structure below a description of the internals.

Glossary
--------

Superproject
The top-level project that contains the manifest. It defines and
coordinates all included projects.

Subproject
A project defined in the manifest that is copied into the
superproject. Subprojects are managed and updated as part of the
superproject's configuration.

Remote
Defines a source repository base URL and a name. Remotes
allow you to avoid repeating common URL bases for multiple
projects in a manifest. A single remote may contain multiple
(sub-)projects to fetch.

Sub-manifest
Some subprojects can themselves contain a manifest. When
fetching a subproject, dfetch can optionally check these
sub-manifests for additional dependencies or recommendations.

Metadata
A file created by *DFetch* to store some relevant information about
a subproject.

Architecture
------------
============
*DFetch* has grown significantly. Below is a description of its internals.

These diagrams are based on `Simon Brown's C4-model`_.

.. _`Simon Brown's C4-model` : https://c4model.com/#CoreDiagrams
Expand Down
8 changes: 0 additions & 8 deletions doc/explanation/vendoring.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ Vendoring does not necessarily imply permanent forks or heavy modification of
third-party code. In many cases, vendored dependencies are kept pristine and
updated mechanically from upstream sources.

----

.. div:: band-tint

:material-regular:`thumb_up;2em;sd-text-primary` **Why vendoring can be helpful**
Expand Down Expand Up @@ -73,8 +71,6 @@ updated mechanically from upstream sources.
teams become **more selective** and more aware of the long-term cost of
that decision.

----

.. div:: band-mint

:material-regular:`warning;2em;sd-text-primary` **The costs and risks of vendoring**
Expand Down Expand Up @@ -233,8 +229,6 @@ Conclusion
Used intentionally and with an understanding of its limitations, vendoring is
simply one tool among many for managing dependencies.

----

Best Practices
--------------

Expand Down Expand Up @@ -391,8 +385,6 @@ eliminate them.
*Dfetch* enables this by allowing you to store the vendored dependency in a folder
using the ``dst:`` attribute.

----

.. div:: band-tint

:material-regular:`public;2em;sd-text-primary` **Real-world projects using vendoring**
Expand Down
12 changes: 2 additions & 10 deletions doc/howto/check-ci.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

.. _check-ci:

Check dependencies in CI
=========================
Check projects in CI
====================

``dfetch check`` exits non-zero when any project is out-of-date or has local
changes, making it a natural pipeline gate. Each supported CI system has its
Expand All @@ -13,8 +13,6 @@ own report format so findings surface natively inside the platform's UI.
- :ref:`check-ci-github` — upload SARIF results to GitHub code scanning
- :ref:`check-ci-gitlab` — publish code-quality reports in GitLab merge requests

----

.. _check-ci-run:

Running dfetch check in CI
Expand All @@ -35,8 +33,6 @@ Pass a ``--*-json`` flag to write a machine-readable report *and* continue
collecting results before deciding the build outcome (each section below shows
the exact flag).

----

.. _check-ci-jenkins:

Jenkins (warnings-ng)
Expand Down Expand Up @@ -90,8 +86,6 @@ the build fails — for example, allow pinned-out-of-date without failing.
.. _`warnings-ng native JSON format`: https://github.com/jenkinsci/warnings-ng-plugin/blob/master/doc/Documentation.md#export-your-issues-into-a-supported-format
.. _`quality gate configuration`: https://github.com/jenkinsci/warnings-ng-plugin/blob/master/doc/Documentation.md#quality-gate-configuration

----

.. _check-ci-github:

GitHub Actions (SARIF)
Expand Down Expand Up @@ -170,8 +164,6 @@ For more information see the `GitHub SARIF documentation`_.

.. _`GitHub SARIF documentation`: https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning

----

.. _check-ci-gitlab:

GitLab CI (Code Climate)
Expand Down
Loading
Loading