Skip to content

Commit

Permalink
Merge c3afb00 into master
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] authored Oct 21, 2022
2 parents e717a5a + c3afb00 commit 8782596
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 85 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ jobs:
echo "result=$VERSION" >>$GITHUB_OUTPUT
- name: Build
run: |
#export GPG_TTY=$(tty)
./gradlew uberJar
java -jar ./build/libs/mavence.uber.jar --version
mv ./build/libs/mavence.uber.jar ./build/libs/mavence.jar
env:
MAVEN_GPG_KEY: ${{ secrets.MAVEN_GPG_KEY }}
Expand Down
115 changes: 64 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,22 @@ This essentially does the same thing as
the [Signing](https://docs.gradle.org/current/userguide/signing_plugin.html) and
[Nexus](https://github.com/gradle-nexus/publish-plugin) plugins.

<details><summary>Why not use plugins?</summary>
<details><summary>Why not publish with plugins?</summary>


- Building locally
- Publishing somewhere

These tasks are almost unrelated.

By placing publishing logic in a build script, you make the foundation of the
project complex, big and ugly.

However, we still use some Gradle plugins. The `maven-publish` creates, i.e.
builds a local copy of the Maven package.
project complex and ugly.

</details>

## Install and run
# Install and run

### Command line
## Command line

```
wget https://github.com/rtmigo/mavence/releases/latest/download/mavence.jar
Expand All @@ -36,8 +34,7 @@ Run:
java -jar mavence.jar
```


### Manually
## Manually

Just get the
latest [mavence.jar](https://github.com/rtmigo/mavence/releases/latest/download/mavence.jar)
Expand All @@ -49,23 +46,39 @@ Run:
java -jar ~/Downloads/mavence.jar
```



## Setting the environment
# Setting the environment

Before publishing, you will need to set the following four environment
variables:

| variable | wtf |
|----------------------|-----------------------------------------------------------|
| `MAVEN_GPG_KEY` | Locally generated private key in ASCII armor |
| `MAVEN_GPG_PASSWORD` | Password protecting the private key |
| `SONATYPE_USERNAME` | Username for Sonatype JIRA (optionally replaced by token) |
| `SONATYPE_PASSWORD` | Password for Sonatype JIRA (optionally replaced by token) |
| `MAVEN_GPG_KEY` | Locally generated private key in ASCII armor |
| `MAVEN_GPG_PASSWORD` | Password protecting the private key |

<details><summary>Where to get Sonatype variables</summary>

[Register](https://getstream.io/blog/publishing-libraries-to-mavencentral-2021/#registering-a-sonatype-account)
on the [Sonatype Jira](https://issues.sonatype.org/secure/Dashboard.jspa)
and chat with bots, 🤪 until they **verify** that you can publish a package.
That gives you `SONATYPE_USERNAME` and `SONATYPE_PASSWORD` you can use for
publishing.

Additionally, you
can [generate tokens](https://central.sonatype.org/publish/manage-user/#generate-token-on-nxrm-servers)
to use them instead of the username and password (tokens are safer). The
tokens can be placed in the same `SONATYPE_USERNAME` and `SONATYPE_PASSWORD` and
do not require other changes.

**May the Google be with you.**

</details>

<details><summary>Where to get GPG variables</summary>

### Generate key
## Generate key

It gives you `MAVEN_GPG_PASSWORD`.

Expand All @@ -76,7 +89,7 @@ $ gpg --gen-key
`gpg` will interactively prompt you to choose a password for the new key. It is
this password that should later be placed in the variable `MAVEN_GPG_PASSWORD`.

### See your private key
## See your private key

It gives you `MAVEN_GPG_KEY`.

Expand Down Expand Up @@ -113,7 +126,7 @@ $ MAVEN_GPG_KEY=$(gpg --export-secret-keys --armor 1292EC426424C9BA0A581EE060C99
$ export MAVEN_GPG_KEY
```

### Send the public key to [a keyserver](https://unix.stackexchange.com/a/692097)
## Send the public key to [a keyserver](https://unix.stackexchange.com/a/692097)

You won't come back to this again, but it will be important for the servers when
publishing the package.
Expand All @@ -136,36 +149,14 @@ $ gpg --keyserver hkps://keys.openpgp.org --send-keys 1292EC426424C9BA0A581EE060
Some servers will just store the key. Some may require prior email verification.
Some servers disappear. You have to choose the right one for the moment.




</details>

<details><summary>Where to get Sonatype variables</summary>

You need
to [register](https://getstream.io/blog/publishing-libraries-to-mavencentral-2021/#registering-a-sonatype-account)
on the [Sonatype Jira](https://issues.sonatype.org/secure/Dashboard.jspa)
and chat with bots, until they **verify** that you can publish a package.
That gives you `SONATYPE_USERNAME` and `SONATYPE_PASSWORD` you can use for
publishing.

If you have enough nerve for one more step, you
can [generate tokens](https://central.sonatype.org/publish/manage-user/#generate-token-on-nxrm-servers)
.
The tokens also can be placed in the `SONATYPE_USERNAME` and `SONATYPE_PASSWORD`
. In some circumstances it is safer.



</details>

## Minimal configuration
# Minimal configuration

We're using Gradle configuration to build a Maven package, but not push
it Central. Creating in this way seems like a reasonable compromise.

#### build.gradle.kts
### build.gradle.kts

```kotlin
plugins {
Expand Down Expand Up @@ -199,7 +190,10 @@ publishing {
}
}
scm {
connection.set(github.replace("https:", "scm:git:") + ".git")
connection.set(
github.replace(
"https:",
"scm:git:") + ".git")
url.set(github)
}
licenses {
Expand All @@ -214,13 +208,13 @@ publishing {
}
```

#### settings.gradle.kts
### settings.gradle.kts

```kotlin
rootProject.name = "thelib"
```

### Package name
## Package name

The published package will have a version like `my.domain:thelib:0.1.2`.

Expand All @@ -247,7 +241,7 @@ It is the second part of `my.domain:thelib:0.1.2`, i.e. `thelib`.
from [archivesBaseName](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:archivesBaseName)
Gradle property.

#### If we release the root project:
### If we release the root project:

```
thelib/ <<< dir name will be the artifact name
Expand All @@ -264,7 +258,7 @@ The redefine the root project name, add the following:
rootProject.name = "newname"
```

#### If we release a subproject:
### If we release a subproject:

```
myrootproject/
Expand All @@ -276,18 +270,23 @@ myrootproject/

</details>

## Keep in mind


# Publishing

<details><summary>Keep in mind</summary>

When publishing, the servers may not return meaningful error responses. They
often return a generic "500 Internal Server Error" code, or accept the file, but
never publish it as a maven package.

If publishing a package fails for any reason, the problem may be in the meta
data. Something does not match with something: package name, authors, signatures.
data. Something does not match with something: package name, authors,
signatures.

## Publishing
</details>

### Publish to Maven Central
## Publish to Maven Central

Set environment variables `MAVEN_GPG_KEY`, `MAVEN_GPG_PASSWORD`
, `SONATYPE_USERNAME`, `SONATYPE_PASSWORD` and run:
Expand All @@ -311,6 +310,20 @@ cd /path/to/thelib
java -jar mavence.jar local
```

<details><summary>stdout</summary>

```
{
"group": "my.domain",
"artifact": "thelib",
"version": "0.1.2",
"notation": "my.domain:thelib:0.1.2",
"mavenRepo": "file:///home/doe/.m2/repository"
}
```

</details>

### Publish to Staging

Set environment variables `MAVEN_GPG_KEY`, `MAVEN_GPG_PASSWORD`
Expand Down Expand Up @@ -356,7 +369,7 @@ Using this data, you can test the package before it is sent.
I usually use Python and [tempground](https://pypi.org/project/tempground/) for
such testing.

## License
# License

Copyright © 2022 [Artsiom iG](https://github.com/rtmigo).
Released under the [ISC License](LICENSE).
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {
}

group = "io.github.rtmigo"
version = "0.2.0" // -SNAPSHOT
version = "0.3.0" // -SNAPSHOT

repositories {
mavenCentral()
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/Build.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// DO NOT EDIT. Generated by Gradle task "generateBuildKt"
object Build {
const val version = "0.2.0"
const val date = "2022-10-20"
const val version = "0.3.0"
const val date = "2022-10-21"
}
37 changes: 27 additions & 10 deletions src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ import stages.build.*
import stages.sign.*
import stages.upload.*
import java.nio.file.*
import kotlin.io.path.absolute


class Cli : NoOpCliktCommand(
name = "mavence",
help = "Publishes Gradle projects to Maven Central\n\nSee: https://github.com/rtmigo/mavence#readme"
) {
private val trace by option("--trace", help = "Show full stack traces on errors").flag()

init {
versionOption(Build.version) {
"$commandName $it (${Build.date})\n" +
Expand All @@ -26,21 +29,20 @@ class Cli : NoOpCliktCommand(
}
}

override fun run() = Unit
override fun run() {
currentContext.findOrSetObject { CliConfig(trace = this.trace) }
}
}

private suspend fun gaa(): GroupArtifact {
val ad = ArtifactDir(Paths.get("."))
val ad = ArtifactDir(Paths.get(".").absolute())
return GroupArtifact(ad.group(), ad.artifact())
}

open class Local(help: String="Build, publish to $m2str") : CliktCommand(help = help) {
//val groupAndArtifact by argument("<artifact>")
data class CliConfig(val trace: Boolean)

override fun run() = runBlocking {
//val gw = Paths.get(".").toGradlew()
//gw.
//val ad = ArtifactDir(Paths.get("."))
open class Local(help: String = "Build, publish to $m2str") : CliktCommand(help = help) {
override fun run() = catchingCommand(this) {
cmdLocal(gaa(), isFinal = true)
Unit
}
Expand All @@ -58,7 +60,7 @@ open class Stage(help: String = "Build, sign, publish to OSSRH Staging") :
"--sonatype-password",
envvar = "SONATYPE_PASSWORD").required()

override fun run() = runBlocking {
override fun run() = catchingCommand(this) {
cmdSign(
cmdLocal(gaa()),
key = GpgPrivateKey(gpgKey),
Expand All @@ -74,7 +76,7 @@ open class Stage(help: String = "Build, sign, publish to OSSRH Staging") :
}

class Central : Stage(help = "Build, sign, publish to OSSRH Staging, release to Central") {
override fun run() = runBlocking {
override fun run() = catchingCommand(this) {
cmdSign(
cmdLocal(gaa()),
key = GpgPrivateKey(gpgKey),
Expand All @@ -90,6 +92,21 @@ class Central : Stage(help = "Build, sign, publish to OSSRH Staging, release to
}
}

fun catchingCommand(cmd: CliktCommand, block: suspend () -> Unit) {
try {
runBlocking {
block()
}
} catch (e: Exception) {
if (cmd.currentContext.findObject<CliConfig>()!!.trace)
e.printStackTrace()
else
System.err.println("ERROR: $e")
System.err.println("Run with --trace to see full stack trace.")
}

}

fun main(args: Array<String>) {
Cli()
.subcommands(Local(), Stage(), Central())
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/stages/build/Building.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import kotlin.io.path.*

suspend fun cmdLocal(ga: GroupArtifact, isFinal: Boolean = false): MavenArtifactDir {
eprintHeader("Publishing to $m2str")
val f = Paths.get(".")
val f = Paths.get(".").absolute()
.toGradlew().publishAndDetect(ga,null)
eprint()

Expand All @@ -22,7 +22,7 @@ suspend fun cmdLocal(ga: GroupArtifact, isFinal: Boolean = false): MavenArtifact
fun debugReplace(fn: String) {
// In case Sonatype freezes or gives uninformative errors, we can try to debug by
// replacing files one at a time. Normally it does not run
val src = Paths.get("...")
val src = Paths.get("---")
println("HACKY REPLACE $fn")
val srcFile = src.resolve(fn)
val dstFile = mad.path.resolve(fn)
Expand Down
5 changes: 5 additions & 0 deletions src/main/kotlin/stages/build/GradleTypes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
import java.nio.file.Path
import kotlin.io.path.*

//class AbsPath(src: Path) {
// val path: Path = src.absolute()
//}

@JvmInline
value class ProjectRootDir(val path: Path) {
init {
Expand All @@ -16,6 +20,7 @@ value class ProjectRootDir(val path: Path) {
@JvmInline
value class ArtifactDir(val path: Path) {
init {
require(path.isAbsolute)
require(
path.resolve("build.gradle.kts").exists() ||
path.resolve("build.gradle").exists()) {
Expand Down
Loading

0 comments on commit 8782596

Please sign in to comment.