From Local Builds to Production DevOps: Automating Joomla Extension Release Management

In 2026, automated release pipelines are no longer a luxury reserved for large engineering teams — they are the baseline expectation for any serious software project. Yet a surprising number of Joomla extension developers are still shipping releases by hand, copying files over SSH, and hoping nothing was missed. This article documents how we migrated our own Joomla extension build process from manual local builds to a fully automated, Git-based release pipeline — and why, in today's environment, that shift is more important than ever.

TL:DR – Moving from a manual, error-prone release process to a robust automated pipeline takes real effort upfront, but the payoff is immediate: faster releases, fewer mistakes, and a professional workflow that scales as your extension portfolio grows.

What's Changed in 2026

When this project was first undertaken, Git-based CI/CD for small CMS extension teams was still considered advanced practice. That's no longer true. The tooling has matured significantly: self-hosted platforms like Gitea (now at version 1.22+) ship with capable Actions support that is broadly compatible with GitHub Actions syntax, lowering the barrier to sophisticated automation considerably. Meanwhile, Joomla 5.x has tightened its update manifest requirements, making cryptographic hash verification and well-formed XML manifests not just best practice but a functional necessity for reliable over-the-air updates.

The broader DevOps ecosystem has also shifted. Concepts like supply-chain security, reproducible builds, and software bills of materials (SBOMs) — once the concern of enterprise teams — are increasingly relevant even for small open-source projects. Automated pipelines are now the natural place to enforce these standards without adding manual overhead. If your release process still lives in a developer's head and a folder of bash scripts on their laptop, 2026 is the year to fix that.

The Challenge: Manual Release Management

Our original workflow relied on local build scripts that required manual intervention at every stage. Developers ran scripts on their own machines, uploaded files to update servers by hand, and trusted that every step had been executed correctly. In practice, that trust was regularly misplaced. The specific risks we experienced included:

  • Human error when manually copying files or editing XML manifests — a missed folder or a stale version string was easy to overlook.
  • Version inconsistencies when different developers built releases from slightly different local environments.
  • No standardised testing gate before a release reached production users.
  • Production deployments that required direct SSH access and manual file transfers, creating both a security surface and a single point of failure.
  • No audit trail linking a deployed release to the exact commit it was built from.

These are not unusual problems. They are the predictable consequences of any release process that depends on human consistency rather than machine repeatability.

The Solution: A Git-Tag-Triggered Pipeline

We built an automation pipeline around a single organising principle: when a developer pushes a version tag to our Gitea repository, everything else happens without further human involvement. The pipeline covers three stages in sequence — build, publish, and deploy — and each stage is fully scripted and version-controlled alongside the extension code itself.

The build stage dynamically generates Joomla-compliant XML manifests by inspecting the actual folder structure of the repository, constructs installable ZIP packages with the layout Joomla expects, and stamps the correct version number and release date into every relevant file. The publish stage creates a formal release entry in Gitea, attaches the ZIP as a downloadable asset, and generates SHA256, SHA384, and SHA512 hashes for integrity verification. The deploy stage pushes the Joomla update manifest — containing those cryptographic hashes — to our production update server via SSH, making the new version immediately visible to any Joomla site running our extension.

Technical Implementation

The pipeline is implemented as a Gitea Actions workflow file committed to the repository. It triggers on pushes that match the tag pattern v*, so tagging a commit v1.0.14 is all a developer needs to do to initiate a full release.

The manifest generation step is worth highlighting. Rather than maintaining a hand-edited XML file that must be kept in sync with the codebase, our workflow inspects the repository at build time, detects which standard Joomla folders are present (administrator, site, media, language, and so on), and writes a manifest that accurately reflects what is actually there. This single change eliminated an entire category of release defects — the kind where a folder exists in the repository but was forgotten in the manifest, causing Joomla's installer to silently skip it.

