mesh/merge-gate pass: builds gitea, mesh-delivery → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer head of the same pull request
Review of #195: the clock restarted on any change in what a head waits on, so a check answering pushed the line back by the time it took; it now restarts only on a newer ask. A head whose check started was announced, so its line no longer says unannounced; pending times are given in UTC like the module's other lines.
102 lines
6.7 KiB
Markdown
102 lines
6.7 KiB
Markdown
# gitea
|
|
|
|
The forge, and the mesh's npm package registry: it claims the `git` and `npm-package-registry` seats.
|
|
Its tools, its events and the provisioner of registry accounts are the TypeScript bundle (`index.ts`,
|
|
`tools/`, `provisioner/`). This README covers the Go bundle beside it.
|
|
|
|
## Announcing pull requests to the merge check (novox/hq to-be 45 §9, issue 347)
|
|
|
|
Every new head of an open pull request is announced as `pull.updated`, once, and the controller has it checked.
|
|
|
|
- **Which repositories a pass looks at.** Each that moved since the last pass, less a minute's margin (issue 250);
|
|
each holding a pull request updated since then, found by the forge's own search — opening, reopening or
|
|
retargeting a pull request moves its own update time and not its repository's, and a pull request opened more
|
|
than a minute after its push was never announced (issue 347); and every repository on a sweep, every ten
|
|
minutes, or when the search fails.
|
|
- **A pull request nobody checks is said — by the delivery's owner, not here.** `gitea_open_pulls` answers every
|
|
open pull request from the forge itself, with the statuses its base requires and the ones its head has. The
|
|
`mesh-delivery` module asks it every five minutes, and a head on a base requiring `mesh/merge-gate` or
|
|
`mesh/repo-check` with neither for ten minutes since it first saw it so is a delivery held past its bound
|
|
(`delivery.<id>.stalled`, state `unannounced`), which the controller raises like any other (issue 347).
|
|
Each of the head's statuses comes with its state and when it was set, so a head whose check started and never
|
|
answered — a required check pending, or never set beside one that is — is said as a stalled line in the state
|
|
`unanswered` once that has lasted the delivery table's bound for a check asked and not answered, an hour, counted
|
|
from its first sight and again only when a check is asked anew (issue 438).
|
|
- **How to see it work.** A pull request opened more than a minute after its branch was pushed — this fix's own
|
|
was one, and the announcer it fixes never saw it — has `mesh/merge-gate` pending within a pass of the next sweep
|
|
at the latest, and `mesh-controller.conditions` names none for it.
|
|
- **A pull request or issue number that is not one is refused** before the forge is asked: a tool called with a
|
|
misnamed argument sent `pulls/NaN`.
|
|
|
|
## The package registry's retention (novox/hq ADR 0251 §4, to-be 51)
|
|
|
|
Every publish adds a version to the registry, and until this nothing removed one. The Go bundle
|
|
`cmd/npm-registry` says which versions each package holds, what keeps each one, and — asked with a why —
|
|
deletes the versions nothing keeps.
|
|
|
|
| tool | | what |
|
|
|---|---|---|
|
|
| `npm_packages` | r | every package of the registry's owner, each version newest first with its publish time, its size and why it is kept |
|
|
| `npm_retention` | a | the versions retention would delete, and the bytes. **A dry run unless `dry_run` is false**; a real run needs `why` |
|
|
|
|
**A version is kept when:**
|
|
|
|
- a lockfile on the default branch of any repository on the forge names it — `package-lock.json`
|
|
(every lockfile version), `npm-shrinkwrap.json`, `yarn.lock` (classic and berry) and `pnpm-lock.yaml`
|
|
(by each resolved `name@version` or `name/version`), whatever the version's age;
|
|
- it is the highest published version satisfying a range that a `package.json` there names in its
|
|
dependencies, development, peer or optional dependencies (an `npm:` alias counts for the package it
|
|
stands for; a path, a URL, git or a workspace is not a range on this registry). npm itself installs
|
|
the `latest` dist-tag when it satisfies the range; that version is kept by its dist-tag;
|
|
- a dist-tag names it — and a range that *is* a dist-tag's name keeps that tag's version;
|
|
- it is among the newest `keep` of its package, five by default (the artifact store's five builds,
|
|
ADR 0189 §3), by semantic-version order. **Pre-releases count** among the newest.
|
|
|
|
A version that is not a semantic version is never ordered, so it is kept. A range that cannot be read,
|
|
or a package whose dist-tags cannot be read, keeps **every** version of its package, and the answer says
|
|
why under `keeps_all`.
|
|
|
|
**Nothing is deleted on partial knowledge.** A repository whose files could not be listed, or a
|
|
manifest or lockfile that could not be fetched, is named under `repositories_unread` in every answer,
|
|
and a real run then deletes nothing at all. A file that was fetched but is not readable (broken JSON) is
|
|
named under `files_not_read`, and so is a lockfile entry of a shape the reader does not know (the rest of
|
|
that file is still read); what it would have named is not known, so a real run then deletes nothing at all
|
|
either. Under `node_modules` nothing is read: that is what a lockfile already says. An empty
|
|
repository, or one without its default branch, holds nothing to read and is not a failure.
|
|
|
|
A real run deletes each version through the forge's own interface (`DELETE
|
|
/api/v1/packages/{owner}/npm/{name}/{version}`), says what it deleted and what the forge refused, and a
|
|
version already gone counts as deleted.
|
|
|
|
### How it reaches the forge
|
|
|
|
Over the forge's HTTP interface on the machine (`MESH_GITEA_URL`), as the admin account the vault
|
|
delivered (`MESH_GITEA_ADMIN_USER`, the password in `MESH_GITEA_ADMIN_PASSWORD_FILE` — the same file
|
|
the TypeScript bundle mints its token with), by basic authentication: this bundle mints no token and
|
|
keeps nothing. The password is read per call and never logged, answered or put in an error. The
|
|
registry's owner is `MESH_NPM_OWNER`, the owner in the seat's `npm-path`.
|
|
|
|
Calls to the forge run eight at a time, and one tool call reads for at most 50 seconds, inside a
|
|
module's 60-second ask.
|
|
|
|
### Why the manifest lists no `tools`
|
|
|
|
The TypeScript bundle's tools are served without a `tools` list, and a claim without `serves` offers
|
|
the module's `tools` as the seat's verbs — so a list here would make these two tools verbs of both the
|
|
`git` and the `npm-package-registry` seats. The two names are kept in `ToolNames`, and a test holds them
|
|
to this README and to what the bundle serves.
|
|
|
|
### Tests
|
|
|
|
```
|
|
go test ./...
|
|
```
|
|
|
|
Against a fake forge (`httptest`): what keeps a version (a lockfile whatever its age, the highest
|
|
version satisfying a range, a dist-tag, the newest `keep`); a dry run deleting nothing; a real run
|
|
without why refused; a real run deleting only what nothing keeps; an unread repository stopping a real
|
|
run before anything is deleted; an unreadable range keeping its whole package; a wrong password failing
|
|
without saying the password. And the range matcher against npm's rules — exact, `^`, `~`, `x` and `*`,
|
|
comparisons with partial versions, hyphen ranges, `||`, and the pre-release rule — and each lockfile
|
|
format.
|