Releases: panter/catladder
Release list
v5.1.3
Patch Changes
- GitHub: the semantic-release release job now pushes the release commit and tag over ssh with the release deploy key (
CATLADDER_RELEASE_KEY), so the push passes the merge-gating ruleset instead of failing withGH013 … Required status check "catladder ✅" is expected— the changesets path already did. The release commit carries[skip ci]on GitHub so the explicitly dispatched tagged-release run stays the only one, the generated tagged-release workflow gets a per-tag concurrency group, andproject doctorreports a committed release workflow that still runs an older release image (regenerate withcatenv).
v5.1.2
Patch Changes
- Fix
catcicrashing withReferenceError: __dirname is not defined in ES module scopein projects whose rootpackage.jsondeclares"type": "module". The generated.catladder-generated/catci/folder now carries a siblingpackage.jsonpinning it to CommonJS, so the release guard, security audit and npm publish jobs run again on both backends.
v5.1.1
Patch Changes
-
fix(github): lowercase the GHCR image paths of mixed-case repositories
GHCR image repository names may not contain uppercase characters, but
${{ github.repository }}interpolates GitHub's display casing. Any
project whose GitHub owner or repo name has an uppercase letter (common
for org logins likeAcmeCorp) therefore failed every docker job
client-side, before any network call:invalid tag "ghcr.io/AcmeCorp/nautilus/catladder/docker-build:b343b099980e": repository name must be lowercasecatladder now resolves the repository from the git remote at generation
time and writes the lowercased path (ghcr.io/acmecorp/nautilus) into
both the workflow-levelCL_REGISTRY_IMAGEand thejobs.<id>.container.image
of every containerized job — the latter is resolved before any step
runs, so it could not have been fixed from a shell step. GHCR serves the
org under that lowercased namespace, so it is the correct address, not a
workaround.All-lowercase repositories are unaffected: they keep the
${{ github.repository }}expression, which stays correct in forks, so
generated output is byte-identical to before.Set
pipelines.github.repositorywhen generation cannot see the git
remote:pipelines: { github: { repository: "AcmeCorp/Nautilus" } },
catladder project doctornow reports a mixed-case repository whose
generated workflows still carry the expression.If you worked around this by hand-editing the generated workflows,
revert those edits after upgrading —.envrcrunseval "$(catenv)"
on everycdinto the repo, so regeneration overwrites them anyway.
v5.1.0
Minor Changes
- Review apps of a merge request can now be pinned so they outlive the auto-stop timer (gitlab). Review deploy jobs read their
auto_stop_infrom the pipeline variableCL_REVIEW_AUTO_STOP; a workflow rule sets it toneverwhile the MR carries the pin label (defaultcatladder::pin-review), so the pin lives on the MR and survives redeploys — unlike gitlab's per-environment pin button, which the next deploy resets. Merging or closing the MR still stops the apps.catladder mr pin/mr unpinmanage the label (creating it in the project when missing) andpintriggers a pipeline so the pin takes effect immediately. The previously hardcoded lifetimes are now configurable via top-levelautoStopin catladder.ts (reviewdefault "1 week",devdefault "4 weeks",pinLabel—falsedisables the mechanism). GitHub is unaffected: it has no auto-stop, review apps live until the pull request closes.
Patch Changes
- Fixed the bitwarden vault dropping secrets on a partial write: it rewrote an env/component's whole yaml note from the keys of that one write, so
project secrets-set dev:web API_KEYdeleted every other secret ofdev:webfrom the vault. Writes are now merged into the existing note, matching the gitlab vault's upsert semantics. project setupnow stores the credentials it provisions — the gcloud deploy service account key, the kubernetes deploy credentials — through the secrets vault and from there to every enabled CI backend, exactly like any other secret. Until now it wrote them straight into GitLab project variables: on a project without a GitLab pipeline the setup of a cloud run or kubernetes component died withError: not found(a 404 from the GitLab API against a host that is not a GitLab), and on a project with a bitwarden vault the credentials silently never reached the vault. The GitLab registry deploy token that kubernetes setup creates is now skipped when no GitLab pipeline is enabled, and a 404 from the GitLab API finally says which call failed against which host.
v5.0.1
Patch Changes
- Changesets releases now create the release entry on the git host (gitlab
/-/releases, github/releases) with the changelog as its description — previously only the tag was pushed, so the releases page stayed empty (on the semantic-release path@semantic-release/gitlabdid this). The api call never fails the job: the commit and tag are already pushed when it runs, so a missing token only warns. semantic-releaseon the github backend now creates the entry on the releases page too, via@semantic-release/github(the counterpart of the gitlab publish plugin, which is gitlab-only — on github the release used to end at the tag). Only the release is created: commenting on released pull requests/issues and labelling them stays off, so the release job keeps itscontents: write-only permissions. Projects with their own.releasercare unaffected, as before.
v5.0.0
Major Changes
-
customJobsjob model:needsStagesis removed in favour of semantic requirements — declarerequires: [{ capability: "deployment" }]instead ofneedsStages: [{ stage: "deploy" }](capabilities:build,qualityGate,deployment, withartifacts,fromandstrict). Jobenvironmentkeys are now platform-neutral:on_stop→onStop,auto_stop_in→autoStopIn, andactionis narrowed tostart|stop|access. Requirements that consume artifacts (artifacts: true) now fail pipeline generation when no job provides them, instead of silently deploying without them. -
Cloud Run
DATABASE_URL/DATABASE_JDBC_URLnow default todbConnectionStringVariablesMode: "embedded": connection strings contain the component's final values instead of$DB_USER/$DB_PASSWORDplaceholders, making them referenceable from other components (${otherComponent:DATABASE_URL}). Embedded mode also respectsvars.publicoverrides of theDB_*vars — a component reusing another component's database viadbBaseNameplusDB_PASSWORD: "${owner:DB_PASSWORD}"now gets the owner's password in its connection string (previously the component's own, usually unset, secret was embedded, producing a password-less URL). The deployed runtime values are unchanged for the common cases, since legacy placeholders were expanded at deploy time anyway — but the generated pipeline YAML changes for every project withcloudSql. SetdbConnectionStringVariablesMode: "legacy"to restore the old behaviour; that escape hatch will be removed in a future major. -
@catladder/pipelineis no longer published to npm. It was always an implementation detail compiled into the CLI;@catladder/cliis the only published package. Projects importing@catladder/pipelinedirectly must switch to the@catladder/cliexports. -
Job images are now always built from your repository (
jobImages: "repo"behavior); the central image registry mode has been removed. Image definitions are materialized into.catladder-generated/images/, tagged by content hash and built by the pipeline only when missing. Projects still configured with the central mode must drop that setting and commit the materialized image definitions on the next regeneration. -
Job images slim down. The
jobs-testing-chromeimage is removed and test/verify jobs now default tojobs-default: if your tests need a browser, pointtest.jobImage(orverify.jobImage) at an image that carries one — best the official playwright image matched to your dependency, e.g.jobImage: "mcr.microsoft.com/playwright:v1.49.0-jammy"— or declare a project image viaimages. The failure mode without this is a loud "browser not found" in the test job.jobs-defaultitself is trimmed: basenode:22(was the EOLnode:18) with node 20/22/24 pre-installed (was 12–24). Pre-installed node versions are a cache, not a contract — a job with an.nvmrcalways gets its version (pre-warmed ornvm installed at runtime), a job without one runs the shipped LTS base, which may bump in future minors. Pin with an.nvmrcif your project depends on a specific node version.
Minor Changes
-
Agent skills: catladder ships agent-facing documentation as skills (
catladder-config,catladder-builds,catladder-deploys,catladder-secrets,catladder-releases,catladder-pipelines,catladder-cliwith a generated command reference). They are materialized into.claude/skills/on every generation (cross-agent.agents/skills/opt-in), so AI coding agents always see documentation matching the installed catladder version. -
catci, catladder's CI companion: a tree-shaken bundle materialized into.catladder-generated/catci/on generation, running the release, security-audit and npm-publish logic in CI with plainnode. Job images no longer need catladder installed, and CI always runs exactly the version that generated the pipeline. -
catenv is interactive when a human runs it: attached to a terminal it can now run the gitlab token setup and vault unlock prompts, instead of aborting with a
NonInteractiveErrormid-wizard. Under direnv, turbo or CI (stdout not a TTY) it stays non-interactive automatically, and--non-interactiveforces that on a terminal too. In non-interactive runs a missing gitlab token now fails fast with the remedy ("runcatenvonce in a terminal") rather than starting a prompt it cannot answer, and the bitwarden unlock prompt is suppressed as well. -
The catladder store:
.catladder-store/store.ymlis a committed, non-secret record of machine-fetched facts (currently gcloud project numbers), populated bycatladder project setup. It makes Cloud Run URLs deterministic at generation time, so generating a pipeline no longer requires cloud access or authentication. -
Changesets guardrails: merge-request pipelines get a
🦋 changeset checkjob reporting what merging would release (changesets added by the MR, everything pending, the resulting version with a changelog preview) — as a warning-only job with an exposed artifact on GitLab (sticky MR comment whenGL_TOKENis available to MR pipelines) and a sticky PR comment on GitHub. The⚠️ force create releasejob now releases a patch bump even without pending changesets, as the recovery path for changes merged without one. -
The github review workflow gains a generated
catladder ✅job that succeeds exactly when every other review job succeeded (needs:all of them,if: always(), skipped counts as failed;continue-on-errorjobs like the audit stay non-blocking). It exists to be the one required status check in branch protection: requiring real job names goes stale on every component change — a renamed required job blocks its own PR forever, a new component's jobs are silently not required — while this context never changes. Combined with the repo's "Allow auto-merge" setting this restores gitlab's built-in "merge when pipeline succeeds" on github. -
GitHub Actions backend:
pipelines: { gitlab: true, github: true }generates workflows for both CI systems in parallel from one config, including build, deploy, review-environment and release jobs. Job scripts are externalized into committed files instead of being inlined into the workflow yaml. -
GitHub environment secrets: secrets are scoped per environment instead of per repository, so
stageandprodcan hold different values for the same variable.secrets-sync-githubtakes an--envfilter to sync a single environment. -
Manual gates on GitHub: manually gated jobs (e.g. a prod deploy) and their build closure are routed into a
workflow_dispatch"manual tasks" workflow, where each gated job becomes a dropdown choice — GitLab's manual jobs without needing GitHub Environments (Enterprise-only approvals). -
The
pagesdeploy type now works on the github backend. The deploy job hands the built site toactions/upload-pages-artifact+actions/deploy-pages, targets thegithub-pagesenvironment and reports the published url from the deploy step, withpages: write/id-token: writegranted on the job. The repository's Pages source must be set to "GitHub Actions" once. Per-merge-request previews stay gitlab-only: github serves one site per repository anddeploy-pagesreplaces all of it, so review environments log why they were skipped instead of generating a deploy job. -
Two new agent skills guide migrations that used to be tribal knowledge:
catladder-migrate-release-methodwalks a project from semantic-release to changesets (or back), including backfilling changesets for everything merged since the last release tag so the changelog and version bump stay correct — asking how to group the changes when the history is large or ambiguous.catladder-migrate-ci-backendguides a move between GitLab CI and GitHub Actions: the blockers to check up front, running both backends in parallel viapipelines, mirroring secrets, the vault and registry consequences, and the manual cleanup a cut-over needs. -
New
npmPackagedeploy type: publishes a component to npm, deriving version and dist-tag from the pipeline trigger — tagged releases publish the tag version aslatest, branches and merge requests publish0.0.0-<slug>-<sha>canaries (withnext/betabranches getting their own dist-tag). Works in workspace monorepos and authenticates via theNPM_TOKENsecret. -
npmPackagecomponents can publish to npm without a stored token, using npm trusted publishing (OIDC). On github the publish job now declaresid-token: write, and when the workflow can mint an OIDC token catladder skips the.npmrcentirely and lets npm exchange the token for short-lived credentials — provenance is attested automatically.NPM_TOKENstays supported and still wins when it is set, so gitlab and untrusted workflows are unaffected.Publishing moved to its own
npm-publishjob image, because trusted publishing needs npm >= 11.5.1, which thejobs-defaultnode does not carry.To use it, register the package's trusted publisher on npmjs.com with the repository and the workflow filename that publishes it (
catladder-release.ymlfor tagged releases). npm allows one trusted publisher per package, so canary publishes from the main-branch and review workflows still needNPM_TOKEN. -
New agent skill
catladder-migrate-package-managerguides a project from yarn to pnpm (or back). It covers what catladder switches on its own once it detects the package manager — install commands, caches, docker prod install, audit and build/start defaults — and, more importantly, the repository work it does not do: the blockers to check first (meteor is yarn-only, Yarn PnP, yarn plugins), writingpnpm-workspace.yamlbeforepnpm importso the resolved versions survive the migration, and the fallout to fix locally rather than in a pipeline round-trip. A reference page maps every yarn command and config key to its pnpm equivalent and catalogs the behavi...