Changelog#

Unreleased#

Added#

Entity models accept a validate list of checks, each with an assert Jinja expression (written without {{ }}) and a message that may contain Jinja. The checks run against each enabled instance after its pre_defines, parameters and post_defines are rendered, so they can read fields of object parameters, for example assert: interrupt_vector.count == 3. A false assertion stops generation with <module>.<name>: validation failed: <message> (#64).

Templates can read the ibek process environment with {{ env.NAME }}, {{ env['NAME'] }}, or {{ env.get('NAME', 'fallback') }}. The mapping is read-only and reflects the environment at render time.

Direct access to a missing variable fails in entity expressions; use get when a fallback is intentional. An empty but defined variable remains empty. The final assembly templates retain their existing permissive handling of missing values. Existing entity fields and shared variables named env take precedence over the new helper.

_global remains supported, with no deprecation or migration requirement. In particular, _global.get_env('NAME') still returns an empty string for an unset variable. Older ibek releases without the new env mapping should continue to use that form.

ibek pattern add takes --include SRC=DEST and --exclude SRC to vendor pattern files the manifest leaves out, to a chosen destination, and to drop files the manifest vendors, for one instance. The selection is recorded as a per-pattern select: in runtime-lock.yaml and reapplied by update and restore. A lock with a selection is written as version: 2; one without stays version: 1, byte for byte. ibek releases that read only version 1 refuse a version 2 lock with “unsupported lock version 2”. See docs/how-to/select-pattern-files.md (#378).

A standalone scripts/convert-runtime-lock.py rewrites a runtime-lock.yaml that is not in the version:/patterns: shape this ibek reads. Run it once per destination, from an ibek checkout: uv run scripts/convert-runtime-lock.py <dest>/runtime-lock.yaml; or from anywhere, including a services repo with no ibek checkout, straight from its raw URL: uv run https://raw.githubusercontent.com/epics-containers/ibek/main/scripts/convert-runtime-lock.py <dest>/runtime-lock.yaml (#363).

Changed#

runtime-lock.yaml refuses top-level keys other than version and patterns rather than ignoring them and dropping them on the next save (#378).

ibek pattern check/add/update refuse a runtime-lock.yaml in any format they do not recognise, rather than special-casing one earlier shape. If you see “lock format not recognised”, convert the lock with uv run scripts/convert-runtime-lock.py <lock> and retry (#363).

The pvi dependency floor is now 0.14.1, with no ceiling. Generated PVI screens use pvi’s updated widget styling (fonts, colours and layout), so the test goldens under tests/samples/outputs were regenerated to match.

The pvi dependency floor is now 0.14.2b1. Each field of a generated $(P)PVI group now names itself as its +trigger, matching the mapping QSRV (pvxs) applies by default, so pvxs no longer logs “Group …PVI defines no +trigger mappings” for every PVI group at IOC start. The *.pvi.template test goldens under tests/samples/outputs were regenerated to match.

Fixed#

A plain dest whose last part has a file extension, in a pattern add --include SRC=DEST or a manifest rule, is the destination file: --include 'sim/x_sim\.template=config/x.template' writes config/x.template. Such a dest that matches more than one file is refused. A dest ending in / is always a folder.

Re-adding or updating a pattern replaces that pattern’s files whatever file and folder shapes its previous file-set left, including a folder where the new file-set writes a file and a file where it needs a folder. A path in the way that holds files the pattern did not vendor is refused before anything is written.

ioc.subst rows for a database file shared by several entity models are now written in the order of the file’s headings. Previously each row followed its own entity model’s arg order, so values could land under the wrong heading when two models listed the same args in a different order. Every entity that loads the same database file must now supply the same set of args; a mismatch fails with an error naming the file, the entity type and the missing and extra args, instead of writing a misaligned pattern row (#349).

ibek pattern schema failed with CERTIFICATE_VERIFY_FAILED on RHEL when run through uvx, because the uv-managed Python looks for CA certificates at /etc/ssl/cert.pem. Schema downloads now verify against the operating system trust store with truststore (#364).

The published schema cache no longer assumes release tags are immutable. Each run revalidates the cached copy with If-None-Match / If-Modified-Since, and uses the cached copy when a fetch fails.

A failed fetch no longer leaves a possibly stale ioc.schema.json in place silently. If nothing is cached for the image tag and the instance already has a schema, ibek pattern schema exits 1. Only a 404 or 410 response still skips generation quietly.

ibek pattern schema parses more image refs. A registry port such as localhost:5000/org/ioc-x-runtime:1.0 is no longer read as the tag, and a ref with no registry host such as epics-containers/ioc-x-runtime:1.0 no longer loses its org. A -linux architecture infix is stripped like -rtems-beatnik. An image on a GitLab registry now reports that GitLab-published schemas are not supported yet, instead of failing to fetch a GitHub URL built from the wrong project (part of #375).

The published schema cache is keyed on registry host, full image path and tag (<host>/<path>/<tag>.json), so images with the same name on different registries no longer share an entry. Entries in the old <org>__<repo>__<tag>.json layout are not read; each schema is downloaded once more (part of #375).

Documentation#

Replaced the maintained guides and references with compact documentation of the CLI lifecycle, YAML and Jinja rendering, ibek-support Ansible recipes, and ibek’s role in epics-containers. Added runnable rendering tutorials and documented the persistent schema cache used by ibek pattern (issue #365).

Published releases are listed on GitHub.