Skip to content

Building and packaging

ernolf edited this page Aug 3, 2026 · 1 revision

Building and packaging

How ncmake turns a checkout into a runtime build and a release tarball — one staged file set that is byte-for-byte what a release ships.

🔨 Building

make build

runs the detected build commands, each in its container:

  • composer install --no-dev --no-scripts --prefer-dist --no-progress when composer.json declares runtime requirements
  • npm ci && npm run build when package.json has a build script

When a side does not apply, it is skipped with a note. Apps with special build steps override the commands in ncmake.mk (see Per-app tuning).

For everything beyond the release build there are generic pass-through targets running in the same throwaway containers — the host needs no toolchain even for the dev setup:

make composer ARGS=install       # install dependencies INCLUDING dev tools (vendor-bin etc.)
make composer ARGS="cs:check"    # run a composer script
make psalm                       # run static analysis (psalm) on the current composer image
make npm ARGS=ci                 # install frontend dependencies
make npm ARGS="run test"         # run the frontend tests

make psalm runs composer psalm on the current composer image, because psalm needs a newer runtime than the build floor; run make composer ARGS=install once beforehand to install the dev tools. Pass extra flags straight to psalm with make psalm ARGS="..."; they are forwarded past composer's own options (composer psalm -- ...), so e.g. make psalm ARGS="--show-info=true" reaches psalm rather than being eaten by composer. make composer uses that same current image by default, so dev tools just work; only make build drops to the min-version for package-correct resolution. Add PHP=min to route any other composer command through the build floor instead.

make dist-clean resets to a pristine checkout first (it removes every git-ignored build output: vendor/, node_modules/, js/, caches), so

make dist-clean && make build

is the reproducible from-scratch build.

📦 Packaging: the shipped file set

What ends up in a release is defined as an allowlist (the keep model), not as an exclude list. Shipped are the standard app paths, each only when it exists:

appinfo/ lib/ l10n/ templates/ img/ css/ js/ vendor/ LICENSES/
CHANGELOG.md AUTHORS.md REUSE.toml COPYING COPYING.md LICENSE LICENSE.md

Note

A new dev file in your repository can never leak into the tarball, because it is not on the list. A missing runtime directory fails loudly instead of silently shipping a broken app.

flowchart LR
    A[working tree] -- "allowlist<br>+ .nextcloudignore" --> B["build/stage/&lt;app_id&gt;/"]
    B -- "tar (make dist)" --> C["build/artifacts/dist/<br>&lt;app_id&gt;-&lt;version&gt;.tar.gz"]
    B -- "rsync (make rsync)" --> D["&lt;apps-dir&gt;/&lt;app_id&gt;/"]
    B -- "docker cp (make cp)" --> E["&lt;container&gt;:&lt;apps-dir&gt;/&lt;app_id&gt;/"]
Loading

make dist materializes the file set once into a staging directory and packs it; make rsync and make cp deploy the very same staging directory. One mechanism, one source of truth: what you deploy for testing is byte-for-byte what a release ships.

🚀 Deploying to a test instance

make build
make rsync TARGET=/var/www/nextcloud/apps OCC=1

make rsync deploys the shipped file set straight into an apps/ directory (local or over SSH); make cp does the same into a running container such as Nextcloud All-in-One. OCC=1 wraps the sync into the full occ app:disable → chown → occ app:enable refresh cycle, so info.xml is re-read and migrations run. make dist, make rsync and make cp all deploy the very same staged file set — one source of truth, byte-for-byte what a release ships.

The full walkthrough — TARGET forms, remote SSH, ENGINE, web_user, the -it/TTY detail — lives in the install guide: Method 3: make rsync and Method 4: make cp.

Tip

That guide is written for the people who install your app rather than develop it, so every ncmake app can link its users straight to Installation and keep its own README down to a couple of lines.

Clone this wiki locally