Skip to content

Publishing

During development, the implementation builds from the local directory:

runtime:
type: container
build:
context: ./worker

That is not publishable — whoever consumes it needs the finished image, not the source. A CI job does not have your directory either, so oren generate refuses implementations like this.

Terminal window
docker build -t ghcr.io/youraccount/oren-my-task-alpine:1.0.0 worker/
docker push ghcr.io/youraccount/oren-my-task-alpine:1.0.0
runtime:
type: container
image: ghcr.io/youraccount/oren-my-task-alpine:1.0.0
Terminal window
oren install # resolves the tag to a digest

With the image up, the contract goes to the catalogue:

Terminal window
oren publish .

The repository should reflect the implementation, not the task:

oren-build-docker-image-kaniko
oren-push-docker-image-skopeo
oren-analyze-commits-alpine

The suffix makes it evident that this is one way of satisfying the contract. Someone publishes -buildkit and the two coexist in the catalogue, comparable by the privilege they require. Named after the task, it would look like the implementation.

terraform-plan and terraform-apply are different contracts — different effects, outputs and dependencies — but use the same binary. Both implementations point at the same image and pick the script by entrypoint:

runtime:
image: ghcr.io/acme/oren-terraform-hashicorp:1.0.0
entrypoint: ["/worker/plan.sh"]

A subcommand is an entrypoint, and the implementation is what chooses it — not an input of the contract. Merging the two into one contract with a command field would force declaring the worst case in effects, losing the information that planning is safe to repeat.

Republishing a version with different content breaks whoever depends on it, with no signal — and silently transfers the access authorisation someone granted to the previous version.

To publish again, bump the implementation’s version.

oren publish is all-or-nothing: it sends the contract, then each implementation. Because a published version is immutable, a worker whose contract changed but whose implementations did not is rejected at the first implementation that already exists.

Bumping their version just to get the command through has a cost: whoever depends on them receives a new version with no difference at all, and oren.lock records a swap that never happened.

Terminal window
oren publish ./my-worker --only task

The symmetric case holds too — the contract goes first, so a new implementation over an unchanged contract would fail on the contract:

Terminal window
oren publish ./my-worker --only implementations