Commit Graph
21 Commits
Author SHA1 Message Date
rootiest cff4f7b414 feat(ci): sync the label taxonomy to the GitHub mirror automatically
Labels don't travel with a mirror push -- mirroring copies files, not
repository settings -- but they matter on the GitHub side anyway, because
GitHub reads the same .github/ISSUE_TEMPLATE/ files and silently drops a
labels: entry naming a label it doesn't have. Until now the only thing
keeping the two sets aligned was remembering to do it by hand, which is
exactly the kind of thing that gets forgotten and then fails invisibly.

Add scripts/sync-labels.py and a workflow that runs it daily, on any change
to the script itself, and on manual dispatch. Gitea stays the source of
truth: labels are managed there and GitHub is made to match.

- **Creates and updates** anything missing or drifted. Colors and
  descriptions are normalized before comparison -- Gitea returns colors
  bare, GitHub sometimes with a leading '#', and a description may be null
  on one side and "" on the other -- so a steady state is a true no-op
  rather than a rewrite of all 33 labels every run.
- **Deletes only unused extras.** An extra label on the mirror is removed
  only when no issue or PR there carries it; one in use is reported with
  its count and left alone. An unattended scheduled job must not be able to
  strip a label off somebody's issue.
- **Refuses to run on an empty source**, since treating that as truth would
  propose deleting every label on the mirror.
- **--dry-run** prints the plan and changes nothing; **--self-test** checks
  the diff logic offline against fixtures, and gates the sync step in CI so
  a broken diff can't mutate anything.

Stdlib only, so the CI step installs nothing beyond python3. The job is
gated with the same github.server_url check ci.yml uses -- without it the
mirror would queue this forever against a runner that only exists on Gitea.

Labels are matched by name, so a rename reads as delete-plus-create; the
new name is created and the old is pruned only if unused. The two forges
share no stable label ID, so a rename can't be tracked across them.
2026-08-31 23:32:16 -04:00
rootiest 877c973e87 docs(contributing): make the issue templates work on the GitHub mirror too
The templates were written against Gitea's schema alone, but the mirror
serves the same .github/ISSUE_TEMPLATE/ files to GitHub, where two of them
would have silently failed:

- **config.yaml -> config.yml.** Gitea accepts either spelling
  (modules/structs/issue.go: `base == "config.yaml" || base == "config.yml"`),
  GitHub only recognizes config.yml. Under the old name the mirror's
  template chooser would have shown neither the contact links nor the
  blank-issue setting.
- **bug.yaml `about:` -> bug.yml `description:`.** GitHub requires
  `description` on a YAML issue form; Gitea's IssueTemplate.About carries
  the comment "Using description in a template file is compatible" and
  falls back to it at modules/issue/template/unmarshal.go:126. So
  `description` is the one spelling both forges accept. The markdown
  templates keep `about:`, which is correct for their format on both.

Both files now carry a comment explaining the constraint, so neither gets
"tidied" back into a broken state.

Also add a contact link pointing at the canonical Gitea tracker, so someone
arriving from the mirror is steered to the right place before they file,
and document mirror parity in CONTRIBUTING.md: the labels must be created
on both sides by hand, since mirroring copies files rather than repository
settings and GitHub drops a labels: entry naming a label it doesn't have.
Note too that GitHub has no exclusive labels, so the one-of rule on
Priority/, Reviewed/, and Status/ holds only by convention there.
2026-08-31 23:16:41 -04:00
rootiest af764903e7 docs(contributing): add issue templates for bugs, features, and docs
Issues had no template at all, so a report arrived in whatever shape the
reporter chose — most often without a fish version, a reproduction, or the
full error text, which is what actually stalls a bug.

Add three templates under .github/ISSUE_TEMPLATE/, beside the PR template
so the GitHub mirror offers the same set:

- **bug.yaml** — a Gitea issue form rather than markdown. Version, OS,
  area, reproduction, expected and actual behavior are required fields, so
  an unactionable report can't be submitted in the first place. The Area
  dropdown exists because contributors without push access can't set an
  Area/ label themselves.
