I'm excited to share my experience in setting up GitHub Actions for automatically publishing a package. While I use pnpm
as an alternative to npm
, this guide should also work for you if you if you use npm
instead.
The Setup
The core of this setup lies in a specific YAML file located in the .github/workflows
directory of the repository.
Here is a detailed description of each section in the file. I will add the contents of the full file at the end of this article.
1. Name
name: Release components package
Specifies the name of the GitHub Action workflow, this is what you will see in the GitHub user interface:
2. Trigger
on:
release:
types: [published]
This defines the event that triggers the workflow. This workflow is triggered when a release is published.
Initially, I used
types: [created]
but I encountered issues with triggering the action. It turns out that creating a draft release before the actual release will not trigger created
GitHub Docs: Events that trigger workflows
3. Jobs
jobs:
build:
runs-on: ubuntu-latest
This workflow defines one single job named "build" that runs on the latest Ubuntu virtual environment.
4. Steps
Step 1: Checkout Repository
steps:
- name: Checkout
uses: actions/checkout@v4
The checkout@v4 action clones the repository into the runner.
Step 2: Install pnpm
- uses: pnpm/action-setup@v2
name: Install pnpm
with:
version: 8
run_install: false
Sets up pnpm in the GitHub runner using pnpm/action-setup@v2 to install pnpm version 8. The run_install: false
parameter prevents automatic installation of dependencies at this stage.
🚀 The pnpm setup must precede the Node.js setup to take advantage of the
cache: pnpm
property in the setup-node action. This will significantly speed up build times by reusing the stored dependencies across workflow executions.
Step 3: Install Node.js
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
cache: pnpm
registry-url: https://registry.npmjs.org
Run actions/setup-node@v3 to install Node.js. While it is not mandatory in this case I like to explicitly define to read the node version from the ".nvmrc" file. It also sets up caching for pnpm.
💡 A crucial discovery was the need to explicitly set the registry URL in the Node.js setup for npm. Otherwise you will run into an authentication issue.
Step 4: Install Dependencies
- name: Install dependencies
run: pnpm install --frozen-lockfile
Executes pnpm install --frozen-lockfile
to install dependencies based on the lock file, ensuring consistent versions across builds. This is the equivalent to npm ci
which is like npm install
but based on the lock file.
Step 5: Publish Package
- name: Publish 🚀
shell: bash
run: pnpm publish packages/components --access public --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Runs the command to publish the package. In my case the package is inside a monorepo and located in packages/components
.
The --access public
flag has to be set explicitly in the command line the first time you publish a public package to npm. This is to prevent private packages from being published accidentally.
The --no-git-checks
flag is needed to bypass an issue with pnpm related to GitHub's detached HEAD state during releases.
Authentication is provided via NODE_AUTH_TOKEN
, set to a value from a GitHub secret called NPM_TOKEN
.
💡 An interesting hiccup occurred with the naming of the authentication environment variable. While using
NPM_TOKEN
seemed correct (it kind of worked), it had to beNODE_AUTH_TOKEN
for the action to work correctly. https://github.com/npm/cli/issues/1637#issuecomment-1888709776
Authentication and Security
The GitHub repository's Secrets feature is used to store the npm token. To get this token you need to log in to your npm account and generate a token that with permission to publish a new version of your package.
I chose a "Granular Access Token" that is valid for a limited time and has access to all packages of my organization.
Conclusion
Automating package publishing with GitHub Actions was generally straightforward, yet it required some fine-tuning to address certain issues. These included configuring workflow triggers, optimizing caching mechanisms, managing authentication tokens, and navigating the nuances of npm and GitHub environments for seamless operation.
Hope you found this guide helpful. Happy coding, and have a great day! 🚀👨💻👩💻
And here is full content of my YAML file (tested and working):
name: Release components package
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
name: Install pnpm
with:
version: 8
run_install: false
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
cache: pnpm
registry-url: https://registry.npmjs.org
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Publish 🚀
shell: bash
run: pnpm publish packages/components --access public --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Top comments (0)