Merge pull request 'docs(contributing): add issue templates and define the labeling standard' (#124) from docs/issue-templates-and-labels into main

This commit was merged in pull request #124.
This commit is contained in:
2026-09-01 03:36:02 +00:00
5 changed files with 563 additions and 0 deletions
+151
View File
@@ -0,0 +1,151 @@
# The key below is `description`, NOT `about`.
#
# GitHub requires `description` on a YAML issue form and rejects the
# template without it; Gitea wants `about` but explicitly accepts
# `description` as a compatible alias. `description` is therefore the
# only spelling that works on both the canonical repo and the mirror.
# The markdown templates beside this one still use `about`, which is
# correct for their format on both forges.
name: Bug report
description: Something in the config is broken or behaves unexpectedly
labels:
- Kind/Bug
body:
- type: markdown
attributes:
value: |
Thanks for filing a bug.
**Title it as a plain description of the problem**, not as a
conventional-commit subject — `mv clobbers a symlink when the target
exists`, not `fix(mv): ...`. The commit format belongs on the PR that
fixes this; the `Kind/` and `Area/` labels carry type and scope here.
Before filing, please confirm the problem survives a fresh shell
(`exec fish`) — a stale function definition in a long-lived session is
the single most common false alarm.
- type: input
id: fish-version
attributes:
label: fish version
description: Output of `fish --version`. This config targets fish 4.x.
placeholder: fish, version 4.0.2
validations:
required: true
- type: input
id: os
attributes:
label: Operating system
description: Distribution and version, or macOS release.
placeholder: Arch Linux (CachyOS), kernel 6.12.4
validations:
required: true
- type: input
id: terminal
attributes:
label: Terminal emulator
description: >-
Only matters for rendering, key bindings, and color problems. Leave it
blank if the bug has nothing to do with those.
placeholder: kitty 0.42.1
validations:
required: false
- type: dropdown
id: area
attributes:
label: Area
description: >-
Which part of the config is affected? Pick the closest match — a
maintainer translates this into the matching `Area/` label at triage,
since contributors without push access can't set labels themselves.
Choose "Not sure" rather than guessing.
options:
- Not sure
- Functions (functions/)
- Completions (completions/)
- Config and startup (config.fish, conf.d/)
- Docs (docs/manual/, man page, docs site)
- Tests (tests/)
- CI (.github/workflows/)
- Integrations (integrations/)
- Prompt and theme (themes/)
- Opinionated components (C1-C6 toggles)
- Scripts (scripts/)
validations:
required: true
- type: textarea
id: summary
attributes:
label: What's broken
description: One or two sentences. Name the function or file if you know it.
placeholder: >-
`mv` replaces an existing symlink instead of prompting, so the link
target is lost with no confirmation.
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
description: >-
Exact commands, starting from a fresh shell, that someone else can
paste and run. Include any setup needed to reach the broken state.
render: fish
placeholder: |
exec fish
mkdir -p /tmp/repro; cd /tmp/repro
touch real; ln -s real link
mv real link
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
description: What you thought those commands would do.
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual behavior
description: >-
What happened instead. Paste the complete output, including any error
text and stack traces — truncated errors are the usual reason a bug
report stalls in Status/Need More Info.
render: text
validations:
required: true
- type: checkboxes
id: preflight
attributes:
label: Pre-flight
options:
- label: I searched the existing issues and this isn't already reported.
required: true
- label: I reproduced this in a fresh shell (`exec fish`), not a long-lived session.
required: true
- label: I ran `fish tests/run-tests.fish` and noted the result below (or in the output above).
required: false
- type: textarea
id: context
attributes:
label: Additional context
description: >-
Anything else worth knowing: a private overlay in
`~/.config/.user-dots/fish/` that may be involved, opinionated
components you've disabled, the last commit where it worked. Never
paste credentials, tokens, or machine-specific paths you'd rather not
publish.
validations:
required: false
+21
View File
@@ -0,0 +1,21 @@
# Read by both Gitea (the canonical repo) and GitHub (the mirror).
#
# The .yml extension is required: Gitea accepts config.yaml or config.yml,
# but GitHub only recognizes config.yml and silently ignores config.yaml.
# Don't "tidy" this back to .yaml — the chooser on the mirror stops working.
#
# Blank issues stay enabled deliberately: the three templates cover bugs,
# features, and docs, and anything else (a chore, a refactor, a question)
# is better served by an empty box than by a template that doesn't fit.
blank_issues_enabled: true
contact_links:
- name: Canonical repository and issue tracker
url: https://git.rootiest.dev/rootiest/fish-config/issues
about: fish-config is developed on Gitea. If you came from the GitHub mirror, please file here instead — the mirror is read-only and issues opened there are easy to miss.
- name: Contributing guide
url: https://git.rootiest.dev/rootiest/fish-config/src/branch/main/CONTRIBUTING.md
about: Branch naming, commit conventions, coding standards, and the label taxonomy.
- name: Customization and personal overrides
url: https://git.rootiest.dev/rootiest/fish-config/src/branch/main/docs/manual/07-customization.md
about: Want to change behavior on just your machine? Use your private overlay — no issue needed.
+80
View File
@@ -0,0 +1,80 @@
---
name: Documentation issue
about: Something in the manual, man page, config-help, or docs site is wrong, missing, or unclear
labels:
- Kind/Documentation
---
<!--
Title this as a plain description of the problem:
config-help shows literal backticks in the customization section
not `docs(help): ...`. See CONTRIBUTING.md § Labels.
Docs in this repo are GENERATED. docs/manual/** plus the doc-header
comments above each function are the single source of truth;
docs/fish-config.md and docs/fish-config.1 are build output and are never
hand-edited. So a fix always lands in the source, not in the page where you
saw the problem — the Location section below asks for both.
Delete these comments as you fill it in.
-->
## Location
<!--
Where you saw it, and where it actually comes from.
- **Where you saw it** — the docs site URL, the `config-help <topic>` you
ran, `man fish-config`, or the README section.
- **Source file** — the docs/manual/** page, or the function whose
doc-header feeds it (e.g. `functions/mv.fish`). If you're not sure which,
say so and leave it to triage rather than guessing.
If the problem appears in one output but not the others — correct on the
site, broken in the pager — say which, since that usually points at the
rendering pass (docs/codespans.py) rather than the source text.
-->
## Problem
<!--
What's wrong. Quote the current text so it can be found and compared.
Common shapes, if it helps you place yours:
- **Wrong** — documents behavior the code doesn't have.
- **Stale** — described a flag or path that has since changed.
- **Missing** — a function, flag, or setting with no entry at all. Note
that a function with no `# CATEGORY` header is omitted from the manual
deliberately, so "missing" may be an intentional opt-out.
- **Unclear** — accurate, but a reader can't act on it. Say what you
expected to learn and what you concluded instead.
- **Renders wrong** — a broken code span, a mangled table, a bad anchor.
-->
## Suggested fix
<!--
Proposed wording or structure, if you have one — a diff-shaped
before/after is ideal, but a rough sketch is welcome too. "I don't know
what it should say, only that this confused me" is a legitimate and useful
report; keep the heading and say that.
Two constraints on any text under docs/manual/, both enforced by
docs/verify-manual.py:
- No backticks inside an indented block.
- No backtick span wrapped across a line break.
Doc-headers in .fish files take no backticks at all — docs/codespans.py
adds code spans when it renders. See CONTRIBUTING.md § Documentation
Pipeline.
-->
## Notes
<!--
Anything else — related issues (`Refs #42`), the commit that introduced the
problem, other pages with the same mistake. Drop this heading if empty.
-->
+111
View File
@@ -0,0 +1,111 @@
---
name: Feature or enhancement request
about: Propose new functionality, or an improvement to something that already exists
labels:
- Kind/Feature
---
<!--
Title this as a plain description of what you want, NOT as a
conventional-commit subject:
A picker for switching themes without editing config.fish
not `feat(theme): add theme picker`. That format belongs on the PR that
implements this; here, the Kind/ and Area/ labels carry type and scope.
See CONTRIBUTING.md § Labels.
This template applies Kind/Feature. If you're proposing an improvement to
something that already exists rather than genuinely new functionality, say
so in the Summary — a maintainer will swap the label to Kind/Enhancement
at triage. Contributors without push access can't set labels directly.
Keep every heading below except Alternatives considered and Notes, which
you can drop if they'd be empty. Delete these comments as you go.
-->
## Summary
<!--
What you want, in one or two sentences. Lead with the capability, not the
implementation — "a way to preview a theme before committing to it" rather
than "add a --preview flag to theme-set".
-->
## Problem
<!--
What's awkward, slow, or impossible today. Be concrete about the situation
that led you here: the sequence of commands you run now, what you have to
remember, or what goes wrong. A proposal is only as good as the problem it
names, and this section is what a reviewer weighs the cost against.
-->
## Proposed behavior
<!--
The concrete shape of the thing. Where they apply:
- The command or function name, and its flags.
- What it prints on success, and what it does on the error paths.
- What happens with no arguments, or with a missing dependency.
- Whether it's interactive, and what it falls back to when it isn't.
A short usage sketch in a ```fish block is worth several paragraphs.
-->
## Alternatives considered
<!--
Other approaches you weighed and why you set them aside — including
"solve it in my own ~/.config/.user-dots/fish/local.fish instead", which is
the right answer for anything genuinely specific to one machine or one
person's taste. See CONTRIBUTING.md § Secrets & Machine-Specific Config.
Drop this heading if there were no real alternatives.
-->
## Scope
<!--
Answer these — they determine how the change has to be built, and getting
them wrong late is expensive:
- Does this shadow a builtin or an existing command?
- Does it run at startup, or bind a key, or set an environment variable?
- Does it need a new external dependency, and what should happen when that
dependency is missing?
- Is it opinionated enough that users should be able to turn it off? If any
of the above is yes, it likely needs a `# COMPONENT` header and an
`__fish_config_op_enabled` guard — see CONTRIBUTING.md § Opinionated
Components.
- Does it need a manual entry (a `# CATEGORY` header), and under which of
the docs/manual/05-functions/ categories?
-->
## Acceptance criteria
<!--
What must be true for this issue to close, as a checkbox list. This is the
issue-side counterpart to a PR's ## Verification: it's the shared
definition of done, agreed before the work starts rather than argued about
after.
- One observable outcome per line — behavior a reader could check, not
implementation steps.
- Cover the error and fallback paths, not just the happy one.
- Include the docs and tests the change will owe.
Leave the boxes unchecked; they get ticked as the work lands.
-->
- [ ]
- [ ]
## Notes
<!--
Anything else: prior art in other shells or dotfiles, links to the relevant
upstream tool's docs, related issues (`Refs #42`). Drop this heading if
there's nothing to add.
-->
+200
View File
@@ -9,7 +9,9 @@ treat it as a living document, not a final word.
## Table of Contents
- [Getting Started](#getting-started)
- [Issues](#issues)
- [Branching & Pull Requests](#branching--pull-requests)
- [Labels](#labels)
- [Commit Conventions](#commit-conventions)
- [Fish Coding Standards](#fish-coding-standards)
- [Opinionated Components](#opinionated-components)
@@ -34,6 +36,79 @@ If you're touching anything under `docs/manual/`, you'll also want `pandoc`,
(see [Documentation Pipeline](#documentation-pipeline)) — otherwise CI will
catch problems on push.
## Issues
Issues live on the Gitea repo. Three templates cover the common cases, each
pre-applying its `Kind/` label; blank issues stay enabled for everything else
— a chore, a refactor, a question, a tracking issue.
| Template | Format | Use it for | Applies |
|---|---|---|---|
| **Bug report** | web form | Something is broken or behaves unexpectedly | `Kind/Bug` |
| **Feature or enhancement request** | markdown | New functionality, or an improvement to what exists | `Kind/Feature` |
| **Documentation issue** | markdown | The manual, man page, `config-help`, or docs site is wrong, missing, or unclear | `Kind/Documentation` |
They live in `.github/ISSUE_TEMPLATE/`, next to the PR template, so the
GitHub mirror offers the same set. The bug report is a Gitea *issue form*
a real web form with required fields — because a bug report missing its
version, reproduction, or full error text can't be acted on, and a form
refuses to submit without them. The other two are markdown templates in the
same comment-guided style as `.github/PULL_REQUEST_TEMPLATE.md`, since what
they ask for is open-ended prose that structure would only get in the way of.
GitHub reads these same files on the mirror, and its schema differs from
Gitea's in two places, so both are pinned to the spelling that works on both
and each file says so in a comment: the chooser config must be `config.yml`
(GitHub ignores `config.yaml`), and `bug.yml` declares `description:` rather
than `about:` (GitHub requires it; Gitea accepts it as an alias). The two
markdown templates keep `about:`, which is correct for their format on both.
### Issue titles
**Issue titles are plain descriptions of the problem, not Conventional
Commits subjects.**
```text
mv clobbers a symlink when the target exists ← yes
fix(mv): prompt before replacing an existing symlink ← no
```
An issue states a problem; a commit states a change. The type and scope that
`fix(mv):` would carry are already on the issue as its `Kind/` and `Area/`
labels, and the conventional subject belongs on the PR that closes it, where
it becomes the commit message. Writing the fix into the title also presumes
one, which is the wrong end to start from for anything still being diagnosed.
### What an issue owes
- **A bug** needs a reproduction someone else can paste and run, starting
from a fresh shell, plus the complete error output. A stale function
definition in a long-lived session is the most common false alarm, so
confirm it survives `exec fish` first. `Status/Need More Info` is where
reports without a reproduction end up.
- **A feature** needs `## Acceptance criteria` — the checkbox list of what
must be true for the issue to close. It is the issue-side counterpart to a
PR's `## Verification`: a definition of done agreed before the work starts
rather than argued about after, and the PR's checks usually grow out of it.
- **A docs issue** needs to name the `docs/manual/**` source, not just the
page where the problem showed up. `docs/fish-config.md` and
`docs/fish-config.1` are generated, and a fix applied there is overwritten
by the next CI run — see [Documentation
Pipeline](#documentation-pipeline).
### Triage
Reporters aren't expected to label anything. Contributors without push access
can't, and the templates apply the `Kind/` label by themselves; the rest is
the maintainer's job when the issue is triaged — add the `Area/` label (the
bug form's **Area** dropdown is how a reporter tells you, since no forge can
map a form field to a label), set a `Priority/` if it isn't ordinary, and
apply `Reviewed/Confirmed` once a bug actually reproduces. See
[Labels](#labels).
When a PR resolves an issue it closes it with a trailing `Closes #N` line —
see [Pull request descriptions](#pull-request-descriptions).
## Branching & Pull Requests
**If you don't have push access to this repo**, fork it and open your PR
@@ -48,6 +123,9 @@ assumes you *do* have push access (maintainers, regular contributors).
branching doesn't touch the working tree.)
- **Merge target is `main`, via PR.** Contributors open the PR; the repo
owner merges it. Don't merge your own PR.
- **Label every PR.** At minimum one `Kind/` and one `Area/`, same as an
issue — see [Labels](#labels). If you can't set labels, say what the
change is in the description and a maintainer applies them.
- **Don't merge until the `## Verification` checklist is fully checked.**
Unchecked boxes are outstanding manual checks, not decoration. See
[Pull request descriptions](#pull-request-descriptions) below.
@@ -112,6 +190,128 @@ bare `#43` is only a link and won't close anything. To point at a related
issue that should stay open, drop the keyword and use `Refs #42`. Leave the
line out entirely when no issue is involved.
## Labels
**Every issue and every pull request carries exactly one `Kind/` label and at
least one `Area/` label.** Everything else is optional, and most of it is
applied by a maintainer at triage rather than by whoever opened the thing.
Labels are scoped: the `Group/Name` form renders as a two-tone chip in Gitea,
and for the three *exclusive* groups below Gitea enforces one-at-a-time by
swapping the old label out when you apply a new one.
### `Kind/` — what this is
Required, and by convention exactly one. Gitea doesn't enforce one-of here,
so pick the dominant character of the change instead of stacking two.
| Label | For |
|---|---|
| `Kind/Bug` | Something is not working |
| `Kind/Feature` | New functionality |
| `Kind/Enhancement` | Improves functionality that already exists |
| `Kind/Documentation` | Documentation changes |
| `Kind/Testing` | The test suite itself |
| `Kind/Refactor` | Restructures code without changing behavior |
| `Kind/Chore` | Tooling, dependencies, housekeeping |
| `Kind/Performance` | Makes existing behavior faster or lighter |
| `Kind/Security` | A security issue |
These deliberately mirror the Conventional Commits types in [Commit
Conventions](#commit-conventions), so a PR's label and its title agree:
`fix``Kind/Bug`, `feat``Kind/Feature` or `Kind/Enhancement`, `docs`
`Kind/Documentation`, `test``Kind/Testing`, `refactor`
`Kind/Refactor`, `chore``Kind/Chore`, `perf``Kind/Performance`.
### `Area/` — what it touches
Required, and non-exclusive on purpose: a change that adds a function, its
completions, and a manual entry gets all three.
| Label | Covers |
|---|---|
| `Area/Functions` | `functions/` |
| `Area/Completions` | `completions/` |
| `Area/Config` | `config.fish`, `conf.d/` — startup and environment |
| `Area/Docs` | `docs/manual/` and the generated manual, man page, and site |
| `Area/Tests` | `tests/` |
| `Area/CI` | `.github/workflows/` and repository automation |
| `Area/Integrations` | `integrations/` |
| `Area/Prompt & Theme` | `themes/` and prompt appearance |
| `Area/Components` | The opinionated-component system (C1-C6) |
| `Area/Scripts` | `scripts/` |
`Area/` is what makes the tracker searchable: it answers "what's still
outstanding in the docs pipeline?" in a way `Kind/` never can. Two edges
worth naming — `Area/Docs` covers the documentation *and its pipeline*, so
`README.md` and this file count even though they sit outside `docs/`; and
`Area/Components` is for the C1-C6 machinery itself, not for every function
that happens to carry a `# COMPONENT` header.
### `Compat/Breaking`
Applied to **any PR whose title carries `!` before the colon**, and to any
issue proposing a change that would. It travels with the `## ⚠️ Breaking
Change` section that such a PR must already include — see [Pull request
descriptions](#pull-request-descriptions).
### `Priority/` — exclusive, maintainer-applied
`Priority/Critical`, `Priority/High`, `Priority/Medium`, `Priority/Low`.
**No priority label means ordinary priority.** Labeling everything defeats
the point, so leave it off unless the item is genuinely more or less urgent
than the rest of the queue.
### `Reviewed/` — exclusive, maintainer-applied
`Reviewed/Confirmed` goes on a bug that has actually been reproduced —
that's the signal separating a report from a known defect.
`Reviewed/Duplicate`, `Reviewed/Invalid`, and `Reviewed/Won't Fix` accompany
closing an issue, always with a comment saying why; a close with only a
label on it is not an explanation.
### `Status/` — exclusive, maintainer-applied
`Status/Blocked`, `Status/Need More Info`, `Status/Abandoned`. These describe
the item's current state, so remove one as soon as it stops being true — a
stale `Status/Need More Info` on an issue that got its answer is worse than
no label, because it reads as still waiting.
### `good first issue` and `help wanted`
Invitations to contributors, applied by a maintainer. Both are deliberately
**unscoped**: they'd be a natural fit under `Status/`, but that group is
exclusive, and an issue is quite often both blocked on something *and* open
for someone to pick up. Keeping them outside the group lets them coexist
with a real status.
Use `good first issue` for work that is genuinely self-contained — a clear
acceptance criterion, one or two files, no need to understand the
opinionated-component system first.
### The GitHub mirror
The repo is mirrored to
[github.com/rootiest/fish-config](https://github.com/rootiest/fish-config),
and **the mirror carries the same labels, by the same names**. That isn't
cosmetic: GitHub reads the same `.github/ISSUE_TEMPLATE/` files, and a
`labels:` entry naming a label that doesn't exist on that side is silently
dropped rather than reported. Mirroring copies files, not repository
settings, so **a label added here must be created on the mirror too** — no
automation does it for you.
One behavioral difference to keep in mind: **GitHub has no exclusive
labels.** Gitea enforces one-at-a-time on `Priority/`, `Reviewed/`, and
`Status/` by swapping the old label out; on the mirror those are ordinary
labels and nothing stops two of a group coexisting, so there the one-of rule
holds by convention alone.
Issues and pull requests belong on the canonical Gitea repo — the template
chooser links there first, on both sides. The mirror's tracker stays open so
that a report which lands there anyway isn't lost, not because it's a second
supported front door.
## Commit Conventions
Commit subjects follow [Conventional Commits](https://www.conventionalcommits.org/):