Skip to content

fix(docs): fix download buttons and migrate deliverables to English#16

Merged
FullGas1 merged 21 commits into
masterfrom
develop
Jul 19, 2026
Merged

fix(docs): fix download buttons and migrate deliverables to English#16
FullGas1 merged 21 commits into
masterfrom
develop

Conversation

@FullGas1

@FullGas1 FullGas1 commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Closes #11

Summary

  • CI copies .lua files to docs/downloads/ for same-origin download
  • Download buttons use download="plugin-name.lua" for correct filename
  • MkDocs hook (hooks.py) adds target="ext-{id}" rel="noopener" to all external links
  • CONTEXT.md and ADRs 0001-0003 migrated to English

Test plan

  • Verified on dev site: .lua download triggers file save with correct filename
  • Verified on dev site: mod button opens in new tab, reused on repeated clicks

Summary by Sourcery

Update Metal FARP plugin and docs to use the FG_small_Helipad mod, introduce a plugin authoring template with supporting docs and tests, and revamp documentation build, validation, and download handling.

New Features:

  • Add a reference template plugin scene with README, generated authoring docs, and tests to guide creation of new CTLD plugins.
  • Generate English and French documentation pages for the Metal FARP plugin from its README and link them from the catalogue.
  • Introduce CONTEXT and ADR documents capturing glossary and architectural decisions for docs, versioning, and plugin downloads.

Enhancements:

  • Refine Metal FARP scene and docs to reference the FG_small_Helipad mod and improve prerequisite and installation guidance.
  • Extend tests and asset gate to cover plugin scenes and type collection, including the new template scene.
  • Adjust Luacheck configuration to recognize ctld as a writable global and CTLD singletons in tests.
  • Configure MkDocs to use mike for versioned docs and add a template docs section for plugin authors.
  • Add a MkDocs hook to annotate external links with stable targets and rel="noopener" attributes.

Build:

  • Enable docs workflow triggers on both develop and master branches and include plugin Lua sources in build inputs.

CI:

  • Update docs workflow to copy plugin .lua files into docs/downloads, inject branch names into raw URLs, and deploy versioned docs with mike for master and develop.
  • Add a validate-docs CI job that checks plugin READMEs, modUrls metadata, and presence of generated doc pages.
  • Extend the existing Lua tests workflow to run busted over both tests and plugins directories.

Documentation:

  • Enhance the main plugin catalogue in English and French with download buttons and updated Metal FARP requirements.
  • Document the documentation process, CI gate, and versioned docs site in README and ADR files, including download origin decisions.

Tests:

  • Add smoke tests for the template plugin scene to ensure scene registration, crate injection, metadata, and menu wiring behave correctly.
  • Improve scene asset gate tests and utilities to de-duplicate spawned types and support function-based unitType descriptors.

davidp57 and others added 21 commits July 17, 2026 14:21
ctld is writable (plugin scenes populate ctld.i18n at load); the design-time
gate spec spies on CTLDObjectRegistry; the vendored dcs_stubs.lua defines the
DCS globals. Configure luacheck accordingly so CI passes.
…sion points

plugins/_template is a heavily-commented reference scene to copy when authoring
a plugin. It exercises the full extension surface: i18n (4 languages),
ObjectRegistry declarations, a scene model with polar + func steps, a crate
injected into Request Equipment, and an F10 radio submenu wired via
deferMenuSection — plus requiresCtld and (empty) modTypes metadata.

The radio submenu is the point Metal FARP alone did not cover: loaded after CTLD
init, its deferMenuSection routes straight to registerMenuSection (CTLD's
load-position-independent fix), so the submenu still attaches. A busted smoke
test asserts registration, crate, metadata and the wired menu section; the asset
gate now validates the template's types too.

CI runs busted over tests/ and plugins/ so per-plugin tests are discovered.
Catalogue: an authoring "Template" page (EN/FR).

