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.
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
amd64andarm64; only the compiled files differ. Check it withGOOS=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 thelibsqlite3-0version underneath it. That one comes from the package you installed:dpkg -s voleorrpm -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.