Definitions and versions
Change a pipeline as a new version, read earlier versions, go back to one, and delete versions and pipelines.
Last updated
On this page
Description and operation
General
A pipeline is a name for an owner and a list of numbered versions. Each version holds one definition and never changes. A run records the version that it ran, so a later change does not alter a run that exists. The format of a definition is in Pipeline definition.
| Action | Result |
|---|---|
| Create | Saves version 1 and answers 201. The name in the definition is the name of the pipeline. It has 1 to 63 lowercase letters, digits and inner hyphens. |
| Update with a changed definition | Saves the next version. A run that starts later uses it. |
| Update with an equal definition | Saves nothing and answers 200 with the newest version. |
| Go back | Send an earlier definition again. It becomes the next version. |
| Delete a version | Removes one old version that no queued or running run uses. |
| Delete the pipeline | Removes the pipeline and all its versions. Finished runs stay. |
A save checks the whole definition and reports every problem at once, each with its job and step. A save also checks facts about the owner. Each secret that the definition names exists. The pipeline of an after trigger exists. Each volume or snapshot that a job names exists, or an earlier job saves to it.
A definition larger than 64 KiB is refused with 422 before any other check. A definition that saves is a definition that can run.
To do these tasks with an AI agent, see Agentic workflows – General.
Canonical form
The platform stores each definition in a canonical form. It keeps the order of jobs, inputs and each matrix as you wrote them, sorts every other map and leaves out every default value. Two spellings of one definition have the same definitionSha256, so a save of an equal definition makes no new version.
| Field of the answer | Meaning |
|---|---|
owner, name | The owner and the name of the pipeline. |
version | The version that the answer shows. |
latestVersion | The newest version of the pipeline. |
definitionSha256 | The SHA-256 hash of the canonical definition. A run records the same hash. |
createdBy, createdAtMs | Who saved the version, and when, in milliseconds since the epoch. |
definition | The definition of the version, with jobs in the order that you wrote them. |
triggers | The schedule, webhook and after trigger of the version. |
webhook | set is true when the pipeline has a webhook secret. |
webhookUrl | The webhook URL. Only in the answer of the save that made the webhook secret. |
Delete rules
You cannot delete the newest version. You cannot delete a version, or a pipeline, while a queued or running run uses it. A finished run of a deleted version stays readable, without its definition. Run records are kept for 90 days after the run ends.
Tasks
Save a new version
Reason for the task: Change what a pipeline does, and keep the earlier definition.
Job set-up
- Access: you. For a team, an admin.
- Conditions: the pipeline
nightly-reportexists, andnightly-report.jsonholds its changed definition. Thenamein the file isnightly-report. - References:
PUT /v1/pipelines/{owner}/{name}, SDKpipelines.update. In the CLI,--file -reads the definition from standard input, and--ownerdefaults to your handle.
Procedure
Send the changed definition as the next version.
import jsonfrom kloudlite import Kloudlitekl = Kloudlite()with open("nightly-report.json") as f: doc = kl.pipelines.update(owner="acme", name="nightly-report", definition=json.load(f))print(doc["version"], doc["latestVersion"])import { readFileSync } from "node:fs";import { Kloudlite } from "./index.ts";const kl = new Kloudlite();const definition = JSON.parse(readFileSync("nightly-report.json", "utf8"));const doc = await kl.pipelines.update({ owner: "acme", name: "nightly-report", definition });console.log(doc.version, doc.latestVersion);kl := kloudlite.New(kloudlite.Options{})raw, err := os.ReadFile("nightly-report.json")if err != nil { log.Fatal(err)}var d kloudlite.PipelineDefinitionif err := json.Unmarshal(raw, &d); err != nil { log.Fatal(err)}doc, err := kl.Pipelines.Update("acme", "nightly-report", d)if err != nil { log.Fatal(err)}fmt.Println(doc.Version, doc.LatestVersion)require "json"require_relative "kloudlite"kl = Kloudlite::Client.newdoc = kl.pipelines.update(owner: "acme", name: "nightly-report", definition: JSON.parse(File.read("nightly-report.json")))puts doc.values_at("version", "latestVersion").join(" ")var kl = new Kloudlite();System.out.println(kl.request(new Kloudlite.RawRequest().method("PUT").path("/v1/pipelines/acme/nightly-report") .body(Files.readString(Path.of("nightly-report.json")))));kloudlite pipelines update acme/nightly-report --file nightly-report.json
Close-out
- Make sure that
versionis one more than before. An equal definition returns the sameversion.
Show the versions of a pipeline
Reason for the task: Find which definition a version holds, for example the version that a run used.
Job set-up
- Access: you. For a team, an active member.
- References:
GET /v1/pipelines/{owner}/{name}/versions,GET /v1/pipelines/{owner}/{name}, SDKpipelines.versions,pipelines.get.
Procedure
Show the list of versions, oldest first.
print(kl.pipelines.versions(owner="acme", name="nightly-report"))console.log(await kl.pipelines.versions({ owner: "acme", name: "nightly-report" }));versions, err := kl.Pipelines.Versions("acme", "nightly-report")if err != nil { log.Fatal(err)}fmt.Printf("%+v\n", versions)p kl.pipelines.versions(owner: "acme", name: "nightly-report")System.out.println(kl.pipelines().versions("acme", "nightly-report"));kloudlite pipelines versions acme/nightly-reportShow the definition of version 1. Leave out the version to show the newest.
print(kl.pipelines.get(owner="acme", name="nightly-report", version=1)["definition"])console.log((await kl.pipelines.get({ owner: "acme", name: "nightly-report", version: 1 })).definition);doc, err := kl.Pipelines.Get(kloudlite.GetPipeline{Owner: "acme", Name: "nightly-report", Version: 1})if err != nil { log.Fatal(err)}fmt.Printf("%+v\n", doc.Definition)p kl.pipelines.get(owner: "acme", name: "nightly-report", version: 1)["definition"]System.out.println(kl.pipelines().get("acme", "nightly-report", 1));kloudlite pipelines get acme/nightly-report --version 1
Close-out
- Examine
definitionSha256of the version and of a run. Equal values mean that the run used that definition.
Go back to an earlier version
Reason for the task: Undo a change that broke a pipeline, and keep a record of the change.
Job set-up
- Access: you. For a team, an admin.
- Conditions: the earlier version exists. See Show the versions of a pipeline.
- References: SDK
pipelines.get,pipelines.update.
Procedure
Read the definition of the earlier version, then send it as the next version.
old = kl.pipelines.get(owner="acme", name="nightly-report", version=1)["definition"]doc = kl.pipelines.update(owner="acme", name="nightly-report", definition=old)print(doc["version"])const old = await kl.pipelines.get({ owner: "acme", name: "nightly-report", version: 1 });const doc = await kl.pipelines.update({ owner: "acme", name: "nightly-report", definition: old.definition });console.log(doc.version);old, err := kl.Pipelines.Get(kloudlite.GetPipeline{Owner: "acme", Name: "nightly-report", Version: 1})if err != nil { log.Fatal(err)}doc, err := kl.Pipelines.Update("acme", "nightly-report", old.Definition)if err != nil { log.Fatal(err)}fmt.Println(doc.Version)old = kl.pipelines.get(owner: "acme", name: "nightly-report", version: 1)["definition"]puts kl.pipelines.update(owner: "acme", name: "nightly-report", definition: old)["version"]// The SDK returns raw JSON. Take "definition" from it with your JSON library, here Jackson.String doc = kl.pipelines().get("acme", "nightly-report", 1);String old = new ObjectMapper().readTree(doc).get("definition").toString();System.out.println(kl.request(new Kloudlite.RawRequest().method("PUT").path("/v1/pipelines/acme/nightly-report").body(old)));kloudlite pipelines get acme/nightly-report --version 1 --json | jq .definition > old.jsonkloudlite pipelines update acme/nightly-report --file old.json
Close-out
- Make sure that the new
versionis the newest, and that itsdefinitionSha256equals that of version 1.
Delete an old version
Reason for the task: Remove a version that is no longer needed. Version numbers are never reused, so this does not free a number.
Job set-up
- Access: you. For a team, an admin.
- Conditions: the version is not the newest, and no queued or running run uses it.
- References:
DELETE /v1/pipelines/{owner}/{name}/versions/{n}. The SDKs have no method for this route, so the procedure sends it as a raw request.
Procedure
Send the delete for version 1.
kl.request("DELETE", "/v1/pipelines/acme/nightly-report/versions/1")await kl.request("DELETE", "/v1/pipelines/acme/nightly-report/versions/1");if err := kl.Request("DELETE", "/v1/pipelines/acme/nightly-report/versions/1", kloudlite.RequestOptions{}); err != nil { log.Fatal(err)}kl.request("DELETE", "/v1/pipelines/acme/nightly-report/versions/1")kl.request("DELETE", "/v1/pipelines/acme/nightly-report/versions/1");
Close-out
- Show the versions of the pipeline. Make sure that version 1 is not listed.
Delete a pipeline
Reason for the task: Remove a pipeline that is no longer used, with all its versions and triggers.
Job set-up
- Access: you. For a team, an admin.
- Conditions: no run of the pipeline is queued or running. See Cancel a run.
- References:
DELETE /v1/pipelines/{owner}/{name}, SDKpipelines.delete.
The definitions of all versions are deleted, and the schedule and the webhook URL stop. Save the definition in a file first to keep it.
Procedure
Delete the pipeline.
kl.pipelines.delete(owner="acme", name="nightly-report")await kl.pipelines.delete({ owner: "acme", name: "nightly-report" });if err := kl.Pipelines.Delete("acme", "nightly-report"); err != nil { log.Fatal(err)}kl.pipelines.delete(owner: "acme", name: "nightly-report")kl.pipelines().delete("acme", "nightly-report");kloudlite pipelines delete acme/nightly-report
Close-out
- Show the pipelines of the owner. Make sure that
nightly-reportis not listed. - Read a finished run of the pipeline. It stays readable for 90 days after it ended.
Troubleshooting
| Symptom | Possible cause | Corrective action |
|---|---|---|
422 with pipeline nightly-report is invalid: and a list of lines | The definition has errors. Each line names the job and the step. | Correct each line and send the definition again. |
422 with `name` is nightly but the path names nightly-report | The name in the definition differs from the pipeline that you update. | Use the same name. To rename, create a new pipeline and delete the old one. |
422 with secret DB_URL does not exist | The definition names a secret that the owner does not have. | Set the secret, then save again. |
422 with `triggers.after`: no pipeline build | The after trigger names a pipeline that does not exist. | Create that pipeline first, or correct the name. |
409 with pipeline nightly-report exists | A create used the name of a pipeline that exists. | Send an update to save a new version. |
409 with pipeline nightly-report changed; retry | Another save won the race. | Read the pipeline again and send the save again. |
409 with pipeline nightly-report has 100 versions; delete an old version | The newest version number is 100, and a deleted version does not free a number. | Create a new pipeline with the definition. |
409 with version 3 is the latest; it cannot be deleted | You tried to delete the newest version. | Save a new version first, or delete the pipeline. |
409 with version 1 is used by run 1760400000000-0a1b2c | A queued or running run uses the version. | Wait for the run to end, or cancel it. |
409 with pipeline nightly-report has a queued or running run | A run has not ended. | Cancel the run, or wait for it to end. |
409 with pipeline nightly-report is being deleted; retry | A pipeline of this name is still being deleted. | Send the save again. |
404 with not found | An update names a pipeline that does not exist. | Create the pipeline first. |
404 with version 1 of nightly-report is gone | The version was deleted, or never existed. | Show the versions and use one that is listed. |
400 with version is not a number | The version in the request is not a number. | Give the version as a number, for example 2. |
503 with secrets cannot be read right now; retry, or the same text with pipelines or volumes | A check of the save could not read its data. | Send the save again. |