From 7ef28d0578eddd896544fcb3aae0c66b33724d56 Mon Sep 17 00:00:00 2001 From: Geert Mulders <62983496+geertmulders@users.noreply.github.com> Date: Sat, 1 Feb 2025 19:55:24 +0100 Subject: [PATCH] Create publishing (#20) --- .github/workflows/publish-release.yml | 53 ++++++++++++ CHANGELOG.md | 15 ++++ CONTRIBUTING.md | 15 ++-- RELEASING.md | 23 +++++ measure/build.gradle.kts | 83 ++++++++++++------- .../com/alliander/open/measure/Measure.kt | 5 +- 6 files changed, 155 insertions(+), 39 deletions(-) create mode 100644 .github/workflows/publish-release.yml create mode 100644 CHANGELOG.md create mode 100644 RELEASING.md diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 0000000..0a0f03b --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,53 @@ +# SPDX-FileCopyrightText: 2022 Free Software Foundation Europe e.V. +# +# SPDX-License-Identifier: CC0-1.0 + +name: Publish Release + +on: + push: + tags: + - '**' + +jobs: + publish: + + runs-on: ubuntu-latest + if: github.repository == 'alliander-opensource/measure' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install JDK + uses: actions/setup-java@v4 + with: + distribution: zulu + java-version: 17 + + - name: Get release notes + run: | + echo "RELEASE_NOTES<> $GITHUB_ENV + echo "$(awk '/^## ${{ github.ref_name }}/{flag=1;next}/^## /{flag=0}flag' CHANGELOG.md)" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Set version for tag + run: | + echo "ORG_GRADLE_PROJECT_VERSION_NAME=${{ github.ref_name }}" >> $GITHUB_ENV + + - uses: gradle/actions/setup-gradle@v4 + + - name: Publish + run: ./gradlew :measure:publishToMavenCentral + env: + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_PRIVATE_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_PASSPHRASE }} + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + body: ${{ env.RELEASE_NOTES }} + if: ${{ env.RELEASE_NOTES != '' }} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5166d70 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ + + +# Change Log + +## 1.3.1 *(tbd)* + +- No changes yet (remove this line on the first change) + +## 1.3.0 *(2024-12-15)* + +- First open source release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8de5678..1657c05 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,9 +13,9 @@ Contribution does not necessarily mean committing code to the repository. We recognize different levels of contributions as shown below in increasing order of dedication: 1. Test and use the libray. Give feedback on the user experience or suggest new features. -3. Report bugs. -4. Improve the documentation -5. Contributing to the Kotlin code +2. Report bugs. +3. Improve the documentation +4. Contributing to the Kotlin code ## Community Guidelines This project follows the following [Code of Conduct][code-of-conduct]. @@ -28,10 +28,10 @@ Documentation is a very important part of a project. If people don't know how to Contribute to the documentation on the [documentation page][project:documentation]. -[code-of-conduct]: https://github.com/Alliander/project/blob/master/CODE_OF_CONDUCT.md -[project:issues]: https://github.com/Alliander/project/issues -[project:discussion]: https://github.com/Alliander/project/discussions -[project:documentation]: https://github.com/Alliander/project/wiki +[code-of-conduct]: https://github.com/alliander-opensource/measure/blob/main/CODE_OF_CONDUCT.md +[project:issues]: https://github.com/alliander-opensource/project/issues +[project:discussion]: https://github.com/alliander-opensource/project/discussions +[project:documentation]: https://github.com/alliander-opensource/project/wiki ## Signing the Developer Certificate of Origin (DCO) @@ -72,6 +72,7 @@ The process for a code change and pull request you should follow: "feature-###" or "fix-###". For more information see the Git branching guideline. 1. Make changes, compile, and test thoroughly. Ensure any install or build dependencies are removed before the end of the layer when doing a build. Code style should match existing style and conventions, and changes should be focused on the topic the pull request will be addressed. For more information see the style guide. 1. Push commits to your fork. +1. Update the CHANGELOG.md with the changes. 1. Create a Github pull request from your topic branch. 1. Pull requests will be reviewed by one of the maintainers who may discuss, offer constructive feedback, request changes, or approve the work. For more information see the Code review guideline. diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..084c8e0 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,23 @@ + + +# Releasing procedure + +After adding new features or bugfixes you might want to release the changes so that they can be used. To do this, we +follow a number of steps to make sure that every release is of a high quality. + +1. Every PR to main the CHANGELOG.md is updated with the changes, this will be reviewed as well. +2. Before starting the actual release we must make sure that the version number is correct in the CHANGELOG.md. We + follow [semantic versioning](https://semver.org/). +3. Merge the last changes to main and create a new tag on main. The tag should be the version number without a 'v'. E.g. + `1.3.5`. +4. A github action will be triggered, the release is build, signed and then pushed to maven central. +5. Maven central will validate the release. If the release passes, it can be published manually. For this someone has to + login in maven central and push the "publish" button. +6. The release in github will be automatically created including the release notes. +7. After everything is done, it is nice to add a new header in the CHANGELOG.md with the next version number. Also + update the version number in the build.gradle.kts. (Note that the version that is used will be taken from the tagname + NOT the version in the build.gradle.kts.) \ No newline at end of file diff --git a/measure/build.gradle.kts b/measure/build.gradle.kts index e09062f..f45d608 100644 --- a/measure/build.gradle.kts +++ b/measure/build.gradle.kts @@ -2,22 +2,24 @@ // // SPDX-License-Identifier: MPL-2.0 +import com.vanniktech.maven.publish.SonatypeHost +import org.jetbrains.dokka.gradle.DokkaTask + plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. - id("org.jetbrains.kotlin.jvm") + kotlin("jvm") // Apply the java-library plugin for API and implementation separation. `java-library` // Apply dokka plugin to allow extraction of ducumentation from KDoc comments - id("org.jetbrains.dokka") version "1.4.20" + id("org.jetbrains.dokka") version "1.9.20" - // Make sure we can publish to maven - `maven-publish` + id("com.vanniktech.maven.publish") version "0.30.0" } group = "com.alliander" -version = "1.2" +version = "1.3.0" repositories { mavenCentral() @@ -30,47 +32,66 @@ dependencies { // Use the Kotlin JDK 8 standard library. implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - testImplementation("io.kotest:kotest-runner-junit5:4.3.2") - testImplementation("io.kotest:kotest-assertions-core:4.3.2") - testImplementation("io.kotest:kotest-property:4.3.2") + testImplementation("io.kotest:kotest-runner-junit5:5.9.1") + testImplementation("io.kotest:kotest-assertions-core:5.9.1") + testImplementation("io.kotest:kotest-property:5.9.1") } -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of("17")) - } +kotlin { + jvmToolchain(17) } -tasks.withType().configureEach { - kotlinOptions { - jvmTarget = "17" - } +java { + // Add a task that will package the sources of the main SourceSet in a JAR with classifier `sources`. + withSourcesJar() } tasks.withType { useJUnitPlatform() } -tasks.withType().configureEach { +tasks.withType().configureEach { outputDirectory.set(buildDir.resolve("dokka")) } -publishing { - publications { - create("maven") { - artifactId = "open.measure" - from(components["kotlin"]) - } - } +mavenPublishing { + // Publishing to https://s01.oss.sonatype.org + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + signAllPublications() - repositories { - maven { - name = "AllianderNexus" - url = uri("https://nexus.apps.ocp-01.prd.ahcaws.com/repository/maven-releases/") - credentials { - username = System.getenv("ALLIANDER_NEXUS_USERNAME") - password = System.getenv("ALLIANDER_NEXUS_PASSWORD") + pom { + name.set("Measure") + description.set("Measure is a Kotlin library for working with units of measurement that are - for example - used in the power system sector.") + url.set("https://github.com/alliander-opensource/measure") + + licenses { + license { + name.set("Mozilla Public License Version 2.0") + url.set("https://www.mozilla.org/en-US/MPL/2.0/") + } + } + developers { + developer { + id.set("dvberkel") + name.set("Daan van Berkel") + email.set("daan.v.berkel.1980@gmail.com") + } + developer { + id.set("gmulders") + name.set("Geert Mulders") + email.set("gmulders@gmail.com") } + developer { + id.set("cflist") + name.set("Coen van der List") + } + developer { + id.set("BaukjeD") + name.set("Baukje Debets") + } + } + scm { + url.set("https://github.com/alliander-opensource/measure") } } } diff --git a/measure/src/main/kotlin/com/alliander/open/measure/Measure.kt b/measure/src/main/kotlin/com/alliander/open/measure/Measure.kt index c25a09e..3147128 100644 --- a/measure/src/main/kotlin/com/alliander/open/measure/Measure.kt +++ b/measure/src/main/kotlin/com/alliander/open/measure/Measure.kt @@ -13,6 +13,10 @@ operator fun Double.times(units: U): Measure = Measure(this.toBig operator fun Float.times(units: U): Measure = Measure(this.toBigDecimal(), units) operator fun BigDecimal.times(units: U): Measure = Measure(this, units) +/** + * [Units] is the base class for a Unit, e.g. [Power] or [Current]. The reason for calling it "Units" is that "Unit" + * was taken in Kotlin. + */ open class Units(val suffix: String, val ratio: BigDecimal = BigDecimal.ONE) { override fun equals(other: Any?): Boolean { if (this === other) return true @@ -107,7 +111,6 @@ data class Measure(val amount: BigDecimal, val units: U) : Comparable * - In case the dividend or the factor is zero, the dividend is returned as is. * - In case the factor is negative, it is assessed as if it were positive. */ - fun roundToMultiple(factor: Measure, roundingMode: RoundingMode): Measure { if (this.isZero() || factor.isZero()) { return this