Context for AI agents (and humans) contributing to this Digital.ai Release
container plugin. Read this first, then see the
Plugin Development Guide for the full how-to. There is also a
portable SKILL.md that routes to both.
- A container plugin for Digital.ai Release. It contributes custom task types.
- Each task is a Python class in
src/that subclassesBaseTask(orApiBaseTask) from thedigitalai-release-sdk. - It is NOT a pure Python package and is never published to PyPI. The
src/tree is copied into a Docker image and executed there by the SDK wrapper (python -m digitalai.release.integration.wrapper, see theDockerfile). - Building produces two artifacts: a plugin zip (type definitions + icons from
resources/, installed into Release) and a Docker image (thesrc/code, pushed to a registry). Thebuild.sh/build.batscripts produce both.
Release identifies a task by its type (e.g. containerExamples.Hello). At run time the
wrapper:
- takes the part of the type after the dot →
Hello; - locates the
.pyfile — from the task'sscriptLocationif set, otherwise the file under the image that defines a class named exactlyHello; - imports it and calls
execute().
Therefore:
- The class name after the dot must match exactly (case-sensitive).
- Without
scriptLocation, resolution is by class name and the file name is irrelevant. WithscriptLocation, the path must point to the exact file undersrc/. Keep class names unique acrosssrc/. - A type defined in
resources/type-definitions.yamlwith no matching class (or vice-versa) is a bug.
- Declare the type in
resources/type-definitions.yaml(extendcontainerExamples.BaseTask; declareinput-properties/output-properties). - Add a class in
src/whose name matches the type after the dot; implementexecute(). - Add a unit test in
tests/unit/(and optionally a live test intests/integration/). - Bump
VERSIONinproject.properties, then build.
Inside execute():
self.input_properties—dictof inputs (keys = theinput-propertiesnames).self.set_output_property(name, value)— value must bestr,int,list,dict, orbool.self.add_comment(text)— adds a line to the task's UI comments.- Raise an exception to fail the task — the message is shown to the user. Do not swallow errors just to report them; the wrapper does that for you.
Use ApiBaseTask (not BaseTask) when the task calls the Release REST API: it
exposes ready-made self.releaseApi, self.phaseApi, self.taskApi, self.templateApi,
etc., all built from the task's "Run as user" context.
Note
The from com.xebialabs.xlrelease... imports are real Python classes provided by the
digitalai-release-api-client package (bundled with the SDK). They import fine under
CPython — they are not Jython-only.
requirements.txt— installed into the Docker image by the Dockerfile (pip install). This is the source of truth for the container runtime.pyproject.toml— the local dev environment, managed byuv.
A new runtime dependency must be added to both files. A dev-only/test dependency
goes in the dev extra of pyproject.toml only.
build.sh / build.bat read project.properties
(PLUGIN, VERSION, REGISTRY_URL, REGISTRY_ORG), substitute the @project.*@ /
@registry.*@ placeholders in resources/, build the zip, build & push the image.
./build.sh— build zip + image, push image../build.sh --zip/--image— build just one../build.sh --upload— also upload the zip to Release (configure.xebialabs/config.yaml).
Treat build.sh, build.bat, and the Dockerfile as canonical build machinery — change
them only with explicit intent. The normal release edit is bumping VERSION in
project.properties.
tests/unit/— fast, mocked, no network. Run in CI.tests/integration/— networked tests. Release-backed tests run against a live Release server and auto-skip when none is reachable (seetests/integration/conftest.py); third-party service tests require internet access.- Naming: the test file mirrors its
srcmodule —test_<module>.pyfor unit tests,test_<module>_live.pyfor live integration tests. - Tests are pytest style (plain functions +
assert, fixtures,parametrize,pytest.raises), notunittest.
Commands (run from the repo root):
uv sync --extra dev # set up the env
uv run pytest # all tests
uv run pytest tests/unit # fast unit tests only
uv run pytest -m "not integration" # same, by markerLive tests read RELEASE_SERVER_URL / RELEASE_USERNAME / RELEASE_PASSWORD
(defaults: http://localhost:5516, admin, admin).
Tip
uv on Windows: if uv warns that VIRTUAL_ENV does not match the project environment,
target the project's env explicitly: uv run --python .venv/Scripts/python.exe pytest.
- Match the surrounding code style; keep task classes small and single-purpose.
- Keep
type-definitions.yamlandsrc/classes in lockstep (the naming contract). - Don't add a runtime dep to only one of
requirements.txt/pyproject.toml. - Don't hand-edit generated build outputs (
build/,tmp/) — they are produced by the scripts. - Prefer
ApiBaseTaskwrappers over rawget_release_api_client()calls for Release APIs.