Security is treated as a first-class concern throughout. SSH authentication to the deployment server uses key-based access with a dedicated deploy key that has write access only to the update server directory — nothing more. Secrets are stored in Gitea's encrypted secrets store and are never written to logs. Hash generation runs as part of the build step, so the values in the published update manifest correspond to the exact bytes in the release asset, not a separately computed approximation.

Quality Assurance and Consistency

Standardisation is the quality benefit that is easiest to underestimate before you have it. When every release is built by the same script running in the same containerised environment, the question "did this build include the language files?" has a deterministic answer. When builds were local, the answer depended on which developer ran the script and whether their working copy was clean.

Every release now includes installation messages, language files, update manifests, and component metadata as a matter of course — not because someone remembered to include them, but because the build script always includes them. Regressions caused by omitted files have effectively disappeared.

Git commit linkage provides a complete audit trail. Every release asset can be traced back to the exact tree it was built from, which matters both for debugging and for the kind of supply-chain transparency that is increasingly expected in 2026's software ecosystem.

Business Impact and Risk Reduction

The operational improvements are straightforward to describe. Release time — from tagging to a live update being available to end users — dropped from a process that could take the better part of an hour (accounting for manual steps, verification, and the inevitable "did I remember to update the version in the manifest?" check) to a pipeline that completes in a few minutes.

Risk reduction is the more important story. Automated deployment removes the direct SSH session from the release critical path. No developer needs production server credentials to ship a release. The deploy key used by the pipeline has the narrowest possible permissions. If the pipeline fails at any stage, the release simply does not proceed — there is no partial deployment state to clean up manually.

For a small team maintaining multiple Joomla extensions, this matters enormously. The cognitive load of managing releases is real, and every hour spent on manual release mechanics is an hour not spent on the code itself.

Developer Experience

From a developer's perspective, the workflow is now: write code, commit, tag, push. The pipeline takes over from there and reports back through the Gitea Actions interface — green for success, red with a log for any failure. There is no tribal knowledge required to ship a release, which means new team members can contribute to production without a handholding session on the release process.

The build scripts and workflow files are version-controlled with the extension code. Changes to the release process go through the same review workflow as changes to the extension itself. This means the release pipeline improves iteratively over time, and any change to it is traceable and reversible.

Extending the Pattern Across the Portfolio

Because the workflow is parameterised rather than hardcoded to a single extension, applying it to additional components, modules, and plugins in our Joomla portfolio is largely a matter of copying the workflow file and adjusting a small number of configuration values. The patterns established for one extension — manifest generation, hash computation, SSH deployment, Gitea release creation — transfer directly.

This composability is deliberate. The goal was never to solve the release problem for one extension; it was to establish infrastructure that makes the right approach the easy approach for everything we build going forward.

Looking Forward

The pipeline as described handles build, publish, and deploy reliably. The natural next additions are automated testing — running a PHPUnit suite and a Joomla integration test against the built package before the release proceeds — and a staging deployment step that pushes to a pre-production environment for smoke testing before the production update server is updated.

We are also watching developments in Joomla's update infrastructure closely. Joomla 5.x introduced improvements to the update manifest format and verification behaviour, and staying current with those changes is easier when the manifest generation is centralised in a single, version-controlled script rather than scattered across manually maintained files.

For teams still running manual release processes in 2026, the argument for automation has never been stronger — and the tooling has never been more accessible. A self-hosted Gitea instance with Actions enabled, a few hundred lines of shell script, and an SSH deploy key are all you need to get started. The investment pays back quickly, and the compounding reliability benefits make it one of the highest-return infrastructure improvements a small development team can make.

Because our pipeline runs on our own self-hosted Gitea installation, the entire process — including repository contents, workflow logs, and deployment keys — remains private and under our control. For setup details, see Running Gitea with Let's Encrypt on macOS via Homebrew. The initial configuration requires familiarity with macOS, Homebrew, SSL certificate management, and Git, but once running it is fast, stable, and entirely self-contained.