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.
Add event, schedule and manual workflow triggers
eb07ff5696e0d83201215966e3ea1e6a24467581 · Keenan Nemetz · 8d ago · parent 1cde8b9e
Add event, schedule and manual workflow triggers Workflows can now react to change requests, issues, comments, cron schedules and manual runs, and a push trigger can filter by the paths it changed. Branch and tag patterns gain ! exclusion. Event runs are pinned with a JSON payload and the runner exposes it as VOLE_EVENT, VOLE_EVENT_ACTION and VOLE_EVENT_PATH. Change-request runs check out the base tip and carry the head and changed files, so an event never executes an unapproved contributor commit. Workflow dispatch resolves typed inputs and is available from the workflows page and `vole workflow dispatch`. Deduplication now includes an occurrence so the same commit can run for a later event or schedule slot while a push remains idempotent. Part of: #138
docs/reference/workflow-reference.md +191−14
| @@ -25,6 +25,10 @@ Unknown keys are rejected. A workflow is validated when it is pushed and again b | |||
| 25 | 25 | | Maximum step command size | 64 KiB | | |
| 26 | 26 | | Maximum display name | 80 bytes | | |
| 27 | 27 | | Maximum description | 500 bytes | | |
| 28 | | Maximum path filters | 20 per list | | ||
| 29 | | Maximum schedules | 5 | | ||
| 30 | | Maximum manual inputs | 10 | | ||
| 31 | | Maximum event payload | 64 KiB | | ||
| 28 | 32 | | Default step timeout | 10 minutes | | |
| 29 | 33 | | Maximum step timeout | 1 hour | | |
| 30 | 34 | ||
| @@ -35,9 +39,16 @@ Unknown keys are rejected. A workflow is validated when it is pushed and again b | |||
| 35 | 39 | | `version` | integer | yes | — | Schema version. Must be `1`. | | |
| 36 | 40 | | `name` | string | no | the workflow file's base name | Display name on the workflows and run pages. | | |
| 37 | 41 | | `description` | string | no | none | One-line summary of what the workflow is for. | | |
| 38 | | `on` | mapping | no | — | Trigger configuration. Only `on.push` is supported. | | ||
| 39 | | `on.push.branches` | list of strings | no | `["*"]` when neither `branches` nor `tags` is present | Branch patterns that trigger the workflow. | | ||
| 42 | | `on` | mapping | no | — | Trigger configuration. | | ||
| 43 | | `on.push.branches` | list of strings | no | `["*"]` for a workflow with no other trigger | Branch patterns that trigger the workflow. | | ||
| 40 | 44 | | `on.push.tags` | list of strings | no | none | Tag patterns that trigger the workflow. | | |
| 45 | | `on.push.paths` | list of strings | no | none | Path patterns a push must touch. | | ||
| 46 | | `on.push.paths-ignore` | list of strings | no | none | Path patterns a push must not change. | | ||
| 47 | | `on.change-request` | mapping or empty | no | none | Change-request actions that trigger the workflow. | | ||
| 48 | | `on.issue` | mapping or empty | no | none | Issue actions that trigger the workflow. | | ||
| 49 | | `on.comment` | mapping or empty | no | none | Comment actions that trigger the workflow. | | ||
| 50 | | `on.schedule` | list of mappings | no | none | Cron schedules, in UTC. | | ||
| 51 | | `on.workflow-dispatch` | mapping or empty | no | none | A manual run, optionally with typed inputs. | | ||
| 41 | 52 | | `jobs` | mapping | yes | — | One or more jobs, keyed by job ID. | | |
| 42 | 53 | ||
| 43 | 54 | ### `version` | |
| @@ -80,9 +91,13 @@ optional; an absent description shows nothing. | |||
| 80 | 91 | ||
| 81 | 92 | A list of branch patterns. The default depends on what else is present: | |
| 82 | 93 | ||
| 83 | - Neither `branches` nor `tags`: the workflow runs on every branch. | ||
| 94 | - A workflow with no `on` trigger at all is an ordinary push ci and runs on every | ||
| 95 | branch. | ||
| 84 | 96 | - `branches` present: only matching branches trigger it. | |
| 85 | 97 | - `tags` present without `branches`: the workflow runs only on matching tags. | |
| 98 | - A workflow with only event triggers (`change_request`, `issue`, `comment`, | ||
| 99 | `schedule`, `workflow_dispatch`) does not run on a branch push. | ||
| 100 | - `push:` with neither `branches` nor `tags` runs on every branch. | ||
| 86 | 101 | ||
| 87 | 102 | Patterns use `path.Match` semantics with one special case: a lone `*` matches every | |
| 88 | 103 | branch, including names containing `/`. Other patterns keep the one-segment rule, | |
| @@ -91,12 +106,21 @@ so `release/*` does not match `release/1.0/hotfix`. | |||
| 91 | 106 | Patterns may contain letters, digits, `*`, `?`, `[`, `]`, `!`, `.`, `_`, `/` and | |
| 92 | 107 | `-`. Empty patterns and patterns containing `..` are rejected. | |
| 93 | 108 | ||
| 109 | A leading `!` excludes what an earlier pattern included. The last matching pattern | ||
| 110 | wins, so `["*", "!main"]` runs everywhere except `main`: | ||
| 111 | |||
| 94 | 112 | ```yaml | |
| 95 | 113 | on: | |
| 96 | 114 | push: | |
| 97 | 115 | branches: [main, "release/*"] | |
| 98 | 116 | ``` | |
| 99 | 117 | ||
| 118 | ```yaml | ||
| 119 | on: | ||
| 120 | push: | ||
| 121 | branches: ["*", "!main"] | ||
| 122 | ``` | ||
| 123 | |||
| 100 | 124 | An explicitly empty list means no branches trigger the workflow. | |
| 101 | 125 | ||
| 102 | 126 | ### `on.push.tags` | |
| @@ -110,9 +134,163 @@ on: | |||
| 110 | 134 | tags: ["v*"] | |
| 111 | 135 | ``` | |
| 112 | 136 | ||
| 113 | Patterns follow the same rules as branch patterns. A workflow with `tags` and no | ||
| 114 | `branches` runs on tags only. A workflow with both runs on matching branches and | ||
| 115 | matching tags. | ||
| 137 | Patterns follow the same rules as branch patterns, including `!` exclusion. A | ||
| 138 | workflow with `tags` and no `branches` runs on tags only. A workflow with both runs | ||
| 139 | on matching branches and matching tags. | ||
| 140 | |||
| 141 | ### `on.push.paths` | ||
| 142 | |||
| 143 | A push runs only when at least one changed path matches one of these patterns. | ||
| 144 | Patterns are relative to the repository root. `*` stays inside one path segment; | ||
| 145 | `**` spans zero or more segments, so `docs/**` covers `docs/` and everything under | ||
| 146 | it. At most 20 patterns may be declared. | ||
| 147 | |||
| 148 | ```yaml | ||
| 149 | on: | ||
| 150 | push: | ||
| 151 | paths: ["src/**", "cmd/**", "go.mod"] | ||
| 152 | ``` | ||
| 153 | |||
| 154 | An empty pattern, an absolute path, or a pattern containing `..` is rejected. A | ||
| 155 | push that changes no files does not match a workflow with a path filter. | ||
| 156 | |||
| 157 | ### `on.push.paths-ignore` | ||
| 158 | |||
| 159 | Paths that do not trigger the workflow. An ignored path is removed before the | ||
| 160 | allow list is consulted, so an ignored file cannot make a workflow run: | ||
| 161 | |||
| 162 | ```yaml | ||
| 163 | on: | ||
| 164 | push: | ||
| 165 | paths-ignore: ["docs/**", "**/*.md"] | ||
| 166 | ``` | ||
| 167 | |||
| 168 | `paths` and `paths-ignore` may be combined. When every changed path is ignored, | ||
| 169 | nothing runs. Both filters are evaluated against the range the push changed; a new | ||
| 170 | branch or tag has no previous tree, so every file counts as changed. | ||
| 171 | |||
| 172 | ### `on.change-request` | ||
| 173 | |||
| 174 | Runs when a change request changes. The run is checked out at the request's base | ||
| 175 | branch tip, not at the proposed head: an event run must not be a way to execute an | ||
| 176 | unapproved contributor commit. The proposed head and the changed files are in the | ||
| 177 | event payload. | ||
| 178 | |||
| 179 | ```yaml | ||
| 180 | on: | ||
| 181 | change-request: | ||
| 182 | types: [opened, updated, ready] | ||
| 183 | ``` | ||
| 184 | |||
| 185 | | Action | Meaning | | ||
| 186 | |---|---| | ||
| 187 | | `opened` | A request was created. | | ||
| 188 | | `updated` | Its head, base, title, description, or followed branch changed. | | ||
| 189 | | `ready` | The required approvals for the exact base and head were reached. | | ||
| 190 | | `closed` | It was closed without landing. | | ||
| 191 | | `merged` | It landed. | | ||
| 192 | |||
| 193 | The default is `[opened, updated, ready]`. An empty value means the default: | ||
| 194 | `change-request:` and `change-request: {}` are the same. | ||
| 195 | |||
| 196 | ### `on.issue` | ||
| 197 | |||
| 198 | Runs when an issue changes, at the default branch tip. | ||
| 199 | |||
| 200 | ```yaml | ||
| 201 | on: | ||
| 202 | issue: | ||
| 203 | types: [opened, closed] | ||
| 204 | ``` | ||
| 205 | |||
| 206 | Actions are `opened`, `edited`, `closed`, and `reopened`. The default is `[opened]`. | ||
| 207 | An empty value means the default. | ||
| 208 | |||
| 209 | ### `on.comment` | ||
| 210 | |||
| 211 | Runs when a comment on an issue or a change request is created, edited, or deleted. | ||
| 212 | The payload names the comment and the issue or change request it belongs to. | ||
| 213 | |||
| 214 | ```yaml | ||
| 215 | on: | ||
| 216 | comment: | ||
| 217 | types: [created] | ||
| 218 | ``` | ||
| 219 | |||
| 220 | Actions are `created`, `edited`, and `deleted`. The default is `[created]`. An | ||
| 221 | empty value means the default. | ||
| 222 | |||
| 223 | ### `on.schedule` | ||
| 224 | |||
| 225 | Cron schedules in UTC. A schedule queues the workflow at the default branch tip. | ||
| 226 | The field syntax is five fields — minute, hour, day of month, month, day of week — | ||
| 227 | with `*`, lists, ranges, and a step on `*` or a range. Names and `@shorthands` are | ||
| 228 | not accepted. | ||
| 229 | |||
| 230 | ```yaml | ||
| 231 | on: | ||
| 232 | schedule: | ||
| 233 | - cron: "0 3 * * 1-5" | ||
| 234 | ``` | ||
| 235 | |||
| 236 | At most 5 schedules may be declared. The run is queued once per matching minute; | ||
| 237 | a server that was not running for a slot does not replay it later. | ||
| 238 | |||
| 239 | ### `on.workflow-dispatch` | ||
| 240 | |||
| 241 | Marks a workflow as runnable by hand. The browser shows a **Run workflow** button | ||
| 242 | on the workflows page, and the CLI has `vole workflow dispatch`. | ||
| 243 | |||
| 244 | ```yaml | ||
| 245 | on: | ||
| 246 | workflow-dispatch: | ||
| 247 | inputs: | ||
| 248 | environment: | ||
| 249 | description: Where to deploy | ||
| 250 | type: choice | ||
| 251 | required: true | ||
| 252 | default: staging | ||
| 253 | options: [staging, production] | ||
| 254 | dry-run: | ||
| 255 | type: boolean | ||
| 256 | default: "true" | ||
| 257 | ``` | ||
| 258 | |||
| 259 | | Input field | Meaning | | ||
| 260 | |---|---| | ||
| 261 | | `description` | One line shown beside the field. | | ||
| 262 | | `type` | `string`, `boolean`, `number`, or `choice`. Default `string`. | | ||
| 263 | | `required` | The run is refused when the input has no value and no default. | | ||
| 264 | | `default` | Value used when the input is omitted. | | ||
| 265 | | `options` | The allowed values for `choice`. | | ||
| 266 | |||
| 267 | At most 10 inputs may be declared. A value must be one line and at most 4 KiB. | ||
| 268 | `choice` inputs need at least one option, and the default must be one of them. | ||
| 269 | A manual run is available to maintainers and instance admins, and the selected | ||
| 270 | branch must exist. | ||
| 271 | |||
| 272 | ### Event data available to steps | ||
| 273 | |||
| 274 | Every run has a `trigger_kind` (`push`, `change_request`, `issue`, `comment`, | ||
| 275 | `schedule`, or `workflow_dispatch`) and an action. A run started by a non-push | ||
| 276 | trigger also gets three variables: | ||
| 277 | |||
| 278 | | Variable | Value | | ||
| 279 | |---|---| | ||
| 280 | | `VOLE_EVENT` | The trigger kind, such as `comment`. | | ||
| 281 | | `VOLE_EVENT_ACTION` | The action, such as `created`. | | ||
| 282 | | `VOLE_EVENT_PATH` | Path to a JSON file, `/run/vole/event.json`. | | ||
| 283 | |||
| 284 | The JSON is pinned when the run is queued. It is data: read it with `jq` or a | ||
| 285 | program, never by interpolating it into a shell command. Common fields are | ||
| 286 | `event`, `action`, `repository`, `ref`, `branch`, `commit`, `sender`, and for a | ||
| 287 | change request `base_sha`, `head_sha`, and `changed_files`. The entity is under | ||
| 288 | `issue`, `change_request`, or `comment`; a manual run puts its resolved values | ||
| 289 | under `inputs`. Long bodies are clipped at 16 KiB and the payload marks that with | ||
| 290 | `body_truncated`. | ||
| 291 | |||
| 292 | These variables are set by the runner and cannot be replaced by a workflow's | ||
| 293 | `env:`, the same rule as `CI` and `HOME`. | ||
| 116 | 294 | ||
| 117 | 295 | ### `jobs` | |
| 118 | 296 | ||
| @@ -355,12 +533,10 @@ longer the newest commit on its branch. See [Workflows § Publish a website](../ | |||
| 355 | 533 | ||
| 356 | 534 | ## What a workflow cannot express | |
| 357 | 535 | ||
| 358 | The format deliberately supports only push triggers and jobs of shell steps. It | ||
| 359 | does not support: | ||
| 536 | The format deliberately supports push and event triggers with jobs of shell steps. | ||
| 537 | It does not support: | ||
| 360 | 538 | ||
| 361 | 539 | - a job graph: there is no `needs`, no job outputs, and no shared artifacts between jobs | |
| 362 | - non-push triggers: no `on.change_request`, `on.schedule`, or `on.workflow_dispatch` | ||
| 363 | - path filters (`paths`, `paths-ignore`) or negated branch patterns (`!main`) | ||
| 364 | 540 | - a build matrix or per-step conditions (`strategy`, `if`, `continue-on-error`) | |
| 365 | 541 | - secrets, secret masking, or an audit trail for secret use | |
| 366 | 542 | - expressions or contexts (`${{ }}`); nothing outside the shell is interpolated | |
| @@ -371,11 +547,12 @@ does not support: | |||
| 371 | 547 | - reusable workflows or composite actions (`uses:`); shell in an image is the | |
| 372 | 548 | reuse mechanism | |
| 373 | 549 | - environments, deployment approvals, per-job permissions, or OIDC | |
| 550 | - event payloads larger than 64 KiB; a long body is clipped in the pinned event | ||
| 374 | 551 | ||
| 375 | Change-request results are produced automatically by the server for a commit | ||
| 376 | under review; they are not an `on:` trigger a workflow can declare. A local | ||
| 377 | `vole workflow run` ignores `on.push` and `runs-on`, publishes no artifacts, and | ||
| 378 | deploys no site. | ||
| 552 | Combined results for a commit under review are still produced automatically by the | ||
| 553 | server; `on.change-request` is the event trigger, not the combined-result scheduler. | ||
| 554 | A local `vole workflow run` ignores triggers and `runs-on`, publishes no artifacts, | ||
| 555 | deploys no site, and has no event payload. | ||
| 379 | 556 | ||
| 380 | 557 | ## Validation and pinning | |
| 381 | 558 | ||