v0.35.2 80d5067

releases.md RawHistoryFolder

Releases

A release binds a Git tag to a title, Markdown notes and named assets. There is one release per tag. Published releases follow repository visibility; drafts are visible only to writers. The web Releases tab is read-only.

ermite release create app v1.0.0 --target main --title 'Version 1' --notes-file notes.md --asset dist/app
ermite release list app --json
ermite release view app latest
ermite release edit app v1.0.0 --notes 'Updated notes'
ermite release upload app v1.0.0 dist/app --clobber
ermite release download app latest --pattern 'app*' --dir downloads
ermite release delete app v1.0.0 --yes

Create/edit accept --draft, --prerelease, --latest, --target and notes. Use edit --publish to publish a draft, --no-prerelease to clear that flag. An existing tag never moves; --target creates a missing tag. A draft can name a missing tag. Deleting a tag turns its release into a draft and keeps its assets; recreating the tag does not republish it. Deleting a release does not delete the tag.

latest is the newest published non-prerelease by creation time and id, unless pinned with --latest / REST make_latest: "true". Drafting or deleting the pinned release clears the pin. Asset names are unique within a release, 1–255 characters, without slashes, backslashes or control characters. CLI --clobber replaces a same-named asset; REST publishers delete it then upload again.

Writes require release:write (included in the cli preset), or a CI job token with permissions: contents: write for that repository. Branch-limited tokens cannot write releases. Read access to a private repository needs repo:read; unreadable releases, including drafts, answer not found. Older servers without the releases feature are refused by the CLI.

Limits and storage

Variable Default
ERMITE_RELEASE_ASSET_MAX 2GiB per asset
ERMITE_RELEASE_ASSETS_MAX 1000 per release
ERMITE_RELEASE_QUOTA 20GiB per repository

Quota includes uploads in progress. Exceeding limits gives REST 422 or RPC resource_exhausted. Assets use the shared blob store, disk by default or S3. Downloads pass through ermite, never redirect to the bucket, and support single byte ranges with 206, Content-Length and Content-Disposition. Stable links:

  • /<repo>/releases/download/<tag>/<asset>
  • /<repo>/releases/latest/download/<asset>

GitHub-compatible publishers

REST is at <public URL>/-/github/api, uploads at <public URL>/-/github/api/uploads. Use the external ERMITE_PUBLIC_URL, not the S3 endpoint. Stored-token publishers need release:write and, for private repository reads, repo:read. The owner component is ERMITE_OWNER (owner by default).

GoReleaser does not read GITHUB_API_URL or GITHUB_SERVER_URL by itself, so template github_urls from them (replace the fallback host and repository):

version: 2
# In CI the runner sets GITHUB_API_URL and GITHUB_SERVER_URL to the address the
# job can reach; the public URLs are the fallback for a local run.
github_urls:
  api: '{{ or (index .Env "GITHUB_API_URL") "https://git.example.org/-/github/api" }}/'
  upload: '{{ or (index .Env "GITHUB_API_URL") "https://git.example.org/-/github/api" }}/uploads/'
  download: '{{ or (index .Env "GITHUB_SERVER_URL") "https://git.example.org" }}/'
release:
  github:
    owner: owner
    name: app

