← Blog

Azure Pipelines templates for MuleSoft: one delivery flow, many applications

Reference: azure-devops-mulesoft-pipelines (templates, ADRs) · mulesoft-orders-api (consumer)

A team with thirty Mule applications should not have thirty copies of the same pipeline. When the delivery process changes — a new check, a new environment, a fix like the one in the previous article — it should change once, and each application should choose when to pick it up. Azure Pipelines templates give you that, if the repository is structured for it.

Two repositories

  • Templates repository — the delivery process. Versioned with tags (v1.0.0, v1.0.1, v1.1.0).
  • Application repository — the Mule app and a ten-line azure-pipelines.yml that extends a tagged version of the templates.
resources:
  repositories:
  - repository: templates
    type: github
    endpoint: github.com_brunosouzas
    name: brunosouzas/azure-devops-mulesoft-pipelines
    ref: refs/tags/v1.1.0

extends:
  template: templates/stages/gitflow.yml@templates
  parameters:
    nextVersionBump: minor

Pinning to a tag is the important part. A change to the templates never alters an application’s pipeline until that application moves its ref. During this project the release job was fixed in v1.0.1 and a smoke test added in v1.1.0; the application adopted each one through a normal pull request.

extends rather than template: inside stages: is deliberate: the application cannot add steps before or after the governed flow, which matters when the templates carry controls you want everyone to run.

Layout of the templates

templates/
  stages/gitflow.yml         entry point: which stages run, from the branch
  jobs/ci.yml                build and package
  jobs/publish-snapshot.yml  develop → Exchange
  jobs/release.yml           Maven release on main
  jobs/deploy.yml            deploy a version from Exchange to CloudHub 2.0
  steps/setup-maven.yml      Java 17, Maven cache, settings.xml
docs/adr/                    the reasons behind each choice

Stages decide when, jobs decide what, steps are the reusable pieces. Decisions that would otherwise live in someone’s head — why the release runs on main, why nothing is rebuilt per environment — are ADRs next to the code.

Secrets without secure files

Maven needs credentials for Exchange. A common approach stores a whole settings.xml as a secure file. The templates generate it instead, from a variable group, at runtime:

- bash: |
    cat > "${SETTINGS_PATH}" <<XML
    <settings>
      <servers>
        <server>
          <id>anypoint-exchange-v3</id>
          <username>~~~Client~~~</username>
          <password>${ANYPOINT_CLIENT_ID}~?~${ANYPOINT_CLIENT_SECRET}</password>
        </server>
      </servers>
    </settings>
    XML
  env:
    ANYPOINT_CLIENT_ID: $(ANYPOINT_CLIENT_ID)
    ANYPOINT_CLIENT_SECRET: $(ANYPOINT_CLIENT_SECRET)

~~~Client~~~ with clientId~?~clientSecret is how Exchange accepts a Connected App instead of a user. The Connected App needs Exchange Contributor, the Runtime Manager deploy scopes and access to each target environment. The secret lives in the variable group vg-00-anypoint-platform, marked secret, so it is masked in logs — and secret variables have to be mapped into env explicitly, as above.

Why MUnit is not in this pipeline

MUnit runs on the Mule Enterprise runtime, which Maven downloads from MuleSoft’s Enterprise repository. Access to it comes with a customer subscription, and the credentials belong to that customer.

This is a public, personal project. I could have used an employer’s credentials — protected as a secure file, nobody would see them — but that would be using their licence outside their business. So the pipeline builds with -DskipMunitTests, MUnit runs locally before each pull request (mvn clean test, six tests, 100% coverage) and the PR template asks for it. In a company pipeline, the change is two lines: provide the Enterprise repository credentials and remove the flag. ADR 4 records the decision.

It is worth confirming that the rest works without those credentials. Packaging the app with an empty settings.xml and an empty local Maven repository succeeds: only MUnit needs the Enterprise repository.

A misleading MUnit failure

While writing the local tests, the suite refused to deploy. The first error in the log was:

[global.xml:15]: Connection is not secure. Should use `HTTPS`

That is a warning from the HTTP connector’s validations, and it appears in healthy projects too. The real error was on the next line: a test called create-order, the same name as a flow. MUnit tests share the application’s global namespace. Prefix test names (test-create-order) and the suite runs.

Private project, public evidence

Microsoft no longer lets this organisation create public Azure DevOps projects, so the project is private. The evidence stays public anyway: every run reports back to GitHub as a check on the commit or pull request, and status badges in the README are readable without signing in.

Checklist

  • Is each application’s pipeline a thin extends of a tagged template version?
  • Can the templates change without silently changing every application?
  • Are credentials generated at runtime from secret variables, mapped explicitly into env?
  • Are the decisions behind the templates written down next to them?