Skip to content

Commit 997a098

Browse files
authored
Merge pull request #1706 from microsoftgraph/feat/ossrh-release-automation
Automate release from OSSRH to Maven central
2 parents 5547b34 + 30b60df commit 997a098

File tree

4 files changed

+142
-74
lines changed

4 files changed

+142
-74
lines changed

.github/workflows/build-and-publish.yml

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: Build and Publish
22

33
on:
4+
workflow_dispatch:
45
push:
56
branches: [main]
67
paths-ignore:
@@ -12,8 +13,10 @@ on:
1213
tags:
1314
- "v[0-9]+.[0-9]+.[0-9]+"
1415
env:
15-
PREVIEW_TASK: publishSnapshotPublicationToSonatypeSnapshotRepository
16-
PUBLISH_TASK: publishMavenCentralReleasePublicationToSonatypeRepository
16+
PREVIEW_TASK: publishToSonatype
17+
PUBLISH_TASK: publishToSonatype closeAndReleaseSonatypeStagingRepository
18+
JAVA_VERSION: 21
19+
JAVA_DISTRIBUTION: 'temurin'
1720

1821
permissions:
1922
contents: write
@@ -23,16 +26,19 @@ jobs:
2326
if: ${{ github.ref == 'refs/heads/main' }}
2427
environment:
2528
name: maven_central_snapshot
29+
needs: validate-package-contents
2630
runs-on: ubuntu-latest
2731
steps:
2832
- uses: actions/checkout@v4
29-
- name: Easy detect-secrets
30-
uses: RobertFischer/[email protected]
33+
- name: Detect secrets
34+
run: |
35+
pip install detect-secrets
36+
git ls-files -z | xargs -0 detect-secrets-hook --baseline .secrets.baseline
3137
- name: Set up JDK
3238
uses: actions/setup-java@v4
3339
with:
34-
java-version: 20
35-
distribution: 'temurin'
40+
java-version: ${{ env.JAVA_VERSION }}
41+
distribution: ${{ env.JAVA_DISTRIBUTION }}
3642
cache: gradle
3743
- name: Download file
3844
run: .\scripts\decodeAndWrite.ps1 -encodedValue $env:ENCODED_VALUE -outputPath $env:OUTPUT_PATH
@@ -55,16 +61,19 @@ jobs:
5561
if: ${{ startsWith(github.ref, 'refs/tags/') && github.actor == 'release-please[bot]'}}
5662
environment:
5763
name: maven_central_release
64+
needs: validate-package-contents
5865
runs-on: ubuntu-latest
5966
steps:
6067
- uses: actions/checkout@v4
61-
- name: Easy detect-secrets
62-
uses: RobertFischer/[email protected]
68+
- name: Detect secrets
69+
run: |
70+
pip install detect-secrets
71+
git ls-files -z | xargs -0 detect-secrets-hook --baseline .secrets.baseline
6372
- name: Set up JDK
6473
uses: actions/setup-java@v4
6574
with:
66-
java-version: 20
67-
distribution: 'temurin'
75+
java-version: ${{ env.JAVA_VERSION }}
76+
distribution: ${{ env.JAVA_DISTRIBUTION }}
6877
cache: gradle
6978
- name: Download file
7079
run: .\scripts\decodeAndWrite.ps1 -encodedValue $env:ENCODED_VALUE -outputPath $env:OUTPUT_PATH
@@ -81,7 +90,7 @@ jobs:
8190
- name: Grant execute permission for gradlew
8291
run: chmod +x gradlew
8392
- name: Publish
84-
run: ./gradlew $PUBLISH_TASK
93+
run: ./gradlew $PUBLISH_TASK -PmavenCentralSnapshotArtifactSuffix=""
8594
- name: Upload Build Artifact
8695
uses: actions/upload-artifact@v4
8796
with:
@@ -105,3 +114,45 @@ jobs:
105114
files: |
106115
build/**/*.jar
107116
117+
validate-package-contents:
118+
runs-on: ubuntu-latest
119+
environment: ${{ contains(github.ref, 'refs/tags/v') && 'maven_central_release' || 'maven_central_snapshot' }}
120+
defaults:
121+
run:
122+
working-directory: ./
123+
steps:
124+
- uses: actions/checkout@v4
125+
- name: Setup JDK
126+
uses: actions/setup-java@v4
127+
with:
128+
java-version: ${{ env.JAVA_VERSION }}
129+
distribution: ${{ env.JAVA_DISTRIBUTION}}
130+
cache: gradle
131+
- name: Download file
132+
run: .\scripts\decodeAndWrite.ps1 -encodedValue $env:ENCODED_VALUE -outputPath $env:OUTPUT_PATH
133+
shell: pwsh
134+
env:
135+
ENCODED_VALUE: ${{ secrets.LOCAL_PROPERTIES }}
136+
OUTPUT_PATH: 'local.properties'
137+
- name: Download file
138+
run: .\scripts\decodeAndWrite.ps1 -encodedValue $env:ENCODED_VALUE -outputPath $env:OUTPUT_PATH
139+
shell: pwsh
140+
env:
141+
ENCODED_VALUE: ${{ secrets.SECRING_GPG }}
142+
OUTPUT_PATH: '.\secring.gpg'
143+
- name: Publish to local Maven cache for validation
144+
run: ./gradlew --no-daemon publishToMavenLocal
145+
- name: Get current SNAPSHOT version
146+
shell: pwsh
147+
run: |
148+
$contents = Get-Content gradle.properties -Raw
149+
$major = $contents | Select-String -Pattern 'mavenMajorVersion\s+= ([0-9]+)' | ForEach-Object { $_.Matches.Groups[1].Value }
150+
$minor = $contents | Select-String -Pattern 'mavenMinorVersion\s+= ([0-9]+)' | ForEach-Object { $_.Matches.Groups[1].Value }
151+
$patch = $contents | Select-String -Pattern 'mavenPatchVersion\s+= ([0-9]+)' | ForEach-Object { $_.Matches.Groups[1].Value }
152+
$version = "$major.$minor.$patch-SNAPSHOT"
153+
echo "Current version is $version"
154+
echo "PACKAGE_VERSION=$version" >> $Env:GITHUB_ENV
155+
- name: Inspect contents of local Maven cache
156+
shell: pwsh
157+
run: |
158+
.\scripts\validatePackageContents.ps1 -ArtifactId microsoft-graph-core -Version $env:PACKAGE_VERSION

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ hs_err_pid*
3535

