Skip to content

Commit 9cade20

Browse files
committed
Release to Maven Central by tag: jars and native as two deployments
1 parent 92be926 commit 9cade20

11 files changed

Lines changed: 271 additions & 62 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: Release
2+
3+
# Tags only, and the tag is the version: the build reads it from GITHUB_REF_NAME and jreleaserDeploy
4+
# refuses anything that is not a clean X.Y.Z.
5+
#
6+
# Two deployments per tag, because a published groupId:artifactId:version can never gain files
7+
# afterwards: the jars go up as one, and every platform's native binary as another. Both are uploaded
8+
# and validated only — the Portal holds them until someone presses publish.
9+
#
10+
# Needs four repository secrets: JRELEASER_MAVENCENTRAL_USERNAME and JRELEASER_MAVENCENTRAL_PASSWORD
11+
# (the Central Portal user token) plus JRELEASER_GPG_SECRET_KEY and JRELEASER_GPG_PASSPHRASE.
12+
on:
13+
push:
14+
tags:
15+
- '*'
16+
17+
permissions:
18+
contents: read
19+
20+
concurrency:
21+
group: release-${{ github.ref }}
22+
cancel-in-progress: false
23+
24+
jobs:
25+
jars:
26+
name: jars
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
30+
with:
31+
fetch-depth: 0
32+
33+
- name: Install JDK 21
34+
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
35+
with:
36+
distribution: temurin
37+
java-version: '21'
38+
39+
- name: Stage, sign and upload the jars
40+
run: ./gradlew jreleaserDeploy
41+
env:
42+
JRELEASER_DEPLOY_MAVEN_MAVENCENTRAL_SONATYPE_USERNAME: ${{ secrets.JRELEASER_MAVENCENTRAL_USERNAME }}
43+
JRELEASER_DEPLOY_MAVEN_MAVENCENTRAL_SONATYPE_PASSWORD: ${{ secrets.JRELEASER_MAVENCENTRAL_PASSWORD }}
44+
JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }}
45+
JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }}
46+
47+
- name: Keep JReleaser's log
48+
if: ${{ failure() }}
49+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
50+
with:
51+
name: jreleaser-log-jars
52+
path: build/jreleaser/trace.log
53+
if-no-files-found: ignore
54+
retention-days: 7
55+
56+
# One job per platform, as in ci.yml, but here each one hands its binary to the deploy job below
57+
# instead of throwing it away.
58+
native-images:
59+
name: native image (${{ matrix.platform }})
60+
runs-on: ${{ matrix.runner }}
61+
timeout-minutes: 90
62+
strategy:
63+
fail-fast: false
64+
matrix:
65+
include:
66+
- platform: linux-x86-64
67+
runner: ubuntu-latest
68+
- platform: linux-aarch64
69+
runner: ubuntu-24.04-arm
70+
- platform: macos-aarch64
71+
runner: macos-15
72+
- platform: macos-x86-64
73+
runner: macos-15-intel
74+
75+
steps:
76+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
77+
78+
- name: Install GraalVM 25 for the image
79+
uses: graalvm/setup-graalvm@5298d94fb55a4f185c602eeac5de1b553882abe2 # v1.6.4
80+
with:
81+
java-version: '25'
82+
distribution: 'graalvm-community'
83+
github-token: ${{ secrets.GITHUB_TOKEN }}
84+
85+
- name: Compile the native image
86+
run: ./gradlew -PnativeImage=true :open-java-format-native:nativeCompile
87+
88+
- name: Hand the binary to the deploy job
89+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
90+
with:
91+
name: native-image-${{ matrix.platform }}
92+
path: |
93+
open-java-format-native/build/native/nativeCompile/open-java-format-*
94+
!open-java-format-native/build/native/nativeCompile/*.txt
95+
if-no-files-found: error
96+
retention-days: 1
97+
98+
# Not `native`: ci.yml already has a job with that id, and `act --job native` could not tell them apart.
99+
native-deploy:
100+
name: native deploy
101+
needs: native-images
102+
runs-on: ubuntu-latest
103+
steps:
104+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
105+
with:
106+
fetch-depth: 0
107+
108+
- name: Install JDK 21
109+
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
110+
with:
111+
distribution: temurin
112+
java-version: '21'
113+
114+
# merge-multiple: every platform's binary lands in one directory under the name it was built
115+
# with, which is where its Maven classifier is read from.
116+
- name: Collect every platform's binary
117+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
118+
with:
119+
path: native-images
120+
pattern: native-image-*
121+
merge-multiple: true
122+
123+
- name: Show what was collected
124+
run: ls -l native-images
125+
126+
# No GraalVM here: nothing is compiled, the binaries are published exactly as they arrived.
127+
- name: Stage, sign and upload the native images
128+
run: ./gradlew -PreleaseTarget=native -PnativeImages=native-images jreleaserDeploy
129+
env:
130+
JRELEASER_DEPLOY_MAVEN_MAVENCENTRAL_SONATYPE_USERNAME: ${{ secrets.JRELEASER_MAVENCENTRAL_USERNAME }}
131+
JRELEASER_DEPLOY_MAVEN_MAVENCENTRAL_SONATYPE_PASSWORD: ${{ secrets.JRELEASER_MAVENCENTRAL_PASSWORD }}
132+
JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }}
133+
JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }}
134+
135+
- name: Keep JReleaser's log
136+
if: ${{ failure() }}
137+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
138+
with:
139+
name: jreleaser-log-native
140+
path: build/jreleaser/trace.log
141+
if-no-files-found: ignore
142+
retention-days: 7

‎CONTRIBUTING.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@ Tips:
2626
- run `mise run format` before pushing; the build fails if the repo is not formatted with the
2727
formatter it builds.
2828

29-
## Working on `:idea-plugin`
29+
## Working on `:open-java-format-idea-plugin`
3030

3131
Tip: run `mise run idea` to spin up an instance of IntelliJ with the plugin applied.

‎README.md‎

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ replaced with something a stranger can run.
119119
| Concern | Today | Replacement |
120120
|---|---|---|
121121
| CI | ~~CircleCI (`.circleci/config.yml`, generated by Palantir's Excavator)~~ | **Done** — [`.github/workflows/ci.yml`](.github/workflows/ci.yml), one explicit job per platform |
122-
| Release | Palantir Autorelease + `com.palantir.gradle.externalpublish` | Tag-triggered workflow → Maven Central Portal, signing keys in a protected GitHub environment |
122+
| Release | ~~Palantir Autorelease + `com.palantir.gradle.externalpublish`~~ | **In progress** — JReleaser → Maven Central Portal, configured as [`buildSrc`](buildSrc/src/main/groovy) conventions and triggered by a tag ([`release.yml`](.github/workflows/release.yml)): one deployment for the jars, one for the native images of every platform. Uploads only for now — each deployment waits in the Portal until someone publishes it. Still to do: the Gradle plugin and the IDE plugins, and signing keys in a protected GitHub environment |
123123
| Dependency updates | Excavator (`.excavator.yml`) | Renovate |
124124
| Auto-merge | Bulldozer (`.bulldozer.yml`) | GitHub merge queue + auto-merge |
125125
| Changelog | Palantir changelog-app (`.changelog.yml`) | Release Drafter, changelog entry in the PR template |
@@ -182,7 +182,7 @@ Remaining gaps, each a self-contained PR:
182182
### Phase 2 — Republish under neutral coordinates
183183

184184
- [ ] Register the Maven group and the Gradle plugin namespace
185-
- [ ] Rename artifacts and plugin IDs (see [coordinates](#coordinates-old--new)); **Java packages
185+
- [x] Rename artifacts and plugin IDs (see [coordinates](#coordinates-old--new)); **Java packages
186186
stay `com.palantir.javaformat.*` for the whole 2.x line** — renaming them would break the SPI,
187187
Spotless and every programmatic user, and would make merging upstream commits painful forever
188188
- [ ] Publish `2.x` releases whose numbers **match upstream exactly**, so migration is a coordinate
@@ -258,19 +258,21 @@ artifact and a long overlap.
258258

259259
## Coordinates (old → new)
260260

261-
The organisation (`github.com/openjavaformat`) and the domain (`openjavaformat.com`) are registered,
262-
so the group id is settled; the rest lands with Phase 2.
261+
The organisation (`github.com/openjavaformat`) is registered, and the Maven namespace
262+
`dev.openjavaformat` is submitted for verification on the Central Portal. The build already uses
263+
every name below — for its Gradle projects and directories as well as for what it publishes.
263264

264265
| | Upstream (today) | This fork |
265266
|---|---|---|
266-
| Maven group | `com.palantir.javaformat` | `com.openjavaformat` |
267+
| Maven group | `com.palantir.javaformat` | `dev.openjavaformat` |
267268
| Core | `palantir-java-format` | `open-java-format` |
268269
| SPI | `palantir-java-format-spi` | `open-java-format-spi` |
269270
| Native image | `palantir-java-format-native` | `open-java-format-native` |
270271
| JDK bootstrap | `palantir-java-format-jdk-bootstrap` | `open-java-format-jdk-bootstrap` |
271272
| Gradle plugin artifact | `gradle-palantir-java-format` | `gradle-open-java-format` |
272-
| Gradle plugin ID | `com.palantir.java-format` | `com.openjavaformat.java-format` |
273+
| Gradle plugin IDs | `com.palantir.java-format`, `-idea`, `-spotless`, `-provider` | `dev.openjavaformat.java-format`, `-idea`, `-spotless`, `-provider` |
273274
| IntelliJ plugin ID | `palantir-java-format` | `open-java-format` |
275+
| Eclipse plugin bundle | `palantir-java-format-eclipse-plugin` | `open-java-format-eclipse-plugin` |
274276
| Java packages | `com.palantir.javaformat.*` | **unchanged in 2.x** |
275277
| Version numbers | `2.x` | **the same `2.x`** |
276278

@@ -322,10 +324,9 @@ OpenTofu all shipped drop-in replacements with matching version numbers. That is
322324
These need a call before the corresponding phase can finish. Recommendations included; disagreement
323325
welcome in the issue tracker.
324326

325-
1. ~~**Maven group and GitHub org.**~~ **Resolved:** the `openjavaformat` GitHub organisation and
326-
the `openjavaformat.com` domain are registered, so the group id is `com.openjavaformat`, verified
327-
on Maven Central by DNS TXT record. Remaining task: claim the namespace on Sonatype before
328-
Phase 2 can publish.
327+
1. ~~**Maven group and GitHub org.**~~ **Resolved:** the `openjavaformat` GitHub organisation is
328+
registered, and the group id is `dev.openjavaformat`, submitted for verification on the Maven
329+
Central Portal. Publishing waits for that verification.
329330
2. **Version numbering.** Recommendation: lockstep with upstream through 2.x, fork the numbering at
330331
3.0 when we start making our own decisions.
331332
3. **Java package rename.** Recommendation: never in 2.x; at 3.0 at the earliest, and only with a
@@ -574,14 +575,14 @@ shortcut.
574575
### Running a pre-release version of the IntelliJ plugin
575576

576577
1. Clone this repo
577-
2. run `./gradlew :idea-plugin:build`
578-
3. In IntelliJ, install a plugin from disk. Build artifacts are located in `./idea-plugin/build/distributions/`
578+
2. run `./gradlew :open-java-format-idea-plugin:build`
579+
3. In IntelliJ, install a plugin from disk. Build artifacts are located in `./open-java-format-idea-plugin/build/distributions/`
579580

580581
![Install plugin from disk](./docs/images/install_plugin_from_disk.png)
581582

582583
## Eclipse plugin
583584

584-
See [eclipse_plugin](./eclipse_plugin).
585+
See [open-java-format-eclipse-plugin](./open-java-format-eclipse-plugin).
585586

586587
## Java 21 support
587588

‎build.gradle‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,3 @@ javaVersions {
125125
libraryTarget = 21
126126
runtime = 21
127127
}
128-
129-
// GraalVM for the native image. gradle-jdks used to pin an exact build in gradle/jdks/**;
130-
// the toolchain spec plus the foojay resolver (settings.gradle) does the same job with the
131-
// JDK the environment already provides — setup-graalvm in CI, mise locally.

‎buildSrc/src/main/groovy/open-java-format.release-conventions.gradle‎

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,26 @@ plugins {
55
id 'org.jreleaser'
66
}
77

8-
// What goes to Maven Central. Each of these applies open-java-format.publishing-conventions, which
9-
// stages its publications in build/staging-deploy.
8+
// Two deployments, one version. A published groupId:artifactId:version can never gain files, so every
9+
// platform's native binary has to travel in a single deployment — and those binaries come from four CI
10+
// jobs, long after the jars are staged. `-PreleaseTarget=native` deploys the binaries those jobs
11+
// collected, the default deploys the jars; on a tag both read the same version from it.
1012
//
11-
// Not released yet: open-java-format-native needs a binary per platform, each from its own CI job,
12-
// and all of them have to go up in one deployment.
13-
def releasedProjects = [
14-
':open-java-format-spi',
15-
':open-java-format',
16-
':open-java-format-jdk-bootstrap',
17-
':gradle-open-java-format',
18-
]
13+
// Not released yet: gradle-open-java-format, whose plugin markers and Gradle Plugin Portal listing are
14+
// a decision of their own. The Eclipse and IntelliJ plugins have no Maven publications at all.
15+
def releaseTarget = providers.gradleProperty('releaseTarget').getOrElse('jars')
16+
def releasedProjects
17+
if (releaseTarget == 'jars') {
18+
releasedProjects = [
19+
':open-java-format-spi',
20+
':open-java-format',
21+
':open-java-format-jdk-bootstrap',
22+
]
23+
} else if (releaseTarget == 'native') {
24+
releasedProjects = [':open-java-format-native']
25+
} else {
26+
throw new GradleException("Unknown -PreleaseTarget=${releaseTarget}: use 'jars' or 'native'")
27+
}
1928
def stagingRepositories = releasedProjects.collect { path ->
2029
relativePath(project(path).layout.buildDirectory.dir('staging-deploy'))
2130
}
@@ -66,6 +75,10 @@ jreleaser {
6675
url = 'https://central.sonatype.com/api/v1/publisher'
6776
namespace = 'dev.openjavaformat'
6877
applyMavenCentralRules = true
78+
// Upload and validate, then stop. The deployment waits in the Portal until someone
79+
// presses publish, so a version stays reversible until every one of its deployments
80+
// is in and has been looked at.
81+
stage = 'UPLOAD'
6982
stagingRepositories.each { stagingRepository(it) }
7083
}
7184
}

‎gradle-open-java-format/build.gradle‎

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
apply plugin: 'java-gradle-plugin'
22
apply plugin: 'groovy'
3+
apply plugin: 'open-java-format.publishing-conventions'
4+
5+
description = 'Gradle plugins for open-java-format: formatting tasks, the Spotless step and IntelliJ configuration'
36

47
configurations {
58
pluginClasspath {
@@ -13,12 +16,12 @@ dependencies {
1316

1417
implementation gradleApi()
1518
implementation libs.guava
16-
implementation project(':palantir-java-format-spi')
17-
implementation project(':palantir-java-format-jdk-bootstrap')
19+
implementation project(':open-java-format-spi')
20+
implementation project(':open-java-format-jdk-bootstrap')
1821
implementation libs.palantir.platform
1922
implementation libs.ideaConfiguration.gradlePlugin
2023

21-
testImplementation project(':palantir-java-format')
24+
testImplementation project(':open-java-format')
2225
testImplementation libs.junit.jupiter
2326
testImplementation libs.assertj
2427
testImplementation libs.jackson.dataformat.xml
@@ -38,35 +41,35 @@ dependencies {
3841
}
3942

4043
gradlePlugin {
41-
website = 'https://github.com/palantir/palantir-java-format/'
42-
vcsUrl = 'https://github.com/palantir/palantir-java-format/'
44+
website = 'https://github.com/openjavaformat/open-java-format'
45+
vcsUrl = 'https://github.com/openjavaformat/open-java-format'
4346
plugins {
4447
palantirJavaFormat {
45-
id = 'com.palantir.java-format'
48+
id = 'dev.openjavaformat.java-format'
4649
implementationClass = 'com.palantir.javaformat.gradle.PalantirJavaFormatPlugin'
47-
description = 'A modern, lambda-friendly, 120 character Java formatter. Applies all other palantir-java-format plugins.'
48-
displayName = 'Palantir Java Format'
50+
description = 'A modern, lambda-friendly, 120 character Java formatter. Applies all other open-java-format plugins.'
51+
displayName = 'Open Java Format'
4952
tags.set(['java', 'style'])
5053
}
5154
palantirJavaFormatIdea {
52-
id = 'com.palantir.java-format-idea'
55+
id = 'dev.openjavaformat.java-format-idea'
5356
implementationClass = 'com.palantir.javaformat.gradle.PalantirJavaFormatIdeaPlugin'
54-
description = 'Plugin to configure the PalantirJavaFormat IDEA plugin based on an optional implementation version of the formatter.'
55-
displayName = 'Palantir Java Format Idea'
57+
description = 'Plugin to configure the open-java-format IDEA plugin based on an optional implementation version of the formatter.'
58+
displayName = 'Open Java Format Idea'
5659
tags.set(['java', 'style'])
5760
}
5861
palantirJavaFormatSpotless {
59-
id = 'com.palantir.java-format-spotless'
62+
id = 'dev.openjavaformat.java-format-spotless'
6063
implementationClass = 'com.palantir.javaformat.gradle.PalantirJavaFormatSpotlessPlugin'
61-
description = 'If spotless is applied, configures a java step that formats using palantir-java-format.'
62-
displayName = 'Palantir Java Format Spotless'
64+
description = 'If spotless is applied, configures a java step that formats using open-java-format.'
65+
displayName = 'Open Java Format Spotless'
6366
tags.set(['java', 'style'])
6467
}
6568
palantirJavaFormatProvider {
66-
id = 'com.palantir.java-format-provider'
69+
id = 'dev.openjavaformat.java-format-provider'
6770
implementationClass = 'com.palantir.javaformat.gradle.PalantirJavaFormatProviderPlugin'
68-
description = 'Exposes a configuration containing the palantir-java-format jars'
69-
displayName = 'Palantir Java Format Provider'
71+
description = 'Exposes a configuration containing the open-java-format jars'
72+
displayName = 'Open Java Format Provider'
7073
tags.set(['java', 'style'])
7174
}
7275
}
@@ -94,8 +97,8 @@ configurations {
9497
}
9598

9699
dependencies {
97-
impl project(':palantir-java-format')
98-
formatterNativeImage(project(':palantir-java-format-native')) {
100+
impl project(':open-java-format')
101+
formatterNativeImage(project(':open-java-format-native')) {
99102
attributes {
100103
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements, 'nativeImage'))
101104
}

0 commit comments

Comments
 (0)