From 99018ff069f6bec67ff335908aede4f014f70136 Mon Sep 17 00:00:00 2001 From: Horatiu Eugen Vlad Date: Mon, 6 Sep 2021 18:27:31 +0200 Subject: [PATCH] Publishing: Gitlab support Add support for publishing [Helm charts in the Gitlab Package Registry](https://docs.gitlab.com/ee/user/packages/helm_repository/#helm-charts-in-the-package-registry). --- docs/publishing-charts.adoc | 43 +++++++++- .../dsl/GitlabHelmPublishingRepository.kt | 78 +++++++++++++++++++ .../dsl/HelmPublishingRepositoryContainer.kt | 16 ++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 helm-publish-plugin/src/main/kotlin/org/unbrokendome/gradle/plugins/helm/publishing/dsl/GitlabHelmPublishingRepository.kt diff --git a/docs/publishing-charts.adoc b/docs/publishing-charts.adoc index 8652e480..41d03bb4 100644 --- a/docs/publishing-charts.adoc +++ b/docs/publishing-charts.adoc @@ -6,7 +6,9 @@ The `helm-publish` plugin allows you to publish your charts to remote repositori ==== There is currently no "official" API to publish Helm charts; Helm defines only how charts should be served from a repository. The plugin directly supports several types of popular repository servers, including -https://chartmuseum.com/[ChartMuseum], https://jfrog.com/artifactory/[Artifactory] and https://goharbor.io/[Harbor]. +https://chartmuseum.com/[ChartMuseum], https://jfrog.com/artifactory/[Artifactory], +https://goharbor.io/[Harbor], https://blog.sonatype.com/nexus-as-a-container-registry[Nexus] and +https://docs.gitlab.com/ce/user/packages/container_registry/[Gitlab]. For other repository types that are not directly supported, you could try using the `custom` repository type, or consider creating a PR to add support for it. @@ -127,6 +129,8 @@ The following repository types are supported: - `artifactory` - `chartMuseum` - `harbor` +- `nexus` +- `gitlab` - `custom` @@ -285,6 +289,43 @@ helm { TIP: Nexus API https://help.sonatype.com/repomanager3/rest-and-integration-api/components-api#ComponentsAPI-UploadComponent[documentation]. +=== Gitlab Repositories + +The plugin provides direct support for Gitlab repositories. The Gitlab API `url` and the `projectId` must be set in the +repository configuration block. + +[source,groovy,role="primary"] +.Groovy +---- +helm { + publishing { + repositories { + gitlab { + url = uri('https://gitlab.example.com/api/v4') + projectId = 1234 + } + } + } +} +---- + +[source,kotlin,role="secondary"] +.Kotlin +---- +helm { + publishing { + repositories { + gitlab { + url.set(uri("https://gitlab.example.com/api/v4")) + projectName.set(1234) + } + } + } +} +---- +TIP: Helm charts in the Gitlab Package Registry +https://docs.gitlab.com/ee/user/packages/helm_repository/#helm-charts-in-the-package-registry[documentation]. + === Custom Repositories If your target repository is not directly supported but involves some sort of HTTP upload, you can try the `custom` diff --git a/helm-publish-plugin/src/main/kotlin/org/unbrokendome/gradle/plugins/helm/publishing/dsl/GitlabHelmPublishingRepository.kt b/helm-publish-plugin/src/main/kotlin/org/unbrokendome/gradle/plugins/helm/publishing/dsl/GitlabHelmPublishingRepository.kt new file mode 100644 index 00000000..bb151874 --- /dev/null +++ b/helm-publish-plugin/src/main/kotlin/org/unbrokendome/gradle/plugins/helm/publishing/dsl/GitlabHelmPublishingRepository.kt @@ -0,0 +1,78 @@ +package org.unbrokendome.gradle.plugins.helm.publishing.dsl + +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.unbrokendome.gradle.plugins.helm.dsl.credentials.internal.SerializableCredentials +import org.unbrokendome.gradle.plugins.helm.dsl.credentials.internal.toSerializable +import org.unbrokendome.gradle.plugins.helm.publishing.publishers.AbstractHttpHelmChartPublisher +import org.unbrokendome.gradle.plugins.helm.publishing.publishers.HelmChartPublisher +import org.unbrokendome.gradle.plugins.helm.publishing.publishers.PublisherParams +import org.unbrokendome.gradle.plugins.helm.publishing.util.toMultipartBody +import org.unbrokendome.gradle.pluginutils.property +import java.io.File +import java.net.URI +import javax.inject.Inject + + +interface GitlabHelmPublishingRepository : HelmPublishingRepository { + /** + * The ID of the Gitlab project. + */ + val projectId: Property +} + + +private open class DefaultGitlabHelmPublishingRepository @Inject constructor( + name: String, + objects: ObjectFactory +) : AbstractHelmPublishingRepository(objects, name), GitlabHelmPublishingRepository { + + override val projectId: Property = + objects.property() + + override val publisherParams: PublisherParams + get() = GitlabPublisherParams( + url = requireNotNull(url.orNull) { "url is required for Gitlab publishing repository" }, + credentials = configuredCredentials.orNull?.toSerializable(), + projectId = requireNotNull(projectId.orNull) { "projectId is required for Gitlab publishing repository" } + ) + + + private class GitlabPublisherParams( + private val url: URI, + private val credentials: SerializableCredentials?, + private var projectId: Int + ) : PublisherParams { + + override fun createPublisher(): HelmChartPublisher = + GitlabPublisher(url, credentials, projectId) + } + + + private class GitlabPublisher( + url: URI, + credentials: SerializableCredentials?, + private val projectId: Int + ) : AbstractHttpHelmChartPublisher(url, credentials) { + + override val uploadMethod: String + get() = "POST" + + override fun uploadPath(chartName: String, chartVersion: String): String = + "/projects/$projectId/packages/helm/api/stable/charts" + + override fun requestBody(chartFile: File): RequestBody = + MultipartBody.Builder().run { + setType(MultipartBody.FORM) + addFormDataPart("chart", chartFile.name, chartFile.asRequestBody(MEDIA_TYPE_GZIP)) + build() + } + } +} + + +internal fun ObjectFactory.newGitlabHelmPublishingRepository(name: String): GitlabHelmPublishingRepository = + newInstance(DefaultGitlabHelmPublishingRepository::class.java, name) diff --git a/helm-publish-plugin/src/main/kotlin/org/unbrokendome/gradle/plugins/helm/publishing/dsl/HelmPublishingRepositoryContainer.kt b/helm-publish-plugin/src/main/kotlin/org/unbrokendome/gradle/plugins/helm/publishing/dsl/HelmPublishingRepositoryContainer.kt index fa2826fa..573bcabf 100644 --- a/helm-publish-plugin/src/main/kotlin/org/unbrokendome/gradle/plugins/helm/publishing/dsl/HelmPublishingRepositoryContainer.kt +++ b/helm-publish-plugin/src/main/kotlin/org/unbrokendome/gradle/plugins/helm/publishing/dsl/HelmPublishingRepositoryContainer.kt @@ -68,6 +68,19 @@ interface HelmPublishingRepositoryContainer : PolymorphicDomainObjectContainer ): NexusHelmPublishingRepository = nexus("default", configuration) + + @JvmDefault + fun gitlab( + name: String, + configuration: Action + ): GitlabHelmPublishingRepository = + create(name, GitlabHelmPublishingRepository::class.java, configuration) + + @JvmDefault + fun gitlab( + configuration: Action + ): GitlabHelmPublishingRepository = + gitlab("default", configuration) } @@ -96,6 +109,9 @@ private open class DefaultHelmPublishingRepositoryContainer registerFactory(NexusHelmPublishingRepository::class.java) { name -> objects.newNexusHelmPublishingRepository(name) } + registerFactory(GitlabHelmPublishingRepository::class.java) { name -> + objects.newGitlabHelmPublishingRepository(name) + } // Default type is "custom" registerDefaultFactory { name ->