DEV Community

Cover image for Using GitHub Workflow with Maven dependencices from a private GitHub Package Registry
Schakko
Schakko

Posted on • Originally published at schakko.de

Using GitHub Workflow with Maven dependencices from a private GitHub Package Registry

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: an alternative to some traditional package registries like Sonatype Nexus. 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. 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 in GitHub Actions CI process.
ninkik required an internal library from our private Artifactory instance.

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.

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 and release:perform.

Instead, I just wanted to publish a new artifact to GitHub Package Registry on each build by using our script and the deploy:deploy 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 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>
Enter fullscreen mode Exit fullscreen mode

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 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

You have to add the personal access token to your Maven’s settings.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>
Enter fullscreen mode Exit fullscreen mode

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

mvn -Pgithub deploy
Enter fullscreen mode Exit fullscreen mode

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:

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 }}
Enter fullscreen mode Exit fullscreen mode

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 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:

Depending upon an artifact in GitHub Package Registry

In ninkik 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 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>
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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 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.

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

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 }}
Enter fullscreen mode Exit fullscreen mode

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

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.

Top comments (0)