# CI Integration

There are two parts to CI integration with beachball:

  1. Add a PR build step to call beachball check to validate that change files are included.
  2. Add a release build step to call beachball publish to publish to npm and push back to git (this page).

To automate the bumping of package versions based on change files, you'll need to configure your release workflow/pipeline so that beachball publish has write access to the git repo and npm registry. The exact steps will vary between CI systems, but general concepts as well as steps for some common setups are outlined below.

# Authentication

Automated publishing from a GitHub repo to the public npm registry (registry.npmjs.org) typically uses personal access tokens for authentication. These tokens are stored as secrets in your CI system. You should ensure that these secrets are only available to release builds.

For Azure DevOps repos publishing to a private registry, there are other possible approaches (such as using a service account with credentials stored in a key vault) which are not currently covered by these docs.

# Generating tokens

# npm token

If publishing to the public npm registry (registry.npmjs.org), create a granular access token (opens new window) with write access to only the relevant package(s) and/or scope(s). Classic automation tokens are not recommended due to their overly broad permissions.

# GitHub token

You should use branch protection (opens new window) for your main/master branch, but this creates some difficulties for pushing changes back during automated publishing.

The main way to allow beachball to push back to a repo with branch protections is by using a classic personal access token (opens new window) with repo permissions. (If the repo is part of an organization that uses SAML single sign-on (SSO), be sure to authorize the token for SSO access (opens new window).) Since classic PATs have broad permissions, they must only be accessible to release builds—instructions below.

An alternative approach is creating a classic PAT with a "machine user" account. Create a new account with an alternate email or subaddress (opens new window) (+ address), give it contributor permissions to only this repo, and add it under "Restrict who can push to matching branches" in the branch protection rule.

(It's unclear if/when branch policy bypass support will be added for fine-grained PATs (opens new window); it's been requested (opens new window) by users with no response and doesn't seem to be on the public roadmap (opens new window). The built-in GITHUB_TOKEN (opens new window) won't work for the same reason.)

# Storing tokens

GitHub Actions

To restrict secret access to appropriate branches, use an environment (opens new window). (The docs for environments focus on cloud deployments or resources, but environments can also be used only for secret storage.)

  1. Create an environment (opens new window).
  2. Restrict deployment branches (opens new window) to "Selected branches" and add a rule to allow only your release branch(es) (often main/master).
  3. Add secrets (opens new window) for the npm and GitHub tokens.
  4. To use the environment (opens new window), add a key environment: your-env-name in your release workflow job. (Full example below.)

Azure Pipelines

There are a couple of options here:

# Setting options for publishing

If you're passing any custom options besides the npm token to beachball publish, it's recommended to set them in either the beachball config (if they don't interfere with other commands), or a package.json script (if specific to publish).

For example, the following script could be used for publishing public scoped packages:

{
  "scripts": {
    "release": "beachball publish --access public"
  }
}

If you're publishing to a private feed, registry should be set in the overall beachball config, since it's also used by the sync command. For example, if your beachball config is in the root package.json (or it works the same in a config file):

{
  "beachball": {
    "registry": "https://pkgs.dev.azure.com/some-org/_packaging/some-feed/npm/registry/"
  }
}

# Publishing

The exact publishing setup will vary depending on your CI setup, but the overall steps are as follows:

  1. Ensure the git user name and email are set, or git will reject the commit. Somewhere in your pipeline:
    git config user.name "someone"
    git config user.email "someone@example.com"
    
  2. Set up git authentication. This could use tokens (covered below), SSH keys, or some other non-interactive method.
  3. Set up npm authentication. This could use tokens passed on the command line (covered below), tokens set in .npmrc, or some other method.
  4. Run beachball publish!

# GitHub repo + GitHub Actions

Here's a sample setup for publishing from a GitHub repo using GitHub actions. The environment, secret, and script names can be modified as you prefer.

This sample assumes the following:

  • An environment called release (set up as described above) with the following secrets:
  • A repo root package.json script release which runs beachball publish
  • The build is running on a Linux/Mac agent. (This could be easily adapted to a Windows agent with different syntax in the commands.)

Note that in GitHub Actions, it's easiest to set up authentication if you set persist-credentials: false when checking out code.

# Example trigger configurations (choose one or more, or another setup)
# on:
#   # Release on push to main
#   push:
#     branches: [main]
#   # Release daily (see https://crontab-generator.org/ for help with schedules)
#   schedule:
#     - cron: '0 8 * * *'
#   # Release on manual trigger (can be used alone or with other options)
#   workflow_dispatch:

environment: release

# Variable syntax below assumes Linux/Mac but could be easily adapted to Windows
runs-on: ubuntu-latest

steps:
  - name: Check out code
    uses: actions/checkout@v3
    with:
      # Prevent the action from storing credentials in a way that's hard to override
      persist-credentials: false

  # ... Other steps to prepare for publishing (install, build, test, etc) ...

  # Set the name, email, and URL with PAT
  - name: Set git credentials
    run: |
      git config user.name "someone"
      git config user.email "someone@example.com"
      git remote set-url origin "https://$REPO_PAT@github.com/your-org/your-repo"
    env:
      REPO_PAT: ${{ secrets.REPO_PAT }}

  # Pass the token on the command line for publishing
  - name: Publish
    run: npm run release -- --token "$NPM_TOKEN"
    env:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

# GitHub repo + Azure Pipelines

Here's a sample setup for publishing from a GitHub repo using Azure Pipelines. The environment, secret, and script names can be modified as you prefer.

This sample assumes the following:

  • A variable group called Beachball secrets (set up as described above) with the following secrets:
  • A repo root package.json script release which runs beachball publish
  • The build is running on a Linux/Mac agent. (This could be easily adapted to a Windows agent with different syntax in the commands.)
# Example trigger configurations (choose one or more, or another setup)
#
# # Release on push to main
# trigger: [main]
#
# # Release on a schedule
# # https://docs.microsoft.com/en-us/azure/devops/pipelines/build/triggers?tabs=yaml&view=azure-devops#supported-cron-syntax
# schedules:
#   - cron: '0 8 * * *'
#     branches:
#       include: [main]

# This group should only be accessible to the release pipeline
variables:
  - group: Beachball secrets

# Variable syntax below assumes Linux/Mac but could be easily adapted to Windows
pool:
  vmImage: ubuntu-latest

steps:
  # ... Other steps to set up repo and prepare for publishing (install, build, test, etc) ...

  # Set the name, email, and URL with PAT
  - script: |
      git config user.name "someone"
      git config user.email "someone@example.com"
      git remote set-url origin "https://$(REPO_PAT)@github.com/your-org/your-repo"
    name: Set git credentials

  # Pass the token on the command line for publishing
  - script: npm run release -- --token "$(NPM_TOKEN)"
    name: Publish

# Azure Repos + Azure Pipelines

This should be very similar to the GitHub version, aside from possibly the authentication method. You could potentially use personal access tokens for git and npm feed authentication (similar to above), or other methods are available which aren't currently covered here.

If you're publishing to a private Azure Artifacts npm feed, be sure to set registry in the beachball config as described above.