This semantic-release publishing flow consists of using a bot for publishing releases. Note that commits by this bot will not be signed/verfied. If this is a requirement for you, refer to this guide. This setup requires creating a Github App and adding the following Github Actions secrets to the repo it is being used in:
NPM_TOKEN
- Refer to “Generating an NPM token” section.
MY_RELEASER_ID
- Refer to “Creating a GitHub App” section
MY_RELEASER_PRIVATE_KEY
- Refer to “Creating a GitHub App” section
- Go to npmjs.com and create an account, if necessary.
- Click “Access Tokens” from the menu.
- Click “Generate New Token”
- Click “Granular Access Token”
- Give the token a descriptive name that differentiates it from the rest of the tokens in your account, such as “My Releaser Bot”
- Provide a description, such as “Token for My Releaser Bot”
- Provide an expiration date, such as “12/31/2100”
- Set permissions to “Read and write”
- Select the package
- Click “Generate token”
- Copy the “Token”
⚠️ This token will never be visible on the NPM website again.
- Create a secret in the Github repo this will be used and name it
NPM_TOKEN
- Paste the token value from the previous step
We need to create an internal GitHub app to act as the release bot with very strict permissions. If the setting is not specified here, it should NOT be checked or filled in when creating the app.
- Got to your Github org homepage
- Click “Settings”
- Click “Developer settings”
- Click the “GitHub Apps” tab
- Click “New GitHub App”
- Configure the app as follows:
- GitHub App name:
- My Releaser (results in a my-releaser slug)
- Description:
- Internal bot to handle automatic releases of packages.
- Homepage URL:
- Callback URL:
- Repository permissions:
- Checks - read/write
- Contents - read/write
- Issues - read/write
- Metadata - read
- Pull requests - read/write
- Secrets - read
- Where can this GitHub App be installed?
- Only on this account (Only allow this GitHub App to be installed on the @your-org account)
- GitHub App name:
- Click “Create GitHub App”
- Make note of the “App ID” to reference later.
- Click “generate a private key”
- This will create a private key and trigger a download of a
.pem
file to your machine - The
.pem
must be stored securely. - If this key is lost, you will have to create a new private key in the Github app settings (you won’t have to create a new app)
- This will create a private key and trigger a download of a
- Click the “Install App” tab and install the app in your organization
- Select the repos that this internal app should have access to.
- Since this is is an internal app with very limited permissions, it should be safe to give it access to all the the org’s repos. However, it probably makes sense to gradually give the app access to more repos as necessary.
- Select the repos that this internal app should have access to.
- In the repo that this bot will be used in, add the following GitHub Actions secrets
MY_RELEASER_ID
- Paste the App ID noted earlier as the value
MY_RELEASER_PRIVATE_KEY
- Paste the contents of the
.pem
file downloaded earlier as the value
- Paste the contents of the
- If the repo has the following protections, we will have to modify the settings so that the
my-releaser
Github app can bypass one of the protections- Protections:
- ☑ Require a pull request before merging
- ☑ Require approvals
- Modify with:
- ☑ Allow specified actors to bypass the required pull requests - Search for and select
my-releaser
as an actor that can bypass this requirement - Repeat the above for every protected branch in the repo (e.g.,main
,beta
, …)
- ☑ Allow specified actors to bypass the required pull requests - Search for and select
- Protections:
The following YAML code should be placed in the projects .github/workflows/release.yml
file of the repo you're using this bot in.
Note that this file makes use of all the environment variables described in the “Overview” section, so it is crucial that they’re all defined in the Github Actions secrets of the repo you're using this bot in.
The only environment variable in this file that does not need to be defined as a Github Actions secret is GITHUB_TOKEN
.
name: release
on:
push:
branches:
- main
- beta
workflow_dispatch:
permissions:
contents: write
issues: write
pull-requests: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Generate bot app token
id: generate_token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.RELEASER_ID }}
private-key: ${{ secrets.RELEASER_PRIVATE_KEY }}
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ steps.generate_token.outputs.token }}
fetch-depth: 0
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20.x"
- name: Get bot user ID
id: bot-user-id
run: |
echo "user-id=$(gh api "/users/${{ steps.generate_token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
- name: Install dependencies
run: npm install
- name: Run tests
run: npm run test
- name: Build package
run: npm run-script build
env:
NODE_ENV: production
- name: Publish package
run: npx semantic-release
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
GIT_AUTHOR_EMAIL: "${{ steps.bot-user-id.outputs.user-id }}+${{ steps.generate_token.outputs.app-slug }}[bot]@users.noreply.github.com"
GIT_COMMITTER_EMAIL: "${{ steps.bot-user-id.outputs.user-id }}+${{ steps.generate_token.outputs.app-slug }}[bot]@users.noreply.github.com"