Writing a contract
apiVersion: oren.sh/v1kind: Taskmetadata: name: count-lines namespace: acme # required in order to publish version: 1.0.0 summary: Counts the lines of code in a projectspec: effects: none inputs: type: object properties: extension: type: string default: js outputs: type: object required: [total] properties: total: { type: integer } dependencies: source: type: directory mutable: falseInputs and outputs are JSON Schema, with one extra keyword: secret.
Unknown fields are refused
Section titled “Unknown fields are refused”A field that is not in the contract fails the step, with a suggestion:
unknown field: "incremenMajorVersion" — did you mean "incrementMajorVersion"?This is not gratuitous strictness. In the pipeline that gave rise to this
project, the worker read incremenMajorVersion while the pipeline sent
incrementMajorVersion — without the “t”. Major and patch were never
incremented, for sixteen releases, without a single error.
effects
Section titled “effects”Determines whether the result may come from the cache.
| Value | Cacheable | Safe to repeat | Example |
|---|---|---|---|
none |
yes | — | analysing commits, computing a version |
reads-external |
no | yes | terraform plan |
external |
no | no | publishing an image, creating a remote tag, deploying |
The criterion: if I run it again with the same inputs and nothing happens,
is the pipeline still correct? If not, it is external.
The mistakes are not symmetric. Marking external too often costs cache.
Marking it too rarely produces a silently absent deploy, with the pipeline
reporting success. When in doubt, external.
reads-external is the middle case: it changes nothing, but reads mutable
external state. Caching would return a stale reading, but repeating is safe.
Secret fields
Section titled “Secret fields”token: type: string secret: trueValid in inputs and outputs. The value is redacted in logs, stays out of the lockfile and of the on-disk state, and contaminates any field that interpolates it.