# Using github packages in Gradle and Maven projects

[Github packages](https://docs.github.com/en/packages/learn-github-packages/introduction-to-github-packages) is an easy way to publish current snapshot versions. The biggest problem with it is **access token requirement** for accessing published packages (no free access).

Yes, I know, there is a super simple [jitpack](https://jitpack.io/) for this, but it can’t be used in some cases because instead of using your build output it searches for packages with some euristic. Moreover, jitpack generates its own BOM, overwriting your own. So for multi-module (or projects with more complex build) projects jitpack is not an option.

The biggest advantage of **github packages** is its simple integration with **github actions** (super simple publication). This covers one important CI use case: test commit - publish new snapshot - use snapshot to run tests.

## Using already published package

### Create access token

On any github page, in the upper top corner, click on your profile icon and select **Settings**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1737267560262/12c30fe1-a065-4741-814e-b8bb7c2ffbbb.png align="center")

On the left bar click **Developer setting**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1737267673066/9f275e12-246f-4a70-8d18-b1d8eb80f101.png align="center")

Click **Tokens (classic)** under **Personal access tokens** section

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1737267834568/36c327c9-a7e7-407e-b30d-eaee32ed5005.png align="center")

Choose **Generate new token (classic)** in the Generate new token dropdown

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1737267897391/49400b2f-b216-49ff-a3b5-e694a891e6f0.png align="center")

Most likely, github would ask you to confirm authentication here.

Set token description. Set token to never expire because this token will only grant a read right on github packages (moreover, you’ll be able to use the same token to access any github packages repository)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1737268073854/7364fff8-8cf5-4024-9e58-d40e472822c7.png align="center")

Select ONLY **read:packages** permission.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1737268232448/e2f1bde0-e224-4583-9a23-4f0a534d7e13.png align="center")

Of course, token with any other rights added will also work, but if you do so consider setting token expiration (as such token stealing might be sensitive).

**IMPORTANT Github will show you token just once**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1737268539399/0e044e2e-139e-4e20-9dea-387f1326f4f2.png align="center")

### Gradle project configuration

Add github packages repository either in **build.gradle** :

```java
repositories {
    mavenCentral()
    maven {
        url  = 'https://maven.pkg.github.com/user/project'
        credentials {
            username = findProperty('gpr.user') ?: System.getenv("USERNAME")
            password = findProperty('gpr.key') ?: System.getenv("TOKEN")
        }
    }
}
```

OR in **settings.gradle**

```java
dependencyResolutionManagement {
    repositories {
        mavenCentral()
        maven {
            url  = 'https://maven.pkg.github.com/user/project'
            credentials {
                username = settings.ext.find('gpr.user') ?: System.getenv("USERNAME")
                password = settings.ext.find('gpr.key') ?: System.getenv("TOKEN")
            }
        }
    }
}
```

Note: **System.getenv** part will be used if you’re goinf to run this project on github actions to consume credentials directly from environment variables. If you don’t plan to run project on CI, you can remove this section (see complete description at the bottom).

Put you access token in the global gradle configuration: **~/.gradle/gradle.properties**

```java
gpr.user=<your github user name>
gpr.key=<your github classic token>
```

### Maven project configuration

Add credentials into **~/.m2/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>USERNAME</username>
            <password>TOKEN</password>
        </server>
    </servers>
</settings>
```

Add github packages repository (directly in project or in profile inside settings.xml)

```xml
<repositories>    
  <repository>
        <id>github</id>
        <url>https://maven.pkg.github.com/user/project</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>
```

IMPORTANT: **repository id** must be the same as **server id** in settings.xml (to apply configured authentication)

## Publishing package in github action

Will show publishing only for gradle project. No special repository configuration is required - just publish new package.

In **build.gradle** add github packages repository:

```java
 // https://docs.github.com/en/actions/use-cases-and-examples/publishing-packages/publishing-java-packages-with-gradle#publishing-packages-to-github-packages
