diff --git a/gradle/conventions/library/build.gradle.kts b/gradle/conventions/library/build.gradle.kts new file mode 100644 index 0000000..b9d90a2 --- /dev/null +++ b/gradle/conventions/library/build.gradle.kts @@ -0,0 +1,5 @@ +plugins { + `kotlin-dsl` +} + +group = "conventions" diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts new file mode 100644 index 0000000..e5c2817 --- /dev/null +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -0,0 +1,123 @@ +package conventions + +import gradle.kotlin.dsl.accessors._b6bea14fb88fd11e46d6fb1ebe601eab.ext +import gradle.kotlin.dsl.accessors._b6bea14fb88fd11e46d6fb1ebe601eab.publishing +import gradle.kotlin.dsl.accessors._b6bea14fb88fd11e46d6fb1ebe601eab.signing + +plugins { + id("maven-publish") + id("signing") +} + +// Global configuration for the repository +// Remember to change this when using in your own project! + +fun MavenPom.buildConfiguration() { + licenses { + license { + name.set("Apache 2.0") + url.set("https://www.apache.org/licenses/LICENSE-2.0") + } + } + + developers { + developer { + id.set("clovis-ai") + name.set("Ivan “CLOVIS” Canet") + email.set("ivan.canet@gmail.com") + } + } + + scm { + url.set("https://gitlab.com/opensavvy/playgrounds/gradle") + } +} + +// region Metadata + +interface LibraryExtension { + val name: Property + val description: Property + val homeUrl: Property +} + +val config = extensions.create("library") + +// endregion +// region GitLab Maven Registry + +// When running in GitLab CI, uses the auto-created CI variables to configure the GitLab Maven Registry. +// For more information on the variables and their values, see: +// - https://docs.gitlab.com/ee/user/packages/maven_repository/ +// - https://docs.gitlab.com/ee/ci/variables/predefined_variables.html +publishing { + repositories { + val projectId = System.getenv("CI_PROJECT_ID") ?: return@repositories + val token = System.getenv("CI_JOB_TOKEN") ?: return@repositories + val api = System.getenv("CI_API_V4_URL") ?: return@repositories + + maven { + name = "GitLab" + url = uri("$api/projects/$projectId/packages/maven") + + credentials(HttpHeaderCredentials::class.java) { + name = "Job-Token" + value = token + } + + authentication { + create("header") + } + } + } +} + +// endregion +// region Maven Central + +val fakeJavadocJar by tasks.registering(Jar::class) { + description = "Fake documentation JAR for MavenCentral" + group = "publishing" + + archiveClassifier.set("javadoc") +} + +publishing { + repositories { + val centralUsername = System.getenv("OSSRH_USERNAME") ?: return@repositories + val centralPassword = System.getenv("OSSRH_PASSWORD") ?: return@repositories + + maven { + name = "Central" + url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") + credentials { + username = centralUsername + password = centralPassword + } + } + } + + publications.withType { + artifact(fakeJavadocJar.get()) + + pom { + name.set(config.name) + description.set(config.description) + url.set(config.homeUrl) + + buildConfiguration() + } + } +} + +run { + ext["signing.keyId"] = System.getenv("SIGNING_KEY_ID") ?: return@run + ext["signing.password"] = System.getenv("SIGNING_PASSWORD") ?: return@run + ext["signing.secretKeyRingFile"] = System.getenv("SIGNING_KEY_RING") ?: return@run + + signing { + sign(publishing.publications) + } +} + +//endregion diff --git a/gradle/conventions/settings.gradle.kts b/gradle/conventions/settings.gradle.kts index 23983ac..d143d50 100644 --- a/gradle/conventions/settings.gradle.kts +++ b/gradle/conventions/settings.gradle.kts @@ -16,6 +16,7 @@ dependencyResolutionManagement { include( "base", "kotlin", + "library", ) enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -- 2.51.2 From 388879c5920c92ac6e42b829286d8e3a6c35cb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 23 Aug 2023 17:10:42 +0200 Subject: [PATCH 02/47] build(core): Core is a library --- core/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index bd5c71b..d847522 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("conventions.base") id("conventions.kotlin") + id("conventions.library") } kotlin { -- 2.51.2 From df6e46f4f89e2b05c6f6a3901b1350a8c6296f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 23 Aug 2023 17:15:45 +0200 Subject: [PATCH 03/47] ci(gitlab): Publish Maven artifacts to the GitLab Registry --- .gitlab-ci.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index da69011..5cafea3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -31,6 +31,24 @@ check: interruptible: true +# endregion +# region Publishing + +publish-maven:gitlab: + extends: [ .os.gradle ] + needs: [ os.version, check ] + stage: deploy + + script: + - > + ./gradlew publishAllPublicationsToGitLabRepository + -PappVersion=$project_version + + interruptible: false + rules: + - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH + - if: $CI_COMMIT_TAG + # endregion # region Build & containerize -- 2.51.2 From 560ab4b64b3b0a2242adf0ed615296b1b612ac37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 23 Aug 2023 17:18:38 +0200 Subject: [PATCH 04/47] ci(gitlab): Publish Maven artifacts to Maven Central --- .gitlab-ci.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5cafea3..bf2615b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,6 +49,22 @@ publish-maven:gitlab: - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_TAG +publish-maven:central: + extends: [ .os.gradle ] + needs: [ os.version, check ] + stage: deploy + + script: + - > + ./gradlew publishAllPublicationsToCentralRepository + -PappVersion=$project_version + + interruptible: false + rules: + - if: $OSSRH_USERNAME == null || $OSSRH_PASSWORD == null + when: never + - if: $CI_COMMIT_TAG + # endregion # region Build & containerize -- 2.51.2 From 0916320935fbeffde7af6ff281f85da02ff2d848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 23 Aug 2023 17:27:04 +0200 Subject: [PATCH 05/47] ci(gitlab): Allow projects to opt-out of Maven publishing by setting a CI variable --- .gitlab-ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bf2615b..131fd9b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,6 +46,10 @@ publish-maven:gitlab: interruptible: false rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + when: never + - if: $PUBLISH_MAVEN == "manual" || $PUBLISH_MAVEN_GITLAB == "manual" + when: manual - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_TAG @@ -61,8 +65,12 @@ publish-maven:central: interruptible: false rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + when: never - if: $OSSRH_USERNAME == null || $OSSRH_PASSWORD == null when: never + - if: $PUBLISH_MAVEN == "manual" || $PUBLISH_MAVEN_CENTRAL == "manual" + when: manual - if: $CI_COMMIT_TAG # endregion -- 2.51.2 From 9f913df7a121ceb0363f5a1bcf175b83b5e79c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 23 Aug 2023 17:53:39 +0200 Subject: [PATCH 06/47] ci(gitlab): Rename the Docker publishing job --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 131fd9b..a562f88 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -107,7 +107,7 @@ app:container: interruptible: true -app:container:deploy: +app:container:publish: extends: [ .os.docker.rename ] needs: [ app:container, os.version ] stage: deploy -- 2.51.2 From 1b02e707cc24cad2bdb96f7fb727b5a51cc12730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 23 Aug 2023 18:06:20 +0200 Subject: [PATCH 07/47] build(gitpod): GitPod configuration --- .gitpod.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..54b5787 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,3 @@ +tasks: + - name: Start + command: echo Hello World -- 2.51.2 From 86736fbccc76b7eb7af86fe36960d5b8968262c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 23 Aug 2023 18:28:33 +0200 Subject: [PATCH 08/47] build(devcontainer): DevContainer configuration --- .devcontainer/Dockerfile | 3 +++ .devcontainer/devcontainer.json | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..ef356df --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,3 @@ +FROM archlinux:base + +RUN pacman -Syuu --noconfirm git diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..b92111d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,5 @@ +{ + "build": { + "dockerfile": "Dockerfile" + } +} -- 2.51.2 From bf018392348a1c88edf95424efe6205458f929fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 30 Aug 2023 20:29:14 +0200 Subject: [PATCH 09/47] build(docker): Remove the docker deployment from the Gradle playground --- .gitlab-ci.yml | 50 -------------------------------------------------- app/Dockerfile | 16 ---------------- 2 files changed, 66 deletions(-) delete mode 100644 app/Dockerfile diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a562f88..bfdb424 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -73,56 +73,6 @@ publish-maven:central: when: manual - if: $CI_COMMIT_TAG -# endregion -# region Build & containerize - -app:build: - extends: [ .os.gradle ] - needs: [ os.version ] - stage: build - - script: - - > - ./gradlew app:distTar - -PappVersion=$project_version - - mv app/build/distributions/app-*.tar app.tar - - artifacts: - paths: - - app.tar - - interruptible: true - -app:container: - extends: [ .os.docker.build ] - needs: - - job: app:build - artifacts: true - stage: build - - variables: - dockerfile: app/Dockerfile - docker_context: app - image: app - - interruptible: true - -app:container:publish: - extends: [ .os.docker.rename ] - needs: [ app:container, os.version ] - stage: deploy - - variables: - image: app - - rules: - - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH - - if: $CI_COMMIT_TAG - variables: - new_version: $project_version - - interruptible: false - # endregion # region Automatically mirror the previous layer of the playground diff --git a/app/Dockerfile b/app/Dockerfile deleted file mode 100644 index 3eb4167..0000000 --- a/app/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM alpine:latest as builder - -COPY app.tar /home/server/app.tar -WORKDIR /home/server -RUN tar -xf app.tar -RUN mkdir -p extracted -RUN mv app-*/* extracted - -FROM alpine:latest - -RUN apk add --no-cache openjdk17-jre-headless -COPY --from=builder /home/server/extracted /opt/app - -WORKDIR /opt/app -EXPOSE 9000 -ENTRYPOINT [ "/opt/app/bin/app" ] -- 2.51.2 From 0a2ba930ff04274c35ee232f77ffb6837916a2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 30 Aug 2023 20:34:53 +0200 Subject: [PATCH 10/47] build(gitpod): Automatically download and initialize Gradle when the pod is started --- .gitpod.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitpod.yml b/.gitpod.yml index 54b5787..e7ae318 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,3 +1,3 @@ tasks: - - name: Start - command: echo Hello World + - name: Download and initialize Gradle + command: ./gradlew projects -- 2.51.2 From 572068587b20b83d50beb912b8dc5c4509edc7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 30 Aug 2023 20:51:45 +0200 Subject: [PATCH 11/47] build(devcontainer): Automatically download and initialize Gradle when the container is started --- .devcontainer/Dockerfile | 5 ++++- .devcontainer/devcontainer.json | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ef356df..6573969 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,3 +1,6 @@ FROM archlinux:base -RUN pacman -Syuu --noconfirm git +# At the moment, Gradle is not compatible with Java 20 + +RUN pacman -Syuu --noconfirm git jre17-openjdk-headless +ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b92111d..fd00fa0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,6 @@ { "build": { "dockerfile": "Dockerfile" - } + }, + "onCreateCommand": "./gradlew projects" } -- 2.51.2 From 7930580e3b3fc124084f299b8c6def90a87a3a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Fri, 1 Sep 2023 21:27:21 +0200 Subject: [PATCH 12/47] build(gradle): Use the FooJay resolver to automatically download JVM toolchains --- settings.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/settings.gradle.kts b/settings.gradle.kts index 5d14854..416788e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,6 +18,10 @@ pluginManagement { includeBuild("gradle/conventions") } +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0" +} + include( "app", "core", -- 2.51.2 From a9a5fe5aabb6af36f4d54725ecc775f9a2a97365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sun, 3 Sep 2023 16:02:51 +0200 Subject: [PATCH 13/47] docs(playground): Explain what Gitpod and dev containers are --- docs/playground/baseline.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/playground/baseline.md b/docs/playground/baseline.md index deac6b2..a58f9ad 100644 --- a/docs/playground/baseline.md +++ b/docs/playground/baseline.md @@ -28,3 +28,40 @@ To use a license in your project, go to `File | Settings | Editor | Copyright` a ### CI/CD The Playground has configuration for GitLab CI for the basic workflow. + +## Remote development and build environment + +Usually, the build process is created to cater to the "developer" archetype, who has the project installed on their workstation and regularly submits changes. However, in the real world, many users of the repository do not fit this archetype: +- artists, product owners and other non-technical roles may want to edit some files, +- a regular developer may want to make some changes from a secondary device, +- a developer from another project may want to make some quick changes (especially common for Open Source projects). + +In all these cases, going through the entire repository setup process is a waste of time when compared to the contribution. +This often feels discouraging for contributors, especially when they try anyway and get stuck on version conflicts of some system dependency. + +To avoid this issue, the Playground is compatible with multiple ways of opening the project without having to go through the project configuration. + +### Gitpod + +[Gitpod](https://gitpod.io/) is a cloud-based development platform. It allows to open a branch of the repository and execute it directly from the browser. It is especially convenient for projects with a web-based frontend, or projects with no UI (e.g. libraries). Gitpod cannot run native GUI apps. + +Gitpod is configured in the [.gitpod.yaml](../../.gitpod.yml) file. + +Useful links: +- [Link your GitLab account](https://docs.gitlab.com/ee/integration/gitpod.html) +- [Develop using JetBrains IDEs](https://www.gitpod.io/docs/integrations/jetbrains-gateway) +- [SSH access](https://www.gitpod.io/docs/references/ides-and-editors/command-line) + +### Dev containers + +[Dev containers](https://containers.dev/) is a standard for containerizing the development environment, created by Microsoft. [GitHub Codespaces](https://github.com/features/codespaces) uses them to run a project in the cloud, and IDEs can use them to locally start a containerized development environment, so you don't have to install anything. + +Because it is possible to start projects locally in a container, and not just in the cloud, dev containers can be used as a daily driver on a project to entirely avoid configuring the environment. The specification is also more complete, allowing to start services using docker-compose, etc (though support by IDE varies). + +Dev containers are configured in the [.devcontainer](../../.devcontainer) directory. + +Useful links: +- [Develop using VS Code](https://code.visualstudio.com/docs/devcontainers/containers) +- [Develop using JetBrains IDEs](https://www.jetbrains.com/help/idea/connect-to-devcontainer.html) +- [Open in the cloud with GitHub Codespace](https://github.com/features/codespaces) +- [Open in the cloud with JetBrains Space](https://www.jetbrains.com/help/space/develop-in-a-dev-environment.html) -- 2.51.2 From 90bf01f686842eef6c2412c34175a5a9a3d1e727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sun, 3 Sep 2023 16:06:30 +0200 Subject: [PATCH 14/47] ci(gitlab): Document the usage of the different CI stages --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index abb3193..8ee1838 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,8 @@ stages: - - docker - - build - - test - - deploy + - docker # create images that are needed by the rest of the build + - build # create any outputs of the project (binaries, containers, charts…) + - test # all quality checks + - deploy # export the outputs (publish to an artifact registry, deploy on a server…) include: - remote: https://gitlab.com/opensavvy/ci-templates/-/raw/main/version.gitlab-ci.yml -- 2.51.2 From e8acab64236a0bae67e5135c19ea9b98eb37d508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Tue, 5 Sep 2023 21:53:12 +0200 Subject: [PATCH 15/47] build(idea): Continue executing tests even if the firsts failed --- .idea/runConfigurations/Check.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/runConfigurations/Check.xml b/.idea/runConfigurations/Check.xml index f1d654e..3b214a8 100644 --- a/.idea/runConfigurations/Check.xml +++ b/.idea/runConfigurations/Check.xml @@ -4,7 +4,7 @@ -- 2.51.2 From eeb5925bd91bac8d8c0bfc67a70dbe3850588c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Mon, 11 Sep 2023 22:47:22 +0200 Subject: [PATCH 16/47] upgrade: Gradle 8.3 --- gradle/wrapper/gradle-wrapper.jar | Bin 62076 -> 63375 bytes gradle/wrapper/gradle-wrapper.properties | 3 ++- gradlew | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c1962a79e29d3e0ab67b14947c167a862655af9b..033e24c4cdf41af1ab109bc7f253b2b887023340 100644 GIT binary patch delta 16170 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/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -- 2.51.2 From 0a907d12c604fc8936df4c060cc2bf8cd9c7387f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Mon, 11 Sep 2023 22:48:05 +0200 Subject: [PATCH 17/47] upgrade: Kotlin 1.9.10 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fff259c..5a1c3e5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -kotlin = "1.9.0" +kotlin = "1.9.10" [plugins] kotlin = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } -- 2.51.2 From 590a5af61eeb68afa46b04b65fbdb40d38456dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Mon, 11 Sep 2023 22:52:10 +0200 Subject: [PATCH 18/47] ci(gitlab): Extract the signing key for Maven Central --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b16e5d1..1385a46 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,6 +59,8 @@ publish-maven:central: stage: deploy script: + - export SIGNING_KEY_RING=$(mktemp) + - <"$SIGNING_KEY_RING_B64" base64 -d >"$SIGNING_KEY_RING" - > ./gradlew publishAllPublicationsToCentralRepository -PappVersion=$project_version -- 2.51.2 From bc49991411c5bf8158d2d2e79ad7e12bf7cd7bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Mon, 18 Sep 2023 21:04:46 +0200 Subject: [PATCH 19/47] docs: Add a contributing guide which lists issue labels --- CONTRIBUTING.md | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 7 ++--- 2 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0b5fe06 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,77 @@ +# Contributing to this project + +Thanks for wanting to contribute to the project! + +There are many things we appreciate help with. The simplest is to report problems you see in the documentation or while using the project, by creating an issue. + +If you have a specific change you'd like to submit, be it documentation, bug fixes or new features, please read our guide on [how to create merge requests following our conventions](https://gitlab.com/opensavvy/wiki/-/blob/main/README.md#wiki). + +> Before starting making large changes, please do talk about it with us! Some things, in particular, deploying to new platforms requires changes on our side as well. + +## Issue tracking + +If you want to contribute, but do not know what to improve, we recommend going through to existing issues. +We assign labels to issues to make them easier to find. + +If you're reading this page in GitLab, the labels should appear in color and be clickable. +If you're reading this on another tool, you can search by label in the issue list. + +**Labels common to all OpenSavvy projects** + +
+Issue type + +- ~feature: High-level feature/use-case description (implementation is split into multiple sub-issues). +- ~discussion: More discussion is required before classification or implementation can be started. +- ~deployment: Issues related to deployment, CI/CD or other kinds of automation. +- ~documentation: Documentation improvements or problems. +- ~bug: Something does not behave as expected. +- ~security: Security risk to users of the project. +- ~incident: Deployment issue (the website is down…). +- ~wontfix: We decided that this issue is out of scope for the project, or cannot be done. +- ~blocked-externally: We cannot go further on this topic, because some external service/library we depend on has a bug/is missing a feature. + +
+
+Contribution difficulty + +These labels are indicators of how hard we think it is to implement them for an external contributor. +We do not always label issues by contribution difficulty. If you are interested in an issue that isn't labelled, don't hesitate to write a comment communicating your interest and asking for precision. + +- ~contribution::easy: Issues that are well explained and require little project knowledge. +- ~contribution::medium: Issues that are well explained, but require some project knowledge. +- ~contribution::difficult: Issues that are well explained, but require a strong understanding of the project. + +
+
+Priority + +- ~priority::low: Implementation is not time-sensitive. +- ~priority::medium: Normal priority. +- ~priority::high: We want to do this soon. +- ~priority::urgent: We want to do this as soon as possible. + +
+
+Severity (only for bugs and incidents) + +- ~severity::cosmetic: Some parts of the project do not look as good as they could, or there is a minor error in documentation. Usage is not impacted. +- ~severity::minor: Some parts of the project are inconvenient to use. +- ~severity::moderate: Some parts of the project cannot be used. +- ~severity::major: Some important parts of the project cannot be used. +- ~severity::critical: The entire project cannot be used. + +
+
+Development state (issues only) + +We do not always use these labels. When in doubt, write a comment asking for precision. +These labels should only be applied to issues, not merge requests. + +- ~issue::doing: Someone is currently working on it. +- ~issue::review: A merge request exists that will close this issue, and it's entered the review cycle. + +
+ + + diff --git a/README.md b/README.md index c76a567..cde119c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ This a template to easily bootstrap your projects. ## Contributing -This project follows the OpenSavvy workflow and code conventions. -To learn how to contribute, please read [our wiki](https://gitlab.com/opensavvy/wiki/-/blob/main/README.md). - -This project also uses the [OpenSavvy Playground](docs/playground/README.md). +See [CONTRIBUTING.md](CONTRIBUTING.md). +- To learn more about our coding conventions and workflow, see the [OpenSavvy Wiki](https://gitlab.com/opensavvy/wiki/-/blob/main/README.md#wiki). +- This project is based on the [OpenSavvy Playground](docs/playground/README.md), a collection of preconfigured project templates. -- 2.51.2 From ea906743d78bdcc16c7a2e0028597bc87f3a5f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Thu, 21 Sep 2023 22:26:28 +0200 Subject: [PATCH 20/47] build(conventions): Always configure the Central repository --- .../conventions/library/src/main/kotlin/library.gradle.kts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts index e5c2817..e194019 100644 --- a/gradle/conventions/library/src/main/kotlin/library.gradle.kts +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -84,15 +84,12 @@ val fakeJavadocJar by tasks.registering(Jar::class) { publishing { repositories { - val centralUsername = System.getenv("OSSRH_USERNAME") ?: return@repositories - val centralPassword = System.getenv("OSSRH_PASSWORD") ?: return@repositories - maven { name = "Central" url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") credentials { - username = centralUsername - password = centralPassword + username = System.getenv("OSSRH_USERNAME") + password = System.getenv("OSSRH_PASSWORD") } } } -- 2.51.2 From fe8ae686b0aa787197069ff999604a54feb57b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Thu, 21 Sep 2023 22:27:43 +0200 Subject: [PATCH 21/47] build(conventions): Workaround for the multi-signing confusion --- .../conventions/library/src/main/kotlin/library.gradle.kts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts index e194019..3c549e5 100644 --- a/gradle/conventions/library/src/main/kotlin/library.gradle.kts +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -112,6 +112,12 @@ run { ext["signing.password"] = System.getenv("SIGNING_PASSWORD") ?: return@run ext["signing.secretKeyRingFile"] = System.getenv("SIGNING_KEY_RING") ?: return@run + // Workaround for https://youtrack.jetbrains.com/issue/KT-61858 + val signingTasks = tasks.withType(Sign::class) + tasks.withType(AbstractPublishToMaven::class).configureEach { + dependsOn(signingTasks) + } + signing { sign(publishing.publications) } -- 2.51.2 From 7e715b04a623916c214dc7c3463a8984e6c0b8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 23 Sep 2023 20:35:06 +0200 Subject: [PATCH 22/47] docs: Explain how to create your own project based on the Playground --- docs/playground/README.md | 4 ++- docs/playground/setup.md | 64 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 docs/playground/setup.md diff --git a/docs/playground/README.md b/docs/playground/README.md index 7ccfdaf..eebfaba 100644 --- a/docs/playground/README.md +++ b/docs/playground/README.md @@ -1,12 +1,14 @@ # OpenSavvy Playground The Playground is a collection of repositories which act as both demonstrators of what we consider "good practice", and as templates to bootstrap projects. -Unlike other template projects, the Playground is meant to be updated continuously so each project which started using it profits from its updates. +Unlike other template projects, the Playground is continuously updated, and is able to create merge requests updating itself automatically. This way, we can ensure our projects follow a familiar structure. You're reading this document either because you're reading one of the projects of the Playground, or because you're reading one of the projects which is based on the Playground. We encourage keeping this documentation as part of projects using the Playground, so it is always available to understand how the project is structured. We do not recommend editing it in projects; instead, contribute to the Playground directly, so all projects get updated. +To create a project based on the Playground, [read this](setup.md). + Each Playground adds its own page to the following list: - [Baseline](baseline.md) diff --git a/docs/playground/setup.md b/docs/playground/setup.md new file mode 100644 index 0000000..bcadb96 --- /dev/null +++ b/docs/playground/setup.md @@ -0,0 +1,64 @@ +# Creating a project based on the Playground + +In its simplest form, basing a project on the Playground is as simple as copying it. +If you want to have it auto-update, however, there is a bit more configuration needed. + +## Creating a project based on the Playground + +First, find the repository of the Playground you want to base your project on. +First-party playgrounds are provided in the [OpenSavvy GitLab group](https://gitlab.com/opensavvy/playgrounds). + +On the top-right of the project page, find the fork button (you may need to log in before it appears). +Use it to create your own project in your own namespace—that's it! + +## Basing an existing on the Playground + +Open a terminal in the existing project, and execute the following commands: +```shell +git remote add playground CLONE_URL_OF_THE_PLAYGROUND_YOU_WANT_TO_USE + +# The Playground will be merged into the current branch +# (use 'git switch' to use another branch) +git pull playground main +# If needed, fix conflicts etc. +``` + +That's it, this branch now uses the Playground. + +## Configuring the Playground to auto-update + +This section assumes you are using GitLab. +You can certainly adapt our configuration for any other CI provider, but it is left as an exercise. + +The Playground auto-updates by running a CI pipeline in which it pulls itself, then creating a merge request with the updated repository. +Because the merge request goes through CI, the repository will not be modified if there is any conflict or if the update breaks your CI. +If that happens, you can look through the created branch and fix it. + +To do this, it needs: +- An SSH key authorized to push to the repository +- CI variables to tell it which Playground to pull +- A configured scheduled pipeline, which decides when it runs + +First, create an SSH key: +```shell +ssh-keygen +``` +When prompted to select a path, put it somewhere in which you won't confuse it with your own, e.g. `/tmp/id_rsa`. +After this configuration phase is over, you will not need it again, so there is no need to store it. + +In your project's settings, go to Settings → Repository → Deploy keys. +Create a new key, name it however you want, and copy the contents of the public key (`/tmp/id_rsa.pub` if you used the same path as us) into the "Key" field. Tick "Grant write permissions to this key". + +Now, still in your project's settings, go to Settings → CI/CD → Variables. +Create the following variables: +- `playground_parent` (type: variable): Clone URL of the playground you want to base yourself on +- `playground_parent_name` (type: variable): Name of the playground you are basing yourself on (will appear in the Git message) +- `playground_mirroring_key_public` (type: file, protected): Contents of the public key (`/tmp/id_rsa.pub` if you used the same path as us) +- `playground_mirroring_key` (type: file, protected): Contents of the private key (`/tmp/id_rsa` if you used the same path as us) + +The mirroring job is now fully configured. However, it still needs to be triggered. +In the project sidebar, go to Build → Pipeline schedules. +Create a new schedule, select how often it runs. +We recommend once a week, but you can choose any frequency you want. + +That's it, the Playground will now automatically update itself. -- 2.51.2 From d00d9aaf456054ae465e7fe2a648dcb53f81b8ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sun, 24 Sep 2023 21:09:20 +0200 Subject: [PATCH 23/47] ci(gitlab): Simplify the publishing pipeline --- .gitlab-ci.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1385a46..c9ef5f9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,10 +46,8 @@ publish-maven:gitlab: interruptible: false rules: - - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $PUBLISH_MAVEN == "no" || $PUBLISH_MAVEN_GITLAB == "no" when: never - - if: $PUBLISH_MAVEN == "manual" || $PUBLISH_MAVEN_GITLAB == "manual" - when: manual - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_TAG @@ -67,12 +65,10 @@ publish-maven:central: interruptible: false rules: - - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - when: never - if: $OSSRH_USERNAME == null || $OSSRH_PASSWORD == null when: never - - if: $PUBLISH_MAVEN == "manual" || $PUBLISH_MAVEN_CENTRAL == "manual" - when: manual + - if: $PUBLISH_MAVEN == "no" || $PUBLISH_MAVEN_CENTRAL == "no" + when: never - if: $CI_COMMIT_TAG # endregion -- 2.51.2 From ebabee578cdc90d3cbd26fef11df2de0523f774a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sun, 24 Sep 2023 21:46:53 +0200 Subject: [PATCH 24/47] build: Use the Gradle Nexus Publish plugin to fix Central staging repository splitting --- .gitlab-ci.yml | 41 ++++++++++++++++++- build.gradle.kts | 3 ++ .../src/main/kotlin/library.gradle.kts | 11 ----- gradle/conventions/root/build.gradle.kts | 9 ++++ .../root/src/main/kotlin/root.gradle.kts | 17 ++++++++ gradle/conventions/settings.gradle.kts | 1 + gradle/libs.versions.toml | 1 + 7 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 gradle/conventions/root/build.gradle.kts create mode 100644 gradle/conventions/root/src/main/kotlin/root.gradle.kts diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c9ef5f9..c5508b2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -51,16 +51,53 @@ publish-maven:gitlab: - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_TAG +publish-maven:central:initialize: + extends: [ .os.gradle ] + needs: [ os.version ] + stage: deploy + + script: + - > + ./gradlew initializeSonatypeStagingRepository + -PappVersion=$project_version + + interruptible: false + rules: + - if: $OSSRH_USERNAME == null || $OSSRH_PASSWORD == null + when: never + - if: $PUBLISH_MAVEN == "no" || $PUBLISH_MAVEN_CENTRAL == "no" + when: never + - if: $CI_COMMIT_TAG + publish-maven:central: extends: [ .os.gradle ] - needs: [ os.version, check ] + needs: [ os.version, publish-maven:central:initialize ] stage: deploy script: - export SIGNING_KEY_RING=$(mktemp) - <"$SIGNING_KEY_RING_B64" base64 -d >"$SIGNING_KEY_RING" - > - ./gradlew publishAllPublicationsToCentralRepository + ./gradlew findSonatypeStagingRepository publishToSonatype + -x initializeSonatypeStagingRepository + -PappVersion=$project_version + + interruptible: false + rules: + - if: $OSSRH_USERNAME == null || $OSSRH_PASSWORD == null + when: never + - if: $PUBLISH_MAVEN == "no" || $PUBLISH_MAVEN_CENTRAL == "no" + when: never + - if: $CI_COMMIT_TAG + +publish-maven:central:close: + extends: [ .os.gradle ] + needs: [ os.version, publish-maven:central ] + stage: deploy + + script: + - > + ./gradlew findSonatypeStagingRepository closeSonatypeStagingRepository -PappVersion=$project_version interruptible: false diff --git a/build.gradle.kts b/build.gradle.kts index 9bec650..67bd65f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,6 +8,9 @@ */ plugins { + id("conventions.base") + id("conventions.root") + // Some plugins *must* be configured on the root project. // In these cases, we explicitly tell Gradle not to apply them. alias(libs.plugins.kotlin) apply false diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts index 3c549e5..0ac7f68 100644 --- a/gradle/conventions/library/src/main/kotlin/library.gradle.kts +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -83,17 +83,6 @@ val fakeJavadocJar by tasks.registering(Jar::class) { } publishing { - repositories { - maven { - name = "Central" - url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") - credentials { - username = System.getenv("OSSRH_USERNAME") - password = System.getenv("OSSRH_PASSWORD") - } - } - } - publications.withType { artifact(fakeJavadocJar.get()) diff --git a/gradle/conventions/root/build.gradle.kts b/gradle/conventions/root/build.gradle.kts new file mode 100644 index 0000000..555f094 --- /dev/null +++ b/gradle/conventions/root/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + `kotlin-dsl` +} + +group = "conventions" + +dependencies { + implementation(libs.gradle.nexusPublish) +} diff --git a/gradle/conventions/root/src/main/kotlin/root.gradle.kts b/gradle/conventions/root/src/main/kotlin/root.gradle.kts new file mode 100644 index 0000000..2352c59 --- /dev/null +++ b/gradle/conventions/root/src/main/kotlin/root.gradle.kts @@ -0,0 +1,17 @@ +package conventions + +plugins { + id("io.github.gradle-nexus.publish-plugin") +} + +nexusPublishing { + repositories { + sonatype { + nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) + snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) + + username.set(System.getenv("OSSRH_USERNAME")) + password.set(System.getenv("OSSRH_PASSWORD")) + } + } +} diff --git a/gradle/conventions/settings.gradle.kts b/gradle/conventions/settings.gradle.kts index d143d50..71aee0e 100644 --- a/gradle/conventions/settings.gradle.kts +++ b/gradle/conventions/settings.gradle.kts @@ -15,6 +15,7 @@ dependencyResolutionManagement { include( "base", + "root", "kotlin", "library", ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5a1c3e5..157d43b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,3 +9,4 @@ kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = # To use existing plugins in convention plugins, we must also declare them as libraries gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +gradle-nexusPublish = { module = "io.github.gradle-nexus:publish-plugin", version = "1.3.0" } -- 2.51.2 From 2ddcbe46c4b5c3a269796ead235410938ba21a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sun, 24 Sep 2023 22:04:50 +0200 Subject: [PATCH 25/47] build: Rename the Gradle group to align it with our MavenCentral credentials --- gradle/conventions/base/src/main/kotlin/base.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/conventions/base/src/main/kotlin/base.gradle.kts b/gradle/conventions/base/src/main/kotlin/base.gradle.kts index 3ca9d87..41cb074 100644 --- a/gradle/conventions/base/src/main/kotlin/base.gradle.kts +++ b/gradle/conventions/base/src/main/kotlin/base.gradle.kts @@ -6,5 +6,5 @@ plugins { val appVersion: String? by project -group = "opensavvy.playground" +group = "dev.opensavvy.playground" version = appVersion ?: "0.0.0-DEV" -- 2.51.2 From 1dd6edbe00fff54ad025826282bab0324fb79b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sun, 24 Sep 2023 22:05:21 +0200 Subject: [PATCH 26/47] build: Crash if someone forgot to change the group when importing the project --- gradle/conventions/base/src/main/kotlin/base.gradle.kts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gradle/conventions/base/src/main/kotlin/base.gradle.kts b/gradle/conventions/base/src/main/kotlin/base.gradle.kts index 41cb074..013cb0f 100644 --- a/gradle/conventions/base/src/main/kotlin/base.gradle.kts +++ b/gradle/conventions/base/src/main/kotlin/base.gradle.kts @@ -8,3 +8,12 @@ val appVersion: String? by project group = "dev.opensavvy.playground" version = appVersion ?: "0.0.0-DEV" + +// region Check the users of the project didn't forget to rename the group + +val projectPath: String? = System.getenv("CI_PROJECT_PATH") +if (projectPath != null && projectPath != "opensavvy/playgrounds/gradle" && group == "dev.opensavvy.playground") { + error("The project is declared to be in the group '$group', which is recognized as the Gradle Playground, but it's hosted in '$projectPath', which is not the Playground. Maybe you forgot to rename the group when importing the Playground in your own project?") +} + +// endregion -- 2.51.2 From e9d5b15937f98bfba4029400d0d278038606ac6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sun, 24 Sep 2023 22:16:10 +0200 Subject: [PATCH 27/47] build: Disable the configuration cache for publishing jobs --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c5508b2..f5ae7d5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,6 +42,7 @@ publish-maven:gitlab: script: - > ./gradlew publishAllPublicationsToGitLabRepository + --no-configuration-cache -PappVersion=$project_version interruptible: false @@ -59,6 +60,7 @@ publish-maven:central:initialize: script: - > ./gradlew initializeSonatypeStagingRepository + --no-configuration-cache -PappVersion=$project_version interruptible: false @@ -80,6 +82,7 @@ publish-maven:central: - > ./gradlew findSonatypeStagingRepository publishToSonatype -x initializeSonatypeStagingRepository + --no-configuration-cache -PappVersion=$project_version interruptible: false @@ -98,6 +101,7 @@ publish-maven:central:close: script: - > ./gradlew findSonatypeStagingRepository closeSonatypeStagingRepository + --no-configuration-cache -PappVersion=$project_version interruptible: false -- 2.51.2 From a8a4773b8343d7ae2905b000a0808ab13012d4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 27 Sep 2023 22:05:39 +0200 Subject: [PATCH 28/47] build(gradle): Configure the 'core' project with the necessary metadata for Central --- core/build.gradle.kts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index d847522..42ac38d 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -7,3 +7,9 @@ plugins { kotlin { jvm() } + +library { + name.set("Playground Core") + description.set("Project template with configured MavenCentral publication") + homeUrl.set("https://gitlab.com/opensavvy/playgrounds/gradle") +} -- 2.51.2 From aa26022beb320cfe25b5b1c9e3dc6890c981a7fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 27 Sep 2023 22:06:04 +0200 Subject: [PATCH 29/47] build(gradle): Automatically set the Central SCM URL from the GitLab predefined variables --- gradle/conventions/library/src/main/kotlin/library.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts index 0ac7f68..1986fdb 100644 --- a/gradle/conventions/library/src/main/kotlin/library.gradle.kts +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -29,7 +29,7 @@ fun MavenPom.buildConfiguration() { } scm { - url.set("https://gitlab.com/opensavvy/playgrounds/gradle") + url.set(System.getenv("CI_PROJECT_URL")) } } -- 2.51.2 From f049d7807e05653206b0b0c0dabc5b4ec06e1ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 27 Sep 2023 22:11:51 +0200 Subject: [PATCH 30/47] build(gradle): More precise description to avoid duplications --- gradle/conventions/root/src/main/kotlin/root.gradle.kts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gradle/conventions/root/src/main/kotlin/root.gradle.kts b/gradle/conventions/root/src/main/kotlin/root.gradle.kts index 2352c59..abf742d 100644 --- a/gradle/conventions/root/src/main/kotlin/root.gradle.kts +++ b/gradle/conventions/root/src/main/kotlin/root.gradle.kts @@ -5,6 +5,11 @@ plugins { } nexusPublishing { + val projectPath = System.getenv("CI_PROJECT_PATH_SLUG") + val refSlug = System.getenv("CI_COMMIT_REF_SLUG") + val pipelineId = System.getenv("CI_PIPELINE_IID") + repositoryDescription.set("$projectPath for $refSlug (pipeline $pipelineId)") // must be globally unique for a pipeline to avoid issues with concurrent builds + repositories { sonatype { nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) -- 2.51.2 From ed5e77435082f5b6a282689b03b93d49ec014025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 7 Oct 2023 14:53:09 +0200 Subject: [PATCH 31/47] build(gradle): Add a delimitation to the Playground parts of the version catalog, to avoid conflicts --- gradle/libs.versions.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 157d43b..2e5eaf7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,20 @@ [versions] +# region Playground kotlin = "1.9.10" +# endregion [plugins] +# region Playground kotlin = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } +# endregion [libraries] +# region Playground kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } +# endregion # To use existing plugins in convention plugins, we must also declare them as libraries +# region Playground gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } gradle-nexusPublish = { module = "io.github.gradle-nexus:publish-plugin", version = "1.3.0" } +# endregion -- 2.51.2 From 00f537afd4973f78b73f4d79ce798958d12d3c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 7 Oct 2023 15:13:11 +0200 Subject: [PATCH 32/47] build(gradle): Add the Dokkatoo plugin --- .idea/runConfigurations/Documentation.xml | 24 +++++++++++++++++++ build.gradle.kts | 14 +++++++++++ gradle/conventions/library/build.gradle.kts | 4 ++++ .../src/main/kotlin/library.gradle.kts | 6 ++--- .../root/src/main/kotlin/root.gradle.kts | 4 ++++ gradle/libs.versions.toml | 3 +++ 6 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 .idea/runConfigurations/Documentation.xml diff --git a/.idea/runConfigurations/Documentation.xml b/.idea/runConfigurations/Documentation.xml new file mode 100644 index 0000000..862dd23 --- /dev/null +++ b/.idea/runConfigurations/Documentation.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 67bd65f..7817fb9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,4 +14,18 @@ plugins { // Some plugins *must* be configured on the root project. // In these cases, we explicitly tell Gradle not to apply them. alias(libs.plugins.kotlin) apply false + + alias(libs.plugins.dokkatoo) +} + +dependencies { + // List the 'library' projects + dokkatoo(projects.core) + + // This is required at the moment, see https://github.com/adamko-dev/dokkatoo/issues/14 + dokkatooPluginHtml( + dokkatoo.versions.jetbrainsDokka.map { dokkaVersion -> + "org.jetbrains.dokka:all-modules-page-plugin:$dokkaVersion" + } + ) } diff --git a/gradle/conventions/library/build.gradle.kts b/gradle/conventions/library/build.gradle.kts index b9d90a2..79a12bd 100644 --- a/gradle/conventions/library/build.gradle.kts +++ b/gradle/conventions/library/build.gradle.kts @@ -3,3 +3,7 @@ plugins { } group = "conventions" + +dependencies { + implementation(libs.gradle.dokkatoo) +} diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts index 1986fdb..bbef86c 100644 --- a/gradle/conventions/library/src/main/kotlin/library.gradle.kts +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -1,12 +1,10 @@ package conventions -import gradle.kotlin.dsl.accessors._b6bea14fb88fd11e46d6fb1ebe601eab.ext -import gradle.kotlin.dsl.accessors._b6bea14fb88fd11e46d6fb1ebe601eab.publishing -import gradle.kotlin.dsl.accessors._b6bea14fb88fd11e46d6fb1ebe601eab.signing - plugins { id("maven-publish") id("signing") + + id("dev.adamko.dokkatoo-html") } // Global configuration for the repository diff --git a/gradle/conventions/root/src/main/kotlin/root.gradle.kts b/gradle/conventions/root/src/main/kotlin/root.gradle.kts index abf742d..d7d7d62 100644 --- a/gradle/conventions/root/src/main/kotlin/root.gradle.kts +++ b/gradle/conventions/root/src/main/kotlin/root.gradle.kts @@ -20,3 +20,7 @@ nexusPublishing { } } } + +repositories { + mavenCentral() +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2e5eaf7..efdadec 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,11 +1,13 @@ [versions] # region Playground kotlin = "1.9.10" +dokkatoo = "2.0.0" # endregion [plugins] # region Playground kotlin = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } +dokkatoo = { id = "dev.adamko.dokkatoo-html", version.ref = "dokkatoo" } # endregion [libraries] @@ -17,4 +19,5 @@ kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = # region Playground gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } gradle-nexusPublish = { module = "io.github.gradle-nexus:publish-plugin", version = "1.3.0" } +gradle-dokkatoo = { module = "dev.adamko.dokkatoo:dokkatoo-plugin", version.ref = "dokkatoo" } # endregion -- 2.51.2 From d407b3a1b68a8faae7cb63e889c91fd05d497855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 7 Oct 2023 15:39:33 +0200 Subject: [PATCH 33/47] build(gradle): Use each module's README as documentation frontpage --- core/README.md | 3 +++ .../src/main/kotlin/library.gradle.kts | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 core/README.md diff --git a/core/README.md b/core/README.md new file mode 100644 index 0000000..fa42f70 --- /dev/null +++ b/core/README.md @@ -0,0 +1,3 @@ +# Module Playground Core + +Example library configuration. diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts index bbef86c..9437e12 100644 --- a/gradle/conventions/library/src/main/kotlin/library.gradle.kts +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -111,3 +111,28 @@ run { } //endregion +// region Documentation + +dokkatoo { + moduleName.set(config.name) + + dokkatooSourceSets.configureEach { + // region Include the correct HTML file, if it exists + if (name.endsWith("Main")) { + val setName = name.removeSuffix("Main") + + val headerName = + if (setName == "common") "README.md" + else "README.$setName.md" + + val headerPath = "${project.projectDir}/$headerName" + if (File(headerPath).exists()) + includes.from(headerPath) + else + logger.info("No specific documentation file found for $setName, expected to find $headerPath") + } + // endregion + } +} + +// endregion -- 2.51.2 From fb403d481e7e70a7fe7a24f806ca5e16c312c5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 7 Oct 2023 15:44:57 +0200 Subject: [PATCH 34/47] build(gradle): Link the documentation with our dependencies --- .../library/src/main/kotlin/library.gradle.kts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts index 9437e12..1cb0cfa 100644 --- a/gradle/conventions/library/src/main/kotlin/library.gradle.kts +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -1,5 +1,7 @@ package conventions +import java.net.URI + plugins { id("maven-publish") id("signing") @@ -132,6 +134,18 @@ dokkatoo { logger.info("No specific documentation file found for $setName, expected to find $headerPath") } // endregion + // region Dependencies + + fun dependencyDocumentation(name: String, url: String) = externalDocumentationLinks.register(name) { + this.url.set(URI(url)) + } + + dependencyDocumentation("KotlinX.Coroutines", "https://kotlinlang.org/api/kotlinx.coroutines/") + dependencyDocumentation("KotlinX.Serialization", "https://kotlinlang.org/api/kotlinx.serialization/") + dependencyDocumentation("Ktor", "https://api.ktor.io/") + dependencyDocumentation("Arrow", "https://apidocs.arrow-kt.io") + + // endregion } } -- 2.51.2 From 277374bbef85c34a6dc6b01ae86659145b7219b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 7 Oct 2023 15:52:12 +0200 Subject: [PATCH 35/47] build(gradle): Add links to the source code --- .../library/src/main/kotlin/library.gradle.kts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts index 1cb0cfa..775e5be 100644 --- a/gradle/conventions/library/src/main/kotlin/library.gradle.kts +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -145,6 +145,22 @@ dokkatoo { dependencyDocumentation("Ktor", "https://api.ktor.io/") dependencyDocumentation("Arrow", "https://apidocs.arrow-kt.io") + // endregion + // region Link to the sources + + val projectUrl = System.getenv("CI_PROJECT_URL") + val commit = System.getenv("CI_COMMIT_SHA") ?: "main" + + if (projectUrl != null) { + sourceLink { + val path = projectDir.relativeTo(rootProject.projectDir) + + localDirectory.set(file("src")) + remoteUrl.set(URI("$projectUrl/-/blob/$commit/$path/src")) + remoteLineSuffix.set("#L") + } + } + // endregion } } -- 2.51.2 From dec0a578427127b402f4c691bf359525d44fbbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 7 Oct 2023 16:00:12 +0200 Subject: [PATCH 36/47] ci(gitlab): Generate the Dokka documentation --- .gitlab-ci.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f5ae7d5..bf3b2ef 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -112,6 +112,21 @@ publish-maven:central:close: when: never - if: $CI_COMMIT_TAG +# endregion +# region API documentation + +dokka: + extends: [ .os.gradle ] + stage: build + needs: [ os.version ] + + script: + - > + ./gradlew :dokkatooGeneratePublicationHtml + -PappVersion=$project_version + + interruptible: true + # endregion # region Automatically mirror the previous layer of the playground -- 2.51.2 From c5f722122090ea788ddd757acaf32046c2597146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 7 Oct 2023 16:00:23 +0200 Subject: [PATCH 37/47] ci(gitlab): Expose the documentation as a review app --- .gitlab-ci.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bf3b2ef..e95bad0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -125,6 +125,22 @@ dokka: ./gradlew :dokkatooGeneratePublicationHtml -PappVersion=$project_version + after_script: + - mkdir -p api-docs + - mv build/dokka/html/* api-docs + - PREFIX="$CI_PROJECT_ROOT_NAMESPACE/" + - echo "URL=https://$CI_PROJECT_ROOT_NAMESPACE.$CI_PAGES_DOMAIN/-/${CI_PROJECT_PATH//$PREFIX}/-/jobs/$CI_JOB_ID/artifacts/api-docs/index.html" >>deploy.env + + artifacts: + paths: + - api-docs + reports: + dotenv: deploy.env + environment: + name: review/$CI_COMMIT_REF_SLUG/api-docs + url: $URL + deployment_tier: development + interruptible: true # endregion -- 2.51.2 From 28db230976ceab03938efcc7cccdf98d7d81c38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 7 Oct 2023 16:14:05 +0200 Subject: [PATCH 38/47] ci(gitlab): Publish the documentation to GitLab Pages --- .gitlab-ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e95bad0..2e1f484 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -167,3 +167,25 @@ mirror-playground: allow_failure: true # endregion +# GitLab Pages + +pages: + image: alpine:latest + stage: deploy + needs: + - job: dokka + artifacts: true + + script: + - mkdir -p public + - mv api-docs public + + artifacts: + paths: + - public + + rules: + - if: $CI_COMMIT_TAG + interruptible: false + +# endregion -- 2.51.2 From f4e40d44250347f9f10eb7475c5ae38bb4be73b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Mon, 9 Oct 2023 21:28:26 +0200 Subject: [PATCH 39/47] build(gradle): Move the libs declared in the Playground to their own version catalog to avoid conflicts --- app/build.gradle.kts | 2 +- build.gradle.kts | 4 ++-- gradle/conventions/kotlin/build.gradle.kts | 2 +- gradle/conventions/library/build.gradle.kts | 2 +- gradle/conventions/root/build.gradle.kts | 2 +- gradle/conventions/settings.gradle.kts | 4 ++++ gradle/libs.versions.toml | 21 ++++----------------- gradle/playground.versions.toml | 19 +++++++++++++++++++ settings.gradle.kts | 8 ++++++++ 9 files changed, 41 insertions(+), 23 deletions(-) create mode 100644 gradle/playground.versions.toml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f446ed5..7d78709 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -19,7 +19,7 @@ kotlin { val commonTest by sourceSets.getting { dependencies { - implementation(libs.kotlin.test) + implementation(playgroundLibs.kotlin.test) } } } diff --git a/build.gradle.kts b/build.gradle.kts index 7817fb9..4b75465 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,9 +13,9 @@ plugins { // Some plugins *must* be configured on the root project. // In these cases, we explicitly tell Gradle not to apply them. - alias(libs.plugins.kotlin) apply false + alias(playgroundLibs.plugins.kotlin) apply false - alias(libs.plugins.dokkatoo) + alias(playgroundLibs.plugins.dokkatoo) } dependencies { diff --git a/gradle/conventions/kotlin/build.gradle.kts b/gradle/conventions/kotlin/build.gradle.kts index 545975e..786b140 100644 --- a/gradle/conventions/kotlin/build.gradle.kts +++ b/gradle/conventions/kotlin/build.gradle.kts @@ -5,5 +5,5 @@ plugins { group = "conventions" dependencies { - implementation(libs.gradle.kotlin) + implementation(playgroundLibs.gradle.kotlin) } diff --git a/gradle/conventions/library/build.gradle.kts b/gradle/conventions/library/build.gradle.kts index 79a12bd..dab59c0 100644 --- a/gradle/conventions/library/build.gradle.kts +++ b/gradle/conventions/library/build.gradle.kts @@ -5,5 +5,5 @@ plugins { group = "conventions" dependencies { - implementation(libs.gradle.dokkatoo) + implementation(playgroundLibs.gradle.dokkatoo) } diff --git a/gradle/conventions/root/build.gradle.kts b/gradle/conventions/root/build.gradle.kts index 555f094..1d430e7 100644 --- a/gradle/conventions/root/build.gradle.kts +++ b/gradle/conventions/root/build.gradle.kts @@ -5,5 +5,5 @@ plugins { group = "conventions" dependencies { - implementation(libs.gradle.nexusPublish) + implementation(playgroundLibs.gradle.nexusPublish) } diff --git a/gradle/conventions/settings.gradle.kts b/gradle/conventions/settings.gradle.kts index 71aee0e..2425369 100644 --- a/gradle/conventions/settings.gradle.kts +++ b/gradle/conventions/settings.gradle.kts @@ -10,6 +10,10 @@ dependencyResolutionManagement { create("libs") { from(files("../libs.versions.toml")) } + + create("playgroundLibs") { + from(files("../playground.versions.toml")) + } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index efdadec..6699f7a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,23 +1,10 @@ +# List of dependencies of the project +# Dependencies shared between all projects based on the Playground are declared in playground.versions.toml + [versions] -# region Playground -kotlin = "1.9.10" -dokkatoo = "2.0.0" -# endregion [plugins] -# region Playground -kotlin = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } -dokkatoo = { id = "dev.adamko.dokkatoo-html", version.ref = "dokkatoo" } -# endregion [libraries] -# region Playground -kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } -# endregion -# To use existing plugins in convention plugins, we must also declare them as libraries -# region Playground -gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } -gradle-nexusPublish = { module = "io.github.gradle-nexus:publish-plugin", version = "1.3.0" } -gradle-dokkatoo = { module = "dev.adamko.dokkatoo:dokkatoo-plugin", version.ref = "dokkatoo" } -# endregion +[bundles] diff --git a/gradle/playground.versions.toml b/gradle/playground.versions.toml new file mode 100644 index 0000000..d425d45 --- /dev/null +++ b/gradle/playground.versions.toml @@ -0,0 +1,19 @@ +# Library versions common between all projects based on the Playground +# This helps ensure all our projects are aligned + +[versions] +kotlin = "1.9.10" +dokkatoo = "2.0.0" + +[plugins] +kotlin = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } +dokkatoo = { id = "dev.adamko.dokkatoo-html", version.ref = "dokkatoo" } + +[libraries] +kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } + +gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +gradle-nexusPublish = { module = "io.github.gradle-nexus:publish-plugin", version = "1.3.0" } +gradle-dokkatoo = { module = "dev.adamko.dokkatoo:dokkatoo-plugin", version.ref = "dokkatoo" } + +[bundles] diff --git a/settings.gradle.kts b/settings.gradle.kts index 416788e..b6f38cb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,6 +18,14 @@ pluginManagement { includeBuild("gradle/conventions") } +dependencyResolutionManagement { + versionCatalogs { + create("playgroundLibs") { + from(files("gradle/playground.versions.toml")) + } + } +} + plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0" } -- 2.51.2 From aa9204ff73468319f1042ae64c11c3011de3527f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Mon, 9 Oct 2023 22:16:09 +0200 Subject: [PATCH 40/47] build(gradle): The dokka source set 'main' should use the README.md file It exists when only a single platform is defined. --- gradle/conventions/library/src/main/kotlin/library.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/conventions/library/src/main/kotlin/library.gradle.kts b/gradle/conventions/library/src/main/kotlin/library.gradle.kts index 775e5be..bc327f2 100644 --- a/gradle/conventions/library/src/main/kotlin/library.gradle.kts +++ b/gradle/conventions/library/src/main/kotlin/library.gradle.kts @@ -120,11 +120,11 @@ dokkatoo { dokkatooSourceSets.configureEach { // region Include the correct HTML file, if it exists - if (name.endsWith("Main")) { + if (name.endsWith("Main") || name == "main") { val setName = name.removeSuffix("Main") val headerName = - if (setName == "common") "README.md" + if (setName == "common" || name == "main") "README.md" else "README.$setName.md" val headerPath = "${project.projectDir}/$headerName" -- 2.51.2 From 06ad59e82b6b7aa20d9589c277eb31a5d16da08e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 14 Oct 2023 11:42:32 +0200 Subject: [PATCH 41/47] upgrade: Gradle 8.4 --- gradle/wrapper/gradle-wrapper.jar | Bin 63375 -> 63721 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4cdf41af1ab109bc7f253b2b887023340..7f93135c49b765f8051ef9d0a6055ff8e46073d8 100644 GIT binary patch delta 28216 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 za%0Aoo~v6{I8ONb#igvxd7=aVnxT2gnj@QKwvmG@`A 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 I?qd)S02EvtYybcN diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34..3fa8f86 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index fcb6fca..0adc8e1 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum -- 2.51.2 From d8ce814d825f278840705177208b73161f26bc5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 14 Oct 2023 11:46:35 +0200 Subject: [PATCH 42/47] build: Make upgrades easier by specifying the URL to find them --- gradle/playground.versions.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gradle/playground.versions.toml b/gradle/playground.versions.toml index d425d45..38a7a6e 100644 --- a/gradle/playground.versions.toml +++ b/gradle/playground.versions.toml @@ -2,9 +2,15 @@ # This helps ensure all our projects are aligned [versions] +# https://kotlinlang.org/docs/releases.html kotlin = "1.9.10" + +# https://github.com/adamko-dev/dokkatoo/releases dokkatoo = "2.0.0" +# https://github.com/gradle-nexus/publish-plugin/releases +nexus-publish = "1.3.0" + [plugins] kotlin = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } dokkatoo = { id = "dev.adamko.dokkatoo-html", version.ref = "dokkatoo" } @@ -13,7 +19,7 @@ dokkatoo = { id = "dev.adamko.dokkatoo-html", version.ref = "dokkatoo" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } -gradle-nexusPublish = { module = "io.github.gradle-nexus:publish-plugin", version = "1.3.0" } +gradle-nexusPublish = { module = "io.github.gradle-nexus:publish-plugin", version.ref = "nexus-publish" } gradle-dokkatoo = { module = "dev.adamko.dokkatoo:dokkatoo-plugin", version.ref = "dokkatoo" } [bundles] -- 2.51.2 From 28b621e499b5177372ce60cbe7d3d9886b90c162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 14 Oct 2023 11:53:06 +0200 Subject: [PATCH 43/47] build: Declare the KotlinX.Serialization plugin It needs to use the same version as Kotlin, so it cannot be declared in the default version catalog --- gradle/playground.versions.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gradle/playground.versions.toml b/gradle/playground.versions.toml index 38a7a6e..60320e2 100644 --- a/gradle/playground.versions.toml +++ b/gradle/playground.versions.toml @@ -15,6 +15,8 @@ nexus-publish = "1.3.0" kotlin = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } dokkatoo = { id = "dev.adamko.dokkatoo-html", version.ref = "dokkatoo" } +kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } + [libraries] kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } -- 2.51.2 From fec9fbd2fe2126e01c21e538e52db384c3b931e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 14 Oct 2023 18:43:45 +0200 Subject: [PATCH 44/47] ci(gitlab): Automatically release the staging Nexus repository for MavenCentral after closing it --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2e1f484..7b1b6d9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -93,14 +93,14 @@ publish-maven:central: when: never - if: $CI_COMMIT_TAG -publish-maven:central:close: +publish-maven:central:release: extends: [ .os.gradle ] needs: [ os.version, publish-maven:central ] stage: deploy script: - > - ./gradlew findSonatypeStagingRepository closeSonatypeStagingRepository + ./gradlew findSonatypeStagingRepository closeAndReleaseSonatypeStagingRepository --no-configuration-cache -PappVersion=$project_version -- 2.51.2 From fc81ef203dfb0b935eda0c17f6e1f829912d1ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Thu, 19 Oct 2023 21:37:28 +0200 Subject: [PATCH 45/47] ci(gitlab): Disable the configuration cache for Dokka --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2e1f484..1bad13f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -123,6 +123,7 @@ dokka: script: - > ./gradlew :dokkatooGeneratePublicationHtml + --no-configuration-cache -PappVersion=$project_version after_script: -- 2.51.2 From f1e814d973d002afa5d78ea25c5e2f6b3b7420f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sun, 22 Oct 2023 15:47:41 +0200 Subject: [PATCH 46/47] docs(state-arrow): Fix a broken link to the Arrow documentation --- state-arrow/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state-arrow/README.md b/state-arrow/README.md index 9139f96..d54a8b3 100644 --- a/state-arrow/README.md +++ b/state-arrow/README.md @@ -1,6 +1,6 @@ # Module State (Arrow compatibility) -Compatibility layer for `state` and [Arrow Core](https://arrow-kt.io/docs/core/). +Compatibility layer for `state` and [Arrow Core](https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/). -- 2.51.2 From 154377bd781018cd8ed83b75750759c1728469ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sun, 22 Oct 2023 15:54:01 +0200 Subject: [PATCH 47/47] docs(logger): Document how each logger implementation works --- logger/README.ios.md | 3 +++ logger/README.js.md | 3 +++ logger/README.jvm.md | 3 +++ logger/README.linuxX64.md | 3 +++ logger/README.md | 3 --- 5 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 logger/README.ios.md create mode 100644 logger/README.js.md create mode 100644 logger/README.jvm.md create mode 100644 logger/README.linuxX64.md diff --git a/logger/README.ios.md b/logger/README.ios.md new file mode 100644 index 0000000..37e3a41 --- /dev/null +++ b/logger/README.ios.md @@ -0,0 +1,3 @@ +# Module Logger + +Logger implementation that delegates to [os_log](https://developer.apple.com/documentation/os/os_log). diff --git a/logger/README.js.md b/logger/README.js.md new file mode 100644 index 0000000..18ff3e7 --- /dev/null +++ b/logger/README.js.md @@ -0,0 +1,3 @@ +# Module Logger + +Logger implementation that delegates to the [browser's console](https://developer.mozilla.org/en-US/docs/Web/API/console). diff --git a/logger/README.jvm.md b/logger/README.jvm.md new file mode 100644 index 0000000..c01a116 --- /dev/null +++ b/logger/README.jvm.md @@ -0,0 +1,3 @@ +# Module Logger + +Logger implementation that delegates to [Slf4j](https://www.slf4j.org/). diff --git a/logger/README.linuxX64.md b/logger/README.linuxX64.md new file mode 100644 index 0000000..a725806 --- /dev/null +++ b/logger/README.linuxX64.md @@ -0,0 +1,3 @@ +# Module Logger + +Logger implementation that prints to the program's standard output. diff --git a/logger/README.md b/logger/README.md index cc19e8b..de5d6bf 100644 --- a/logger/README.md +++ b/logger/README.md @@ -2,9 +2,6 @@ Simple multiplatform [Logger][opensavvy.logger.Logger] interface that delegates to the logging facilities of the underlying platform. -- JVM: Slf4J -- JS: `console` API -