Files
mesh-forge/DEVELOPER.md
2026-04-17 03:32:18 -07:00

112 lines
7.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Firmware projects on MeshForge
This guide is for maintainers of **GitHub-hosted PlatformIO firmware** that users open in MeshForge.
## Quick tips
- **Optional `meshforge.yaml`** — full reference in the next section. Commit it on your **default branch** so MeshForge can narrow the tag and target pickers.
- After you push tags or change how the project should be discovered, hit **Refresh tags** on the repo page so MeshForge pulls the latest from GitHub.
- Set your repositorys **default branch** in GitHub to the branch you commit custom changes on (many maintainers name it after the mod). MeshForge periodically scans that branch.
## meshforge.yaml
`meshforge.yaml` is an **optional file at the repository root** (same level as `platformio.ini`). It tells MeshForge how to **filter Git tags** and **PlatformIO environments** (`[env:…]` names) in the web UI so users only see combinations that make sense for your project.
### Where MeshForge reads it
The **tag** and **target** dropdowns use the copy of `meshforge.yaml` from your repos **GitHub default branch** (via the GitHub contents API). That means:
- Put the file on whatever branch you set as **default** in GitHub settings.
- When you change the profile, merge or push to that default branch, then use **Refresh tags** so MeshForge refetches it.
- The profile is **not** read separately per selected tag for the pickers—one file on the default branch drives the filters for the whole repo view.
### File shape
MeshForge only understands a top-level `meshforge:` block with optional `tags:` and `targets:` sections. Other keys are ignored. The built-in parser is intentionally small: it expects **2-space indentation** under `meshforge:` (`tags:` / `targets:` at two spaces, their fields at four), supports **line comments** (`# …`), **quoted or unquoted** string values, and **inline lists** like `[wifi, ble]` for `require_capabilities`. If the file is missing or unparsable, MeshForge shows all tags and all scanned environments (subject to the normal scan).
```yaml
meshforge:
tags:
include: ^v2\.
targets:
include: HELTEC|TLORA|TBEAM
require_capabilities: [wifi]
```
### `tags.include`
- **Type:** string interpreted as a **JavaScript `RegExp`** source (same as `new RegExp(…)` in the browser).
- **Effect:** Only **tag names** that match this pattern stay in the tag dropdown. If the pattern is missing, every tag from GitHub is listed (still sorted as usual).
- **Invalid regex:** MeshForge treats the filter as absent and keeps the full tag list.
Use this to hide CI-only tags, old experiments, or anything you do not want offered as a firmware ref—for example `^v\d` for SemVer-looking tags only.
### `targets.include`
- **Type:** string → **JavaScript `RegExp`** over **PlatformIO environment names** (not display names).
- **Effect:** When no `include_template` applies (see below), environments whose names do not match are hidden from the target picker.
- **Invalid regex:** the regex filter is skipped (capabilities can still apply).
### `targets.include_template` (tag-aware targets)
When you want **which targets appear** to depend on **which tag is selected**, use **`tags.include` together with `targets.include_template`**:
1. `tags.include` must match the **currently selected tag**; the match is run with `RegExp.exec`, so you can use **capturing groups** `(...)` or **named groups** `(?<name>…)` (JavaScript regex syntax).
2. `targets.include_template` is a string that becomes a **new regex** after **placeholders** are filled in. Each substituted piece is **regex-escaped** so literal tag text does not break the pattern.
**Placeholders**
| Placeholder | Meaning |
| ------------------ | ---------------------------------------------- |
| `${1}`, `${2}`, … | Numbered capture groups from `tags.include` |
| `${myName}` | Named group `(?<myName>…)` from `tags.include` |
| `${myName_snake}` | Same capture, converted to **snake_case** |
| `${myName_camel}` | **lowerCamelCase** |
| `${myName_pascal}` | **PascalCase** |
**Precedence:** If both `include_template` and `tags.include` are set and the current tag **matches** `tags.include`, the expanded template is the target regex. Otherwise MeshForge uses **`targets.include`** as a plain static regex. If neither yields a valid regex, there is no name-based filter (capabilities may still apply).
**Example:** Tags like `acme-1.0.0` where environments are named `acme_1_0_0` and `acme_1_0_0_debug`:
```yaml
meshforge:
tags:
include: ^(?<mod>[a-z]+)-(?<ver>[0-9]+(?:\.[0-9]+)*)$
targets:
include_template: ^${mod_snake}_${ver_snake}
```
The template becomes a regex that still matches if you suffix env names (for example `_debug`). Adjust the tag regex and template to match how **you** name tags vs `env:` sections.
### `targets.require_capabilities`
- **Type:** inline list of strings, e.g. `[wifi, ble]`.
- **Effect:** An environment is shown only if **every** listed capability is present on that env. Capabilities are **inferred** by MeshForge from PlatformIOs `platform` / `board` for each env (not read from `meshforge.yaml`). Today that means roughly:
- **Espressif32** (including `pioarduino` URLs) → `wifi`, `ble`
- **nordicnrf52** → `ble`
- **Raspberry Pi / Pico** → `wifi` and `ble` only when the board looks like a **Pico W** (e.g. name contains `picow` or ends with `_w`)
- Other platforms → **no** inferred capabilities
You can use **only** `require_capabilities` (no `include` / `include_template`) to, for example, restrict the list to ESP32-class boards. If every env shows **no** capabilities (for example an old scan completed before capability detection), open the repo again on that ref so MeshForge can **rescan**; otherwise the capability filter may hide everything.
### Practical tips
- **Start without a file**, add `meshforge.yaml` once tag and env lists feel noisy or unsafe for end users.
- **Test regexes** in a JavaScript console (`new RegExp('…').test('tag-name')`) before committing.
- **Refresh tags** after editing the file on the default branch so the UI picks up changes quickly.
## Release tag naming
Tag releases so users can read both your mod and the upstream base at a glance, for example:
`<modName>-<modVersion>-<baseName>-<baseVersion>`
That makes it clear which upstream firmware version a release is built on.
## Maintaining a fork
- **Start from upstream** — Pick a tagged upstream release (often the latest) or any commit, and branch from there for your project (Meshtastic, MeshCore, or any PlatformIO-based LoRa mesh firmware).
- **Default branch** — Set that branch as the GitHub default. MeshForge uses it for periodic scans.
- **When upstream tags a new release** — **Merge** that tag into your branch and continue development. That keeps older release tags meaningful. **Do not rebase** published history you care about, or those tags will no longer sit on the older base revision users expect.
- **Branch-only workflow** — You can maintain a branch without tags; MeshForge builds from the **tip** of that branch. That works well for experimental projects before you cut releases.