Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Code

396 commit(s) on main

Turn off the disk reserve for test-spawned runners Keenan Nemetz · 2h ago c284cb2c
source preview history blame raw 4.9 KiB

Releases

A release should travel with the code. In Vole, it does: a release is a Git tag with a message. The message is the release notes, and the tagged code is the source. Both travel with every clone, so there is no separate release database to keep in sync.

Create a release

vole release create v1.0.0 -F notes.md
git push --follow-tags

Plain Git works the same way:

git tag -a v1.0.0 -F notes.md
git push --follow-tags

Use an annotated tag (git tag -a). It has a message and a tagger. A lightweight tag appears in the release list for completeness, but it has no notes and cannot carry release files. vole release create refuses to overwrite an existing tag and tells you to choose a new name.

Create a release in the browser

A repository maintainer can create the same annotated tag from Releases → New release: choose a tag name, a target branch or commit, and write the notes. The notes become the tag message and the tagger is the account that submitted the form. Edit notes changes the message of an annotated tag while the release has no files attached; once an artifact is published the release is immutable, and the web refuses the edit. Lightweight tags are never editable.

Download source archives

The /<repo>/releases page lists every tag. A release page shows the notes, the commits since the previous release, and two generated downloads:

curl -O  http://host/demo/releases/v1.0.0/archive.tar
curl -OJ http://host/demo/releases/v1.0.0/archive.tar.gz

Vole builds the archives from the tagged tree when someone requests them, so they cannot go stale. The ETag is the tag’s id, so repeat downloads get a 304, and the same tag produces the same bytes on every instance.

If a repository tracks files with Git LFS, the release page shows a warning. git archive copies pointer files, not the files themselves.

Attach release files

Binaries attach over SSH into the shared storage, and Vole records a pointer for them:

vole release attach v1.0.0 dist/vole-linux-amd64 dist/vole-darwin-arm64
curl -O http://host/demo/releases/v1.0.0/artifacts/vole-linux-amd64
sha256sum vole-linux-amd64

Attach files after pushing the tag, not before. The pointer is what publishes the file, and Vole refuses a pointer whose file was never uploaded. That way a download link never points at nothing.

If you attach the same file twice, Vole stores one copy and the second upload transfers nothing. Downloads support ETag, 304, Content-Disposition: attachment, and Range requests, so large files can resume. Files from a private repository return 404.

Releases do not change

Once a release has files attached, Vole refuses to move or delete that tag, remove a file, or point a file name at different bytes. A saved download keeps meaning what it meant.

You can add another file; that does not invalidate anything. An admin can repair a mistyped release, and the override is recorded in data/audit.log.

Release file pointers live on the vole branch, so vole admin gc --dry-run treats a published release file as something to keep.

Build a release in CI

A workflow can build and publish a release instead of attaching files by hand:

artifacts:
  - path: dist/*
    release: true

The run records the same pointers that vole release attach writes, so the release page, download behavior, and immutability rules stay the same. See Workflows § Build a release.

A bill of materials for each release

A release built by the workflow carries an SBOM: vole-<version>.sbom.cdx.json, in CycloneDX JSON, listed on the release page beside the packages and covered by SHA256SUMS.

It names every Go module the application links, with the version and hash that go.sum pins, the Go toolchain, and each module’s licence as detected evidence rather than an asserted conclusion. That is what makes it useful for the question it exists to answer: an advisory names a module version, and the SBOM says whether the binary you downloaded contains it.

Two limits, stated so nobody reads more into it than is there:

  • One file covers both architectures. The module graph is the same for amd64 and arm64; only the compiled files differ. Check it with GOOS=linux GOARCH=arm64 go list -deps ./cmd/vole.
  • The system SQLite library is not a Go module. The SBOM names github.com/mattn/go-sqlite3, the binding the build links, not the libsqlite3-0 version underneath it. That one comes from the package you installed: dpkg -s vole or rpm -q --requires vole.

To regenerate it for a tag you already have:

go run github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@v1.9.0 \
  app -json -noserial -std -licenses -main cmd/vole -output SBOM.cdx.json .

The only field the tool takes from the clock is metadata.timestamp; the workflow replaces it with the tag’s commit time, so building one tag twice produces the same file.