- **feature.md** and **docs.md** — comment-guided markdown in the same
  house style as PULL_REQUEST_TEMPLATE.md, since what they ask for is
  open-ended prose. feature.md carries `## Acceptance criteria`, the
  issue-side counterpart to a PR's `## Verification`. docs.md insists on
  the docs/manual/** source rather than the generated page, which the next
  CI run would overwrite.
- **config.yaml** — keeps blank issues enabled for what the three don't
  cover, and links the contributing guide and the customization docs.

Each template pre-applies its Kind/ label. Document the set, the plain-
description title convention (an issue states a problem; the conventional
subject belongs on the PR that closes it), and the triage split in a new
CONTRIBUTING.md § Issues.
2026-08-31 23:07:44 -04:00
rootiest 1dc86b9ff0 docs(contributing): document the WIP: title prefix for in-progress PRs
Gitea treats a `WIP:` title prefix as a draft marker and refuses to merge
while it's present. Verified empirically against this instance by
temporarily retitling PR #123: the API flipped `draft` to true and
`mergeable` to false, and both reverted when the prefix was removed.

The distinction from the verification merge gate is the point, so it's
stated explicitly in both files: `WIP:` means more code changes are
coming, NOT "finished but unverified". A complete branch with unticked
`## Verification` boxes is an ordinary PR — that case is already covered
by the merge gate and does not want the prefix. The two signals are
independent and can occur in any combination.

Documented as a merge rule under Branching & Pull Requests, next to the
verification gate, and in the template's title guidance where an author
picking a title will actually encounter it.
2026-08-31 22:41:12 -04:00
rootiest ea8b13b38a docs(contributing): rename Manual Verification to Verification, make it a merge gate
The old name implied the list was only for by-hand steps, which sat badly
with the fact that most entries in practice are programmatic — the test
suite, `fish_indent`, `docs/verify-manual.py`, CI. Dropping "Manual" lets
one list carry both kinds, and gives the checkbox state real meaning:

- **Checked** — verified, whether it ran programmatically or the author
  performed it by hand.
- **Unchecked** — an outstanding manual check the reviewer still has to
  perform. Left visible rather than dropped.
- **The list is the merge gate.** A PR isn't merged until every box is
  checked; added as an explicit rule under Branching & Pull Requests
  alongside the other merge rules.

Because unchecked boxes now block the merge, the guidance also states that
only resolvable checks belong here — one nobody can run would block the PR
indefinitely. Genuinely unverifiable caveats and assumptions go in
`## Notes`, which already existed in the optional-sections list.

Incidentally realigns with PRs 121-122, which had already shortened the
heading to `## Verification`; that part of the recent drift was right.
2026-08-31 22:35:30 -04:00
rootiest 2f49960149 docs(contributing): establish Closes #N issue-linking convention
The repo has no issue-tracking history yet — a grep across all 122 prior
PRs found zero `Closes #N` references — so this is forward-looking rather
than derived from precedent. Establishing it now means the first PR that
does close an issue has a rule to follow instead of inventing one.

- Placement is a trailing line at the end of `## Summary`, not the bottom
  of the body, because `## Manual Verification` is always last.
- `Fixes`/`Resolves` noted as equivalent; `Refs #N` for a related issue
  that should stay open.
- Guidance calls out that the keyword must be repeated per issue, since a
  bare `#43` after a comma links without closing.
- Lives in the template's HTML comments, so a PR with no associated issue
  leaves no stray `Closes #` behind.

Also drops an unverified claim that the GitHub mirror pre-loads the
template; PRs are opened on Gitea, and the mirror is push-only.
2026-08-31 22:32:52 -04:00
rootiest f52bfaa55e docs(contributing): add PR description template and convention
Codifies the PR body format the repo has converged on across its first
122 pull requests, which until now lived only as an implicit pattern
agents and contributors had to reverse-engineer from prior PRs.

- **`.github/PULL_REQUEST_TEMPLATE.md`** — `## Summary`, optional `##`
  sections, then `## Manual Verification` as a checkbox list. Gitea falls
  back to `.github/` when `.gitea/` is absent, and the GitHub mirror reads
  the same path, so one file covers both.
- **`CONTRIBUTING.md`** — new "Pull request descriptions" subsection under
  Branching & Pull Requests, documenting the same three-part structure.

Section names were chosen by frequency across all 122 PRs: `## Summary`
(86) and `## Manual Verification` (63) are the clear majority. The later
`## Manual Verification Checklist` (12, PRs 90-113), `## Test plan` (11)
and `## Verification` (3, PRs 121-122) variants are drift away from that
baseline, not a newer standard, so the template restores the dominant
form. Checkboxes ship unchecked but are meant to be checked before the
PR opens, matching the 585-to-12 ratio of `[x]` to `[ ]` in merged PRs.
2026-08-31 22:27:26 -04:00
rootiest a89a5576a3 fix(ci): skip queued-forever jobs on the GitHub mirror
The test/build-docs jobs target a self-hosted runner (racknerd-mini)
that only exists on the Gitea instance. When GitHub re-runs this same
workflow on the mirror, those jobs sit queued forever with no matching
runner, so the commit never gets a completed status.

Gate both jobs to skip when github.server_url is github.com, and add a
trivial github-mirror job (runs-on: ubuntu-latest, which GitHub does
provide) that only runs on the mirror, so the check completes instead
of hanging.
2026-08-31 20:19:40 -04:00
rootiest 4d7ad64c3a fix(ci): drop remaining cd for working-directory consistency
The only other cd left in the workflow mixed two working directories
in one step: docs/build-manual.py --site runs from the repo root, then
npm ci/astro build need docs/site. Split into two steps so each can
use working-directory instead, keeping the whole file cd-free and
consistent with the Cloudflare deploy step's fix.
2026-08-21 01:23:34 -04:00
rootiest 3c27e52ada fix(ci): use working-directory instead of cd for Cloudflare deploy
Gitea/GitHub Actions auto-groups a multi-line run: script under
"Run <first line>". With `cd docs/site` as the first line, the
collapsed log tree showed that instead of the actual wrangler deploy
command. Moving the directory change to the step's working-directory
key drops cd from the script entirely, so the group label now reflects
the command that's actually running.
2026-08-21 01:21:29 -04:00
rootiest c47b51cd6e feat(ci): allow triggering test or build-docs individually
workflow_dispatch already ran the whole pipeline manually, but there
was no way to fire just one job (e.g. re-run docs generation without
re-running the fish test suite) the way the old standalone
build-docs.yml let you. Add a job choice input (all/test/build-docs,
defaulting to all) and gate each job on it via `if:`, while leaving
the push-triggered path's needs: test gating untouched.
2026-08-21 00:58:30 -04:00
rootiest c4e225b007 fix(ci): retry apt-get update and skip recommended packages
Two more sources of CI noise/fragility alongside the debconf frontend
fix: fish's install pulls in man-db/groff-base/xsel as recommends,
triggering a slow mandb rebuild for tooling nothing here uses;
--no-install-recommends skips that. apt-get update had no retry
policy, so a transient blip against the PPA mirror failed the whole
job; -o Acquire::Retries=3 gives it a few chances first.
2026-08-21 00:54:54 -04:00
rootiest f7598e5e23 fix(ci): set DEBIAN_FRONTEND=noninteractive for apt-get installs
apt-get install was probing for a Dialog then Readline debconf frontend
before falling back to Teletype on the non-interactive CI runner,
adding noise and failed-negotiation log lines to every run. Passing
DEBIAN_FRONTEND=noninteractive directly on the sudo command line (env
vars set via step-level `env:` don't survive sudo's env_reset) skips
the negotiation and goes straight to the frontend that actually works
here.
2026-08-21 00:52:55 -04:00
rootiest 7466188d35 chore(ci): rename build-docs.yml to ci.yml
The workflow now runs the fish config test suite before building and
publishing docs, so "build-docs" no longer describes its full scope.
2026-08-20 01:15:10 -04:00
rootiest 642c981e4b test(ci): add fish config test suite and gate docs build on it
Adds tests/run-tests.fish (syntax lint over every .fish file, plus a
sandboxed interactive load) and tests/functional.fish (10 checks
covering XDG/PATH/CDPATH setup, key bindings, abbreviations, core
functions, exit rewiring, and the opinionated-component registry).

The sandbox copies config-relevant files into a scratch HOME/XDG tree
rather than symlinking the checkout, since this repo also serves as a
live ~/.config/fish and a symlink would let universal-variable writes
leak into the real fish_variables file.

Wires the suite into build-docs.yml as a `test` job that `build-docs`
now depends on, so a broken config can no longer get published to the
docs site. Documents the workflow in the README's new Testing section.
2026-08-20 01:03:40 -04:00
rootiest 6689e69ece fix(ci): install fish from the official 4.x PPA
Ubuntu 24.04's default repo only carries fish 3.7, but
docs/manual/06-dependency-catalog.md states fish >= 4.0 as a
project dependency. ppa:fish-shell/release-4 is the fish-shell
maintainers' own PPA and explicitly supports 24.04.
2026-08-18 22:03:23 -04:00
rootiest df929c5335 fix(ci): install fish in build-docs workflow
Generate documentation / build-docs (push) Failing after 50s
The registry round-trip test spawns a real fish subprocess to verify
conf.d/__fish_config_op_registry.fish sources correctly, but the
runner image has no fish binary, so the workflow failed with
FileNotFoundError.
2026-08-18 21:50:43 -04:00
rootiest 31d04a2fe0 chore(ci): reflect registry regeneration in auto-commit message 2026-08-18 21:37:12 -04:00
rootiest 1cb6f37b5b fix(registry): quote keys, dedupe tags, and document sourcing order; CI commits regenerated registry
- Quote both keys and values in the generated __fish_config_op_registry.fish
  keys array so a future identity/tag containing a glob-special character
  (*, ?, [) can't be silently dropped by fish's set, desyncing the
  positionally-paired keys/values arrays.
- Deduplicate the tag list per site in build_registry() so an identity
  collision across sources (e.g. auto-pull tagged autoexec/sync in both
  functions/auto-pull.fish and conf.d/auto-pull.fish) no longer produces a
  duplicated tag in the committed registry.
- Add a comment to the generated file's header noting it must sort first
  among conf.d/*.fish guard-callers, since that ordering is currently
  implicit in the filename rather than stated anywhere.
- CI's auto-commit step now also stages conf.d/__fish_config_op_registry.fish
  alongside the docs it already regenerates, so a # COMPONENT header change
  pushed without a manual __fish_config_op_registry_rebuild self-heals
  instead of silently drifting from what CI just regenerated.
2026-08-18 18:12:49 -04:00
rootiest 040c98c0a7 fix(config-settings,docs): address final whole-branch review findings
Bundled fix wave for six findings from the sub-category-granularity
whole-branch review:

- config-settings: reset in_subcat on Tab/Shift-Tab so up/down keep
  routing to cur_row instead of freezing on the Sponge/Paths pages
  after a drill-down
- verify-manual: _parsed_components() now delegates to
  generate_component_registry.collect_components() instead of a
  lossy dict.update() merge, closing a taxonomy-check blind spot on
  identity collisions
- verify-manual: add test_committed_registry_matches_headers to
  catch the committed registry drifting from current # COMPONENT
  headers
- build-docs workflow: trigger on conf.d/** and config.fish edits,
  not just functions/**
- __config_settings_draw_subcat: show (Universal)/(Session) in the
  drill-down title so the persistence scope is visible before toggling
- __config_settings_draw / config-settings: mention the Enter
  sub-category drill-down in the on-screen hint and --help text
- generate_component_registry: send the "wrote ..." progress line to
  stderr so it no longer corrupts --concat's stdout output
2026-08-18 16:46:46 -04:00
rootiest 86d20105e5 ci: move workflow to .github to increase hosting compatibility 2026-08-06 16:09:57 -04:00