Environments
Warning
This feature is under license.
Note
Documentation is in progress.
The Environments home
Environments in the user menu opens a matrix: one row per project, one column per environment,
and in each cell what that project currently has running in that environment.
- A cell shows the deployed build, its top promotion and how long it has been there, with an overlay for a deployment still on its way, a red dot when that deployment is held up, and a behind badge when an environment earlier in the chain holds something newer. Clicking a cell opens the slot drawer, which shows what is deployed now, what is in flight, what could go next and the last few deployments.
- A project deploying more than once into the same environment — a canary, for instance — has one row per qualifier, nested under the project's own row.
- A column is only drawn for an environment some visible row has a slot in.
- The toolbar filters by project name, by favourites or all projects, by project label and by environment tag, and can keep only what has a deployment on the way. The filters are part of the address, so a filtered matrix can be bookmarked and shared.
- The matrix refreshes itself every 30 seconds and says when it last did.
Creating environments and slots is behind the Setup command, out of the way of the operational screens — see Setup — and is usually not done by hand at all, see Configuration.
The slot page
Clicking Open slot in the drawer opens that slot's own page — "production · petclinic [canary]". It is the home of one project's deployments into one environment.
- The header block is the drawer's own Now / In flight / Next, in full: what is deployed, what is trying to replace it and what could go next, with the one action that would move the deployment in flight. It refreshes itself every 30 seconds and says when it last did.
- Deployments is the whole history: number, build, status, who, when it started, how long it took, and the error if there was one. It can be filtered by status, by build and by user — user meaning anybody on the deployment's audit trail, not only whoever started it — and the filtering is done by the server, so the answers do not depend on how much of the history is on screen.
- Eligible builds lists what could go into the slot next, with Deploy on each. By default it lists the deployable builds — the ones the slot's rules already accept. The Show all eligible builds switch widens the list to every eligible one, so that "why can I not deploy this?" has somewhere to be asked.
- Setup holds the slot's settings — its description, and whether it admits agents — its admission rules and its workflows: adding, editing and deleting them, and deleting the slot itself. The whole tab is hidden from a user who may not configure the slot.
Agents admitted
A registered agent may start a deployment pipeline, start the deployment and finish it — or mark it as failed — only in a slot which admits agents, and only if its owner may. In any other slot, it is refused with a message saying so:
agent claude-code-ci[agent] may not start a pipeline on production/petclinic: the slot does not admit agents (agent policy)
A slot does not admit agents by default. Edit the settings in the slot's Setup tab, set
agentsAdmitted: true for the slot's environment in the CI configuration or in
the CasC, or call the updateSlot mutation.
Even in a slot which admits agents, an agent never satisfies a manual approval, whoever the rule lists: its approval is refused with "an agent cannot approve; ask owner", and the pipeline stays a candidate. This is how agent asks, human approves works for deployments: the agent starts the pipeline, a person approves it, and the agent — or anybody — then deploys. An agent never overrides an admission rule either.
Admission rules
A slot admits builds through its admission rules, and a build must pass all of them. Each one is
configured by its id and a ruleConfig:
| Rule | Id | Admits a build when |
|---|---|---|
| Branch pattern | branchPattern |
its branch matches includes and no excludes; with lastBranchOnly, deploying it also needs its branch to be the last of those branches |
| Promotion | promotion |
its branch has the promotion level; deploying it needs the build to be promoted to it |
| Environment | environment |
it has been deployed in the slot of environmentName (and qualifier) |
| Manual approval | manual |
someone approves the deployment, optionally restricted to users or groups |
| Version pattern | versionPattern |
its version matches includes and no excludes |
Version pattern
The version pattern rule reads the build's version: its release
label when it has one, its name otherwise. It tells a GA or a beta from an alpha when they all come
from the same branch and reach the same promotion, which neither branchPattern nor promotion
can.
includes— regular expressions, one of which the version must match. None means every version.excludes— regular expressions, none of which the version must match. An exclusion wins over an inclusion.
Every expression must match the whole version, ignoring case: \d+\.\d+\.\d+ admits 6.0.0
but not 6.0.0-alpha.3. The expressions are read both by Yontrack and by its database, so keep to
the syntax they share — classes such as \d, groups, alternations and quantifiers. A pattern
either of them refuses, like a possessive \d++ or an inline (?i), is refused when the rule is
saved.
The version is a fact of the build, so a build the rule admits is both eligible and deployable.
For example, GA and beta releases, but no alpha nor release candidate:
admissionRules:
- ruleId: versionPattern
ruleConfig:
includes:
- "\\d+\\.\\d+\\.\\d+(-beta\\.\\d+)?"
Eligible and deployable builds
Every admission rule of a slot answers two questions about a build:
- Eligible — the build could go to this slot. A deployment can be started for it, and waits as
a candidate. For the
promotionrule, the build's branch has the promotion level. - Deployable — the build can go now: its candidate would run at once. For the
promotionrule, the build itself is promoted to that level.
A build can be eligible and not yet deployable — not promoted yet, not deployed in the previous
environment yet, or not on the last branch when the branchPattern rule has lastBranchOnly.
Starting a deployment for it is allowed: the candidate becomes runnable once the rules accept it.
The deploy dialog opened from a build, and its mobile counterpart, say so beside the slot — Not
deployable yet: Build not promoted — and still offer the action.
A manual approval is given on the deployment itself, so it can never be satisfied before the
deployment exists. It is not counted against deployability; the deploy dialog only notes Needs
approval once started.
In the GraphQL API:
Slot.eligibleBuildsandSlot.eligibleBuildreturn the deployable builds by default. Passdeployable: falseto get every eligible build.eligibleSlotsForBuildgives, for each slot of the build's project,eligibleandnonEligibleRules, and alsodeployable,nonDeployableRules(each with the rule and its reason) andpipelineOnlyRules(the rules decided on the deployment only, likemanual).startSlotPipelinecreates a candidate for any eligible build. Whether it can run is on the returned pipeline, inrunAction { ok }andadmissionRules { check { ok reason } }.Build.readiness(slotId)lists, in one read, everything the build still lacks for one slot: the rules which make it not eligible or not deployable, and a manual approval not given yet. See Readiness.
The deployment page
Clicking a deployment — from the matrix cell's drawer, from a slot, or from a build — opens that one deployment. It answers three questions, in three places:
- The header names the build, its branch and its top promotion, says when the deployment started and who started it, and draws where it has got to: Candidate → Running → Deployed, or → Cancelled, or → Failed. Beside the bar is the one action that would move it — Start the deployment on a candidate, Finish the deployment on a running one — with Cancel as a secondary action, and Mark as failed on a running one (see Failed deployments). The action is disabled while something is blocking, and is not shown at all to a user without the right, or on a deployment which is over.
- What's blocking lists the checks of the phase the deployment is in, failing ones first, with the fix on the failing row itself: Answer a rule waiting on somebody, Override a rule or a workflow which refuses. Checks which passed are folded behind "N of M checks passed". The phases already over are below, collapsed and read-only; a finished deployment has no current phase and shows all of them, expanded.
- A check which is only pending — a workflow still running or not started yet, a manual approval nobody has answered — blocks the deployment like a failed one, but is not drawn as an error: it shows a spinner or an hourglass, reads Running or Waiting, and the header says what the deployment is waiting for in a blue notice rather than a red one. A failed check stays red.
- The timeline down the side is the audit trail, newest first: every status change, every answer given to a rule, and every override — with the justification its author wrote.
The page refreshes itself every 30 seconds and says when it last did. Force deployment and Delete deployment remain header commands, and are hidden from a user without the right.
Failed deployments
A deployment goes through CANDIDATE and RUNNING, and ends as one of:
| Status | Meaning |
|---|---|
DONE |
The build is deployed: it is now what the slot runs. |
FAILED |
The deployment ran and did not make it. |
CANCELLED |
The deployment was stopped — by hand, or because a more recent deployment replaced it. |
A failed deployment is not a cancelled one: it was attempted, and its failure is a fact worth keeping — the delivery scorecard counts it in the success rate and the time to restore of the slot, where a cancelled deployment is left out.
- Only a
RUNNINGdeployment can be marked as failed; a candidate which never started is cancelled instead. It needs the same right as finishing a deployment, and takes an optional message saying why it failed. FAILEDis final: a failed deployment cannot be finished, even by forcing it, nor cancelled. Deploying the build again means starting a new deployment.- A failure does not change what the slot runs: the last
DONEdeployment stays the deployed one. - On the deployment page, Mark as failed sits beside Finish the deployment, and the timeline shows the failure with its message. The matrix, the slot drawer and the slot page show the Failed status. The mobile UI shows it too, without offering to mark a deployment as failed: a failure is reported by the CI which ran the deployment.
- Marking a deployment as failed sends the
slot-pipeline-failedevent, and runs the slot workflows whose trigger isFAILED(On deployment failed).
From CI, or any automation, through GraphQL:
mutation {
failSlotPipeline(input: {pipelineId: "...", message: "Helm upgrade timed out"}) {
failStatus { ok }
errors { message }
}
}
or with the KDSL, pipeline.fail(message = "Helm upgrade timed out").
Backdating deployments
A deployment can be recorded after the fact — when importing a deployment history, for example,
or when the CI reports late. The GraphQL mutations moving a deployment accept an optional
dateTime, which is then used instead of the current time:
| Mutation | dateTime is |
|---|---|
startSlotPipeline |
the start of the deployment |
startSlotPipelineDeployment |
the time it started running |
finishSlotPipelineDeployment |
its end, as DONE |
failSlotPipeline |
its end, as FAILED |
cancelSlotPipeline |
its end, as CANCELLED |
The time is stored on the deployment — its start and end — and in its history. It must be:
- not in the future;
- not before the creation of the build;
- not before the previous change of the deployment;
- for a start, not before the start of the slot's latest deployment.
A time breaking one of these rules is refused, and nothing changes. So, a slot's history is recorded in order: deployment by deployment, oldest first.
Starting a deployment cancels the slot's deployment still in progress, if any, and that
cancellation takes the start time of the new deployment. Without a dateTime, nothing is checked
and the current time is used, as before.
Backdating needs no other right than the action's own. The events are sent, and the slot workflows run, as for any other deployment — at the time they are recorded, not at the backdated one.
In the KDSL:
build.startPipeline(slot, dateTime = start)
.startDeploying(dateTime = start.plusMinutes(1))
.finishDeployment(dateTime = start.plusMinutes(10))
// or .fail(message = "...", dateTime = ...), or .cancel(reason = "...", dateTime = ...)
Setup
The Setup command on the Environments home opens the one page where environments and slots are created, edited and deleted. It is deliberately out of the operational screens: configuring is not what somebody opens the Environments home to do, and in practice it is done as code — see Configuration.
- Environments lists every environment in order, with its icon (editable in place), its tags and how many slots it has. New environment lives here, and so does deleting one.
- Slots lists every slot grouped by project, with its qualifier, its environment, how many admission rules and workflows it carries, and a link to that slot's own Setup tab. New slot lives here.
Every control is hidden from a user without the matching right, and the Setup command itself is hidden from a user who has none of them.
Configuration
While environments and their slots can be configured through the UI, it's recommenced to use either:
CI configuration
Using the CI config feature, one can define the environments and slots linked to a project directly from its Yontrack CI config file.
For example:
version: v1
configuration:
defaults:
project:
environments:
environments:
- name: self.yontrack.com
description: Production environment for Yontrack itself
order: 200
tags:
- yontrack
- release
slots:
- project: yontrack
environments:
- name: self.yontrack.com
agentsAdmitted: true
admissionRules:
- ruleId: promotion
ruleConfig:
promotion: GOLD
- ruleId: branchPattern
ruleConfig:
includes:
- main
workflows:
- name: Creation
trigger: CANDIDATE
nodes:
- id: start
executorId: mock
data:
text: Start
- id: end
parents:
- id: start
executorId: mock
data:
text: End
In this case, unless in the CasC setup where this behavior is configurable, the environments are not authoritative. Only the slots are for the configured project.
A typical use case for this CI config of environments would be done at the level where the actual environment is actually deployed, like in a GitOps repository.
CasC
The environments section of the CasC takes the same environments and slots as the
CI configuration, agentsAdmitted included.
Removed setting: settings.environments
The environments extension used to contribute a buildDisplayOption setting, which chose how a
build's environments were drawn on the promotion dots of the build page. Those dots are gone —
a build's environments are now the journey strip on the build page, which always shows every
slot of the project — and the setting went with them.
A casc.ontrack.config.settings.environments block left in a configuration-as-code file is
rejected as an unknown settings section, so remove it when upgrading.