-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First draft of Sonatype Central Portal API client (#724)
* related to #722 initial implementation of a (not fully tested) client for the portal api * related to #722 move api to separate module * remove API which fails the build --------- Co-authored-by: Gabriel Ittner <[email protected]>
- Loading branch information
1 parent
8b71655
commit 3e6872a
Showing
7 changed files
with
279 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
plugins { | ||
id("shared") | ||
} | ||
|
||
dependencies { | ||
kapt(libs.moshi.codegen) | ||
|
||
implementation(libs.okhttp) | ||
implementation(libs.moshi) | ||
implementation(libs.retrofit) | ||
implementation(libs.retrofit.converter.moshi) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
POM_ARTIFACT_ID=central-portal | ||
POM_NAME=Sonatype related APIs and tasks | ||
POM_DESCRIPTION=APIs and tasks to help working with the Sonatype Central Portal |
132 changes: 132 additions & 0 deletions
132
central-portal/src/main/kotlin/com/vanniktech/maven/publish/portal/SonatypeCentralPortal.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package com.vanniktech.maven.publish.portal | ||
|
||
import java.io.File | ||
import java.io.IOException | ||
import java.util.concurrent.TimeUnit | ||
import okhttp3.MediaType.Companion.toMediaType | ||
import okhttp3.MultipartBody | ||
import okhttp3.OkHttpClient | ||
import okhttp3.RequestBody | ||
import okhttp3.RequestBody.Companion.asRequestBody | ||
import retrofit2.Retrofit | ||
import retrofit2.converter.moshi.MoshiConverterFactory | ||
|
||
class SonatypeCentralPortal( | ||
private val baseUrl: String, | ||
private val usertoken: String, | ||
userAgentName: String, | ||
userAgentVersion: String, | ||
okhttpTimeoutSeconds: Long, | ||
private val closeTimeoutSeconds: Long, | ||
) { | ||
private val service by lazy { | ||
val okHttpClient = OkHttpClient.Builder() | ||
.addInterceptor(SonatypeCentralPortalOkHttpInterceptor(usertoken, userAgentName, userAgentVersion)) | ||
.connectTimeout(okhttpTimeoutSeconds, TimeUnit.SECONDS) | ||
.readTimeout(okhttpTimeoutSeconds, TimeUnit.SECONDS) | ||
.writeTimeout(okhttpTimeoutSeconds, TimeUnit.SECONDS) | ||
.build() | ||
val retrofit = Retrofit.Builder() | ||
.addConverterFactory(MoshiConverterFactory.create()) | ||
.client(okHttpClient) | ||
.baseUrl(baseUrl) | ||
.build() | ||
|
||
retrofit.create(SonatypeCentralPortalService::class.java) | ||
} | ||
|
||
private fun deleteDeployment(deploymentId: String) { | ||
val deleteDeploymentResponse = service.deleteDeployment(deploymentId).execute() | ||
if (!deleteDeploymentResponse.isSuccessful) { | ||
throw IOException( | ||
"Failed to delete deploymentId $deploymentId code: ${deleteDeploymentResponse.code()} msg: ${ | ||
deleteDeploymentResponse.errorBody()?.string() | ||
}", | ||
) | ||
} | ||
} | ||
|
||
private fun publishDeployment(deploymentId: String) { | ||
val publishDeploymentResponse = service.publishDeployment(deploymentId).execute() | ||
if (!publishDeploymentResponse.isSuccessful) { | ||
throw IOException( | ||
"Failed to delete deploymentId $deploymentId code: ${publishDeploymentResponse.code()} msg: ${ | ||
publishDeploymentResponse.errorBody()?.string() | ||
}", | ||
) | ||
} | ||
} | ||
|
||
// trying logic outlined on: https://www.megumethod.com/blog/downloading-files-retrofit-library | ||
private suspend fun getDeploymentDownloadByIdAndPath(deploymentId: String, relativePath: String, outputPath: String): File { | ||
val destinationFile = File(outputPath) | ||
val response = service.getDeploymentDownloadByIdAndPath(deploymentId, relativePath).execute() | ||
if (response.isSuccessful) { | ||
response.body()?.byteStream().use { inputStream -> | ||
destinationFile.outputStream().use { outputStream -> | ||
inputStream?.copyTo(outputStream) | ||
} | ||
} | ||
} else { | ||
throw IOException( | ||
"Failed to retrieve content for $deploymentId on relativePath: $relativePath. msg: ${ | ||
response.errorBody()?.string() | ||
}", | ||
) | ||
} | ||
return destinationFile | ||
} | ||
|
||
private suspend fun getDeploymentDownload(relativePath: String, outputPath: String): File { | ||
val destinationFile = File(outputPath) | ||
val response = service.getDeploymentDownload(relativePath).execute() | ||
if (response.isSuccessful) { | ||
response.body()?.byteStream().use { inputStream -> | ||
destinationFile.outputStream().use { outputStream -> | ||
inputStream?.copyTo(outputStream) | ||
} | ||
} | ||
} else { | ||
throw IOException( | ||
"Failed to retrieve content on relativePath: $relativePath. msg: ${ | ||
response.errorBody()?.string() | ||
}", | ||
) | ||
} | ||
return destinationFile | ||
} | ||
|
||
private fun getPublished(namespace: String, name: String, version: String): String? { | ||
val stringResponse = service.getPublished(namespace, name, version).execute() | ||
if (stringResponse.isSuccessful) { | ||
return stringResponse.body() | ||
} else { | ||
throw IOException( | ||
"Failed to get published status for $namespace:$name:$version. msg: ${ | ||
stringResponse.errorBody()?.string() | ||
}", | ||
) | ||
} | ||
} | ||
|
||
private fun getStatus(deploymentId: String): DeploymentStatus { | ||
val statusResponse = service.getStatus(deploymentId).execute() | ||
if (statusResponse.isSuccessful) { | ||
return statusResponse.body()!! | ||
} else { | ||
throw IOException("Failed to get status for $deploymentId. msg: ${statusResponse.errorBody()?.string()}") | ||
} | ||
} | ||
|
||
private fun upload(name: String?, publishingType: String?, file: File): String { | ||
val uploadFile: RequestBody = file.asRequestBody("application/octet-stream".toMediaType()) | ||
val multipart = | ||
MultipartBody.Part.createFormData("bundle", file.getName(), uploadFile) | ||
val uploadResponse = service.uploadBundle(name, publishingType, multipart).execute() | ||
if (uploadResponse.isSuccessful) { | ||
return uploadResponse.body()!! | ||
} else { | ||
throw IOException("Upload failed: ${uploadResponse.errorBody()?.string()}") | ||
} | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
...-portal/src/main/kotlin/com/vanniktech/maven/publish/portal/SonatypeCentralPortalModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package com.vanniktech.maven.publish.portal | ||
|
||
import com.squareup.moshi.Json | ||
import com.squareup.moshi.JsonClass | ||
|
||
@JsonClass(generateAdapter = true) | ||
internal data class FileRequest( | ||
val page: Int, | ||
@Json(name = "size") val sizze: Int, | ||
val sortField: String, | ||
val sortDirection: String, | ||
val deploymentIds: List<String>, | ||
val pathStarting: String, | ||
) | ||
|
||
@JsonClass(generateAdapter = true) | ||
internal data class DeployedComponentVersion( | ||
val name: String, | ||
val path: String, | ||
val errors: List<String>, | ||
) | ||
|
||
@JsonClass(generateAdapter = true) | ||
internal data class DeploymentResponseFile( | ||
val deploymentId: String, | ||
val deploymentName: String, | ||
val deploymentState: String, | ||
val deploymentType: String, | ||
val createTimestamp: Long, | ||
val purls: List<String>, | ||
val deployedComponentVersions: List<DeployedComponentVersion>, | ||
) | ||
|
||
@JsonClass(generateAdapter = true) | ||
internal data class DeploymentStatus( | ||
val deploymentId: String, | ||
val deploymentName: String, | ||
val deploymentState: String, | ||
val purls: List<String>, | ||
val errors: List<String>, | ||
) | ||
|
||
@JsonClass(generateAdapter = true) | ||
internal data class DeploymentResponseFiles( | ||
val deployments: List<DeploymentResponseFile>, | ||
val page: Int, | ||
val pageSize: Int, | ||
val pageCount: Int, | ||
val totalResultCount: Int, | ||
) |
20 changes: 20 additions & 0 deletions
20
...main/kotlin/com/vanniktech/maven/publish/portal/SonatypeCentralPortalOkHttpInterceptor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.vanniktech.maven.publish.portal | ||
|
||
import okhttp3.Interceptor | ||
import okhttp3.Response | ||
|
||
internal class SonatypeCentralPortalOkHttpInterceptor( | ||
private val usertoken: String, | ||
private val userAgentName: String, | ||
private val userAgentVersion: String, | ||
) : Interceptor { | ||
override fun intercept(chain: Interceptor.Chain): Response { | ||
val requestBuilder = chain.request().newBuilder() | ||
|
||
requestBuilder.addHeader("Accept", "application/json") // request json by default, XML is returned else | ||
requestBuilder.addHeader("Authorization", "UserToken $usertoken") | ||
requestBuilder.addHeader("User-Agent", "$userAgentName/$userAgentVersion") | ||
|
||
return chain.proceed(requestBuilder.build()) | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
...ortal/src/main/kotlin/com/vanniktech/maven/publish/portal/SonatypeCentralPortalService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package com.vanniktech.maven.publish.portal | ||
|
||
import okhttp3.MultipartBody | ||
import okhttp3.ResponseBody | ||
import retrofit2.Call | ||
import retrofit2.http.Body | ||
import retrofit2.http.DELETE | ||
import retrofit2.http.GET | ||
import retrofit2.http.Multipart | ||
import retrofit2.http.POST | ||
import retrofit2.http.Path | ||
import retrofit2.http.Query | ||
import retrofit2.http.Streaming | ||
|
||
/* | ||
* Sonatype Central Portal Publishing based on https://central.sonatype.org/publish/publish-portal-api/ | ||
*/ | ||
internal interface SonatypeCentralPortalService { | ||
@DELETE("publisher/deployment/{deploymentId}") | ||
fun deleteDeployment( | ||
@Path("deploymentId") deploymentId: String, | ||
): Call<Unit> | ||
|
||
@POST("publisher/deployment/{deploymentId}") | ||
fun publishDeployment( | ||
@Path("deploymentId") deploymentId: String, | ||
): Call<Unit> | ||
|
||
@Streaming | ||
@GET("publisher/deployment/download/{deploymentId}/{relativePath}") | ||
suspend fun getDeploymentDownloadByIdAndPath( | ||
@Path("deploymentId") deploymentId: String, | ||
@Path("relativePath") relativePath: String, | ||
): Call<ResponseBody> | ||
|
||
@GET("publisher/published") | ||
fun getPublished( | ||
@Query("namespace") namespace: String, | ||
@Query("name") name: String, | ||
@Query("version") version: String, | ||
): Call<String> | ||
|
||
@POST("publisher/status") | ||
fun getStatus( | ||
@Query("id") id: String, | ||
): Call<DeploymentStatus> | ||
|
||
@Multipart | ||
@POST("publisher/upload") | ||
fun uploadBundle( | ||
@Query("name") name: String?, | ||
@Query("publishingType") publishingType: String?, | ||
@Body input: MultipartBody.Part, | ||
): Call<String> | ||
|
||
@Streaming | ||
@GET("publisher/deployments/download") | ||
suspend fun getDeploymentDownload( | ||
@Query("relativePath") relativePath: String, | ||
): Call<ResponseBody> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters