Kai Ole Hartwig
pinup · documentation

Platforms

Datasources and managers are platform-neutral. The platform is where the merge requests, the dashboard issue, the local> presets and the project listing live: one interface (publish.Platform) with two implementations.

  • GitLab: proven in production across an estate of 200 repositories
  • GitHub: in production since September 2026 on a first repository, as a GitHub App without automerge; automerge is proven against a fake that speaks the API
  • Others: a package under platform/, a test server, a case in wire

GitLab

Proven in production across an estate of 200 repositories.

Variable
PINUP_GITLAB_URL / CI_SERVER_URLthe instance
PINUP_GITLAB_TOKEN / GITLAB_TOKENa personal or project access token with api and write_repository; CI_JOB_TOKEN is used when none is set, and it can only read
PINUP_REGISTRY_HOST / CI_REGISTRYthe instance's container registry, where the token is exchanged for a pull token

Merge requests are found by source branch (open ones only; a closed one is history and is not reopened), created and aligned with title, description, labels and merge-when-pipeline-succeeds. An automerge the permissions refuse stands next to the request, not as an error. A request whose branch the plan no longer names is closed with autoclosed appended to its title. A commit's signature verdict comes from the API, so a run knows whether its commits show as Verified. The dashboard is the bot's own issue with exactly that title; an issue somebody else names that way is not the dashboard. local> presets come through the raw-file endpoint. Autodiscovery walks every non-archived project the token is a member of.

pinup token rotate renews the bot's own token before it expires and writes the new one into the CI variables it names, at group or project level. A job token cannot rotate itself.

GitHub

In production since September 2026 on a first repository: a Helm chart whose workflow runs pinup as a GitHub App and opens pull requests without automerge. The dashboard works with such an installation token from version 0.49.5 on. Automerge on GitHub is proven against a fake that speaks the API, not yet in production.

Variable
PINUP_PLATFORM=githubor implied by a GitHub token with no GitLab instance in the environment
PINUP_GITHUB_URL / GITHUB_SERVER_URLthe host; github.com when empty; an Enterprise host under /api/v3
PINUP_GITHUB_TOKEN / GITHUB_TOKENclassic repo, or fine-grained with contents, pull requests and issues read/write; on github.com it serves the github-* datasources as well

Pull requests are found by head as owner:branch (a fork's branch of the same name is a different request), created and aligned (title, body, labels). Auto-merge is armed and withdrawn over GraphQL, the only API GitHub has for it; “not yet” (nothing to wait for) is told apart from “not allowed” (repository setting), and the latter stands next to the request. git authenticates through the askpass as x-access-token. The dashboard is the bot's own issue with exactly that title; the pull requests the issues endpoint returns along with it stay out. A GitHub App installation token and a workflow's GITHUB_TOKEN have no user; /user answers 403. For them the dashboard is the open issue of that title written by a bot account. A person's issue of the same title is never taken, and two bot-written issues of the title are an error, not a choice. Autodiscovery lists the repositories the token may push to and that are not archived.

What GitHub does not know is said, not simulated: a request cannot ask for its branch to be deleted on merge (that is the repository setting delete_branch_on_merge), and auto-merge needs a repository that allows it.

Adding one

An implementation is a package under platform/ with the methods of publish.Platform, an iface.go that asserts them, a test server that speaks the protocol (pagination included) behind the refusing transport, a case in wire.Platform and one in the environment reader. Gitea and Forgejo are close to GitLab's shape.

Next

Back to pinup

The overview: the problem, the fit check, the quickstart, every chapter.

pinup →
Back to pinup

Security

Where the token goes, what a repository can and cannot make the bot do, how commits are signed.

Read →
Security