How To Set Up GitHub Actions to Publish a Lerna Monorepo

UPDATED:

This configuration actually works end-to-end. The key features of this config are:

  • setting the remote with git remote set-url origin https://$GITHUB_ACTOR:[email protected]/bennypowers/apollo-elements GITHUB_ACTOR is provided by the runner, GITHUB_PAT is a Github Personal Access Token set in the repository's secrets.
  • re-checking and pulling with git checkout "${GITHUB_REF:11}" && git pull
  • logging out of yarn, since lerna cannot handle yarn for whatever reason.
  • using the specific, finicky .npmrc setup shown below, since this is a scoped package.
  • running npm whoami after setting up auth. This will throw if authentication is broken lerna publish will push tags for each of your packages, and maybe write to the CHANGELOG.md and package.json files as well, even if it doesn't publish due to bad auth. Running npm whoami here to check that you actually can publish before running lerna prevents the headache of manually restoring the state of the repo.
  • passing GITHUB_TOKEN, GH_TOKEN, and NPM_TOKEN to lerna publish
name: CD

on:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v1

      - name: Configure CI Git User
        run: |
          git config --global user.name '@bennypowers'
          git config --global user.email '[email protected]'
          git remote set-url origin https://$GITHUB_ACTOR:[email protected]/bennypowers/apollo-elements
        env:
          GITHUB_PAT: ${{ secrets.GITHUB_PAT }}

      - name: Checkout and pull branch
        run: git checkout "${GITHUB_REF:11}" && git pull

      - name: Install Packages
        run: yarn install

      - name: Authenticate with Registry
        run: |
          yarn logout
          echo "@apollo-elements:registry=http://registry.npmjs.org/" > .npmrc
          echo "registry=http://registry.npmjs.org/" >> .npmrc
          echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc
          npm whoami
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Publish package
        run: lerna publish --yes --message 'chore: release new versions'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_PAT }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_PAT }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Note the above config redacts some irrelevant steps. See the complete workflow for the unredacted version

ORIGINAL ANSWER:

With help from StackOverflow user @rmunn, I arrived at this solution:

  - name: Configure CI Git User
    run: |
      git remote rm origin
      git remote add origin "https://$USER_NAME:[email protected]/apollo-elements/apollo-elements.git"
      git fetch
      git config --global user.email [email protected]
      git config --global user.name GitHub Actions
    env:
      USER_NAME: ${{ secrets.DEPLOYING_USER_NAME }}
      GITHUB_PAT: ${{ secrets.GITHUB_PAT }}

Where GITHUB_PAT is a personal access token with repo scope, saved in secrets.

The git fetch is required to set up local branches on the altered remote. The personal access token is required to push back to the repository.


Its now possible to use simpler configuration by using checkout@v2 and setup-node@v2

jobs:
  build:

    runs-on: ubuntu-latest
    env:
      NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
    steps:

    # 1. provide Personal Access Token for checkout@v2
    - name: Checkout
      uses: actions/checkout@v2
      with:
          submodules: recursive
          token: ${{ secrets.PUBLISH_PAT }}

    # 2. setup .npmrc it uses NODE_AUTH_TOKEN
    - name: Setup .npmrc file for publish
      uses: actions/setup-node@v2
      with:
        node-version: '12.x'
        registry-url: 'https://registry.npmjs.org'

    # 3. configure git user used to push tag
    - name: Configure Git User
      run: |
        git config --global user.email "[email protected]"
        git config --global user.name "ci@$GITHUB_ACTOR"

    - name: Install dependencies
      run: yarn install

    - name: Publish
      run: |
        lerna publish --yes

Setup repository secret with below:

NPM_TOKEN is NPM token with publish permission, more info

PUBLISH_PAT is github personal access token with repo permission, more info