Support
Log In

CI/CD Setup

Automated package versioning and publishing with GitHub Actions

Your data models are Malloy code in plain files, so they fit the engineering workflow you already have: version them in Git, review them in pull requests, and publish automatically when changes merge. This page sets up that last step — a CI/CD pipeline using our GitHub Actions template.

Two ways to work in Git. This page is for models built in your IDE and kept in a repository you own. Models built in the Credible App get the same review and history through git-backed modeling, where each change becomes a branch and a pull request in a repository Credible hosts and merging is what publishes. The two coexist in one environment, package by package — see How this fits with git-backed modeling.

How It Works

When you push changes to your main branch:

  1. Detect — the pipeline identifies which packages changed
  2. Version — it bumps the patch version in each changed package's publisher.json, because a published version is immutable
  3. Publish — it publishes the new versions to your Credible environment with the CLI

A compile error fails the publish step, so a broken model never becomes a served version.

Rolling back never touches CI: re-pin the previous version as latest in the Credible App and every consumer follows, with nothing to rebuild (see Serving and version management).

Prerequisites

  • A GitHub repository for your packages
  • Admin access to the repository
  • A Credible organization and environment

Setup

Step 1: Create Repository from Template

  1. Go to the CI/CD template repository
  2. Click "Use this template""Create a new repository"
  3. Choose your organization and enter a repository name

The template includes all necessary scripts and GitHub Actions workflows.

Step 2: Configure GitHub App

The CI/CD bot needs a GitHub App to commit version bumps back to your repository.

Create the App:

  1. Go to your GitHub organization: SettingsDeveloper settingsGitHub AppsNew GitHub App
  2. Configure:
    • Name: a name unique across all of GitHub (e.g., credible-<company>-cicd-bot). GitHub App names are global, so credible-cicd-bot is already taken — pick your own. The name is cosmetic; the workflow authenticates with the App ID and private key, not the name.
    • Homepage URL: required by GitHub — any valid URL works (e.g., your repository URL)
    • Webhook: Uncheck "Active"
    • Repository permissions: Contents (Read/Write), Pull requests (Read/Write), Metadata (Read), Environments (Read)
    • Installation: "Only on this account"
  3. Click Create GitHub App
  4. Note the App ID at the top of the page
  5. Scroll to Private keysGenerate a private key (save the .pem file)
  6. Go to Install AppInstall, choose Only select repositories, and select your repository. Avoid All repositories: the App can write repository contents, and this pipeline only ever needs the one.

Step 3: Configure Secrets

Go to your repository: SettingsSecrets and variablesActionsNew repository secret

SecretValue
CICD_BOT_APP_IDYour GitHub App ID
CICD_BOT_APP_PRIVATE_KEYEntire contents of the .pem file, including the -----BEGIN and -----END lines
JWT_ACCESS_TOKENCredible API token (see note below)

Generate a Credible API token using the CLI: cred add group-access-token. Create a group whose only member is the pipeline, so the token carries exactly the access the pipeline needs. The token is shown once — store it as a repository secret, never in the repository itself. See the CLI documentation for details.

The group used to generate the token needs Modeler access to your environment:

Environment sharing dialog with a group granted Modeler access

Step 4: Configure Variables

Go to: SettingsSecrets and variablesActionsVariables

VariableValue
CRED_ORGYour Credible organization name
CRED_ENVYour Credible environment name
SET_LATESTtrue or false (optional, defaults to true)

Step 5: Configure Branch Protection

  1. Go to SettingsBranchesAdd branch protection rule
  2. Branch name pattern: main
  3. Enable:
    • Require a pull request before merging, with at least one approval
    • Allow specified actors to bypass required pull requests → add your App
    • Require status checks to pass before merging
    • Require conversation resolution before merging
    • Restrict who can push to matching branches → add your App

The two App entries are what let the pipeline commit its version bump to a branch that otherwise refuses direct pushes. Without them the bump cannot land and the publish never runs.

Publishing to More Than One Environment

The template publishes to a single environment. To promote through staging and production, give deploy.yaml one publish job per environment and pass each an environment name, which binds that job to a GitHub Environment and applies its protection rules:

jobs:
  publish-staging:
    needs: bump
    if: needs.bump.outputs.bumped != ''
    uses: ./.github/workflows/publish-packages.yml
    with:
      environment: staging
      packages: ${{ needs.bump.outputs.bumped }}
      cred_org: ${{ vars.CRED_ORG }}
      cred_env: ${{ vars.CRED_ENV_STAGING }}
    secrets:
      jwt_access_token: ${{ secrets.JWT_ACCESS_TOKEN_STAGING }}

Referencing a GitHub Environment is what buys you the gate: add a required reviewer to production and the production publish waits for a human while staging proceeds untouched. Each environment carries its own token, so a staging credential can never publish to production.

This is why the App needs Environments (Read) in Step 2. Give each environment its own CRED_ENV* variable and token secret rather than reusing one pair.

Repository Structure

Your repository should follow this structure:

your-repo/
├── .github/workflows/    # CI/CD workflows (from template)
├── packages/
│   ├── package-one/
│   │   ├── publisher.json
│   │   └── [your .malloy files]
│   └── package-two/
│       └── ...
└── scripts/              # CI/CD scripts (from template)

Each package needs a publisher.json:

{
  "name": "your-package-name",
  "version": "0.0.0",
  "description": "Package description"
}

Merge Strategy

Do not use "Squash and merge" for pull requests that modify packages. Squashing can cause the pipeline to miss package changes. Use Merge commit or Rebase and merge instead.

How This Fits With Git-Backed Modeling

Both paths give a model change a pull request, a review, and a published version with a record of where it came from. They differ in who builds the model and where the source lives.

CI/CD from your repository (this page)Git-backed modeling
Where the model is builtYour IDE and your coding agentThe Credible App, by the in-app agent
Where the source livesA repository you own, in your layoutA repository per environment that Credible hosts
What publishes a versionYour pipeline runs cred publish on mergeMerging the pull request Credible opened for the draft
Review and checksYour pull requests, your rules, your CIA pull request per change, with Credible's compile verdict as a check run
Who contributesEngineersEngineers, analysts, and domain experts, in plain language

They work side by side in one environment:

  • Packages you publish from here keep publishing from here after an environment is enrolled in git-backed modeling. Enrollment applies to drafts created in the App; a package git-backed modeling has never seen is untouched by it.
  • A package becomes git-backed the first time it is edited in the App. The agent imports the published version as the starting point, and from then on that package publishes only through a pull request.
  • Decide per package which side owns it, and keep it there. Both serve from the same environment and the same governed model.

Next Steps

When a run fails, the workflow logs in the GitHub Actions tab name the step. Email us the run ID and the error if the cause isn't there.

On this page