Per-environment properties
deploy.region: us-central1deploy.trafficPercent: 50deploy.platforms: [linux/amd64, linux/arm64]deploy.canary: falsepipelines: deploy: propertyFiles: production: ./config/production.yaml staging: ./config/staging.yaml steps: - id: publish task: techlite/gcp-cloud-deploy@^1.0.0 implementation: techlite/gcp-cloud-deploy-gcloud inputs: region: ${properties.deploy.region}oren run deploy -p production-p accepts an alias declared in propertyFiles or a direct path.
An alias can say which branch it belongs to
Section titled “An alias can say which branch it belongs to”Only for oren generate, and only when you want CI to pick the environment on
its own:
propertyFiles: producao: file: ./config/producao.yaml branches: [main] staging: file: ./config/staging.yaml branches: [develop, 'feature/*']The short form still works, and both live side by side in the same pipeline.
branches changes nothing about oren run — there the alias stays an
explicit choice by whoever runs it. It does not read git to guess the branch, or
the same command would start meaning different things depending on where it is
typed.
The map lives here, and not inside the properties file, because that file has no
schema: it is free, and you put whatever keys you want in it. A reserved
branch: field inside it would end that.
See Running in CI for what each platform generates from it.
A property can point at a step’s output
Section titled “A property can point at a step’s output”A property value may itself be an expression:
versao: ${outputs['versao'].version}
# config/develop.yamlversao: ${outputs['versao'].candidateTag}inputs: image: registry/app:${properties.versao}This is the one thing no plain value can do: choose a different field of the
same output. ${outputs['versao'].${properties.campo}} is not expressible, and
should not be — so the choice moves into the property file, where it is one line
per environment.
It is what lets a single pipeline serve two branches: main publishes
0.1.4, develop publishes 0.1.4-rc.b43c8f5.20260809035558, and nothing in
oren.yaml changes.
Only outputs and env are resolved inside a properties file. A property
cannot reference another property — which removes the cycle problem entirely,
and keeps the file from becoming where the logic hides.
Secrets carry over. A property that interpolates a secret output comes out marked as secret, and is redacted the same way. Without that, passing a credential through a property would launder it into the logs.
A step can be conditional
Section titled “A step can be conditional”enabled accepts a boolean or an expression:
- id: tag enabled: ${properties.commita} task: techlite/commit-and-tag@^2.0.0 implementation: techlite/commit-and-tag-alpineOnly properties and env — never outputs. Which steps run has to be known
before the run starts; that is what lets oren validate and the CI
generator say anything at all about the pipeline.
It must resolve to a real boolean. The string "false" is refused rather than
coerced: accepting it would run the step exactly against what was written.
It does not disappear from oren validate
Section titled “It does not disappear from oren validate”A step that vanished depending on a value would be the very defect this project exists to avoid. So it is always listed:
[8/8] Commit and tag · tag · commit-and-tag conditional · enabled = ${properties.commita}With --properties, the same line becomes concrete — → runs or → skipped.
The flag is optional: without it every step is still validated, and only the
decision is left open.
It is still locked
Section titled “It is still locked”oren install needs no --properties, and locks the conditional step anyway.
The rule is that the lock excludes only what the file proves never runs. A
literal enabled: false proves it, and stays out of the lock — which is what
lets you park a step whose worker is not published yet. An expression proves
nothing at install time, so it is locked, and the decision is left to the run.
That is what keeps oren.lock independent of which properties file was used.
oren generate is the exception
Section titled “oren generate is the exception”A generated CI has a fixed set of jobs, and ${properties.commita} does not
exist inside GitLab or Cloud Build to be evaluated there. So the decision has to
be made at generation time:
oren generate gitlab entrega -p main # 8 jobsoren generate gitlab entrega -p develop # 7 jobsWithout the flag, generating a pipeline that has a conditional step is refused and names the step. Deciding on its own would silently produce a CI different from the one asked for.
Why YAML and not .properties
Section titled “Why YAML and not .properties”A dotted key gives the visual simplicity of a .properties file, but the format
is YAML because of types: contracts declare integer, boolean and
array, and a format where everything is a string would force conversion by the
destination’s type — making the same file behave differently depending on who
consumes it.
Here 50 is a number, false is a boolean and the list is a list.
Explicit nesting works too, and both forms coexist in the same file. What is not allowed is the same key being a value and a grouping at once — one of the two would be lost silently.