Using the GitHub Package Registry
This repo exists in order to test out various things with the GitHub
Package Registry. Play around to your heart's content!
Learnings about the processes
Here are some things I've learned while experimenting. I've tried to
keep this specific to Planning Center's workflow as much as possible.
Setting up a package project to use GPR
Here are some simple steps to take to publish the package to GPR.
Configure the package to use GPR
Add a publishConfig key to the package.json file. The namespace
should be the same namespace that the package will be published under
(e.g. @planningcenter or @ministrycentered).
"publishConfig": {
"@ministrycentered:registry": "https://npm.pkg.github.com"
}
Publish a new release when a GitHub release is drafted
Add a GitHub workflow to publish the package when a release is cut
within GitHub. Note that this action will fail if a version with the
same number is already in the registry. So...
Make sure to bump the version number before cutting a release.
Put the following (or something like it) in
.github/workflows/release-package.yml. The current version in this
repo may have more features or implement things learned after writing
this introductory README. You can check it out
here.
name: Release package
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 12
- run: npm ci
- run: npm test
publish-gpr:
needs: build
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 12
registry-url: https://npm.pkg.github.com/
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Publishing prereleases
There are going to be times in which we need to test a package within
our apps and therefore cut a release without actually wanting to
release something. I've played around a bit with how best to do this
and haven't found an answer yet that is satisfying to me.
But here's what I've got for now.
Tagging the prerelease
In npm-land, the tag latest has special meaning. Anyone not
specifying a hyper-specific version in their package.json file will
get the package release tagged as latest. Furthermore, unless a
specific tag is used when publishing the package, npm will tag it as
latest automatically. We therefore don't want to tag a prerelease as
latest and force it to have a tag of our choosing. So what should we
tag it?
I've been toying with the idea of tagging the prereleases with the
branch name involved. For example, a prerelease based off of version
1.2.3 whose work is being done in a branch named gl/fix-bugs would
be released and tagged as something like v1.2.4-gl--fix-bugs.0 (tags
can't have slashes so I've converted the slash to a double dash). A
subsequent prerelease would be v1.2.4-gl--fix-bugs.1. These names
are valid according to the semver
spec (which I really want to
adhere to).
This tagging is a manual process at the moment, so in the package's
directory, you would run this code:
npm version prerelease --preid=gl--fix-bugs
This will bump the version numbers where required in the package and
create a git commit with the changes along with a git tag with the
version name. If you'd like to skip the git commit and tagging (like
if you want to group the version bump with other changes), pass the
--git-tag-version=false flag to the command above. Push up that
commit (or commits) in your branch. The actual release is done via
GitHub's UI.
Configuring our workflow to package the prerelease
In the workflow definition, break up the release packaging to two
separate steps guarded by if statements: one for the prerelease and
one for the release. Since we don't specify a tag for a full release,
it defaults to latest. If it is a prerelease, it'll use the branch
name the release targets with slashes replaced by double dashes1
(e.g. gl--fix-bugs for branch gl/fix-bugs) (see the next section).
steps:
- name: Publish prerelease
if: ${{ github.event.release.prerelease }}
run: npm publish --tag=${TAG_NAME}
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
TAG_NAME: ${{ github.event.release.target_commitish }}
- name: Publish release
if: ${{ github.event.ref_name == github.event.repository.default_branch }}
run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
Releasing via GitHub's UI
Now that we have the package versioned with a prerelease version name
(e.g. v1.2.4-gl--fix-bugs.1) and the release workflow configured to
handle releases and prereleases separately, it's time to cut a
prerelease on GitHub.
-
Head to the "Releases" page in the GitHub repo.

-
Hit the "Draft a new release" button.

-
Create a new tag for your release (it would be
v0.0.2-gl--branch-tags.5 in the screenshot below). Be sure to
target your branch. Name the release the same as your tag.

-
Be sure to hit the "This is a prerelease" checkbox!

-
Publish the release!
-
After the action/workflow creates the package, check to see that it
is in the Packages section.

-
Make sure that the "Latest version" tag is not on your
prerelease.

-
You can verify it was tagged correctly by checking the dist-tags on
the command line. Note that I have to specify the GitHub registry
on this command (it doesn't seem to honor our publishConfig
setting in package.json).
npm dist-tag --registry=https://npm.pkg.github.com @ministrycentered/packages-test

-
Use the prerelease in an app. You can do this either by specifying
the release version or the release tag. The difference is a tag can
point to various versions throughout its life while a version can
never be changed.
yarn add @ministrycentered/packages-test@0.0.2-gl--branch-tags.4
or for the most recently tagged version of the gl--branch-tags tag:
yarn add @ministrycentered/packages-test@gl--branch-tags
Using a published package in an app
We need to give the yarn and/or npm commands on your machine
access to our private packages on GitHub in order to install them in
apps or update them in any way. To do that, first generate a Personal
Access Token in GitHub at . The
permissions need to at least be
repo
write:packages
delete:packages
Name it something memorable, give it a reasonable expiration, and
create it.
Copy the token it shows you—we'll be using it in the next step.
Your configuration for packages is in the file ~/.npmrc. Add the
following line that that file.
//npm.pkg.github.com/:_authToken=THE_TOKEN_THAT_YOU_COPIED_FROM_THE_PREVIOUS_STEP
This will allow yarn and npm to have access to the packages hosted
in GPR.
Since using GitHub's Package Repository is not the default for package
management, we need to configure our app to look for packages there
instead of npmjs.org. To do so, we must specify that for a certain
scope of package name, look in GPR instead of npmjs. I'm still not
sure what happens during the transitional period where we have
packages scoped as @planningcenter in both npmjs and GPR. Thus, I've
scoped my test packages to @ministrycentered.
Regardless of scope, configure your app by adding a .npmrc file in
the app repo's root directory. It needs to have the following line
added for each scope name. For example, this file scopes all
@ministrycentered package names to look in GPR instead of the
default of npmjs.
@ministrycentered:registry=https://npm.pkg.github.com
Now that all that is configured correctly, you can finally install
your package as required. For example, in ~/Code/people:
yarn add @ministrycentered/packages-test@gl--branch-tags
Some good resources