This action will scan a code base and publish any public JavaScript modules it detects. It supports publishing one or more modules, custom npm registries, npm dist-tags, and custom .npmrc
files.
Modules are detected by the presence of a package.json
file. Private packages will not be published (unless forced) and .npmrc
files will be respected if they exist within the module's root directory.
This action was designed for workflows which require variations of a module to be published under different names. For example, a Node version and a browser version of the same library.
This action serves as the last step of a multi-phase deployment process:
- Build & Test for multiple runtimes.
- Autotag new versions by updating
package.json
. - Publish multiple modules (i.e., this action).
First, you'll need an npm security token.
To get this, login to your npm account and find/create a token:
Additional instructions are available here.
Once you've created your npm token, you'll need to make your Github repo aware of it. To do this, create an encrypted secret (called REGISTRY_TOKEN
).
The following is an example .github/publish.yml
that will execute when a release
occurs. There are other ways to run this action too (described later), but best practice is to publish whenever code is released.
name: Publish
on:
release:
types:
- published
# - created
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: author/action-publish@stable
with:
# Optionally specify the directories to scan
# for modules. If this is not specified, the
# root directory is scanned.
scan: "./dist/browser, ./dist/node"
# Optionally force publishing as a public
# module. We don't recommend setting this,
# unless you have a very specific use case.
force: true
env:
# Typically an npm token
REGISTRY_TOKEN: "${{ secrets.NPM_TOKEN }}"
To make this work, the workflow must have the checkout action before the publish action.
This order is important!
- uses: actions/checkout@v2
- uses: author/action-publish@stable
If the repository is not checked out first, the publisher cannot find the
package.json
file(s).
There are several options to customize how the publisher handles operations.
-
scan
The scan attribute tells the publish action to "look for modules in these directories". If this is not specified, the publish action will scan the project root. Multiple directories can be supplied using a comma-separated string. Do not use a YAML array (Github actions does not recognized them).
This supports glob syntax. Any
node_modules
directories are ignored automatically.A module is detected when a
package.json
file is recognized. Private packages will not be published.- uses: author/action-publish@stable with: scan: ".browser_dist, .node_dist" env: REGISTRY_TOKEN: "${{ secrets.NPM_TOKEN }}"
-
ignore
The ignore attribute tells the publish action to skip any modules matching the ignored patterns.
- uses: author/action-publish@stable with: scan: "./" ignore: "**/build, **/test" env: REGISTRY_TOKEN: "${{ secrets.NPM_TOKEN }}"
-
force
It's somewhat possible to force publishing, even if the
private: true
attribute is specified in apackage.json
file. Whether this option will be respected or not is dependent on the registry where the module is being published. Generally, it is not a good idea to use this option. It exists to help with edge cases, such as self-hosted private registries.- uses: author/action-publish@stable with: force: true env: REGISTRY_TOKEN: "${{ secrets.NPM_TOKEN }}"
-
dist_tag
Set a npm dist-tag by configuring this attribute. This tag will be applied to all non-prerelease versions (i.e.
x.x.x
, notx.x.x-prerelease
).This allows users to install your module via tag name. For example
npm install mymodule@current
.To apply multiple tags, separate with commas.
- uses: author/action-publish@stable with: dist_tag: latest, current env: REGISTRY_TOKEN: "${{ secrets.NPM_TOKEN }}"
Notice: npm automatically creates a
latest
tag on every publish (this attribute can override it). -
prerelease_dist_tag
Set a npm dist-tag for a prerelease version by configuring this attribute. This tag will be applied to all prerelease versions (i.e.
x.x.x-prerelease
, notx.x.x
).This allows users to install your module via tag name. For example
npm install mymodule@next
.To apply multiple tags, separate with commas.
- uses: author/action-publish@stable with: prerelease_dist_tag: next, beta, canary env: REGISTRY_TOKEN: "${{ secrets.NPM_TOKEN }}"
This differs from
dist_tag
because it only applies to pre-releases.A common approach is to set a dist-tag for prereleases so users will not automatically install a pre-release version when they want the latest stable version. In other words, running
npm install mymodule
(which is the equivalent ofnpm install mymodule@latest
) should install the latest stable version whilenpm install mymodule@canary
would install the latest prerelease/bleeding edge version.
This action is best used as part of a complete deployment process. Consider the following workflow:
name: Tag, Release, & Publish
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
# Checkout your updatd source code
- uses: actions/checkout@v2
# If the version has changed, create a new git tag for it.
- name: Tag
id: autotagger
uses: butlerlogic/action-autotag@stable
with:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
# The remaining steps all depend on whether or not
# a new tag was created. There is no need to release/publish
# updates until the code base is in a releaseable state.
# Create a github release
# This will create a snapshot of the module,
# available in the "Releases" section on Github.
- name: Release
id: create_release
if: steps.autotagger.outputs.tagcreated == 'yes'
uses: actions/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.autotagger.outputs.tagname }}
release_name: ${{ steps.autotagger.outputs.tagname }}
body: ${{ steps.autotagger.outputs.tagmessage }}
draft: false
prerelease: ${{ steps.autotagger.outputs.prerelease == 'yes' }}
# Use this action to publish a single module to npm.
- name: Publish
id: publish
if: steps.autotagger.outputs.tagname != ''
uses: author/action-publish@stable
env:
REGISTRY_TOKEN: "${{ secrets.NPM_TOKEN }}"
The configuration above will run whenever new code is merged into the master branch. It will check the code out and use the butlerlogic/action-autotag tag to automatically create a new git tag if a new version is detected. If there is no new tag, the action exits gracefully and successfully.
If a new tag exists, the action will create a new Github Release. It is smart enough to determine whether it's a prerelease or not (draft releases are not applicable to this workflow). Once the release/pre-release is created, the code is published to npm.
If you're using our cross-runtime template, then you will likely want to publish multiple versions of your module for Node.js and the browser. This requires modified pre-release, release, and publish steps.
We like to archive each module in our releases, making it easier for developers to find prior editions they may need to function in older environents. This can be accomplished by adding a build step after the release step. It may seem counterintuitive to do it after, but you'll need to create a release before uploading artifacts to it.
- name: Build Release Artifacts
id: build
run: |
cd ./build && npm install && cd ../
npm run build --if-present
for d in .dist/*/*/ ; do tar -cvzf ${d%%/}-x.x.x.tar.gz ${d%%}*; done;
- name: Upload Release Artifacts
# This is not one of our actions
uses: AButler/[email protected]
with:
files: './.dist/**/*.tar.gz'
repo-token: ${{ secrets.GITHUB_TOKEN }}
The last line of the build step above looks for a directory called .dist
. By default, the cross runtime template generates bundles in:
.dist
> node
- module
- module
> browsers
- module
- module
The .dist/*/*
finds all of the module
directories and generates a tarball from them. If you do not care about taking a snapshot of these individual modules for your release, you can remove the last line.
If you do want a snapshot of your modules, none of this is necessary.
The final publish step needs to be modified to:
- name: Publish
id: publish
if: steps.autotagger.outputs.tagname != ''
uses: author/action-publish@stable
with:
scan: './.dist'
env:
REGISTRY_TOKEN: "${{ secrets.NPM_TOKEN }}"
The publish action will scan the .dist
directory (and recursively scan subdirectories) to find all modules and publish them.
This action was written and is primarily maintained by Corey Butler.
If you use this or find value in it, please consider contributing in one or more of the following ways:
- Click the "Sponsor" button at the top of the page.
- Star it!
- Tweet about it!
- Fix an issue.
- Add a feature (post a proposal in an issue first!).
Copyright © 2020 Author.io, Corey Butler, and Contributors.