SCENE-PLUGINS ticket 09.
feat(template): _template reference plugin + luacheck CI fix
CTLD SCENE-PLUGINS ticket 05 removed Metal FARP from the core deliverable; refresh the vendored test runtime so the metal-farp plugin registers cleanly (no duplicate) and the gate runs against the real baseline.
chore(vendor): refresh CTLD.lua baseline (Metal FARP removed from core)
…ion)

The asset gate read desc.units[].type and so silently skipped GROUND groups, whose unit types come from unitType(coalitionId). It now resolves both coalitions (mirrors CTLD's CTLDTypeCollector.typesOfDescriptor). metal-farp's Fuel_Truck / repare_Truck GROUND types are now validated (all in the datamine set). ASSET-VALIDATION-REVAMP ticket 01 (plugins side).
fix(gate): validate GROUND descriptor unit types
Add CONTEXT.md glossary and two ADRs:
- 0001: plugin README as single doc source of truth
- 0002: mike-versioned docs (latest/dev on one site)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e pages

Closes #5

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Provides front-matter structure (modUrls) and French prose sections
as a model for new plugin READMEs.

Closes #6

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- plugins/metal-farp/README.md: authored prose + modUrls front-matter
- CTLD_metalFarpScene.lua: rename Farp_FG_Petit_Helipad -> FG_small_Helipad
- docs/plugins/metal-farp.{md,fr.md}: regenerated via generate-plugin-doc skill
- .claude/skills/generate-plugin-doc: skill definition for doc generation

Closes #7

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tools/ci/validate_docs.py: checks front-matter, modUrls structure,
  and presence of docs/plugins/{name}.{fr.}md for every plugin
- .github/workflows/ci.yml: new validate-docs job (pip pyyaml + script)
- README.md: document the CI gate and plugin authoring steps

Closes #8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docs.yml: triggers on master+develop, mike deploy instead of gh-deploy
  master -> version 'master' aliased 'latest' (set as default)
  develop -> version 'develop' aliased 'dev'
- Inject GITHUB_REF_NAME into /master/ download URLs before build
  so dev docs link to develop-branch sources
- mkdocs.yml: add version selector (mike provider, default: latest)

Closes #9

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docs/index.md, index.fr.md: Farp_FG_Petit_Helipad -> FG_small_Helipad
- validate_docs.py: distinguish absent front-matter (None) from
  malformed structure (Exception) for a clearer error message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: catalogue download buttons, mod links, generated docs, CI gate
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CI: copy plugin .lua files to docs/downloads/ before MkDocs build so
  they are served same-origin, making the download attribute effective
  in all browsers (closes #12)
- Docs: switch .lua buttons to relative downloads/ path + download attr;
  add target="ext-{mod}" rel="noopener" on mod buttons;
  add target="_blank" rel="noopener" on external prose links (closes #13)
- Domain: update CONTEXT.md (Bouton download, Mod button, External prose
  link entries); add ADR-0003 for docs/downloads/ serving decision (closes #14)
- Skill: update generate-plugin-doc template with new button/link rules (closes #15)
- Migrate CONTEXT.md and ADR 0001-0003 from French to English

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add hooks.py: MkDocs hook that adds target="ext-{id}" rel="noopener"
  to all external links at build time (attr_list does not reliably apply
  target to inline links in Python-Markdown)
- Register hook in mkdocs.yml
- Switch download attribute to download="{name}.lua" to force correct
  filename instead of browser defaulting to "download"
- Remove target/rel from attr_list in doc files and skill (hook owns this)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Reviewer's Guide

Docs CI and site are updated to serve plugin Lua downloads from same-origin paths with versioned docs via mike, external links get consistent target/rel attributes, the Metal FARP plugin is switched to the FG_small_Helipad mod with a new template plugin and documentation validation tooling, and CONTEXT/ADRs/doc authoring guidance are migrated and added in English/French.

Sequence diagram for MkDocs external link processing hook

sequenceDiagram
    participant MkDocs as MkDocs
    participant Hook as hooks.on_page_content
    participant Util as _url_target

    MkDocs->>Hook: on_page_content(html, page, config)
    Hook->>Hook: site = config.get(site_url)
    Hook->>Hook: re.sub("<a ([^>]+)>", process, html)

    loop for each <a ...> match
        Hook->>Hook: Extract attrs and href
        alt href is non-http or same site or has target
            Hook-->>MkDocs: Return original <a> tag
        else external link without target
            Hook->>Util: _url_target(href)
            Util-->>Hook: target name ext-{id}
            Hook-->>MkDocs: Return <a ... target="ext-{id}" rel="noopener">
        end
    end

    MkDocs-->>MkDocs: Use transformed HTML for page output
Loading

Flow diagram for validate-docs CI gate

flowchart TD
    A[Start validate_docs.py] --> B[Scan plugins/ excluding _template]
    B --> C{Any plugins?}
    C -- No --> D[Print 'nothing to validate'] --> Z[Exit 0]
    C -- Yes --> E[For each plugin]

    E --> F[Check plugins/<name>/README.md]
    F --> G{README.md exists?}
    G -- No --> H[Add WARNING: README absent]
    G -- Yes --> I[parse_frontmatter]

    I --> J{Front-matter result}
    J -- None --> K[Add ERROR: no YAML front-matter]
    J -- Exception --> L[Add ERROR: malformed front-matter]
    J -- Dict --> M[Get modUrls]

    M --> N{modUrls is not None?}
    N -- Yes --> O[validate_mod_urls]
    O --> P{Valid?}
    P -- No --> Q[Add ERROR: modUrls invalid]
    P -- Yes --> R[Continue]
    N -- No --> R

    R --> S[Check docs/plugins/<name>.md and .fr.md exist]
    S --> T[Add ERROR for each missing doc]

    T --> U[After all plugins]
    H --> U
    K --> U
    L --> U
    Q --> U

    U --> V[Print warnings]
    V --> W[Print errors]
    W --> X{Any errors?}
    X -- Yes --> Y[Print summary, Exit 1]
    X -- No --> Z[Print OK summary, Exit 0]
Loading

File-Level Changes

Change Details Files
Metal FARP scene now targets the FG_small_Helipad mod and has minor Lua style cleanups.
  • Update all references from Farp_FG_Petit_Helipad to FG_small_Helipad in comments, registry entries, scene metadata, and step definitions.
  • Ensure CTLDObjectRegistry registration and metalFarpScene.modTypes/use of requiresMod align with the new mod type.
  • Normalize Lua table formatting, alignment, and comment spacing for registry unit definitions and warehouse fuel logic.
plugins/metal-farp/src/CTLD_metalFarpScene.lua
Docs deployment workflow now builds versioned sites with mike, serves Lua downloads from docs/downloads/, and keeps raw URLs branch-coherent.
  • Rename docs GitHub Actions job and extend triggers to include master and plugin Lua sources.
  • Install mike alongside MkDocs, configure git identity, and use mike deploy/set-default for master/develop branches.
  • Copy plugin .lua files from plugins/*/src into docs/downloads/ before building docs.
  • Inject current branch name into raw GitHub URLs inside docs markdown where needed for non-download links.
.github/workflows/docs.yml
Metal FARP documentation pages and index tables are aligned with the new FG_small_Helipad mod and provide proper download buttons.
  • Add generated-doc preface comments and primary download buttons pointing to CTLD_metalFarpScene.lua in both EN and FR plugin pages.
  • Update prerequisite text to reference FG_small_Helipad and add a dedicated mod download button.
  • Simplify and clarify installation steps, removing redundant notes sections.
  • Extend index tables (EN/FR) with a Download column and metal-farp.lua download buttons using relative paths.
docs/plugins/metal-farp.md
docs/plugins/metal-farp.fr.md
docs/index.md
docs/index.fr.md
Introduce a reference template plugin scene, its tests, and author-facing docs to guide new plugin development.
  • Add CTLD_templateScene.lua showing i18n, ObjectRegistry, scene model, crate, steps, and F10 menu wiring, including deferMenuSection usage.
  • Add a busted spec to smoke-test template scene registration, crate declaration, requiresCtld/modTypes metadata, and menu section wiring.
  • Create author documentation pages (EN/FR) explaining how to copy and adapt the template plugin and the authoring checklist.
  • Expose the template in the MkDocs navigation under a "For authors" section.
plugins/_template/src/CTLD_templateScene.lua
plugins/_template/tests/template_spec.lua
docs/plugins/template.md
docs/plugins/template.fr.md
mkdocs.yml
Add a CI documentation coherence gate and supporting README/skill/CONTEXT/ADR docs to make plugin docs generation and validation robust.
  • Create tools/ci/validate_docs.py that walks plugins, parses README front-matter, validates modUrls structure, and checks for generated docs presence, emitting warnings/errors for CI.
  • Wire a validate-docs job into the main CI workflow to run the Python validator on every push/PR.
  • Add plugins/metal-farp/README.md with French prose and structured modUrls front-matter as the source of truth for generated docs.
  • Document the generate-plugin-doc Claude skill, plugin docs process, glossary, and ADRs covering README-as-source-of-truth, mike-based versioning, and serving Lua from docs/downloads.
  • Update README.md with instructions for documenting plugins and running validate-docs locally, and add a Documentation site section with URLs.
  • Add metal-farp entry guidance in CONTEXT.md and cross-linking between catalogue and docs processes.
tools/ci/validate_docs.py
.github/workflows/ci.yml
plugins/metal-farp/README.md
.claude/skills/generate-plugin-doc/SKILL.md
CONTEXT.md
docs/adr/0001-readme-as-doc-source-of-truth.md
docs/adr/0002-mike-versioned-docs.md
docs/adr/0003-serve-lua-from-docs-downloads.md
README.md
MkDocs is extended with a hook that rewrites external links to add stable targets and rel="noopener", and luacheck config is updated for new globals and tests.
  • Add hooks.py implementing on_page_content to detect external links, skip same-site/non-HTTP links, and inject target="ext-{stable-id}" and rel="noopener" attributes.
  • Configure mkdocs.yml to load hooks.py and add version metadata for mike.
  • Adjust .luacheckrc to treat ctld as a writable global, expand exclusion patterns, and declare additional globals for tests and CTLD singletons.
  • Extend busted invocation to include plugins/ tests next to core tests.
hooks.py
mkdocs.yml
.luacheckrc
.github/workflows/ci.yml

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@FullGas1
FullGas1 merged commit d27455c into master Jul 19, 2026
12 checks passed

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • The MkDocs hook in hooks.py treats any HTTP link as external unless it starts with config.site_url, but site_url is not set in mkdocs.yml, so internal links will get target="ext-*" and rel="noopener"; consider using a more robust check (e.g. comparing netloc against the docs host or leaving relative URLs untouched) or setting site_url explicitly.
  • validate_docs.py imports PyYAML inside parse_frontmatter and treats a README with leading "---" but no closing "---" as a hard error; if you expect authors to sometimes omit front-matter, it may be worth relaxing this to a warning unless modUrls or other metadata is required.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The MkDocs hook in hooks.py treats any HTTP link as external unless it starts with config.site_url, but site_url is not set in mkdocs.yml, so internal links will get target="ext-*" and rel="noopener"; consider using a more robust check (e.g. comparing netloc against the docs host or leaving relative URLs untouched) or setting site_url explicitly.
- validate_docs.py imports PyYAML inside parse_frontmatter and treats a README with leading "---" but no closing "---" as a hard error; if you expect authors to sometimes omit front-matter, it may be worth relaxing this to a warning unless modUrls or other metadata is required.

## Individual Comments

### Comment 1
<location path=".github/workflows/docs.yml" line_range="29-32" />
<code_context>
+        run: |
+          git config user.name "github-actions[bot]"
+          git config user.email "github-actions[bot]@users.noreply.github.com"
+      - name: Copy plugin .lua files to docs/downloads/
+        run: |
+          mkdir -p docs/downloads
+          cp plugins/*/src/*.lua docs/downloads/
+      - name: Inject branch into download URLs
+        # Replace /master/ with the actual branch in raw download links,
</code_context>
<issue_to_address>
**issue:** Copy step will fail if no plugin src trees or no .lua files exist

This `cp plugins/*/src/*.lua docs/downloads/` pattern will fail if any plugin lacks a `src` directory or if there are no `.lua` files (e.g. new plugin skeletons, partial checkouts), causing the docs job to error unnecessarily. Please make this step resilient, e.g. by using `find` to locate `.lua` files or by tolerating a non-zero `cp` exit:

```bash
mkdir -p docs/downloads
find plugins -mindepth 2 -maxdepth 2 -type d -name src -exec find {} -name '*.lua' -exec cp {} docs/downloads/ \;
# or
cp plugins/*/src/*.lua docs/downloads/ 2>/dev/null || true
```
</issue_to_address>

### Comment 2
<location path="docs/index.fr.md" line_range="21" />
<code_context>
-| [Metal FARP](plugins/metal-farp.md) | Un FARP à hélisurface métallique | Mod DCS `Farp_FG_Petit_Helipad` |
+| Plugin | Ce qu'il construit | Requiert | Télécharger |
+|--------|--------------------|----------|-------------|
+| [Metal FARP](plugins/metal-farp.md) | Un FARP à hélisurface métallique | Mod DCS `FG_small_Helipad` | [⬇ metal-farp.lua](downloads/CTLD_metalFarpScene.lua){ download .md-button } |
</code_context>
<issue_to_address>
**suggestion (bug_risk):** The download button attribute syntax looks inconsistent with other examples and may not be parsed as intended.

This link uses `{ download .md-button }`, while other examples use `download="metal-farp.lua" .md-button .md-button--primary`. For consistent behavior and reliable parsing, consider adding an explicit `download="metal-farp.lua"` attribute and matching the class list to the existing button examples.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +29 to +32
- name: Copy plugin .lua files to docs/downloads/
run: |
mkdir -p docs/downloads
cp plugins/*/src/*.lua docs/downloads/

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue: Copy step will fail if no plugin src trees or no .lua files exist

This cp plugins/*/src/*.lua docs/downloads/ pattern will fail if any plugin lacks a src directory or if there are no .lua files (e.g. new plugin skeletons, partial checkouts), causing the docs job to error unnecessarily. Please make this step resilient, e.g. by using find to locate .lua files or by tolerating a non-zero cp exit:

mkdir -p docs/downloads
find plugins -mindepth 2 -maxdepth 2 -type d -name src -exec find {} -name '*.lua' -exec cp {} docs/downloads/ \;
# or
cp plugins/*/src/*.lua docs/downloads/ 2>/dev/null || true

Comment thread docs/index.fr.md
| [Metal FARP](plugins/metal-farp.md) | Un FARP à hélisurface métallique | Mod DCS `Farp_FG_Petit_Helipad` |
| Plugin | Ce qu'il construit | Requiert | Télécharger |
|--------|--------------------|----------|-------------|
| [Metal FARP](plugins/metal-farp.md) | Un FARP à hélisurface métallique | Mod DCS `FG_small_Helipad` | [⬇ metal-farp.lua](downloads/CTLD_metalFarpScene.lua){ download .md-button } |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): The download button attribute syntax looks inconsistent with other examples and may not be parsed as intended.

This link uses { download .md-button }, while other examples use download="metal-farp.lua" .md-button .md-button--primary. For consistent behavior and reliable parsing, consider adding an explicit download="metal-farp.lua" attribute and matching the class list to the existing button examples.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants