# Maven extension

> Publish from Maven with the Telesphorepo extension. No password in settings.xml.

Source: https://docs.telesphorepo.com/publishing/maven-extension/

The Telesphorepo Maven extension gets a [publish session](/publishing/overview/) before `maven-deploy-plugin` uploads. It closes the session when the build ends. `settings.xml` needs no password for the server.

It needs Maven 3.9 and Java 17. The source is in the [clients repository](https://github.com/Telesphorepo/clients).

## Install

Declare the extension in `.mvn/extensions.xml`:

```xml title=".mvn/extensions.xml"
<extensions>
  <extension>
    <groupId>com.telesphorepo</groupId>
    <artifactId>telesphorepo-maven-extension</artifactId>
    <version>0.1.0</version>
  </extension>
</extensions>
```

Maven Central does not have the artifacts yet (coming soon). A core extension resolves from the repositories in `~/.m2/settings.xml`, not from `pom.xml`. Add the Nexus repository there, in an active profile:

```xml title="~/.m2/settings.xml"
<profiles>
  <profile>
    <id>telesphorepo-clients</id>
    <repositories>
      <repository>
        <id>telesphorepo-clients</id>
        <url>https://nexus.telesphoreo.me/repository/gradle-plugins-releases/</url>
      </repository>
    </repositories>
    <pluginRepositories>
      <pluginRepository>
        <id>telesphorepo-clients</id>
        <url>https://nexus.telesphoreo.me/repository/gradle-plugins-releases/</url>
      </pluginRepository>
    </pluginRepositories>
  </profile>
</profiles>
<activeProfiles>
  <activeProfile>telesphorepo-clients</activeProfile>
</activeProfiles>
```

Name your server in `pom.xml` and deploy to it as usual:

```xml title="pom.xml"
<properties>
  <telesphorepo.url>https://repo.acme.com</telesphorepo.url>
</properties>
<distributionManagement>
  <repository>
    <id>telesphorepo</id>
    <url>https://repo.acme.com/maven/releases</url>
  </repository>
  <snapshotRepository>
    <id>telesphorepo</id>
    <url>https://repo.acme.com/maven/snapshots</url>
  </snapshotRepository>
</distributionManagement>
```

You can also set the server with `-Dtelesphorepo.url=...` or the environment variable `TELESPHOREPO_URL`. The extension handles every deployment repository whose URL is `<telesphorepo.url>/maven/<repo>`. This includes `-DaltDeploymentRepository` and `deploy:deploy-file`.

## Enroll your machine

1. Add the plugin group to `~/.m2/settings.xml` so that `telesphorepo:` resolves:

   ```xml
   <pluginGroups>
     <pluginGroup>com.telesphorepo</pluginGroup>
   </pluginGroups>
   ```

2. Run the login goal once on each machine:

   ```sh
   mvn telesphorepo:login -Dtelesphorepo.url=https://repo.acme.com
   ```

   Without the plugin group, use the full name:

   ```sh
   mvn com.telesphorepo:telesphorepo-maven-plugin:login -Dtelesphorepo.url=https://repo.acme.com
   ```

3. Open the URL that the goal prints. Sign in with your password and second factor, and approve the code.

The goal saves the key in `~/.telesphorepo/<host>/device.json`. Only you can read the file. The Gradle plugin uses the same file. Add `-Dtelesphorepo.deviceName=laptop` to set the name that the device list shows.

## Publish

```sh
mvn deploy
```

There is no password in `settings.xml`. The extension proves who you are in this order:

1. **GitHub Actions.** The identity token of the job, when `ACTIONS_ID_TOKEN_REQUEST_URL` is set. See [GitHub Actions](/publishing/github-actions/).
2. **Other CI.** The identity token in the environment variable that `telesphorepo.oidcTokenEnv` names. When that variable is empty, the extension uses the device key. See [Jenkins](/publishing/jenkins/).
3. **The device key** from `mvn telesphorepo:login`.

With no proof, `mvn deploy` stops before the build and tells you to run `mvn telesphorepo:login`.

## Gotchas

- The session lives at most `publish.session_ttl` (15 minutes by default). The extension gets it when the deploy goal of the first module starts.
- With `-DdeployAtEnd=true`, the deploy plugin keeps each module until the last module uploads. The whole reactor must finish within the session time, or the last upload fails.
- CI needs an admin [trust policy](/security/trust-policies/) that lists the repository.
- Maven 3.8.1 and later blocks `http://` URLs on hosts other than localhost. Use HTTPS.
- To read a private repository, you still need a `<server>` entry with a [read token](/security/read-tokens/) and the same `<id>`. The extension handles writes only.
