The newest go-json-experiment/json, which wails/v3's application package imports, declares go 1.26, so taking it raises our go directive with it. Every other place that names a Go version moves in the same commit: GO_VERSION in ci, desktop-assets and android-apk, the Arch makedepends, and CONTRIBUTING's table. index-artifact's container image moves too, and it is the one that matters most. The official golang images set GOTOOLCHAIN=local, so a golang:1.25 container refuses a go 1.26 module outright rather than fetching a newer toolchain, and that job owns the ~205 GB checkpoint. Closes #265 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HJiuc3ZZhxsPXz3ozTirT
174 lines
7.9 KiB
Markdown
174 lines
7.9 KiB
Markdown
# Contributing to YellowJacket
|
|
|
|
This is the contributor's half of the [README](README.md): how to build it, how
|
|
to check a change, and how a change gets in. [`CLAUDE.md`](CLAUDE.md) is the
|
|
deep reference — the architecture, and the reasons behind the shape of it —
|
|
and is worth reading before a change of any size, because most of this
|
|
codebase's traps are written down there and nowhere else.
|
|
|
|
## Building from source
|
|
|
|
YellowJacket is [Go](https://go.dev/) with a [Lit](https://lit.dev/)/TypeScript
|
|
frontend, bridged by [Wails v3](https://wails.io/).
|
|
|
|
| Tool | Version |
|
|
|------|---------|
|
|
| Go | 1.26+ |
|
|
| Node.js | 22+ |
|
|
| pnpm | 10+ |
|
|
| Wails CLI | v3 — vendored, no install needed (`go tool wails3`) |
|
|
|
|
The Wails v3 CLI resolves from the `tool` block in `go.mod`, so there is nothing
|
|
to install globally; `make setup` fetches it with the rest of the tooling.
|
|
|
|
On Linux, install the system libraries Wails needs. v3 builds against GTK4 +
|
|
WebKitGTK 6.0 by default:
|
|
|
|
```bash
|
|
sudo apt-get install libasound2-dev libgtk-4-dev libwebkitgtk-6.0-dev # Debian/Ubuntu
|
|
sudo pacman -S alsa-lib gtk4 webkitgtk-6.0 # Arch
|
|
```
|
|
|
|
A machine without `webkitgtk-6.0` can still build with `-tags gtk3` against the
|
|
older WebKit2GTK 4.1 stack, but that is an escape hatch, not what CI or a
|
|
release builds. macOS and Windows need no extra system packages. Run
|
|
`go tool wails3 doctor` to check your environment.
|
|
|
|
```bash
|
|
make setup # install tooling, frontend packages and the git hooks
|
|
make dev # run with hot-reload
|
|
make build-dev # debug build with symbols
|
|
make build-prod # production build (stripped and trimmed)
|
|
make android # the arm64 APK, into bin/
|
|
```
|
|
|
|
The `Makefile` is the front door and carries a one-line description against
|
|
each target; `Taskfile.yml` and `build/<platform>/Taskfile.yml` are the build
|
|
implementation behind it and are not called directly.
|
|
|
|
## Generated code
|
|
|
|
Two generators run from `go generate ./...`, which `make generate` wraps:
|
|
**sqlc** turns `backend/database/sql/queries/` into Go in
|
|
`backend/database/sql/sqlcgen/`, and **templ** turns `.templ` files into
|
|
`*_templ.go` beside them. Never edit either output by hand — run
|
|
`make generate` after touching a `.sql` or a `.templ` file.
|
|
|
|
The TypeScript bindings in `frontend/bindings/` are generated by `wails3`
|
|
rather than by `go generate`, so they are a separate step: `make bindings`
|
|
regenerates them and `make bindings-check` fails if they are stale.
|
|
`frontend/src/events.ts` is generated too, from `backend/events/events.go`.
|
|
|
|
A pre-commit hook checks that all of this is fresh, so the usual way to meet it
|
|
is a failing commit rather than a bug.
|
|
|
|
## Checking a change
|
|
|
|
Run the tier the change actually demands, not the cheapest one.
|
|
|
|
| Change | Command |
|
|
|---|---|
|
|
| Go | `make lint` and `make test` — both cover all three build configurations |
|
|
| A frontend component or store | `make ui-test` (Vitest in a real Chromium, no backend) |
|
|
| A user-visible flow | `make e2e`, against a running `make dev-headless` |
|
|
| CSS | `make css-check` — see the Chrome 113 note below |
|
|
| Anything cosmetic | look at a screenshot; several bugs here were invisible to every assertion and obvious in an image |
|
|
|
|
`make test` needs the fixture library, which is generated rather than
|
|
committed — it runs `make testdata` itself (about a second).
|
|
|
|
The end-to-end tier drives the real app with no display at all: `make
|
|
dev-headless` starts it in the background on `:34115` (add `SEED=<name>` for a
|
|
seeded library, built by `make sandbox-seed NAME=<name>`), `make dev-logs` tails
|
|
it and `make dev-stop` stops it. **Check the port before starting one** — if
|
|
`:34115` is already answering, someone else's app is there, and a green result
|
|
about their build is worse than no result.
|
|
|
|
Two smaller checks exist because the failure they catch is silent:
|
|
`make bindings-check` (stale generated bindings) and `make css-check`, which is
|
|
two passes — one fails on a `css` literal ended early by a backtick inside a
|
|
comment, the other on a nested CSS rule that begins with a bare element
|
|
selector. Chrome 113 is what the reference Android device renders with, and it
|
|
drops such a rule without a word.
|
|
|
|
`make vulncheck` runs govulncheck over the module.
|
|
|
|
## The issue tracker is the source of truth
|
|
|
|
Work is described by issues before it is described by branches, and the tracker
|
|
is shared with people who cannot see your terminal.
|
|
|
|
- **Search before starting**, closed issues included: `./scripts/issue.sh search
|
|
<terms>`. "That was fixed three weeks ago" is the cheapest possible answer.
|
|
- **Claim before the first edit**, not before the commit:
|
|
`./scripts/issue.sh claim <n>` sets the assignee, applies `Status/In Progress`
|
|
and comments with the branch, so the work is visibly taken *while it is being
|
|
done*. It refuses if somebody else holds it — talk to them rather than working
|
|
around it.
|
|
- **If no issue covers the work, open one first** (`./scripts/issue.sh new`).
|
|
- **Findings get filed.** A bug tripped over on the way to something else is an
|
|
issue with a reproduction, not a wider diff and not a sentence in a chat log.
|
|
- **#73 is the roadmap** and states the order the backlog should be worked in.
|
|
|
|
`scripts/issue.sh` is the whole interface (`list`, `mine`, `search`, `show`,
|
|
`new`, `claim`, `unclaim`, `comment`, `close`, `label`, `depends`, `labels`) and
|
|
wants a `GITEA_TOKEN` with `write:issue`. The labels are a taxonomy rather than
|
|
tags: `Kind/*`, `Area/*`, `Priority/*`, `Platform/*`, plus `Reviewed/*` and
|
|
`Status/*`, of which the last two are exclusive scopes.
|
|
|
|
## Commits and pull requests
|
|
|
|
`main` is protected, so a branch and a PR are the only way in. Branch from
|
|
`origin/main`, and name the branch after the issue (`fix/140-…`, `feat/25-…`).
|
|
|
|
Commit subjects are [Conventional Commits](https://www.conventionalcommits.org/)
|
|
— `type(scope): subject`, imperative, ≤72 characters — and are enforced by a
|
|
`commit-msg` hook and by CI (`make commit-check`). This is load-bearing rather
|
|
than decorative: semantic-release reads the **type** to decide the next version,
|
|
so a CI-only change is `ci:` and never `fix(ci):`, which would ship a patch
|
|
release. `make release-dry` prints what a release would cut right now.
|
|
|
|
**The closing keyword goes in the commit body**, one issue per line, because
|
|
Gitea parses commit messages that reach `main` and does not parse the PR body:
|
|
|
|
```
|
|
docs: rewrite the README as a landing page
|
|
|
|
<why>
|
|
|
|
Closes #50
|
|
```
|
|
|
|
A PR body carries a commit-to-issue table, the verification you actually ran
|
|
(with results), and a `Closes` list for whoever reads it.
|
|
|
|
## Style
|
|
|
|
- **Go** — golangci-lint v2, strict: `err113` (static errors), `nlreturn`,
|
|
`wsl_v5`, `godot`, `sloglint`, `perfsprint`, and imports grouped stdlib →
|
|
third-party → `yellowjacket/…` by gci.
|
|
- **TypeScript** — strict mode, no implicit `any`, no unused locals or
|
|
parameters.
|
|
- Match the surrounding code. Where `CLAUDE.md` explains why something is shaped
|
|
the way it is, that shape is load-bearing and there is usually a test pinning
|
|
it.
|
|
|
|
Hooks do most of the enforcing (`lefthook.yml`, installed by `make setup`):
|
|
pre-commit runs vet, lint, the codegen checks, the frontend typecheck and the
|
|
two CSS checks in parallel; pre-push runs the Go suite and the UI tier,
|
|
deliberately one after the other rather than together.
|
|
|
|
## Where the rest of the documentation is
|
|
|
|
- [`CLAUDE.md`](CLAUDE.md) — architecture and constraints, in depth.
|
|
- [`docs/PROFILING.md`](docs/PROFILING.md) — Go pprof and frontend profiling.
|
|
- [`docs/android-release.md`](docs/android-release.md) — the APK, its signing
|
|
key, and what the release workflow checks.
|
|
- [`docs/index-cache.md`](docs/index-cache.md) — the search-index build cache
|
|
and why it has a snapshot.
|
|
- [`packaging/arch/README.md`](packaging/arch/README.md),
|
|
[`packaging/homebrew/README.md`](packaging/homebrew/README.md) — the two
|
|
package channels.
|
|
- `.planning/` — design documents and measured history, not a queue. The queue
|
|
is the tracker.
|