From c42f8b73b3391bef7eca9cb6c5c845901826bbf8 Mon Sep 17 00:00:00 2001 From: Ravil Galeyev Date: Sun, 9 Oct 2022 20:33:53 +0200 Subject: [PATCH] Release Add publishing plugin Add signing plugin Generate sources and javadocs jars (but they can bt empty) Describe hot to set up plugins and prolong keys. Remove "-gradle-plugin" from plugin id. Made first publishing to Maven Central --- .gitignore | 4 +- build.gradle.kts | 86 ++++++- devnotes.adoc | 231 ++++++++++++++++-- gradle.properties | 1 - publish.sh | 5 + .../linter/LinterPluginFunctionalTest.kt | 2 +- 6 files changed, 301 insertions(+), 28 deletions(-) delete mode 100644 gradle.properties create mode 100755 publish.sh diff --git a/.gitignore b/.gitignore index 9acd20f..7f43a9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .idea .gradle build -gradle/wrapper \ No newline at end of file +gradle/wrapper +gradle.properties +publish.log diff --git a/build.gradle.kts b/build.gradle.kts index 70de831..3d87106 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,10 +2,17 @@ plugins { id("org.jetbrains.kotlin.jvm").version("1.5.31") id("java-gradle-plugin") id("maven-publish") + signing } group = "me.dehasi" -version = "LATEST-SNAPSHOT" + +val isPublishing = project.hasProperty("releaseVersion") +if (isPublishing) { + project.version = project.property("releaseVersion").toString() +} else { + project.version = "LATEST-SNAPSHOT" +} java { sourceCompatibility = JavaVersion.VERSION_17 @@ -25,11 +32,16 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.0") } +val pluginName = "Jenkins Pipeline Linter Gradle Plugin" +val pluginDescription = "A plugin to lint jenkins pipelines." + gradlePlugin { plugins { - create("jenkins-pipeline-linter-gradle-plugin") { - id = "me.dehasi.jenkins-pipeline-linter-gradle-plugin" + create("jenkins-pipeline-linter") { + id = "me.dehasi.jenkins-pipeline-linter" implementationClass = "me.dehasi.jenkins.linter.LinterPlugin" + description = pluginDescription + displayName = pluginName } } } @@ -39,3 +51,71 @@ tasks { useJUnitPlatform() } } + +val javadocJar: TaskProvider by tasks.registering(Jar::class) { + archiveClassifier.set("javadoc") +} + +val sourcesJar: TaskProvider by tasks.registering(Jar::class) { + archiveClassifier.set("sources") +} + +publishing { + publications.withType { + artifact(javadocJar) + artifact(sourcesJar) + + repositories { + maven { + name = "OSSRH" + url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2") + credentials { + username = project.property("ossrhUsername").toString() + password = project.property("ossrhPassword").toString() + } + } + } + groupId = "me.dehasi" + artifactId = "jenkins-pipeline-linter-gradle-plugin" + version = project.version.toString() + + pom { + val projectGitHubUrl = "https://github.com/dehasi/jenkins-pipeline-linter-gradle-plugin" + + name.set(pluginName) + description.set(pluginDescription) + url.set(projectGitHubUrl) + inceptionYear.set("2022") + + scm { + connection.set("scm:git:$projectGitHubUrl") + developerConnection.set("scm:git:$projectGitHubUrl") + url.set(projectGitHubUrl) + } + licenses { + license { + name.set("MIT") + url.set("https://opensource.org/licenses/MIT") + } + } + developers { + developer { + id.set("dehasi") + name.set("Ravil") + email.set("dehasi@proton.me") + url.set("http://dehasi.me") + } + } + issueManagement { + system.set("GitHub") + url.set("$projectGitHubUrl/issues") + } + } + the().sign(this) + } +} + +signing { + isRequired = isPublishing + sign(configurations.archives.get()) +} diff --git a/devnotes.adoc b/devnotes.adoc index 118ffec..cc16d39 100644 --- a/devnotes.adoc +++ b/devnotes.adoc @@ -4,23 +4,54 @@ * Add `id("maven-publish")` and `id("java-gradle-plugin")` plugins -Set up plugin id -[source, groovy] +== Set Up Plugin Id +I have to add `description` and `displayName`. Solution taken from JetBrains https://github.com/JetBrains/kotlin/tree/master/libraries/tools/kotlin-gradle-plugin[repository]. + +[source,groovy] ---- gradlePlugin { plugins { - create("jenkins-pipeline-linter-gradle-plugin") { - id = "me.dehasi.jenkins-pipeline-linter-gradle-plugin" + create("jenkins-pipeline-linter") { + id = "me.dehasi.jenkins-pipeline-linter" implementationClass = "me.dehasi.jenkins.linter.Linter" + description = pluginDescription // will need for publishing + displayName = pluginName // will need for publishing } } } ---- +`PluginMarkerMaven` creates a separate `pom` with `groupId`=`${PLUGIN_ID}` and `artifactId` = `${PLUGIN_ID}.gradle.plugin`. +That's why there is no necessaty to have words "gradle" and "plugin" in the plugin id name. +In my case: + +[source,xml] +---- + + me.dehasi.jenkins-pipeline-linter + me.dehasi.jenkins-pipeline-linter.gradle.plugin + pom + +---- + +This pom has the actual project as a dependency + +[source,xml] +---- + + + me.dehasi + jenkins-pipeline-linter-gradle-plugin + 2022.10.09 + + +---- + == Use from local `.m2` Add to `settings.gradle.kts` -[source, groovy] + +[source,groovy] ---- pluginManagement { repositories { @@ -31,41 +62,47 @@ pluginManagement { ---- Add to `build.gradle` + ---- plugins { - id 'me.dehasi.jenkins-pipeline-linter-gradle-plugin' version 'LATEST-SNAPSHOT' + id 'me.dehasi.jenkins-pipeline-linter' version 'LATEST-SNAPSHOT' } ---- == Run + ---- $ gradle --quiet lint Hello from the jenkinsfile ---- == Test + To run groovy tests add plugin `id("groovy")`. -Don't know if `testImplementation(gradleTestKit())` is needed. Test work without it. +Don't know if `testImplementation(gradleTestKit())` is needed. +Test work without it. == Parametrisation -First `project.extensions.create` then `project.tasks.register` otherwise Gradle doesn't have a chance to resolve parameters. +First `project.extensions.create` then `project.tasks.register` otherwise Gradle doesn't have a chance to resolve parameters. == Jenkins -To validate pipeline, Jenkins need `pipeline-model-definition` plugin. Official docker images goes without plugins. + +To validate pipeline, Jenkins need `pipeline-model-definition` plugin. +Official docker images goes without plugins. I created my customised docker image with this plugin based on https://www.jenkins.io/doc/book/installing/docker/::[official instruction]. My Dockerfile (mostly copy-pasted from official instruction): -[source, dockerfile] +[source,dockerfile] ---- include::src/test/resources/Dockerfile[] ---- We need to turn off `setup wizard` and set password form environment variables. -[source, bash] +[source,bash] ---- docker run --rm --detach --name myjenkins \ --env JENKINS_OPTS='--argumentsRealm.roles.user=admin --argumentsRealm.passwd.admin=admin --argumentsRealm.roles.admin=admin' \ @@ -77,7 +114,7 @@ docker run --rm --detach --name myjenkins \ Then we can call `/pipeline-model-converter/validate`. Filename in the multipart request must be `jenkinsfile` (lowercase). -[source, bash] +[source,bash] ---- curl --user admin:admin -X POST -F "jenkinsfile= +---- + +==== Prolong if expired + +Period can be in `m` - months, `y` - years. + +---- +gpg --quick-set-expire ${FINGERPRINT} 5y +---- + +==== Upload key + +---- +gpg --export ${KEYID} | curl -T - https://keys.openpgp.org +gpg --keyserver keyring.debian.org --send-keys ${KEYID} +---- + +=== Signing Jars + +If you don't use `useGpgCmd()` only following properties are needed. + +---- +signing.keyId= +signing.password= +signing.secretKeyRingFile= +---- + +We need to add and set up `signing` plugin. + +[source,kotlin] +---- +plugins { + signing // <- need for signing +} +publishing { + publications.withType { + repositories {} + pom {} + the().sign(this) // <- need for signing + } +} + +signing { + sign(configurations.archives.get()) +} +---- + +=== Creating jars + +We expect to have the following files + +---- +jenkins-pipeline-linter-gradle-plugin-${VERSION}.jar +jenkins-pipeline-linter-gradle-plugin-${VERSION}.jar.asc +jenkins-pipeline-linter-gradle-plugin-${VERSION}-javadoc.jar +jenkins-pipeline-linter-gradle-plugin-${VERSION}-javadoc.jar.asc +jenkins-pipeline-linter-gradle-plugin-${VERSION}-sources.jar +jenkins-pipeline-linter-gradle-plugin-${VERSION}-sources.jar.asc +---- + +==== Jar + +Will be created automagically. + +==== Javadoc + +[source,kotlin] +---- +val javadocJar: TaskProvider by tasks.registering(Jar::class) { + archiveClassifier.set("javadoc") +} +---- + +then + +[source,kotlin] +---- + publications.withType { + artifact(javadocJar) +} +---- + +==== Sources + +[source,kotlin] +---- +val sourcesJar: TaskProvider by tasks.registering(Jar::class) { + archiveClassifier.set("sources") +} +---- +then +[source,kotlin] +---- + publications.withType { + artifact(sourcesJar) +} +---- + +=== Publishing + +[source,kotlin] +---- +publishing { + publications.withType { + } +} +---- + +The following properties are needed to connect to maven central (in my case). + +---- +ossrhUsername= +ossrhPassword= +---- + +[source,kotlin] +---- +repositories { + maven { + name = "OSSRH" + url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2") + credentials { + username = project.property("ossrhUsername").toString() + password = project.property("ossrhPassword").toString() + } + } +} +---- + == ToDo + .todo +- [ ] Release to maven central +- [ ] Add more properties, like fail the build or not, crumble, ignore ssl, etc. +- [ ] Add an assertion that all necessary properties are set +- [ ] Check with https +- [ ] Find less broad name for the task, current "lint" is too broad +- [ ] *Maybe* Add jenkins as test container, extract some functional tests to unit tests maybe +- [ ] Use nice assertions, like assertj +- [ ] Use jenkins crumble +- [ ] Add debug/trace logging +- [ ] Add readme + +.done - [x] Maybe rename to `jenkins-pipeline-linter-gradle-plugin` - [x] Add unit-tests - [x] Add parametrisation @@ -134,13 +329,5 @@ Log level can be put as argument `.withArguments(LINT_TASK_NAME, "--info")` - [x] Add properties: path to jenkinsfiles. - [x] Add properties: authorisation to jenkins, timeouts - [x] Combine task and jenkins gateway -- [ ] Add more properties, like fail the build or not, crumble, ignore ssl, etc. -- [ ] Add an assertion that all necessary properties are set -- [ ] Check with https - [x] Add logging -- [ ] Find less broad name for the task, current "lint" is too broad -- [ ] *Maybe* Add jenkins as test container, extract some functional tests to unit tests maybe - [x] *Maybe* rewrite functional tests to kotlin -- [ ] Use nice assertions, like assertj -- [ ] Use jenkins crumble -- [ ] Add debug/trace logging diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 29e08e8..0000000 --- a/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -kotlin.code.style=official \ No newline at end of file diff --git a/publish.sh b/publish.sh new file mode 100755 index 0000000..85aaee2 --- /dev/null +++ b/publish.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +gradle -PreleaseVersion=$(date +%Y.%m.%d) --info publish | tee publish.log + +# login https://oss.sonatype.org/ diff --git a/src/test/kotlin/me/dehasi/jenkins/linter/LinterPluginFunctionalTest.kt b/src/test/kotlin/me/dehasi/jenkins/linter/LinterPluginFunctionalTest.kt index 6bcb1ce..968301a 100644 --- a/src/test/kotlin/me/dehasi/jenkins/linter/LinterPluginFunctionalTest.kt +++ b/src/test/kotlin/me/dehasi/jenkins/linter/LinterPluginFunctionalTest.kt @@ -18,7 +18,7 @@ internal class LinterPluginFunctionalTest { gradleBuildFile = File(testProjectDir, "build.gradle") gradleBuildFile.writeText(""" plugins { - id 'me.dehasi.jenkins-pipeline-linter-gradle-plugin' version 'LATEST-SNAPSHOT' + id 'me.dehasi.jenkins-pipeline-linter' version 'LATEST-SNAPSHOT' } """) }