This project is under very early, active development and may contain bugs or security issues. It is likely not ready for production websites.

You are responsible for reviewing, testing, and securing any deployment. Ava CMS is provided as free, open-source software without warranty (GNU General Public License), see LICENSE.

Releasing

This guide is for maintainers who are releasing a new version of Ava CMS.

Versioning

Ava CMS uses Calendar Versioning (CalVer): YY.MM.release.

Important: Ava CMS’s release checks currently require a strict numeric CalVer of the form:

  • ^\d+\.\d+\.\d+$

So versions like 26.02.0-beta.1 will fail release tests today.

Examples:

  • 26.02.0 = Initial release of February 2026
  • 26.02.1 = First patch/update of February 2026
  • 26.03.0 = First release of March 2026

How to Release

  1. Update Version: Change AVA_VERSION in bootstrap.php.
  2. Install dependencies (if needed): Ensure vendor/ exists and vendor/autoload.php is present.
  3. Lint: Run ./ava lint.
  4. Test: Run ./ava test.
  5. Release Tests: Run ./ava test --release.
  6. Tag: Create a git tag (recommended format: v26.02.0).
  7. Push: Push the tag to GitHub.
  8. Release: Create a GitHub Release from that tag.

That’s it. Ava CMS’s updater checks GitHub Releases and compares the installed version (from AVA_VERSION) to the latest release tag.

Release Tests

The --release flag runs additional tests that verify the project is ready for public release:

./ava test --release

What it checks:

These checks are implemented in core/tests/Release/ReleaseChecksTest.php.

Note: these checks are intentionally opinionated. They validate the defaults of the Ava CMS distribution / starter install (safe config defaults, placeholder URLs/tokens, empty media directory, etc.). If you run them inside a real customised site (for example, a production docs site), you should expect them to fail unless you reset that site back to the starter defaults.

Security & Git

  • .gitignore should include app/config/users.php (or a users.php entry)
  • .gitignore should include .env
  • .gitignore should include storage/cache (or /storage/cache/)

Default Configuration Expectations

The release suite expects a “fresh install / safe defaults” configuration in app/config/ava.php:

  • debug.enabled is false
  • theme is default
  • admin.enabled is false
  • admin.path is /ava-admin
  • admin.theme is cyan
  • cli.theme is cyan

And default site identity values:

  • site.name is My Ava CMS Site
  • site.base_url contains localhost
  • site.timezone is UTC
  • site.locale is en_GB

Security placeholder expectation:

  • security.preview_token should be a placeholder value containing your-preview-token (or be empty)

Version Checks

  • AVA_VERSION must match strict YY.MM.release
  • AVA_VERSION should be higher than the latest GitHub release

The “higher than GitHub” check requires the curl extension and network access. If curl is missing (or GitHub cannot be reached), the test is skipped.

Project Structure

  • Default theme directory exists: app/themes/default/
  • Default theme has bootstrap file: app/themes/default/theme.php
  • Example content exists: content/pages/index.md
  • app/config/users.php should ideally be absent; if it exists, it must be gitignored
  • public/media/ should be empty (except .gitkeep)

Documentation

  • README.md must exist
  • LICENSE must exist

Dependencies

  • composer.json must exist and be valid JSON (and contain a name field)
  • vendor/ must exist
  • vendor/autoload.php must exist

Changelog Format

Include a changelog in the release notes following this format:

## What's New

- ✨ New feature description
- 🔧 Improvement description
- 🐛 Fixed issue description

## Breaking Changes

- ⚠️ Description of breaking change and migration steps

## New Bundled Plugins

- `plugin-name` — Brief description (not activated by default)

What's Included in Releases

GitHub’s release zipball includes the repository contents.

When a user runs ./ava update:apply, Ava CMS should not blindly overwrite their entire site. Instead, it downloads the zipball and synchronises a specific set of paths (see core/Updater.php).

See Updates →

Testing the Update Flow

Before releasing, test the update mechanism:

  1. Create a test installation
  2. Set it to an older version in bootstrap.php
  3. Create a test release on GitHub
  4. Run ./ava update:check --force
  5. Run ./ava update:apply
  6. Verify files were updated correctly
  7. Verify user files were preserved

Hotfix Releases

For urgent bug fixes:

  1. Increment release number: 26.02.026.02.1
  2. Follow the normal release process
  3. Note in changelog that it's a hotfix

Pre-release / Beta

Pre-release versions are not supported by the current release tests (they require strict YY.MM.release).

The updater itself uses PHP’s version_compare() for comparisons, but if you want release tests to pass, stick to strict numeric CalVer.

Repository Settings

Ensure the GitHub repository has:

  • Releases enabled
  • Public visibility (for API access without auth)
  • Tags following the v{VERSION} format

Troubleshooting

Users can't fetch updates

  • Ensure releases are published (not draft)
  • Ensure repository is public
  • Check GitHub API status

Version comparison issues

The updater uses PHP’s version_compare() and strips a leading v from Git tags.

Numeric CalVer examples that compare as expected:

  • 26.02.0 < 26.02.1
  • 26.02.9 < 26.02.10
  • 26.12.9 < 27.01.0

Release tests failing locally

  • If ./ava test --release fails because LICENSE is missing, add a LICENSE file (the release suite requires it).
  • If the “higher than GitHub” check is skipped, install/enable the curl extension so the suite can verify you’re not re-releasing an old version.