GitHub Packages is a place where you are able to publish and download packages for a variety of different platforms. At the time of writing, it supports NPM, Docker, NuGet, Apache Maven and RubyGems. There are no storage or transfer limits for open-source projects. Private projects have a 500MB storage and 1GB transfer limit under the free tier. These increase for paid customers respectively.
In this guide, we are going to focus on publishing an NPM package to GitHub packages using GitHub Actions and also show you how to install and use that package in a project. This guide will use Yarn as the preferred package manager.
Create a new blank repository on GitHub called my-project
with main
being the branch. Ensure the visibility of the project is public.
Next, let's create our project locally and set the upstream to track our new repository. Ensure @github_username
is your GitHub username.
mkdir new-project
cd $_
git init
git remote add origin git@github.com:github_username/my-project.git
echo "# my-project" > README.md
git add -A
git commit -m "Initial commit"
git push -u origin main
package.json
file with one dependency. It will then commit the package.json
.git checkout -b v1
cat > package.json << EOF
{
"name": "@github_username/my-project",
"version": "1.0.0",
"license": "UNLICENSED",
"author": "Your name",
"dependencies": {
}
}
EOF
git add -A
git commit -m "Add package.json"
git push -u origin v1
mkdir src
echo 'console.log("hello")' > src/index.js
git add -A
git commit -m "Add index.js"
git push
mkdir -p .github/workflows
cat > .github/workflows/ci.yml << EOF
name: CI
on: push
jobs:
pipeline:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '14.x'
registry-url: 'https://npm.pkg.github.com'
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish to GitHub Registry
run: |
pkg_name=$(cat package.json | jq -r '.name')
pkg_version=$(cat package.json | jq -r '.version')
branch=${GITHUB_REF##*/}
if [[ $branch != "main" ]]; then
yarn version --new-version "$pkg_version-beta$GITHUB_RUN_NUMBER" --no-git-tag-version
yarn publish --tag beta --access public
else
yarn publish --access public
fi
EOF
Let's go through the steps of what's going on above
on: push
Checkout repository
Install Node.js
registry-url
to https://npm.pkg.github.com which is what we need to publish to GitHub packages. Lastly, we need to provide the step with a token. GitHub gives us GITHUB_TOKEN
automatically for use with Actions.Publish to GitHub Registry
This is where things get interesting. Luckily the GitHub runners provide some built-in utils on the image they run on. Good for us because we want to use jq
to parse the contents of the package.json
file.
We extract the package name and version number.
Important - the published version of the package will be derived from the version
in package.json. Ensure you update this adequately when you push.
We also retrieve the branch name using a special GitHub variable called GITHUB_REF
.
If branch is not main
If we are on a branch, we want to publish a beta version of the package appended with the Actions run number. This means for testing, we can keep committing and pushing without manually needing to change the version number.
For example, in our case, when pushed on a branch other than main
, the package version will be 1.0.0-beta1
with 1 incrementally increasing each time a new push is made.
If branch is main
If we're on main
, we will publish a non-beta version and this will solely be derived from the version specified in your package.json
.
Please note: We are working with a public package so pass the --access public
flag. You can adjust this for private packages if required.
git add -A
git commit -m "Add workflow file"
git push
Once you have done this, if you head over to https://github.com/github_username/my-project/actions, you should see the action start.
Once complete, go to the repository homepage and click the settings cog next to About in the top right corner of the screen. You can then toggle the visibility of packages and they should appear, after ticking the packages checkbox, on the right hand sidebar.
Time to merge our branch to main
and get the non-beta version published. The below code will also delete the v1
branch.
git checkout main
git merge v1
git branch -d v1
git push origin :v1
git push
Again, check the Actions area on the repository to ensure it successfully publishes.
Now we are ready to use our package. Unlike NPM, GitHub packages is what's known as a custom registry. This is basically the case for anything not published to NPM.
It means, we can't just do the below as we need to tell Yarn to look somewhere else for our package:
yarn add @github_username/my-project
In order to install packages from GitHub packages, we need a token.
You'll need a GitHub Personal Access Token with read:packages
permission. You can create one at https://github.com/settings/tokens.
Once you have it, copy it to your clipboard as you'll never see it again and add it to your .zshrc
or .bash_profile
export GITHUB_REGISTRY_TOKEN=YOUR_TOKEN_HERE
Then source ~/.zshrc
or source ~/.bash_profile
.
To confirm it's in your environment, run the following and it should show the contents of your token.
echo $GITHUB_REGISTRY_TOKEN
Create a folder somewhere where you'd like to use your new package.
Now we have our token, we need to create an .npmrc
file. Go to the folder you just created from the last step and run the following:
cat > .npmrc << EOF
always-auth=true
@github_username:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=\${GITHUB_REGISTRY_TOKEN}
EOF
This is doing a couple of things. Firstly, we're saying that any dependencies prefixed with @github_username
should be derived from the GitHub packages registry. Secondly, as we need to authenticate with GitHub to do this, we tell .npmrc
to grab the required authToken from the $GITHUB_REGISTRY_TOKEN
variable we created earlier.
Now we can do:
yarn add @github_username/my-project
With custom registries, Yarn/NPM will try to resolve from the custom registries first before defaulting to https://www.npmjs.org.
Congratulations, you should now have your custom package finally installed in a project!
Tip - To install a beta version of a package:
yarn add @github_username/my-project@beta
As package authors are already probably aware, you can selectively decide what you want your published package to contain.
Run yarn pack
inside the folder the package resides in to see what your published package will actually include. If there's files and directories in there that you don't want published, you can create an .npmignore
file in your package that will exclude things you tell it. This works similar to a .gitignore
with glob patterns supported.