diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index e55e98256e..b0296f45e4 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -10,7 +10,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v6 + - uses: actions/stale@v9 with: exempt-issue-labels: pinned include-only-assigned: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 97cbc82b08..8241c78e6b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: key: ${{ runner.os }}-mkdocs-${{ hashFiles('**/*.gradle*', '**/gradle*.properties') }} restore-keys: ${{ runner.os }}-mkdocs- @@ -16,7 +16,7 @@ jobs: ~/.local/bin ~/.local/lib/python*/site-packages - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release_branch.yml b/.github/workflows/release_branch.yml index 3f52a2f8c5..ec8ec926d4 100644 --- a/.github/workflows/release_branch.yml +++ b/.github/workflows/release_branch.yml @@ -8,7 +8,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/cache@v4 + with: + key: ${{ runner.os }}-mkdocs-${{ hashFiles('**/*.gradle*', '**/gradle*.properties') }} + restore-keys: ${{ runner.os }}-mkdocs- + path: | + ~/.local/bin + ~/.local/lib/python*/site-packages + + - uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} @@ -19,11 +27,26 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} cache: gradle + - env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + export REMOTE="https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" + git remote set-url origin "$REMOTE" + git clone "$REMOTE" --branch gh-pages build/gh-pages + ./gradlew build + ./gradlew -x build buildSite + ls -AlF site/build/site + - env: OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} SIGNING_KEY: ${{ secrets.SIGNING_KEY }} SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - run: | - ./gradlew build - ./gradlew --no-daemon -x test release + run: ./gradlew --no-daemon -x test release + + - run: | + cp -rf site/build/site/* build/gh-pages/ + cd build/gh-pages + git add --all + git commit -m "Publishing to gh-pages" + git push origin gh-pages diff --git a/.github/workflows/site.yml b/.github/workflows/site.yml index 6706d960ff..41e5455d4d 100644 --- a/.github/workflows/site.yml +++ b/.github/workflows/site.yml @@ -35,7 +35,7 @@ jobs: defaults: run: { shell: bash } steps: - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: key: ${{ runner.os }}-mkdocs-${{ hashFiles('**/*.gradle*', '**/gradle*.properties') }} restore-keys: ${{ runner.os }}-mkdocs- @@ -43,7 +43,7 @@ jobs: ~/.local/bin ~/.local/lib/python*/site-packages - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} diff --git a/core/src/test/kotlin/com/hexagonkt/core/media/MediaTypesTest.kt b/core/src/test/kotlin/com/hexagonkt/core/media/MediaTypesTest.kt index 83dd48f9e7..f3d0fce84c 100644 --- a/core/src/test/kotlin/com/hexagonkt/core/media/MediaTypesTest.kt +++ b/core/src/test/kotlin/com/hexagonkt/core/media/MediaTypesTest.kt @@ -23,9 +23,9 @@ internal class MediaTypesTest { @Test fun `Parse correct media types`() { MediaType("*/*").apply { assertEquals(ANY, group) + assertEquals("any", group.text) assertEquals("*", type) assertEquals("*/*", fullType) - } MediaType("text/plain").apply { diff --git a/gradle.properties b/gradle.properties index 0791f81fad..582f063de9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ org.gradle.warning.mode=all org.gradle.console=plain # Gradle -version=3.6.0 +version=3.6.1 group=com.hexagonkt description=The atoms of your platform diff --git a/gradle/kotlin.gradle b/gradle/kotlin.gradle index c9c1dff8c7..5b774127a3 100644 --- a/gradle/kotlin.gradle +++ b/gradle/kotlin.gradle @@ -35,7 +35,7 @@ repositories { } dependencies { - final String scriptJunitVersion = findProperty("junitVersion") ?: "5.10.2" + final String scriptJunitVersion = findProperty("junitVersion") ?: "5.10.3" implementation("org.jetbrains.kotlin:kotlin-stdlib") diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6f7a6eb33e..dedd5d1e69 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.8-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/http/http/src/test/kotlin/com/hexagonkt/http/HttpTest.kt b/http/http/src/test/kotlin/com/hexagonkt/http/HttpTest.kt index 0fa0e3afa3..15e6f61669 100644 --- a/http/http/src/test/kotlin/com/hexagonkt/http/HttpTest.kt +++ b/http/http/src/test/kotlin/com/hexagonkt/http/HttpTest.kt @@ -14,6 +14,16 @@ import kotlin.test.assertTrue internal class HttpTest { + @Test fun `Format query string with empty keys`() { + assertEquals("", formatQueryString(QueryParameters(QueryParameter("", 1)))) + assertEquals("", formatQueryString(QueryParameters(QueryParameter(" ", 1)))) + } + + @Test fun `Basic auth is encoded correctly`() { + assertEquals("YTo", basicAuth("a")) + assertEquals("YTpi", basicAuth("a", "b")) + } + @Test fun `Format query string`() { fun testParseFormat(expected: String, queryString: String) { assertEquals(expected, formatQueryString(parseQueryString(queryString))) diff --git a/http/http/src/test/kotlin/com/hexagonkt/http/model/CookieTest.kt b/http/http/src/test/kotlin/com/hexagonkt/http/model/CookieTest.kt index c810b70268..213285dc0f 100644 --- a/http/http/src/test/kotlin/com/hexagonkt/http/model/CookieTest.kt +++ b/http/http/src/test/kotlin/com/hexagonkt/http/model/CookieTest.kt @@ -1,5 +1,6 @@ package com.hexagonkt.http.model +import com.hexagonkt.http.model.CookieSameSite.* import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Test import kotlin.IllegalArgumentException @@ -20,6 +21,10 @@ internal class CookieTest { assertEquals(5, cookie.maxAge) assertTrue(cookie.secure) assertFalse(cookie.deleted) + + assertEquals(LAX, cookie.copy(sameSite = LAX).sameSite) + assertEquals(NONE, cookie.copy(sameSite = NONE).sameSite) + assertEquals(STRICT, cookie.copy(sameSite = STRICT).sameSite) } @Test fun `Cookie can be deleted`() { diff --git a/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeRequestCallback.kt b/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeRequestCallback.kt index 4ca94062f6..e23e49317a 100644 --- a/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeRequestCallback.kt +++ b/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeRequestCallback.kt @@ -7,6 +7,12 @@ import com.hexagonkt.serialization.serialize class SerializeRequestCallback : HttpCallback { + init { + check(SerializationManager.formats.isNotEmpty()) { + "Serialization callbacks require at least one registered format" + } + } + override fun invoke(context: HttpContext): HttpContext { val requestBody = context.request.body diff --git a/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeResponseCallback.kt b/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeResponseCallback.kt index bc23fbb3b7..d66872dff5 100644 --- a/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeResponseCallback.kt +++ b/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeResponseCallback.kt @@ -7,6 +7,12 @@ import com.hexagonkt.serialization.serialize class SerializeResponseCallback: HttpCallback { + init { + check(SerializationManager.formats.isNotEmpty()) { + "Serialization callbacks require at least one registered format" + } + } + override fun invoke(context: HttpContext): HttpContext { val responseBody = context.response.body diff --git a/http/rest/src/test/kotlin/com/hexagonkt/rest/SerializeRequestCallbackTest.kt b/http/rest/src/test/kotlin/com/hexagonkt/rest/SerializeRequestCallbackTest.kt index fdc32b322f..e29275fd5a 100644 --- a/http/rest/src/test/kotlin/com/hexagonkt/rest/SerializeRequestCallbackTest.kt +++ b/http/rest/src/test/kotlin/com/hexagonkt/rest/SerializeRequestCallbackTest.kt @@ -8,13 +8,25 @@ import com.hexagonkt.serialization.SerializationManager import com.hexagonkt.serialization.jackson.json.Json import org.junit.jupiter.api.Test import kotlin.test.assertEquals +import kotlin.test.assertFailsWith import kotlin.test.assertSame internal class SerializeRequestCallbackTest { - private val callback = SerializeRequestCallback() + private val callback by lazy { SerializeRequestCallback() } + + @Test fun `Serialization callback fails if no formats are defined`() { + val formats = SerializationManager.formats + + SerializationManager.formats = emptySet() + val e = assertFailsWith { SerializeRequestCallback() } + assertEquals("Serialization callbacks require at least one registered format", e.message) + + SerializationManager.formats = formats + } @Test fun `Serialize empty request callback creates the proper response`() { + SerializationManager.formats = setOf(Json) val stringContext = HttpContext().send(body = "") assertSame(stringContext, callback(stringContext)) diff --git a/http/rest/src/test/kotlin/com/hexagonkt/rest/SerializeResponseCallbackTest.kt b/http/rest/src/test/kotlin/com/hexagonkt/rest/SerializeResponseCallbackTest.kt index 642d8a0c92..6aa8043371 100644 --- a/http/rest/src/test/kotlin/com/hexagonkt/rest/SerializeResponseCallbackTest.kt +++ b/http/rest/src/test/kotlin/com/hexagonkt/rest/SerializeResponseCallbackTest.kt @@ -8,13 +8,25 @@ import com.hexagonkt.serialization.SerializationManager import com.hexagonkt.serialization.jackson.json.Json import org.junit.jupiter.api.Test import kotlin.test.assertEquals +import kotlin.test.assertFailsWith import kotlin.test.assertSame internal class SerializeResponseCallbackTest { - private val callback = SerializeResponseCallback() + private val callback by lazy { SerializeResponseCallback() } + + @Test fun `Serialization callback fails if no formats are defined`() { + val formats = SerializationManager.formats + + SerializationManager.formats = emptySet() + val e = assertFailsWith { SerializeResponseCallback() } + assertEquals("Serialization callbacks require at least one registered format", e.message) + + SerializationManager.formats = formats + } @Test fun `Serialize empty response callback creates the proper response`() { + SerializationManager.formats = setOf(Json) val stringContext = HttpContext().send(body = "") assertSame(stringContext, callback(stringContext)) diff --git a/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/DynamicHttpServerTest.kt b/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/DynamicHttpServerTest.kt index 42bd4e81d5..06491d2a5f 100644 --- a/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/DynamicHttpServerTest.kt +++ b/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/DynamicHttpServerTest.kt @@ -31,6 +31,7 @@ class DynamicHttpServerTest { private val dynamicServer: DynamicHttpServer = DynamicHttpServer(JettyServletAdapter()) @BeforeAll fun `Set up mock services`() { + SerializationManager.formats = setOf(Json) dynamicServer.start() } diff --git a/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/StateHttpClientTest.kt b/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/StateHttpClientTest.kt index f05f2fcb98..96881323fb 100644 --- a/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/StateHttpClientTest.kt +++ b/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/StateHttpClientTest.kt @@ -8,6 +8,8 @@ import com.hexagonkt.http.model.HttpMethod.PUT import com.hexagonkt.http.model.HttpResponsePort import com.hexagonkt.http.model.OK_200 import com.hexagonkt.http.server.jetty.JettyServletAdapter +import com.hexagonkt.serialization.SerializationManager +import com.hexagonkt.serialization.jackson.json.Json import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test @@ -22,6 +24,7 @@ internal class StateHttpClientTest { private val text = ContentType(TEXT_PLAIN) @BeforeAll fun `Set up mock services`() { + SerializationManager.formats = setOf(Json) server.start() } diff --git a/serverless/serverless_http_google/build.gradle.kts b/serverless/serverless_http_google/build.gradle.kts index 4d680dcae5..f126f4f5bb 100644 --- a/serverless/serverless_http_google/build.gradle.kts +++ b/serverless/serverless_http_google/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } apply(from = "$rootDir/gradle/kotlin.gradle") -//apply(from = "$rootDir/gradle/publish.gradle") +apply(from = "$rootDir/gradle/publish.gradle") apply(from = "$rootDir/gradle/dokka.gradle") apply(from = "$rootDir/gradle/detekt.gradle") diff --git a/settings.gradle.kts b/settings.gradle.kts index 989d4816f4..b1b8133e2e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,21 +19,21 @@ dependencyResolutionManagement { versionCatalogs { create("libs") { // Build - version("kotlin", "2.0.0") + version("kotlin", "2.0.20-RC") version("dokka", "1.9.20") version("licenseReport", "2.8") - version("binValidator", "0.15.0-Beta.2") + version("binValidator", "0.16.3") version("nativeTools", "0.10.2") version("detekt", "1.23.6") version("jmhGradle", "0.7.2") - version("gradleWrapper", "8.8") - version("mkdocsMaterial", "9.5.27") + version("gradleWrapper", "8.9") + version("mkdocsMaterial", "9.5.31") version("mermaidDokka", "0.6.0") version("maven", "3.9.8") // Testing - version("junit", "5.10.2") - version("mockk", "1.13.11") + version("junit", "5.10.3") + version("mockk", "1.13.12") // TODO Latest version breaks stress test (consider using JMeter) //version("gatling", "3.11.3") version("gatling", "3.10.5") @@ -43,21 +43,21 @@ dependencyResolutionManagement { version("slf4j", "2.0.13") // http_server_netty - version("netty", "4.1.111.Final") + version("netty", "4.1.112.Final") version("nettyTcNative", "2.0.65.Final") // http_server_helidon - version("helidon", "4.0.10") + version("helidon", "4.0.11") // http_server_servlet version("servlet", "6.0.0") - version("jetty", "12.0.10") + version("jetty", "12.0.12") // rest_tools version("swaggerRequestValidator", "2.41.0") // serialization - version("jackson", "2.17.1") + version("jackson", "2.17.2") version("dslJson", "2.0.2") // serverless_http_google diff --git a/site/build.gradle.kts b/site/build.gradle.kts index a1b08dd27a..731e78b53f 100644 --- a/site/build.gradle.kts +++ b/site/build.gradle.kts @@ -132,6 +132,7 @@ tasks.register("installMkDocs") { exec { commandLine("python -m venv $venv".split(" ")) } exec { commandLine("$venv/bin/pip install mkdocs-material==$mkdocsMaterialVersion".split(" ")) } exec { commandLine("$venv/bin/pip install mkdocs-htmlproofer-plugin".split(" ")) } + exec { commandLine("$venv/bin/pip install mike".split(" ")) } } } diff --git a/site/mkdocs.yml b/site/mkdocs.yml index fe59520381..b31a46ff8c 100644 --- a/site/mkdocs.yml +++ b/site/mkdocs.yml @@ -2,7 +2,7 @@ dev_addr: 127.0.0.1:8000 site_name: Hexagon -site_url: https://hexagontk.com +site_url: https://hexagontk.com/ site_author: Hexagon Toolkit site_dir: build/site site_description: The atoms of your platform @@ -129,6 +129,9 @@ extra: provider: google property: G-BEKWF2E4DJ +# version: +# provider: mike + twitter_user: hexagontk social: - icon: fontawesome/brands/github diff --git a/site/pages/gradle.md b/site/pages/gradle.md index 909a59ee37..2fcc74371c 100644 --- a/site/pages/gradle.md +++ b/site/pages/gradle.md @@ -68,7 +68,7 @@ IDEs. ## Icons Create web icons (favicon and thumbnails for browsers/mobile) from SVG images (logos). -For image rendering you will need [rsvg] (librsvg2-bin) and [imagemagick] installed in the +For image rendering you will need [rsvg] (librsvg2-bin) and `imagemagick` installed in the development machine. To use it, apply `$gradleScripts/icons.gradle` to your `build.gradle.kts`. @@ -81,7 +81,6 @@ To set up this script's parameters, check the [build variables section]. These h * iconsDirectory: directory inside `build` where icons will be generated. The default is `icons`. [rsvg]: https://github.com/GNOME/librsvg -[imagemagick]: https://imagemagick.org/index.php ## Kotlin Adds Kotlin's Gradle plugin.