If an extension is built on a laptop and deployed from a zip, every release wave is a gamble. How we set up AL-Go for GitHub on every customer repository, what a useful test codeunit looks like, and the pipeline that compiles against the next version before Microsoft ships it.
There are still per-tenant extensions being built in Visual Studio Code on one developer's machine, packaged as an .app file, and uploaded through the Extension Management page. It works, until the developer leaves, the laptop dies, or Microsoft ships a release wave that the extension has never been compiled against. The fix is not exotic: a repository, a pipeline and some tests. Microsoft gives you the pipeline for free.
AL-Go is Microsoft's open-source set of GitHub Actions and templates for Business Central development. You create a repository from the per-tenant extension template, put your app folder in it, and you get: a build on every commit against the current version, a nightly or on-demand build against the next major (the NextMajor schedule), test execution, versioning, release artefacts, and deployment to named environments (sandbox on merge, production on release) using an Entra app registration. It takes an afternoon to set up and it removes most of the ways an extension fails at update time.
The settings that matter in AL-Go-Settings.json: runNumberOffset and the versioning strategy so version numbers always increase; enableCodeCop, enableUICop and enablePerTenantExtensionCop (or AppSourceCop for marketplace apps) switched on so the analysers fail the build; NextMajorSchedule set; and the environments block with the customer's sandbox and production names. Secrets (the auth context for deployment) live in GitHub secrets, never in the repository.
main is what is in production. Feature branches, a pull request to main with the build and tests as required checks, merge deploys to the sandbox automatically, and a GitHub release (tag) deploys to production, by a person, in the agreed window. For a customer with one or two developers this is all the process you need. For more, add a develop branch and a release branch per major.
AL tests are codeunits with Subtype = Test, run by the test runner against a database with the library apps installed. A good one:
Library codeunits (LibrarySales, LibraryInventory, LibraryERM), so it does not depend on demo data or on the order tests run in.asserterror and Assert.ExpectedError for the negative cases, which are where bugs live.[HandlerFunctions] for confirm dialogs and pages, so it runs headless.You do not need hundreds. Twenty tests covering the extension's actual rules, run on every commit and against the next major, will catch most of what a release wave changes.
main.NextMajor build compiles and tests against the next release wave's preview. Warnings and failures land in an issue. By the time the update is scheduled there is nothing left to find.If a customer asks us to take over an extension and there is no repository, the first week is setting this up before we change a line, because it is the only way to know what we are changing. If you are a developer or a customer with code in a zip somewhere, the AL code check includes getting it into a pipeline; and the design rules are the other half.