3636
# Maven
3737
/target/
38-
local.properties
38+
local.properties
39+
*.gpg

build.gradle

Lines changed: 18 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ plugins {
77
id 'jacoco'
88
id 'com.github.spotbugs' version '6.0.20'
99
id "org.sonarqube" version "5.1.0.4882"
10+
id 'io.github.gradle-nexus.publish-plugin' version '2.0.0'
1011
}
1112

1213
java {
@@ -90,10 +91,6 @@ sonarqube {
9091
}
9192
}
9293

93-
//Publishing tasks-
94-
//Maven Central Snapshot: publishSnapshotPublicationToMavenRepository
95-
//Maven Central Release: publishMavenCentralReleasePublicationToMaven2Repository
96-
//Bintray Snapshot: publishSnapshotPublicationToMaven3Repository
9794

9895
tasks.jar {
9996
manifest {
@@ -104,79 +101,38 @@ tasks.jar {
104101
publishing {
105102

106103
publications {
107-
108-
maven(MavenPublication) {
109-
groupId project.property('mavenGroupId')
110-
artifactId project.property('mavenArtifactId')
111-
version "${mavenMajorVersion}.${mavenMinorVersion}.${mavenPatchVersion}${mavenArtifactSuffix}"
112-
from components.java
113-
pom.withXml {
114-
def root = asNode()
115-
root.appendNode('name', 'Microsoft Graph Core SDK for Java')
116-
root.appendNode('url', 'https://github.com/microsoftgraph/msgraph-sdk-java-core')
117-
root.children().last() + pomConfig
118-
def pomFile = file("${project.buildDir}/libs/microsoft-graph-core.pom")
119-
writeTo(pomFile)
120-
}
121-
122-
}
123-
Snapshot(MavenPublication) {
124-
customizePom(pom)
125-
groupId project.property('mavenGroupId')
126-
artifactId project.property('mavenArtifactId')
127-
version "${mavenMajorVersion}.${mavenMinorVersion}.${mavenPatchVersion}${mavenCentralSnapshotArtifactSuffix}"
128-
from components.java
129-
pom.withXml {
130-
def pomFile = file("${project.buildDir}/generated-pom.xml")
131-
writeTo(pomFile)
132-
}
133-
}
134-
135-
mavenCentralRelease(MavenPublication) {
104+
maven(MavenPublication) {
136105
customizePom(pom)
137106
groupId project.property('mavenGroupId')
138107
artifactId project.property('mavenArtifactId')
139-
version "${mavenMajorVersion}.${mavenMinorVersion}.${mavenPatchVersion}"
108+
version getVersionName()
140109
from components.java
141110
pom.withXml {
142111
def pomFile = file("${project.buildDir}/generated-pom.xml")
143112
writeTo(pomFile)
144113
}
145114
}
146115
}
147-
repositories {
148-
maven {
149-
url = 'https://oss.sonatype.org/content/repositories/snapshots'
150-
name = 'sonatypeSnapshot'
151-
152-
credentials {
153-
if (project.rootProject.file('local.properties').exists()) {
154-
Properties properties = new Properties()
155-
properties.load(project.rootProject.file('local.properties').newDataInputStream())
156-
username = properties.getProperty('sonatypeUsername')
157-
password = properties.getProperty('sonatypePassword')
158-
}
159-
}
160-
}
161-
162-
maven {
163-
url = 'https://oss.sonatype.org/service/local/staging/deploy/maven2'
164-
name = 'sonatype'
116+
}
165117

166-
credentials {
167-
if (project.rootProject.file('local.properties').exists()) {
168-
Properties properties = new Properties()
169-
properties.load(project.rootProject.file('local.properties').newDataInputStream())
170-
username = properties.getProperty('sonatypeUsername')
171-
password = properties.getProperty('sonatypePassword')
172-
}
118+
nexusPublishing {
119+
repositories {
120+
sonatype {
121+
if (project.rootProject.file('local.properties').exists()) {
122+
Properties properties = new Properties()
123+
properties.load(project.rootProject.file('local.properties').newDataInputStream())
124+
username = properties.getProperty('sonatypeUsername')
125+
password = properties.getProperty('sonatypePassword')
173126
}
174127
}
175128
}
176129
}
177130

131+
group = project.property('mavenGroupId')
132+
version = "${mavenMajorVersion}.${mavenMinorVersion}.${mavenPatchVersion}${mavenCentralSnapshotArtifactSuffix}"
133+
178134
signing {
179-
sign publishing.publications.mavenCentralRelease
135+
sign publishing.publications.maven
180136
}
181137
tasks.withType(Sign)*.enabled = mavenCentralPublishingEnabled.toBoolean()
182138

@@ -199,7 +155,7 @@ def getVersionCode() {
199155
}
200156

201157
def getVersionName() {
202-
return "${mavenMajorVersion}.${mavenMinorVersion}.${mavenPatchVersion}${mavenArtifactSuffix}"
158+
return "${mavenMajorVersion}.${mavenMinorVersion}.${mavenPatchVersion}${mavenCentralSnapshotArtifactSuffix}"
203159
}
204160

205161
artifacts {
@@ -261,7 +217,7 @@ gradle.taskGraph.whenReady { taskGraph ->
261217
}
262218

263219
model {
264-
tasks.generatePomFileForMavenCentralReleasePublication {
220+
tasks.generatePomFileForMavenPublication {
265221
destination = file("${project.buildDir}/generated-pom.xml")
266222
}
267223
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Checks that expected files are present & have contents after the publish process to the local cache
2+
param(
3+
[Parameter(Mandatory=$true)][string] $ArtifactId,
4+
[Parameter(Mandatory=$true)][string] $Version,
5+
[Parameter()][string] $GroupId = "com.microsoft.graph",
6+
[Parameter()][string] $MavenLocalCachePath = "~" + [System.IO.Path]::DirectorySeparatorChar + ".m2" + [System.IO.Path]::DirectorySeparatorChar + "repository"
7+
)
8+
9+
$groupIdPath = $GroupId -replace "\.", [System.IO.Path]::DirectorySeparatorChar
10+
$packagePath = Join-Path -Path $groupIdPath -ChildPath $ArtifactId
11+
$packageFullPath = Join-Path -Path $MavenLocalCachePath -ChildPath $packagePath -AdditionalChildPath $Version
12+
13+
Write-Output "---------------------------------------------------"
14+
Write-Output "Validating package contents at $packageFullPath"
15+
16+
if(-not (Test-Path -Path $packageFullPath)) {
17+
Write-Output "Package not found in local cache."
18+
exit 1
19+
}
20+
21+
Write-Output "Package exists in local cache."
22+
23+
$expectedFiles = @(
24+
"-javadoc.jar",
25+
"-javadoc.jar.asc",
26+
"-sources.jar",
27+
"-sources.jar.asc",
28+
".module",
29+
".module.asc",
30+
".pom",
31+
".pom.asc",
32+
".jar",
33+
".jar.asc"
34+
)
35+
36+
foreach($file in $expectedFiles) {
37+
$file = $ArtifactId + "-" + $Version + $file
38+
$filePath = Join-Path -Path $packageFullPath -ChildPath $file
39+
if(-not (Test-Path -Path $filePath)) {
40+
Write-Output "Expected file $file not found in package."
41+
exit 1
42+
}
43+
$fileSize = (Get-Item -Path $filePath).length
44+
if($fileSize -eq 0) {
45+
Write-Output "File $file is empty."
46+
exit 1
47+
}
48+
}
49+
50+
$mavenMetadataFiles = Get-ChildItem -Path $packageFullPath -Filter "maven-metadata*.xml"
51+
if($mavenMetadataFiles.Count -eq 0) {
52+
Write-Output "No maven-metadata*.xml files found in package."
53+
exit 1
54+
}
55+
56+
Write-Output "Package $ArtifactId is valid."
57+
Write-Output "---------------------------------------------------"
58+
exit 0
59+
60+

0 commit comments

Comments
 (0)