publishing {
    repositories {
        maven {
            name = "GitHub"
            url = "https://maven.pkg.github.com/user/project"
            credentials {
                username = System.getenv("GITHUB_ACTOR")
                password = System.getenv("GITHUB_TOKEN")
            }
    }
}
```

**GITHUB\_ACTOR** and **GITHUB\_TOKEN** are provided automatically (no configuration required)

In “[https://maven.pkg.github.com/user/project](https://maven.pkg.github.com/user/project)” **user** - github user name, **project** - github project name (same as in github project url)

CI script:

```yaml
name: Publish snapshot

on:
  push:

jobs:
  publish:
    name: Publish snapshot
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3

      - name: Build without tests
        run: |
          chmod +x gradlew
          ./gradlew build -x test -x check --no-daemon

      - name: Publish
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SNAPSHOT: true
        run: ./gradlew publishAllPublicationsToGitHubRepository --no-daemon
```

Here on each commit project would be built without tests and new snapshot package published.

## Real project with packages publication

In [my project](https://github.com/xvik/dropwizard-guicey/), I use a series of connected workflows:

1. [CI](https://github.com/xvik/dropwizard-guicey/blob/master/.github/workflows/CI.yml) - run and test project
    
2. If test success, [publish](https://github.com/xvik/dropwizard-guicey/blob/master/.github/workflows/publish-snapshot.yml) new package
    
3. [Run examples project](https://github.com/xvik/dropwizard-guicey/blob/master/.github/workflows/examples-CI.yml) build with just published package
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1737270048807/effe6ac7-62e2-42c4-8bb4-96773c92f9c1.png align="center")

## Use github package repo on gtihub actions

On github actions you don’t need an additional token to access githubg packages because **GITHUB\_TOKEN** is already provided.

**Gradle project**

Just add repository, as it was shown in the first chapter.

```java
repositories {
    maven {
        url  = 'https://maven.pkg.github.com/user/project'
        credentials {
            username = findProperty('gpr.user') ?: System.getenv("USERNAME")
            password = findProperty('gpr.key') ?: System.getenv("TOKEN")
        }
    }
}
```

This time, token would not be configured in global gradle properties, but, instead, would be provided **in the environment variables**.

Mapping these variables in the [CI scipt:](https://github.com/xvik/dropwizard-guicey/blob/master/.github/workflows/examples-CI.yml)

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: examples
    name: Examples run
    env:
      USERNAME: ${{ github.actor }}
      TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

Note that

```yaml
    defaults:
      run:
        working-directory: examples
```

Required only in my case, because examples project is in github repository **subfolder** (examples).

**Maven project**

For maven project, credentials must be inside settings file. Custom settings file could reference environemnt variables [maven-settings.xml](https://github.com/xvik/dropwizard-guicey/blob/master/examples/maven-settings.xml):

```xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <activeProfiles>
        <activeProfile>github</activeProfile>
    </activeProfiles>
    <profiles>
        <profile>
            <id>github</id>
            <repositories>
                <repository>
                    <id>central</id>
                    <url>https://repo1.maven.org/maven2</url>
                </repository>
                <repository>
                    <id>github</id>
                    <url>https://maven.pkg.github.com/user/project</url>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
            </repositories>
        </profile>
    </profiles>

    <servers>
        <server>
            <id>github</id>
            <username>${env.USERNAME}</username>
            <password>${env.TOKEN}</password>
        </server>
    </servers>

</settings>
```

In my case, I run maven projects from gradle, using [maven-exec-plugin](https://github.com/dkorotych/gradle-maven-exec-plugin) and so could simply [specify](https://github.com/xvik/dropwizard-guicey/blob/master/examples/maven-simple/build.gradle) custom settings file:

```java
tasks.register('maven-test', MavenExec) {
    goals 'test'
    options {
        settings = rootProject.file('maven-settings.xml')
    }
}
```

But for pure maven project, you could simply override existing settings.xml with a custom file with an additional CI job step.

## Gradle plugin snapshots and github package

If you develop gradle plugin, you know that it requires two publications:

1. Plugin itself
    
2. Redirection pom for gradle plugins syntax
    

Publication method above will correctly publish both into github packages repository.

In order to use such snapshot, repositorty must be specified in **settings.gradle**’s **pluginManagement** section:

```java
pluginManagement {
    repositories {
        mavenLocal()
        gradlePluginPortal()
        maven {
            url  = 'https://maven.pkg.github.com/user/project'
            credentials {
                username = settings.ext.find('gpr.user') ?: System.getenv("USERNAME")
                password = settings.ext.find('gpr.key') ?: System.getenv("TOKEN")
            }
        }
    }
}
```

For **kotlin** syntax (**settings.gradle.kts**):

```java
pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
        maven {
            url  = uri("https://maven.pkg.github.com/user/project")
            credentials {
                username = extra.has("gpr.user").let { if (it) extra["gpr.user"] as String else System.getenv("USERNAME")}
                password = extra.has("gpr.key").let { if (it) extra["gpr.key"] as String else System.getenv("TOKEN")}
            }
        }
    }
}
```

[Example project](https://github.com/xvik/gradle-animalsniffer-plugin) with “test - publish - run tests” cyle for gradle plugin