In a CI job the runner rewrites the server and API URLs to an origin the job can reach, which may differ from the public URL (for example http://ermite:7341 with a relayed forge). Sandboxes block private and CGNAT ranges, so a job that targets only the public URL times out (dial tcp 100.x:443: i/o timeout). A plain-http relay needs no TLS option. The API base gets api/v3/ appended by the client; ermite accepts that alias. Locally, run GITHUB_TOKEN=<token> goreleaser release --clean from a tagged checkout; the fallbacks apply.

Workflow:

name: release
on:
  push:
    tags: ['v*']
permissions:
  contents: write
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-go@v5
        with:
          go-version-file: go.mod
      - uses: goreleaser/goreleaser-action@v6
        with:
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

An existing GitHub workflow must be enabled on ermite: ermite workflow enable <repo> .github/workflows/release.yml.

On an ermite runner, the job supplies GITHUB_API_URL, GITHUB_SERVER_URL and GITHUB_TOKEN; no endpoint override is needed for action-gh-release:

name: release
on:
  push:
    tags: ['v*']
permissions:
  contents: write
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: mkdir -p dist && printf 'hello\n' > dist/app.txt
      - uses: softprops/action-gh-release@v2
        with:
          files: dist/*
          body: Release built by CI

contents: read is insufficient and gets 403. Automatic release-note generation, discussions, reactions, immutability and attestations are not supported.

source
1# Releases
2
3A release binds a Git tag to a title, Markdown notes and named assets. There is
4one release per tag. Published releases follow repository visibility; drafts
5are visible only to writers. The web Releases tab is read-only.
6
7```sh
8ermite release create app v1.0.0 --target main --title 'Version 1' --notes-file notes.md --asset dist/app
9ermite release list app --json
10ermite release view app latest
11ermite release edit app v1.0.0 --notes 'Updated notes'
12ermite release upload app v1.0.0 dist/app --clobber
13ermite release download app latest --pattern 'app*' --dir downloads
14ermite release delete app v1.0.0 --yes
15```
16
17Create/edit accept `--draft`, `--prerelease`, `--latest`, `--target` and notes.
18Use `edit --publish` to publish a draft, `--no-prerelease` to clear that flag.
19An existing tag never moves; `--target` creates a missing tag. A draft can name a
20missing tag. Deleting a tag turns its release into a draft and keeps its assets;
21recreating the tag does not republish it. Deleting a release does not delete the tag.
22
23`latest` is the newest published non-prerelease by creation time and id, unless
24pinned with `--latest` / REST `make_latest: "true"`. Drafting or deleting the
25pinned release clears the pin. Asset names are unique within a release, 1–255
26characters, without slashes, backslashes or control characters. CLI `--clobber`
27replaces a same-named asset; REST publishers delete it then upload again.
28
29Writes require `release:write` (included in the `cli` preset), or a CI job token
30with `permissions: contents: write` for that repository. Branch-limited tokens
31cannot write releases. Read access to a private repository needs `repo:read`;
32unreadable releases, including drafts, answer not found. Older servers without
33the `releases` feature are refused by the CLI.
34
35## Limits and storage
36
37| Variable | Default |
38|---|---|
39| `ERMITE_RELEASE_ASSET_MAX` | `2GiB` per asset |
40| `ERMITE_RELEASE_ASSETS_MAX` | `1000` per release |
41| `ERMITE_RELEASE_QUOTA` | `20GiB` per repository |
42
43Quota includes uploads in progress. Exceeding limits gives REST 422 or RPC
44`resource_exhausted`. Assets use the shared [blob store](storage.md), disk by
45default or S3. Downloads pass through ermite, never redirect to the bucket, and
46support single byte ranges with 206, Content-Length and Content-Disposition.
47Stable links:
48
49- `/<repo>/releases/download/<tag>/<asset>`
50- `/<repo>/releases/latest/download/<asset>`
51
52## GitHub-compatible publishers
53
54REST is at `<public URL>/-/github/api`, uploads at
55`<public URL>/-/github/api/uploads`. Use the external `ERMITE_PUBLIC_URL`, not
56the S3 endpoint. Stored-token publishers need `release:write` and, for private
57repository reads, `repo:read`. The owner component is `ERMITE_OWNER` (`owner` by
58default).
59
60GoReleaser does not read `GITHUB_API_URL` or `GITHUB_SERVER_URL` by itself, so
61template `github_urls` from them (replace the fallback host and repository):
62
63```yaml
64version: 2
65# In CI the runner sets GITHUB_API_URL and GITHUB_SERVER_URL to the address the
66# job can reach; the public URLs are the fallback for a local run.
67github_urls:
68  api: '{{ or (index .Env "GITHUB_API_URL") "https://git.example.org/-/github/api" }}/'
69  upload: '{{ or (index .Env "GITHUB_API_URL") "https://git.example.org/-/github/api" }}/uploads/'
70  download: '{{ or (index .Env "GITHUB_SERVER_URL") "https://git.example.org" }}/'
71release:
72  github:
73    owner: owner
74    name: app
75```
76
77In a CI job the runner rewrites the server and API URLs to an origin the job
78can reach, which may differ from the public URL (for example `http://ermite:7341`
79with a relayed forge). Sandboxes block private and CGNAT ranges, so a job that
80targets only the public URL times out (`dial tcp 100.x:443: i/o timeout`). A
81plain-http relay needs no TLS option. The API base gets `api/v3/` appended by
82the client; ermite accepts that alias. Locally, run
83`GITHUB_TOKEN=<token> goreleaser release --clean` from a tagged checkout; the
84fallbacks apply.
85
86Workflow:
87
88```yaml
89name: release
90on:
91  push:
92    tags: ['v*']
93permissions:
94  contents: write
95jobs:
96  release:
97    runs-on: ubuntu-latest
98    steps:
99      - uses: actions/checkout@v4
100        with:
101          fetch-depth: 0
102      - uses: actions/setup-go@v5
103        with:
104          go-version-file: go.mod
105      - uses: goreleaser/goreleaser-action@v6
106        with:
107          args: release --clean
108        env:
109          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
110```
111
112An existing GitHub workflow must be enabled on ermite:
113`ermite workflow enable <repo> .github/workflows/release.yml`.
114
115On an ermite runner, the job supplies `GITHUB_API_URL`, `GITHUB_SERVER_URL` and
116`GITHUB_TOKEN`; no endpoint override is needed for action-gh-release:
117
118```yaml
119name: release
120on:
121  push:
122    tags: ['v*']
123permissions:
124  contents: write
125jobs:
126  publish:
127    runs-on: ubuntu-latest
128    steps:
129      - uses: actions/checkout@v4
130      - run: mkdir -p dist && printf 'hello\n' > dist/app.txt
131      - uses: softprops/action-gh-release@v2
132        with:
133          files: dist/*
134          body: Release built by CI
135```
136
137`contents: read` is insufficient and gets 403. Automatic release-note generation,
138discussions, reactions, immutability and attestations are not supported.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 45

↑↓ moveenter openesc close