Skip to content

How ncmake understands your app

ernolf edited this page Aug 3, 2026 · 1 revision

How ncmake understands your app

Nothing is configured twice, everything is read from files your app has anyway.

🧠 What is read, and from where

Fact Source
App id <id> in appinfo/info.xml
Version <version> in appinfo/info.xml
PHP build needed? composer.json declares runtime requirements (anything besides php and ext-*)
Frontend build needed? package.json has a build script
Is js/ (or vendor/) a build artifact? .gitignore (evaluated via git check-ignore)
PHP container images build image from the min-version in appinfo/info.xml; analysis on the current composer image
Node container image engines.node in package.json

The .gitignore line deserves a word: when js/ is gitignored, it is a build output and must exist before packaging (make dist refuses otherwise and tells you to run make build). When js/ is committed, as in apps that ship their built frontend in git, a fresh checkout is already complete and packages without building. The same logic applies to vendor/.

The tarball and the deployed directory are always named after the app id, regardless of what your checkout directory is called.

🐳 The container runtime

composer and npm never run on your host by default. Each invocation starts a throwaway container (--rm), does its work in your bind-mounted checkout and disappears. Your host needs no PHP, no Node, no version juggling, and you can build against exactly the PHP the app declares as its minimum.

The runtime is auto-detected (podman preferred, then docker) and can be chosen per call, for example make build RUNTIME=docker:

RUNTIME= What it is Notes
podman rootless podman (default when podman exists) daemonless, no idle cost, files owned by you
docker standard rootful docker ncmake maps your uid/gid into the container, so no root-owned files appear
docker-rootless rootless docker
bare no container composer and npm must be on the PATH

Two PHP images are picked per task, both maintained upstream so ncmake ships no image of its own. The build runs in the Nextcloud CI image for your declared min-version (ghcr.io/nextcloud/continuous-integration-php<min>): fully tooled (composer, git, unzip) and resolving dependencies against the support floor, which is what packaging needs — its frozen patch level is irrelevant for shipping runtime deps. Everything interactive (make composer, make psalm) runs in the official composer image (docker.io/library/composer:2), which always ships the newest PHP patch alongside composer, git and unzip; psalm needs a current runtime, while the analysed PHP level stays pinned through psalm.xml, so the image's fixed PHP version does not affect the result. Node runs in node:<major> from your engines.node. An app that needs a specific PHP version or an extra extension (ext-gd, ext-intl, …) points php_image/analysis_image at another image in ncmake.mk. All images can be overridden (see Per-app tuning).

Caution

On SELinux hosts (Fedora, RHEL) bind mounts may need a :z label. If you hit permission errors there, run with RUNTIME=bare or adjust your container policy.

Clone this wiki locally