Using GitHub Workflow with Maven dependencices from a private GitHub Package Registry
Tags: github, cicd, java
Published: 2020-12-19 11:39:11

GitHhub Package Repository provides an easy way to share dependencies like Maven artifacts between GitHub projects. Publishing of new artifacts into GitHub Package Repository can be automated with GitHub Actions.

In May 2019 [GitHub introduced the GitHub Package Registry](https://github.blog/2019-05-10-introducing-github-package-registry/): an alternative to some traditional package registries like [Sonatype Nexus](https://www.sonatype.com/nexus/repository-pro). During that time I had no use for it, because all of our internal dependencies had been stored in our private company Artifactory instance.

Fast forward to 2020: With the beginning of the year we had privately started the work on [ninkik](https://ninkik.com/). GitHub and GitHub Actions had been used from the beginning for storing the repository and doing CI/CD stuff. We included some Maven dependencies from our [company’s Artifactory](https://www.schakko.de/2020/05/24/how-to-use-a-private-maven-repository-in-artifactory-with-github-actions/) in GitHub Actions CI process.
![ninkik required an internal library from our private Artifactory instance.](https://www.schakko.de/wp-content/uploads/2020/12/gh-actions-dependencies-to-internal-artifactory.png)

# Project reorganization required

In November 2020 we reached the point that we had to re-organize ninkik’s project structure:

1. The Maven project had to be broken up into a multi-module Maven project.
2. In the long term, our internal library (Library A) had to be transitioned from Jenkins and Artifactory to GitHub Actions and GitHub Package Registry.

![New location of dependencies. Moving everything to GitHub.](https://www.schakko.de/wp-content/uploads/2020/12/restructuring-ninkik.png)

# Publishing a Maven artifact to GitHub Package Registry
For our *Library A* we already had a simple script which prepared new for Artifactory. I explicitly did not wanted to switch those process to the Maven goals [release:prepare](https://maven.apache.org/maven-release/maven-release-plugin/examples/prepare-release.html) and [release:perform](https://maven.apache.org/maven-release/maven-release-plugin/examples/perform-release.html).

Instead, I just wanted to publish a new artifact to GitHub Package Registry on each build by using our script and the [deploy:deploy](https://maven.apache.org/plugins/maven-deploy-plugin/) goal.

## Adjusting pom.xml for distribution management

Using the `deploy:deploy` goal requires you to set up a new repository in the `distributionManagement` tag of the `pom.xml`. In my case I decided to enable the additional repository by using a Maven profile:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.dreitier</groupId>
    <artifactId>library-a-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <!-- ... -->
    <profiles>
        <profile>
            <id>github</id>
            <distributionManagement>
                <repository>
                    <id>github</id>
                    <name>GitHub Packages</name>
                    <url>https://maven.pkg.github.com/dreitier/library-a</url>
                </repository>
            </distributionManagement>
        </profile>
    </profiles>
    <!-- ... -->
</project>
```

With Maven’s `-P` command line parameter you can now use the Maven profile `github`. To test the configuration locally, you have to create a [Personal Access Token](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token) for your GitHub acocount.

To upload artifacts into the GitHub Package Registry, your Personal Access Token must have the scope `write:packages`:

![This Personal Access Token needs the write:packages scope](https://www.schakko.de/wp-content/uploads/2020/12/pat-permissions-for-private-account.png)

You have to add the personal access token to your Maven’s `settings.xml`:

```xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <id>github</id>
            <username>your-username</username>
            <password>your-personal-access-token</password>
        </server>
    </servers>
</settings>
```

Locally, you can now publish a new Maven artifact into the GitHub Package Registry with

```
mvn -Pgithub deploy
```

## GitHub Actions workflow
To make the publishing of this artifact working in the GitHub Actions workflow is straightforward. You just need to add a few lines in your `.github/workflows/maven.yml`:

```yaml
on:
  push:
    branches: ["**"]
 
jobs:
  build:
 
    runs-on: ubuntu-latest
 
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 11.0.2
        uses: actions/setup-java@v1
        with:
          java-version: 11.0
 
      - name: Deploy
        run: mvn -B -Pgithub deploy
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

`actions/setup-java` does automatically set up a Maven settings.xml with a proper configuration for deployment. It references the `${env.GITHUB_TOKEN}` variable. `GITHUB_TOKEN` is a private token which is automatically available and has assigned permissions for the repository of the current GitHub Actions Workflow.

**Warning**
You have to make sure that you clean-up old packages in your registry. Depending upon your commit rate and package size your repository will reach the package registry’s quota.

At the moment, there is no custom action available which discards all published package **but** the latest *n* versions. [actions/delete-package-versions](https://github.com/actions/delete-package-versions) currently only supports to discard the last *n* versions.

With the next GitHub Actions build, your artifacts will be published and pop up in the repository’s dashboard:
![](https://www.schakko.de/wp-content/uploads/2020/12/github-released-packages.png)

# Depending upon an artifact in GitHub Package Registry
In [ninkik](https://ninkik.com/) I had to replace the old Artifactory Maven registry with the GitHub Package registry. From the previous steps, you have locally the Maven `github` profile already available. In my case I added the additional GitHub Package Registry repository to ninkik’s `pom.xml`:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.dreitier</groupId>
    <artifactId>ninkik-parent</artifactId>
    <packaging>pom</packaging>
 
    <profiles>
        <profile>
            <id>github</id>
            <repositories>
                <repository>
                    <id>central</id>
                    <url>https://repo1.maven.org/maven2</url>
                    <releases><enabled>true</enabled></releases>
                    <snapshots><enabled>true</enabled></snapshots>
                </repository>
                <repository>
                    <id>github</id>
                    <name>GH dreitier</name>
                    <url>https://maven.pkg.github.com/dreitier/library-a</url>
                    <snapshots><enabled>true</enabled></snapshots>
                    <releases><enabled>true</enabled></releases>
                </repository>
            </repositories>
        </profile>
    </profiles>
    <modules>
        <!-- ... -->
</project>
```

With those settings, a normal mvn package on your local machine will work. All required depdenencies are either downloaded from Maven Central or from GitHub Package Registry.

Using GitHub Package Registry repositories in GitHub Actions workflows
I expected that the GitHub Actions workflow above could be also used without any modifications for ninkik. But instead I received the following error in GitHub Actions:

```
[INFO] Downloading from github: https://maven.pkg.github.com/dreitier/library-a/library-a.jar
[DEBUG] Writing tracking file /home/runner/.m2/repository/com/dreitier/library-a/library-a.jar.lastUpdated
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for ninkik-parent 0.0.1-SNAPSHOT:
[INFO] 
[INFO] ninkik-parent ...................................... SUCCESS [  0.007 s]
[INFO] ninkik api spec .................................... FAILURE [  4.620 s]
[INFO] ...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  23.400 s
[INFO] Finished at: 2020-12-16T21:34:31Z
[INFO] ------------------------------------------------------------------------
Error:  Failed to execute goal on project ninkik-api-spec: Could not resolve dependencies for project com.dreitier:ninkik-api-spec:jar:0.0.1-SNAPSHOT: Could not find artifact com.dreitier.library-a-data-commons:jar:0.0.38-SNAPSHOT in central (https://repo1.maven.org/maven2) -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal on project ninkik-api-spec: Could not resolve dependencies for project com.dreitier:ninkik-api-spec:jar:0.0.1-SNAPSHOT: Could not find artifact com.dreitier.library-a-data-commons:jar:0.0.38-SNAPSHOT in central (https://repo1.maven.org/maven2)
    at org.apache.maven.lifecycle.internal.LifecycleDependencyResolver.getDependencies (LifecycleDependencyResolver.java:269)
The resolution of the library-a depdenency could neither be found in Maven Central (that’s correct) nor in the GitHub Package Registry.
```

After some further reading I found the reason why:

1. As I’ve already mentioned above, the `GITHUB_TOKEN` has permissions for the repository of the **current** GitHub Actions workflow but not for other organization’s or user’s repositories.
2. At the time of this writing (December 2020) GitHub Package Registry does [not allow unauthenticated](https://github.community/t/github-package-registry-as-maven-repo-trouble-uploading-artifact/14226/13) access to public repositories.
The *library-a* had been private at the moment but I would have been open to make it public in the near future.
3. This being said, *Personal Access Token*s have to be used:
  3.1 Personal Access Tokens can not be scoped on specific repositories. Your PAT would give the GitHub Actions Workflow access to all of your private published packages.
  3.2 You can create a dediciated GitHub user with permissions for your project and the depending library and then create a Personal Access Token for this dedicated user.

For testing purposes, you can go with 3.1 and create an additional *Personal Access Token* in your GitHub account below *Settings > Developer settings > Private access tokens*. The *Personal Access Token* must have the scope `read:packages`.


![](https://www.schakko.de/wp-content/uploads/2020/12/pat-permissions.png)

The `.github/worfklows/maven.yml` of the main project has to be adjusted to the following:

```yaml
on:
  push:
    branches: ["**"]
 
jobs:
  build:
 
    runs-on: ubuntu-latest
 
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 11.0.2
        uses: actions/setup-java@v1
        with:
          java-version: 11.0
          server-id: github # value of repository/id field of the pom.xml
          server-username: GITHUB_USER_REF  # env variable name for username
          server-password: GITHUB_TOKEN_REF # env variable name for GitHub Personal Access Token
 
      - name: Build with Maven
        run: mvn -B -Pgithub package --file pom.xml
        env:
          GITHUB_USER_REF: ${{ secrets.GH_PACKAGE_REPO_USERNAME }}
          GITHUB_TOKEN_REF: ${{ secrets.GH_PACKAGE_REPO_PASSWORD }}
```

The secrets `GH_PACKAGE_REPO_USERNAME` and `GH_PACKAGE_REPO_PASSWORD` are your or your dedicated user’s username and the previously generated *Personal Access Token*.

You have to add both secrets in your repository’s *Settings > Secrets* page:

![Required secrets to access Package Registry with Personal Access Token](https://www.schakko.de/wp-content/uploads/2020/12/project-secrets-for-gh-actions-workflow.png)

# Summing it up
In this blog post I’ve shown you how to set up your GitHub Actions workflow to publish Maven artifacts in GitHub Package Registry and use those dependencies in other Maven- or Gradle-based projects, also with GitHub Actions.