chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
# @pdsjs/git-ci
## 0.5.2
### Patch Changes
- Updated dependencies
- @pdsjs/core@2.5.2
- @pdsjs/git@0.1.5
## 0.5.1
### Patch Changes
- Updated dependencies [542c4dc]
- @pdsjs/core@2.5.1
- @pdsjs/git@0.1.4
## 0.5.0
### Minor Changes
- 861663f: Startup no longer adopts a ref whose latest check is still `running`. A run
cut off mid-flight leaves its check record half written, and adopting the ref
told the daemon that ref was handled, so nothing ever finished the record and
the check read `running` for good. The runner's own check records outlive its
state file, so startup reads them: a ref left mid-run stays unadopted and runs
again on the next event for that repository.
### Patch Changes
- 04b15d0: The Jetstream re-exports are gone. `subscribeJetstream`, `jetstreamUrl` and
`jetstreamWrite` were reachable from the package root, and nothing consumed
them: the watch loop reads the repository's own firehose. `@pdsjs/appview`
leaves the dependency list with them.
- 0466ca6: `@pdsjs/git-ci` exports its record-key module under `./spec`. A reader that
wants the latest check for one ref computes the key rather than paging the
runner's history, and the derivation has to match the runner's exactly. The
root entry pulls in the checkout, the daemon and the firehose reader, so a
browser could not import it; `./spec` holds the key functions alone.
- c3c4caa: A repository's config record carries two DID lists, `collaborators` and
`reviewers`, read by `collaboratorsOf` and `reviewersOf`. A collaborator holds
their own copy of the repository under the same name, and a reader that knows
where to look can gather the open branches across every copy. atproto has no
reverse index, so a copy names no upstream and an upstream finds no copy
without being told. Neither list grants anything: nobody can write into
somebody else's repo whatever they say.
A pull request is a branch in one account's copy, identified by that account's
DID and the ref name. The pair survives amend, rebase, force-push and a commit
added on top, so a check or a review written against one version still names
the work after any of them. A branch canonical main reaches is merged and one
it does not is open, both read from the graph rather than from a stored state.
The `dev.pdsjs.git.pull` lexicon describes what the author says about their own
branch: a title, an optional `status` of draft or withdrawn, and a note. It is
in the author's own repo and nothing is written to the repository it names. A
push with no such record is still a pull request, titled by its tip commit.
`dev.pdsjs.git.pulls` is the index a runner publishes of the records it has
seen, under `pullsKey`, because atproto has no reverse index and the owner has
no inbound address. The config may name several runners (`runnersOf`), and a
reader unions their indexes, so one runner omitting a pull request does not
bury it.
The `dev.pdsjs.git.review` lexicon describes a verdict on one version of one
pull request, published in the reviewer's own repo. `author` and `ref` name the
pull request and `sha` names the version read, so a review of an earlier
version still reads against the work and still says which version it answered.
The verdicts are `approve`, `changesRequested` and `comment`.
The browser reader gains `changedPaths`, `readRange` and `listRange`, which
answer for two commits what `readCommit` and `listCommits` answer for one and
for a ref. A pull request written over a dozen commits is one thing to read,
and the paths it touches are one tree walk from its merge base rather than a
diff per commit.
The repository browser reads all of it on a pull request list. The model, and
what is still unbuilt, is in `docs/plans/2026-08-24-pull-requests.md`.
- 83083a5: Issues, as the model's one primitive: a `dev.pdsjs.git.issue` record in its
filer's own repo names the repository, a record with `replyTo` answers one,
and the repository owner's record with a `disposition` is what a reader shows
as the issue's state. Nobody closes an issue; the owner states resolved,
declined or reopened, attributed, and disagreement sits beside it. The latest
word wins, so each of the three is answered by another one and none of them
shuts a thread. The repository's own server lists the statements, reading
the listed voices from their own servers and finding anybody else through
its discovery index, and the repository browser lists threads, files, and
replies with the session the reviews use. A thread reads its state as a pill, and a
disposition reads as the event it is rather than as another comment. The
list holds an Open tab and a Closed one, each a real address, and closed
holds both of the words the owner settles a thread with, so the mark on a
row still says which. Both lists draw through one row, so a size moves in
one place.
- 32db640: The pull request and issue lists are served by the repository's own server:
`dev.pdsjs.git.listPulls` and `dev.pdsjs.git.listIssues`. The owner's copy
is read through the server's browser, every collaborator the config names
through a browser over their server, and anybody else through a discovery
port that answers which records about the repository exist in accounts the
config does not name. The first provider is Constellation, a hosted reverse
index over the public firehose, asked once per collection on the path
`subject.uri`; a deployment may pass its own port to `createGitExtension`,
or null to read the listed voices alone. Open and merged are computed from
the object graph on every read and stored nowhere. The repository browser
asks its server for the two lists, where it read five servers itself.
The runner is CI only. Its pull request index, issue index and push log
(`dev.pdsjs.git.pulls`, `.issues`, `.versions`) and `PDSJS_CI_PULL_SOURCES`
are gone, since the discovery port answers what the indexes did and the
version numbers the push log fed left the interface. A check or comment
written against a commit the branch has since replaced still reads as
outdated, from the tips the checks and reviews themselves name.
A push into a fork writes `upstream` on the pushed record, the repository
record the copy was taken from, when the checkout's remotes say which that
is. The repository's server asks its discovery index which copies name it and
reads every branch of each, so a bare push into a fork is listed before its
author has written a pull request record.
An author still writes their own words from the page: a title, a note, and
open, draft or withdrawn, as a `dev.pdsjs.git.pull` record in their own
repo. The form appears for the account holding the branch and nobody else.
- a56be28: A pull request is identified by the account whose copy holds the work and the
ref that holds it, in place of the `Change-Id:` trailer. The pair costs nothing
to compute, needs no hook in the author's push path, and survives the one case
the trailer did not: a commit added on top of a branch gave the tip a new
trailer, which detached every check and review keyed to the old one.
`git-remote-atproto install-hook` and the `changeId` fields on the check,
review and index records go with it. A `dev.pdsjs.git.review` record names
`author` and `ref` instead, and its verdicts are `approve`, `changesRequested`
and `comment`.
A merged branch is read from the merge that brought it in: the merge commit's
second parent is the tip merged and its first parents are main's trunk, so the
branch's earliest commit outside that trunk is where the work began. A branch
fast-forwarded into main leaves no such commit and opens at its tip alone.
The vocabulary follows the concept where the concept matches. `contributors`
becomes `collaborators` in the config record (`collaboratorsOf`), and
`dev.pdsjs.git.offer` becomes `dev.pdsjs.git.pull`, which gains a `title`. Work
from an account the repository has not named sorts into the one list, marked as
coming from a fork.
The repository browser serves the list at `/<repo>/pulls`, with open and merged
tabs, and one pull request at `/<repo>/pull/<did>/<branch>` with its diffs
under `/files`.
None of these lexicons is published, so there is nothing to migrate.
- f27dcf7: A git repository's record key is minted at creation, and its name is an
ordinary field. The name was the key, so it was the identity, and renaming a
repository changed its AT-URI: every review, pull request, issue and check
naming it, every fork naming it upstream, and the reverse index all pointed at
an address that no longer existed.
The rule is that the name is an address and the key is an identity. Every
public surface still takes a name, `resolveRepo` is the one place that turns
one into a key, and everything below it works in keys. `dev.pdsjs.git.repo`
already declared `key: 'any'` and already required `name`, so no record's
value changes, only its key.
`dev.pdsjs.git.renameRepo` writes that one field. A repository in a space
keeps the name it has: the space is what an address resolves to and is keyed
by that name.
The config record moves to the repository's key, which the write guard already
assumed when it joins the two. A collaborator's copy is found by the name the
two copies share rather than by assuming their key matches. Pull request keys,
check request keys and latest-check keys all derive from the repository's own
key, so a rename leaves them where they are.
`@pdsjs/git-ci` reads a repository's name from its record rather than from the
firehose write's key, which a minted key would have matched against nothing.
Its two key derivations are duplicated in the server and must agree, so the
runner is deployed with it. Secret grants keep naming repositories the way a
person writes them and resolve to a record key at startup, where a grant
naming a repository the account does not hold is reported.
Existing repositories are moved by `scripts/migrate-git-repo-keys.mjs`. The
resolver finds an unmigrated repository unchanged, so a deploy can precede the
migration. See `docs/plans/2026-09-04-stable-repo-keys.md`.
- Updated dependencies [d66fcff]
- Updated dependencies [05a11b4]
- Updated dependencies [f79dd82]
- Updated dependencies [c68858b]
- Updated dependencies [04b15d0]
- Updated dependencies [288063a]
- Updated dependencies [c3c4caa]
- Updated dependencies [bcb5758]
- Updated dependencies [e0b38cd]
- Updated dependencies [4fb8f23]
- Updated dependencies [1cf113d]
- Updated dependencies [04b15d0]
- Updated dependencies [c4af198]
- Updated dependencies [f777a2c]
- Updated dependencies [a981627]
- Updated dependencies [3febe1c]
- Updated dependencies [ac5c8eb]
- Updated dependencies [00bd461]
- Updated dependencies [83083a5]
- Updated dependencies [2c68bdc]
- Updated dependencies [fe7ffe0]
- Updated dependencies [211c7c8]
- Updated dependencies [6cf84d5]
- Updated dependencies [35f794f]
- Updated dependencies [522071f]
- Updated dependencies [32db640]
- Updated dependencies [04b15d0]
- Updated dependencies [cc4577b]
- Updated dependencies [cc4577b]
- Updated dependencies [f5aae7c]
- Updated dependencies [cc4577b]
- Updated dependencies [fe3c9ac]
- Updated dependencies [b99acf8]
- Updated dependencies [c1ec3d6]
- Updated dependencies [04b15d0]
- Updated dependencies [7c06024]
- Updated dependencies [6935a55]
- Updated dependencies [15c69af]
- Updated dependencies [a56be28]
- Updated dependencies [673ec05]
- Updated dependencies [74819af]
- Updated dependencies [4dfdbfa]
- Updated dependencies [04b15d0]
- Updated dependencies [aeb61f9]
- Updated dependencies [04b15d0]
- Updated dependencies [04b15d0]
- Updated dependencies [f27dcf7]
- Updated dependencies [c9e3550]
- Updated dependencies [c01859b]
- Updated dependencies [41df38b]
- Updated dependencies [411b47b]
- Updated dependencies [ca47f96]
- Updated dependencies [861663f]
- Updated dependencies [617df4a]
- Updated dependencies [154e7d7]
- Updated dependencies [10c91f6]
- Updated dependencies [0e1bf66]
- Updated dependencies [77eb9db]
- Updated dependencies [76f5187]
- Updated dependencies [b51250e]
- Updated dependencies [799286b]
- Updated dependencies [4adc49e]
- Updated dependencies [e83838c]
- Updated dependencies [9149663]
- Updated dependencies [16ea1fe]
- Updated dependencies [fd401a4]
- Updated dependencies [93816a1]
- Updated dependencies [3d475f8]
- Updated dependencies [078c2df]
- Updated dependencies [d5f111c]
- @pdsjs/core@2.5.0
- @pdsjs/git@0.1.3
## 0.4.0
### Minor Changes
- d307f57: The daemon reads each watched repository's refs at startup when its state
file says nothing about them. Without that, a daemon whose state was lost
read every ref in the record as new on the next event and started a run for
each, so every tag ran its release workflow again. The first run now comes
from a ref that moves after startup, which is what starting at the live head
means. A repository whose record cannot be read is still watched, and its
first event still runs it.
- 2d0d653: The runner image carries the docker client and buildx, and the entrypoint
puts the daemon's user in the group of a mounted docker socket. A deployment
that mounts one can then run workflows that build, run and push container
images, which previously needed a forge. The socket is the whole grant: a
step commanding the host's daemon is root on that host, so mount it only
where every contributor to every watched repository is trusted that far.
Without the mount nothing changes and no step can reach a daemon.
### Patch Changes
- Updated dependencies [d307f57]
- Updated dependencies [2d0d653]
- @pdsjs/core@2.4.3
## 0.3.0
### Minor Changes
- c235e96: Workflow files may be YAML. A step is a shell script, and a block scalar
carries one as written where a JSON string carries it as a single line of
escaped newlines. The parser is YAML 1.2, which subsumes JSON, so existing
`.json` workflows and the `.pdsjs/ci.json` fallback read unchanged. The
workflows directory now reads `.yml`, `.yaml` and `.json`, and passes over
anything else, so a README can sit beside the workflows it describes.
### Patch Changes
- Updated dependencies [c235e96]
- @pdsjs/core@2.4.2
## 0.2.0
### Minor Changes
- fa1558c: The runner reads one workflow per file from `.pdsjs/workflows/*.json`, falling
back to `.pdsjs/ci.json` when the directory is absent. Every workflow naming
the moved ref runs and publishes its own check; the latest-check record holds
one entry per workflow under the unchanged key, and the account checks
endpoint flattens the entries, reading records from before entries existed as
one entry. Workflows declare secrets by name, and the daemon grants them per
repository from the file `PDSJS_CI_SECRETS` names; the runner's own
credentials no longer reach any step's environment. The runner image is based
on trixie so a repository under test can load prebuilt native addons that
need glibc 2.38.
### Patch Changes
- Updated dependencies [fa1558c]
- @pdsjs/core@2.4.1
## 0.1.1
### Patch Changes
- 4895bc1: A repository's owner can ask for a check run. The daemon listens on no port,
so the request is a record: `dev.pdsjs.git.checkRequest` in the owner's own
repo, which the firehose connection the daemon already holds carries to it.
The record's authority is the authorisation, since only the owner can write
into that repo, and the runner acts on a request only for a repository it
watches. The record key is derived from the repository and the ref, so asking
twice replaces the record rather than leaving one per click, and the state
file remembers the version acted on so a replayed event starts no second run.
`sha` is optional: without it the run takes whatever the ref points at when
the daemon reads the repository record.
- 0665ecc: Check record writes retry twice on a server error or a dropped connection
before the run is abandoned. One transient failure on the outcome write
used to leave the check `running` forever, indistinguishable from a
runner that died mid-run. A client error, such as a failed swap, still
throws at once.
- Updated dependencies [ee6d696]
- Updated dependencies [cb64c59]
- Updated dependencies [54bec84]
- Updated dependencies [922fb50]
- Updated dependencies [68ad18f]
- Updated dependencies [f716d9d]
- Updated dependencies [68ad18f]
- Updated dependencies [68ad18f]
- Updated dependencies [ae02630]
- Updated dependencies [68ad18f]
- Updated dependencies [4c334b3]
- Updated dependencies [86d8eb4]
- Updated dependencies [6b79149]
- Updated dependencies [8616855]
- Updated dependencies [af8b1fd]
- Updated dependencies [715c475]
- @pdsjs/core@2.4.0
- @pdsjs/git@0.1.2