Maven
Deploy and depend on a workspace's Java and Kotlin libraries with Maven or Gradle, from a Maven repository of its own on g1t.sh, SNAPSHOTs included.
Every workspace has a Maven repository of its own, in the standard
layout that Maven, Gradle and every other JVM build tool read. mvn deploy and Gradle’s publish upload to it, and builds resolve
dependencies from it, private ones included.
https://g1t.sh/-/maven/<workspace>/Dependencies from Maven Central still come from Maven Central; only the artifacts you deploy here come from g1t.
Credentials
Section titled “Credentials”Maven and Gradle send Basic credentials: any username, and an
access token as the password. A token
with full access works; one with scopes needs packages:read to resolve
private artifacts and packages:write to deploy. Public artifacts resolve
without one.
For Maven, put the credentials in ~/.m2/settings.xml, as a <server>
whose id is the one you give the repository in pom.xml. These pages use
the workspace’s slug:
<settings> <servers> <server> <id>acme</id> <username>ada</username> <password>${env.G1T_TOKEN}</password> </server> </servers></settings>Maven reads ${env.G1T_TOKEN} from the environment, so the token stays
out of the file.
For Gradle, keep them in ~/.gradle/gradle.properties, named for the
repository (acmeUsername and acmePassword for a repository named
acme), or read them from the environment as the examples below do.
Deploy with Maven
Section titled “Deploy with Maven”Name the repository in pom.xml, for releases and SNAPSHOTs alike, and say
which repository the source is in:
<project> <groupId>com.acme</groupId> <artifactId>http-client</artifactId> <version>0.3.1</version>
<scm> <url>https://g1t.sh/acme/http-client</url> </scm>
<distributionManagement> <repository> <id>acme</id> <url>https://g1t.sh/-/maven/acme/</url> </repository> <snapshotRepository> <id>acme</id> <url>https://g1t.sh/-/maven/acme/</url> </snapshotRepository> </distributionManagement></project>mvn deployMaven uploads the artifact, its POM and their checksums, then the
artifact’s maven-metadata.xml. The artifact is named by its coordinates,
com.acme:http-client, and its page on g1t.sh shows the description from
the POM of its highest release.
Deploy with Gradle
Section titled “Deploy with Gradle”With the maven-publish plugin, in build.gradle.kts:
plugins { `java-library` `maven-publish`}
group = "com.acme"version = "0.3.1"
publishing { publications { create<MavenPublication>("library") { from(components["java"]) pom { scm { url = "https://g1t.sh/acme/http-client" } } } } repositories { maven { name = "acme" url = uri("https://g1t.sh/-/maven/acme/") credentials(PasswordCredentials::class) } }}./gradlew publishcredentials(PasswordCredentials::class) reads acmeUsername and
acmePassword from gradle.properties or from the environment as
ORG_GRADLE_PROJECT_acmeUsername and ORG_GRADLE_PROJECT_acmePassword.
Gradle uploads the jar, the POM, the sources and javadoc jars if you build
them, and its Gradle Module Metadata (.module), each with its .md5,
.sha1, .sha256 and .sha512. The .module file is served beside the
POM, so a Gradle build that depends on the artifact reads its variants
(API and runtime dependencies, capabilities) from it, and Maven reads the
POM. Gradle’s HEAD requests, which it makes to check files it has
cached (with --refresh-dependencies, or for a SNAPSHOT), are answered
with each file’s size and type.
Which repository an artifact belongs to
Section titled “Which repository an artifact belongs to”The first file deployed makes the artifact. When a repository of the
workspace is named like its artifactId (http-client), it is linked to
that repository and has its visibility and roles: deploying needs Write
on it. Otherwise, the POM’s <scm><url> (or its <url>) naming a g1t.sh
repository of the workspace links a new artifact to that repository, if you
may write to it. An artifact linked to neither is the workspace’s, private,
and needs the workspace’s Write base permission. See
who can see and publish a package.
Depend on an artifact
Section titled “Depend on an artifact”In pom.xml, name the repository, with the same id as the <server>
holding your credentials:
<repositories> <repository> <id>acme</id> <url>https://g1t.sh/-/maven/acme/</url> </repository></repositories>
<dependencies> <dependency> <groupId>com.acme</groupId> <artifactId>http-client</artifactId> <version>0.3.1</version> </dependency></dependencies>In Gradle:
repositories { mavenCentral() maven { name = "acme" url = uri("https://g1t.sh/-/maven/acme/") credentials(PasswordCredentials::class) }}
dependencies { implementation("com.acme:http-client:0.3.1")}To fetch one artifact without a project:
mvn dependency:get -Dartifact=com.acme:http-client:0.3.1 \ -DremoteRepositories=acme::default::https://g1t.sh/-/maven/acme/Maven plugins
Section titled “Maven plugins”A plugin is deployed like any other artifact, with <packaging>maven-plugin</packaging>.
g1t lists the plugins of each group in the group’s own
maven-metadata.xml (com/acme/maven-metadata.xml for the group
com.acme), with the prefix each is called by: the goalPrefix from the
descriptor maven-plugin-plugin puts in its jar, else the one Maven
works out from its artifactId (hello-maven-plugin is hello).
To call a plugin by its prefix, as mvn hello:greet, name its group in
~/.m2/settings.xml and the repository as a plugin repository:
<settings> <pluginGroups> <pluginGroup>com.acme</pluginGroup> </pluginGroups> <profiles> <profile> <id>acme</id> <pluginRepositories> <pluginRepository> <id>acme</id> <url>https://g1t.sh/-/maven/acme/</url> </pluginRepository> </pluginRepositories> </profile> </profiles> <activeProfiles> <activeProfile>acme</activeProfile> </activeProfiles></settings>The group’s metadata lists only the plugins the credentials’ owner may
see. A plugin’s full coordinates (mvn com.acme:hello-maven-plugin:1.0.0:greet)
work without the plugin group.
SNAPSHOTs
Section titled “SNAPSHOTs”A version ending in -SNAPSHOT takes a new build each time it is
deployed. Maven and Gradle upload each build’s files with a timestamp and
build number in their names (http-client-0.4.0-20261006.120000-3.jar),
and the version’s maven-metadata.xml names the newest build of each file,
which is what a build depending on 0.4.0-SNAPSHOT resolves. Earlier
builds stay, by their full names.
Versions and files
Section titled “Versions and files”- A release’s files are written once. Deploying a file of a released
version again with different content is refused with
409; the same content again is accepted, so a deploy that stopped part way can be run again. Bump the version to change a release. - Checksums are worked out by g1t. The
.md5,.sha1,.sha256and.sha512beside every file are answered from the file itself. Checksums uploaded are checked against it, and a mismatch is refused with400. maven-metadata.xmlis made by g1t from the versions there, so it always lists every version, with the highest aslatestand the highest that is not a SNAPSHOT asrelease, and a group’s lists its plugins. The one a build uploads is accepted and not kept.- The deploy’s last step publishes it. Maven and Gradle upload the
artifact’s
maven-metadata.xmlafter its files. Then each version (or SNAPSHOT build) whose POM arrived in the deploy is published: it is an audit entry and apackage.publishedevent, with every file in place. A POM whosegroupId,artifactIdorversionis not the one in its path is refused with400.
Delete a version, or the artifact, on its page on g1t.sh, with Admin on the linked repository (an owner, for the workspace’s own artifacts).
Private and public artifacts
Section titled “Private and public artifacts”An artifact linked to a repository has the repository’s visibility; one of the workspace’s own is private until an owner makes it public on its page.
| The workspace’s artifacts | Without credentials | With credentials |
|---|---|---|
| All public | Maven and Gradle download them. | The same; credentials are sent to deploy. |
| Some private | Every request without credentials is answered 401, which makes Maven and Gradle send theirs. |
Each artifact the credentials’ owner may see. |
A private artifact you cannot see looks exactly like one that does not exist.
In workflows
Section titled “In workflows”A workflow’s G1T_TOKEN is the workspace’s own token for the run, and can
resolve and deploy the workspace’s artifacts. With the settings.xml
above, give it to Maven as G1T_TOKEN:
jobs: deploy: runs-on: ubuntu-latest env: G1T_TOKEN: ${{ secrets.G1T_TOKEN }} steps: - uses: actions/checkout@v4 - run: | mkdir -p ~/.m2 printf '<settings><servers><server><id>acme</id><username>g1t</username><password>${env.G1T_TOKEN}</password></server></servers></settings>\n' > ~/.m2/settings.xml - run: mvn --batch-mode deployFor Gradle, set ORG_GRADLE_PROJECT_acmeUsername: g1t and
ORG_GRADLE_PROJECT_acmePassword: ${{ secrets.G1T_TOKEN }} and run
./gradlew publish.
Each file is one request and may be at most 100 MB. Without the g1t plan, a workspace’s private packages may hold 500 MB and its public ones 10 GB, as for container images. A file is stored once, by its content.
Errors
Section titled “Errors”| Error | Means |
|---|---|
401 |
No credentials, or a wrong or expired token. Check the <server> whose id matches the repository’s, or Gradle’s acmeUsername and acmePassword. |
403 |
Signed in, but your role or your token’s scopes do not allow it, or the workspace is out of free package storage. The response says which. |
404 |
No such artifact, version or file, or a private one you cannot see. |
409 |
That file of a release is already there with other content. Bump the version. |
400 |
The upload was refused: a POM that does not match its path, or a checksum that does not match its file. The response says which. |
413 |
The file is over 100 MB. |