vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Require an image for every CI job
70b702649b875d841e294f5a085ca784d43e5bc4 · Keenan Nemetz · 15d ago · parent 7da9111e
Require an image for every CI job Runners now require an OCI runtime, and each workflow job must name either a registry image or an image-file definition under .vole/images. Definitions are validated at push time, pinned with the run, built locally by the runner, and cached by definition digest. Records and the run page carry the image and definition digest. Split the CI guide into workflows and runners, and add reference pages for workflow and image definition fields.
docs/reference/workflow-reference.md +293
| @@ -0,0 +1,293 @@ | |||
| 1 | # Workflow reference | ||
| 2 | |||
| 3 | This page lists every field Vole accepts in `.vole/workflows/*.yaml`, with its | ||
| 4 | defaults and limits. For a task-oriented introduction, see [Workflows](../workflows.md). | ||
| 5 | For `.vole/images` definitions, see [Image reference](image-reference.md). | ||
| 6 | |||
| 7 | Unknown keys are rejected. A workflow is validated when it is pushed and again by | ||
| 8 | `vole workflow check`, so a typo fails before a job is queued. | ||
| 9 | |||
| 10 | ## File location and limits | ||
| 11 | |||
| 12 | | Item | Value | | ||
| 13 | |---|---| | ||
| 14 | | Location | Directly under `.vole/workflows/`; subdirectories are rejected | | ||
| 15 | | Extension | `.yaml` or `.yml` | | ||
| 16 | | Maximum file size | 256 KiB | | ||
| 17 | | Schema version | `1` | | ||
| 18 | | Maximum jobs per workflow | 50 | | ||
| 19 | | Maximum steps per job | 100 | | ||
| 20 | | Maximum artifact declarations per job | 32 | | ||
| 21 | | Maximum `runs-on` labels per job | 8 | | ||
| 22 | | Maximum step command size | 64 KiB | | ||
| 23 | | Default step timeout | 10 minutes | | ||
| 24 | | Maximum step timeout | 1 hour | | ||
| 25 | |||
| 26 | ## Top-level fields | ||
| 27 | |||
| 28 | | Field | Type | Required | Default | Meaning | | ||
| 29 | |---|---|---|---|---| | ||
| 30 | | `version` | integer | yes | — | Schema version. Must be `1`. | | ||
| 31 | | `on` | mapping | no | — | Trigger configuration. Only `on.push` is supported. | | ||
| 32 | | `on.push.branches` | list of strings | no | `["*"]` when neither `branches` nor `tags` is present | Branch patterns that trigger the workflow. | | ||
| 33 | | `on.push.tags` | list of strings | no | none | Tag patterns that trigger the workflow. | | ||
| 34 | | `jobs` | mapping | yes | — | One or more jobs, keyed by job ID. | | ||
| 35 | |||
| 36 | ### `version` | ||
| 37 | |||
| 38 | The only supported value is `1`: | ||
| 39 | |||
| 40 | ```yaml | ||
| 41 | version: 1 | ||
| 42 | ``` | ||
| 43 | |||
| 44 | ### `on.push.branches` | ||
| 45 | |||
| 46 | A list of branch patterns. The default depends on what else is present: | ||
| 47 | |||
| 48 | - Neither `branches` nor `tags`: the workflow runs on every branch. | ||
| 49 | - `branches` present: only matching branches trigger it. | ||
| 50 | - `tags` present without `branches`: the workflow runs only on matching tags. | ||
| 51 | |||
| 52 | Patterns use `path.Match` semantics with one special case: a lone `*` matches every | ||
| 53 | branch, including names containing `/`. Other patterns keep the one-segment rule, | ||
| 54 | so `release/*` does not match `release/1.0/hotfix`. | ||
| 55 | |||
| 56 | Patterns may contain letters, digits, `*`, `?`, `[`, `]`, `!`, `.`, `_`, `/` and | ||
| 57 | `-`. Empty patterns and patterns containing `..` are rejected. | ||
| 58 | |||
| 59 | ```yaml | ||
| 60 | on: | ||
| 61 | push: | ||
| 62 | branches: [main, "release/*"] | ||
| 63 | ``` | ||
| 64 | |||
| 65 | An explicitly empty list means no branches trigger the workflow. | ||
| 66 | |||
| 67 | ### `on.push.tags` | ||
| 68 | |||
| 69 | A list of tag patterns. Tags have no default: a workflow runs on a tag only when | ||
| 70 | `tags:` is present and the tag matches. | ||
| 71 | |||
| 72 | ```yaml | ||
| 73 | on: | ||
| 74 | push: | ||
| 75 | tags: ["v*"] | ||
| 76 | ``` | ||
| 77 | |||
| 78 | Patterns follow the same rules as branch patterns. A workflow with `tags` and no | ||
| 79 | `branches` runs on tags only. A workflow with both runs on matching branches and | ||
| 80 | matching tags. | ||
| 81 | |||
| 82 | ### `jobs` | ||
| 83 | |||
| 84 | A mapping of job IDs to job definitions. Job IDs must match: | ||
| 85 | |||
| 86 | ```text | ||
| 87 | ^[a-z][a-z0-9_-]{0,31}$ | ||
| 88 | ``` | ||
| 89 | |||
| 90 | That is 1–32 characters: lowercase letters, digits, `_` and `-`, starting with a | ||
| 91 | letter. At least one job is required. | ||
| 92 | |||
| 93 | ## Job fields | ||
| 94 | |||
| 95 | | Field | Type | Required | Default | Meaning | | ||
| 96 | |---|---|---|---|---| | ||
| 97 | | `image` | string | one of `image` / `image-file` | — | Registry image the job runs in. | | ||
| 98 | | `image-file` | string | one of `image` / `image-file` | — | Name of a definition under `.vole/images/`. | | ||
| 99 | | `runs-on` | string or list of strings | no | any runner | Runner labels the job requires. | | ||
| 100 | | `steps` | list | yes | — | Commands the job runs. At least one is required. | | ||
| 101 | | `artifacts` | list | no | none | Files the job publishes. | | ||
| 102 | | `pages` | mapping | no | none | Directory published as the repository's website. | | ||
| 103 | |||
| 104 | Exactly one of `image` and `image-file` must be present. Declaring both, or | ||
| 105 | neither, is an error. | ||
| 106 | |||
| 107 | ### `image` | ||
| 108 | |||
| 109 | An OCI image reference used exactly as written: | ||
| 110 | |||
| 111 | ```yaml | ||
| 112 | jobs: | ||
| 113 | build: | ||
| 114 | image: golang:1.27-bookworm@sha256:... | ||
| 115 | ``` | ||
| 116 | |||
| 117 | The runner pulls and runs this image. Pin it by digest when reproducibility | ||
| 118 | matters; a mutable tag can change between runs. | ||
| 119 | |||
| 120 | References are limited to 255 bytes and must start with a letter or digit. They may | ||
| 121 | contain letters, digits, `.`, `_`, `/`, `:`, `@`, `+`, `~` and `-`. A leading `-`, | ||
| 122 | `..`, `://`, or a `file:` prefix is rejected. `file:` is reserved for | ||
| 123 | `image-file:`. | ||
| 124 | |||
| 125 | ### `image-file` | ||
| 126 | |||
| 127 | The name of a definition under `.vole/images/`: | ||
| 128 | |||
| 129 | ```yaml | ||
| 130 | jobs: | ||
| 131 | build: | ||
| 132 | image-file: go | ||
| 133 | ``` | ||
| 134 | |||
| 135 | `image-file: go` resolves `.vole/images/go.yaml`. The `.yaml` or `.yml` extension | ||
| 136 | is optional in the reference; `image-file: go.yaml` is also accepted. | ||
| 137 | |||
| 138 | Names are 1–64 characters: lowercase letters, digits, `.`, `_` and `-`, starting | ||
| 139 | with a letter or digit. A definition must live directly under `.vole/images/`, not | ||
| 140 | in a subdirectory. Two files for the same name (`go.yaml` and `go.yml`) are | ||
| 141 | rejected as ambiguous. | ||
| 142 | |||
| 143 | The definition is validated and pinned when the run is queued. See | ||
| 144 | [Image reference](image-reference.md) for its fields and limits. | ||
| 145 | |||
| 146 | ### `runs-on` | ||
| 147 | |||
| 148 | A single label or a list of labels: | ||
| 149 | |||
| 150 | ```yaml | ||
| 151 | runs-on: linux | ||
| 152 | runs-on: [linux, arm64] | ||
| 153 | ``` | ||
| 154 | |||
| 155 | A runner must carry every listed label to receive the job. An absent or empty | ||
| 156 | `runs-on` means any runner may take the job. Duplicate labels are ignored; at most | ||
| 157 | 8 labels may be declared. Each label must match: | ||
| 158 | |||
| 159 | ```text | ||
| 160 | ^[a-z0-9][a-z0-9._-]{0,31}$ | ||
| 161 | ``` | ||
| 162 | |||
| 163 | That is 1–32 characters: lowercase letters, digits, `.`, `_` and `-`, starting | ||
| 164 | with a letter or digit. | ||
| 165 | |||
| 166 | See [Runners § Start a runner](../runner.md#start-a-runner) for how a machine | ||
| 167 | advertises labels. | ||
| 168 | |||
| 169 | ### `steps` | ||
| 170 | |||
| 171 | A non-empty list of shell steps, at most 100. Steps run in order. A step that exits | ||
| 172 | non-zero stops the job and becomes the job's exit code. | ||
| 173 | |||
| 174 | Steps run inside the job's image, in the disposable checkout. They share the | ||
| 175 | container and filesystem with the other steps in the same job. | ||
| 176 | |||
| 177 | #### Step fields | ||
| 178 | |||
| 179 | | Field | Type | Required | Default | Meaning | | ||
| 180 | |---|---|---|---|---| | ||
| 181 | | `name` | string | no | first line of `run` | Display name in the log. | | ||
| 182 | | `run` | string | yes | — | Shell command executed with `/bin/sh -c`. | | ||
| 183 | | `timeout` | duration string | no | `10m` | Maximum time for this step. | | ||
| 184 | |||
| 185 | ```yaml | ||
| 186 | steps: | ||
| 187 | - name: test | ||
| 188 | run: go test ./... | ||
| 189 | timeout: 20m | ||
| 190 | ``` | ||
| 191 | |||
| 192 | `run` is trimmed and must not be empty. The maximum size is 64 KiB. `name` is | ||
| 193 | trimmed; when omitted it is derived from the first line of `run`, shortened to 60 | ||
| 194 | characters. | ||
| 195 | |||
| 196 | `timeout` uses Go duration syntax (`90s`, `10m`, `1h`). It must be positive and no | ||
| 197 | more than `1h`. When a step times out, the job fails and its container is stopped. | ||
| 198 | |||
| 199 | ### `artifacts` | ||
| 200 | |||
| 201 | A list of file patterns to publish when the steps succeed. At most 32 declarations | ||
| 202 | are allowed. | ||
| 203 | |||
| 204 | | Field | Type | Required | Default | Meaning | | ||
| 205 | |---|---|---|---|---| | ||
| 206 | | `path` | glob string | yes | — | Files to publish, relative to the checkout. | | ||
| 207 | | `release` | boolean | no | `false` | Also attach the matches to the tag's release. | | ||
| 208 | |||
| 209 | ```yaml | ||
| 210 | artifacts: | ||
| 211 | - path: dist/* | ||
| 212 | - path: dist/checksums.txt | ||
| 213 | release: true | ||
| 214 | ``` | ||
| 215 | |||
| 216 | `path` rules: | ||
| 217 | |||
| 218 | - Must be relative to the checkout; absolute paths and `..` segments are rejected. | ||
| 219 | - Maximum 256 bytes. | ||
| 220 | - Must name files, not a directory: a trailing `/` is rejected. | ||
| 221 | - Uses one-segment glob semantics. `dist/*` matches files directly in `dist/` but | ||
| 222 | not files in `dist/sub/`. | ||
| 223 | - `**` is rejected; use `dist/*` or declare more patterns. | ||
| 224 | - A pattern that matches nothing fails the job. | ||
| 225 | - Two matches with the same base name are refused because they would publish under | ||
| 226 | the same download name. | ||
| 227 | - `.git` is never published; symlinks and non-regular files are skipped. | ||
| 228 | |||
| 229 | `release: true` requires the workflow to declare `on.push.tags`. The job must run | ||
| 230 | for an annotated tag; a branch run or a lightweight tag cannot publish a release. | ||
| 231 | Release artifacts are attached to the tag's release in addition to being run | ||
| 232 | artifacts. See [Releases](../releases.md). | ||
| 233 | |||
| 234 | ### `pages` | ||
| 235 | |||
| 236 | Publishes one directory as the repository's website. | ||
| 237 | |||
| 238 | | Field | Type | Required | Default | Meaning | | ||
| 239 | |---|---|---|---|---| | ||
| 240 | | `path` | directory string | yes | — | Directory to publish, relative to the checkout. | | ||
| 241 | |||
| 242 | ```yaml | ||
| 243 | pages: | ||
| 244 | path: site/ | ||
| 245 | ``` | ||
| 246 | |||
| 247 | `path` must be relative, at most 256 bytes, and must not climb out of the | ||
| 248 | checkout with a `..` path segment or contain glob characters (`*`, `?`, `[`). A trailing `/` is accepted and trimmed. The directory | ||
| 249 | is published after the steps pass, using the same rules as | ||
| 250 | `vole pages deploy`. | ||
| 251 | |||
| 252 | Only one job in a workflow may declare `pages`. The target branch is set by the | ||
| 253 | instance (`pages_ref`), not by the workflow. The deploy is refused if the run is no | ||
| 254 | longer the newest commit on its branch. See [Workflows § Publish a website](../workflows.md#publish-a-website). | ||
| 255 | |||
| 256 | ## Validation and pinning | ||
| 257 | |||
| 258 | - The whole file is validated before a push is accepted. | ||
| 259 | - Unknown keys are errors; use the field names on this page. | ||
| 260 | - `version` must be `1`. | ||
| 261 | - The commit, workflow blob, and image definition are pinned when a run is queued. | ||
| 262 | Later edits do not change that run. | ||
| 263 | - `vole workflow check` and `vole workflow run` use the same validation as a push. | ||
| 264 | A local run ignores `on.push`, `runs-on`, and the image. | ||
| 265 | |||
| 266 | ## Complete example | ||
| 267 | |||
| 268 | ```yaml | ||
| 269 | version: 1 | ||
| 270 | on: | ||
| 271 | push: | ||
| 272 | branches: [main, "release/*"] | ||
| 273 | tags: ["v*"] | ||
| 274 | jobs: | ||
| 275 | test: | ||
| 276 | runs-on: [linux, arm64] | ||
| 277 | image: golang:1.27-bookworm@sha256:... | ||
| 278 | steps: | ||
| 279 | - name: unit tests | ||
| 280 | run: go test ./... | ||
| 281 | timeout: 20m | ||
| 282 | artifacts: | ||
| 283 | - path: coverage/* | ||
| 284 | release: | ||
| 285 | runs-on: linux | ||
| 286 | image-file: release-toolchain | ||
| 287 | steps: | ||
| 288 | - name: build | ||
| 289 | run: make dist | ||
| 290 | artifacts: | ||
| 291 | - path: dist/* | ||
| 292 | release: true | ||
| 293 | ``` | ||