Repository navigation
Target reference
Every target at a glance, and what a machine needs to run them.
make without a target prints the annotated, colorized help, including the detected app, version and certificate status. Colors turn off automatically when stdout is not a terminal and honor NO_COLOR. make help-<target> (for example make help-rsync) prints extended help for a single target — options and worked examples where they help.
| Area | Targets |
|---|---|
| Release versioning |
version, changelog, tag, stable-branch
|
| Build |
build, dist, composer ARGS=..., npm ARGS=..., psalm [ARGS=...], reuse [FORCE=1]
|
| Local deploy |
rsync TARGET=..., cp TARGET=...
|
| Bundle analysis (module) |
bundle-report [ARGS=...] [JSON=...], build-audit [ARGS=...] [JSON=...]
|
| Checkout audit (module) |
consistency-audit [ARGS=...] [JSON=...] [NO_NETWORK=1], build-verify [ARGS=...] [JSON=...], changelog-lint [ARGS=...] [JSON=...], php-compat [PHP=all] [NEXT=1] [ARGS=...] [JSON=...], deps-audit [ARGS=...] [JSON=...] [NO_ADVISORIES=1], secrets-audit [SCOPE=shipped|history] [TARBALL=...] [COMMITS=...] [ARGS=...] [JSON=...], secrets-ignore [REASON=...] [COMMIT=1|PR=1]
|
| App Store (module) |
csr, register, publish, sign, release, list-releases, list-releases-full, list-for-author, delete-release, ratings
|
| Integrity signature (module) |
integrity-enable, integrity-sign, integrity-check, dist-signed
|
| Lint (module) |
lint, lint-actions [ARGS=...] [JSON=...], lint-actions-security [ARGS=...] [JSON=...] [SARIF=...], lint-containerfiles, lint-markdown, lint-php-syntax [PHP_VERSIONS=...], lint-shell, lint-vue-imports, lint-web, lint-yaml, each [ARGS=...] [JSON=...]
|
| Translations (module) |
l10n-init [COMMIT=1|PR=1], l10n-check, l10n-lint [FIX=1]
|
| CI workflows (module) |
workflows-list, workflows-install W=..., workflows-update
|
| GitHub CLI (module) | gh-install |
| Utility |
clean, dist-clean, image-clean [OWN=1] [OLD=1] [DRY=1], cache-clean [ALL=1] [DRY=1], image-setup, php-containerfile, self-update, skill-install, dev-init, dev-clean, help, help-<target>
|
Targets marked [m] in the help are maintainer-only: they need repository write access and/or the App Store signing key. Everything else works for anyone who clones the app. The areas marked (module) come from the developer modules (make dev-init, see Workflows, App Store, Bundle analysis, Checkout audit, Lint, Integrity signature and Translations); without the modules those targets simply do not exist — which keeps the help of a plain checkout down to build, deploy and utility.
make psalm runs composer psalm on the current composer image; install the dev tools once with make composer ARGS=install beforehand. ARGS is forwarded past composer's own options (composer psalm -- ...), so make psalm ARGS="--show-info=true" reaches psalm. Details on Building and packaging.
make reuse lints only an app that is set up for REUSE, that is one with LICENSES/, REUSE.toml or .reuse/dep5. Without any of them it says so in one line and exits non-zero, rather than list every file of an app that never claimed compliance. FORCE=1 runs the full lint anyway, with ARGS passed on as usual.
make bundle-report reports what a browser downloads when a page of this app opens, and which packages those bytes are made of. It reads the build output and nothing else, so make build comes first. make build-audit reads the half that never ships — bundler config, package.json, src/ — and prices what it finds there in the bytes the build delivers. Options, output and findings: Bundle analysis.
make consistency-audit holds the statements the metadata makes against each other and names what a release still needs; it reads metadata only, no build, and from the network only the newest released major of nextcloud/server, the major on its master and, for an app with a package.json, the Node.js release schedule, and it asks whether each link of the App Store listing in info.xml answers, which NO_NETWORK=1 leaves out. make build-verify copies the tracked files into a scratch tree outside the app, installs and builds them twice and compares the result against the build output the checkout carries, so it is the one analyser that needs the network and takes minutes. make changelog-lint reads CHANGELOG.md and CHANGELOG.<code>.md as the App Store does and exits 1 when the store would publish this release without its changelog; make tag runs it before its confirmation. make php-compat runs the checkout on the PHP floor and on the newest PHP its highest declared server runs on, in the build image of each, and reports a package that refuses one of them, a file that does not parse, a <php max-version> below that ceiling and one above the ceiling of Nextcloud master; it exits 1 on such a finding. make deps-audit asks composer audit and the audit of npm, pnpm or yarn whether a package of composer.lock or of the npm lock file that ships has a published vulnerability, names the release that fixes it and whether the declared constraints let an update reach it, holds the licence of each against the one the app declares, writes the report to build/reports/deps-audit.{txt,json} and exits 0 with findings. make secrets-audit runs gitleaks over what ships and over every commit, names private keys, key stores, .env files and credential files by their names as well, never shows a secret, and exits 1 on a finding; make tag and make dist stop on a secret in what ships. make secrets-ignore adds the findings a maintainer marks as false positives to .gitleaksignore, with the reason. Details: Checkout audit.
make l10n-init writes what the repository needs for the Nextcloud Transifex sync, l10n/.gitkeep, .l10nignore and .tx/config with the app id, and covers them in REUSE.toml. make l10n-check validates that setup on every branch the translation bot syncs, in the image the bot runs in, and exits 1 on a finding. make l10n-lint holds the source strings against the rules of the translation team in lib/l10n-rules.json, and FIX=1 rewrites what has a fix. Details: Translations.
Every lint workflow of ncmake-workflows has a target of the same name, which collects the same tracked files, runs the same tool in the same version and exits 1 where the workflow fails: make lint-actions (actionlint), make lint-actions-security (zizmor, offline and without a token; SARIF=<file> writes the findings for GitHub code scanning as well), make lint-containerfiles (hadolint), make lint-markdown (markdownlint-cli2), make lint-php-syntax (php -l on every version of PHP_VERSIONS), make lint-shell (shellcheck), make lint-vue-imports, make lint-web (ESLint, Stylelint and html-validate) and make lint-yaml (yamllint). make lint runs every lint target of the module. Details: Lint.
All six analysers run in the throwaway Node container and are mounted in from the ncmake cache, so the host needs no Node toolchain and nothing is written into the app.
Every analyser target, the two of the bundle analysis included, takes JSON=<file>, which writes the JSON of ARGS=--json to <file> as well, from the same run, and the report is printed as without it. The file can lie outside the app; it is replaced once the run is complete, and a run that stops on an error writes none. make reuse has no such option; ARGS=--json prints its report as JSON.
make integrity-enable marks an app as signed by putting the public certificate in the repository as .ncmake/certificate.crt; from then on make tag offers to produce appinfo/signature.json — the per-file hash list the Nextcloud server's integrity check reads — and the release workflow verifies it before it packs. make integrity-sign and make integrity-check are the two halves on their own (DIR=<path> for a tree that already exists, TARBALL=<file> for a packed release), make dist-signed is stage + sign + check + tarball in one go. The module adds two more targets that are only ever run as a step of another: integrity-tag inside make tag, integrity-gist-drop inside make publish. Everything about it, including why the signing key never reaches CI: Integrity signature.
make image-clean lists the images of every container CLI on the host, podman and docker alike, numbered, with their size, when ncmake last used them and their status: ncmake (pulled by ncmake), built (built by ncmake on the host, a local PHP build image), ncmake-used (on the host before, used by ncmake), dangling (no tag), in use (a container uses it) or foreign. Without a flag it asks which ones to remove, by number or range (1 3-5), and reports the space that freed; without a terminal it only lists. For scripts, OWN=1 picks every image ncmake pulled but none it built, OLD=1 every dangling image and every image ncmake pulled or built and has not used for IMAGE_IDLE_MIN minutes (default 10), and DRY=1 marks the pick without removing anything. ENGINE=podman|docker on the command line limits it to one CLI. A flag never picks a foreign image or one in use, and nothing is removed with -f, so an image that a container uses or another tag names stays and the target says why.
make cache-clean lists what the per-machine ncmake cache holds, numbered, with the size, the last change and the status of each entry: ncmake (the core, the developer modules, the analyser libraries and the registry list of a ref, a Node.js line, the release index of nodejs.org, the download caches npm/ and corepack/, a tool the lint module fetched into tools/, last-run), leftover (what an interrupted download left, or a file where an older ncmake kept it), in use (mounted by a running ncmake container, and last-run while one runs) or foreign (a file ncmake does not know). It asks which entries to remove, by number or range (1 3-5) or all, and reports the space that freed; without a terminal it only lists. ALL=1 removes every entry but a foreign one, the whole cache, and DRY=1 marks what ALL=1 would remove without removing anything. An entry in use and a foreign one always stay, all and ALL=1 are refused while an ncmake container runs, and the cache directory goes only once it is empty. The next run that needs a removed entry fetches it again, as on a new machine; the developer modules come back only with make dev-init. The container images are make image-clean's, and the image record is not part of the cache.
make image-setup shows for each container CLI where ncmake keeps its image record: ${XDG_STATE_HOME:-~/.local/state}/ncmake/images.txt for a rootless store, /var/lib/ncmake/images.txt for a store of the whole host. For rootful docker run by a member of the docker group it asks again whether to create /var/lib/ncmake through sudo, which an earlier no declined, see How ncmake understands your app.
make php-containerfile prints the Containerfile of the PHP build image, php/Containerfile of ncmake-images as ncmake caches it, with the build arguments base, composer and extensions. That repository publishes it as ghcr.io/ernolf/ncmake-php:<minor> and ncmake builds it on the host when that image cannot be pulled or php_extensions adds an extension it lacks. For every PHP minor above the ceiling of Nextcloud master, it publishes the same Containerfile as ghcr.io/ernolf/ncmake-php:<minor>-next, from the release or, before it, from the newest alpha, beta or RC, and the newest of those minors as ghcr.io/ernolf/ncmake-php:next; the label ncmake.php names the exact PHP. An extension of php_extensions that does not build or does not load on that PHP yet is left out of that image, and the label ncmake.missing names it. Nothing is built on the host in its place.
make gh-install sets up the official GitHub CLI package source and installs gh, following the upstream install guide. The package manager is auto-detected (apt, dnf5, dnf4, yum, zypper, pacman, apk, brew, conda); on Debian and Ubuntu the source is written in deb822 format with the signing key ASCII-armored inside the file and verified against the documented fingerprints. The target is idempotent and asks for privileges per step through sudo. gh is what PR=1 needs, see Workflows.
GNU make, git, curl, openssl, rsync, python3. xmllint (libxml2) for reading info.xml is optional: without it ncmake reads the file with python3, so a bare CI runner works too. Optional: podman or docker for containerized builds (strongly recommended; without them use RUNTIME=bare and provide composer and npm yourself).
© 2026 [ernolf] Raphael Gradenwitz · MIT-licensed · Report an issue
For app developers
- Getting started
- How ncmake understands your app
- Building and packaging
- Bundle analysis
- Build tools
- Checkout audit
- Lint
- Releasing
- Integrity signature
- Translations
- Per-app tuning
- Target reference
- AI assistant
CI workflows
App Store
For app users
Git
Background
Reference