From 4c031d7a61ea224a90e3a3e62e1b079ed9bacf93 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 18 Oct 2023 21:26:13 -0700 Subject: [PATCH 01/60] Updated dependencies --- .github/workflows/gradle.yml | 2 +- build.gradle.kts | 14 +++++++------- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 14 +++++++------- pom.xml | 4 ++-- settings.gradle.kts | 17 ++++++++++++++++- 6 files changed, 34 insertions(+), 19 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 42bc1da..658abb4 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -39,7 +39,7 @@ jobs: - name: Test with Gradle uses: gradle/gradle-build-action@v2 with: - arguments: build check --stacktrace + arguments: build check --stacktrace --scan - name: SonarCloud if: success() && matrix.java-version == env.SONAR_JDK diff --git a/build.gradle.kts b/build.gradle.kts index fbea59b..1ed612b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,20 +4,20 @@ import org.jetbrains.dokka.gradle.DokkaTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("com.github.ben-manes.versions") version "0.48.0" + id("com.github.ben-manes.versions") version "0.49.0" id("io.gitlab.arturbosch.detekt") version "1.23.1" id("java") id("maven-publish") - id("org.jetbrains.dokka") version "1.9.0" - id("org.jetbrains.kotlinx.kover") version "0.7.3" - id("org.sonarqube") version "4.3.1.3277" + id("org.jetbrains.dokka") version "1.9.10" + id("org.jetbrains.kotlinx.kover") version "0.7.4" + id("org.sonarqube") version "4.4.1.3373" id("signing") kotlin("jvm") version "1.9.10" } description = "Retrieve jokes from Sv443's JokeAPI" group = "net.thauvin.erik" -version = "0.9.0" +version = "0.9.1-SNAPSHOT" val deployDir = "deploy" val gitHub = "ethauvin/$name" @@ -33,7 +33,7 @@ dependencies { implementation(platform(kotlin("bom"))) implementation("net.thauvin.erik.urlencoder:urlencoder-lib:1.4.0") - implementation("org.json:json:20230618") + implementation("org.json:json:20231013") testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") @@ -63,7 +63,7 @@ sonarqube { property("sonar.organization", "ethauvin-github") property("sonar.host.url", "https://sonarcloud.io") property("sonar.sourceEncoding", "UTF-8") - property("sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/kover/report.xml") + property("sonar.coverage.jacoco.xmlReportPaths", "${layout.buildDirectory.get()}/reports/kover/report.xml") } } 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 0adc8e1..1aa94a4 100755 --- a/gradlew +++ b/gradlew @@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/pom.xml b/pom.xml index 31a633b..fcf6fe4 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ 4.0.0 net.thauvin.erik jokeapi - 0.9.0 + 0.9.1-SNAPSHOT jokeapi Retrieve jokes from Sv443's JokeAPI https://github.com/ethauvin/jokeapi @@ -62,7 +62,7 @@ org.json json - 20230618 + 20231013 runtime diff --git a/settings.gradle.kts b/settings.gradle.kts index dc0111b..44c4276 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,18 @@ +plugins { + id("com.gradle.enterprise").version("3.15") +} + +gradleEnterprise { + buildScan { + link("GitHub", "https://github.com/ethauvin/jokeapi/tree/master") + if (!System.getenv("CI").isNullOrEmpty()) { + isUploadInBackground = false + publishOnFailure() + tag("CI") + } + termsOfServiceUrl = "https://gradle.com/terms-of-service" + termsOfServiceAgree = "yes" + } +} rootProject.name = "jokeapi" - From f613b8cdfcf03855aea0841ef54d58b3acc035cc Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 8 Nov 2023 22:15:17 -0800 Subject: [PATCH 02/60] Switched from Gradle to bld --- .circleci/config.yml | 45 +-- .github/workflows/gradle.yml | 44 +-- .gitignore | 135 +++----- .idea/app.iml | 30 ++ .idea/bld.iml | 14 + .idea/libraries/bld.xml | 17 + .idea/libraries/compile.xml | 13 + .idea/libraries/runtime.xml | 14 + .idea/libraries/test.xml | 14 + .idea/misc.xml | 6 +- .idea/modules.xml | 9 + .idea/runConfigurations/Run Tests.xml | 9 + .vscode/launch.json | 11 + .vscode/settings.json | 15 + README.md | 17 +- bin/main/net/thauvin/erik/jokeapi/JokeApi.kt | 318 ++++++++++++++++++ .../net/thauvin/erik/jokeapi/JokeConfig.kt | 96 ++++++ bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt | 173 ++++++++++ .../jokeapi/exceptions/HttpErrorException.kt | 49 +++ .../erik/jokeapi/exceptions/JokeException.kt | 56 +++ .../thauvin/erik/jokeapi/models/Category.kt | 45 +++ .../net/thauvin/erik/jokeapi/models/Flag.kt | 45 +++ .../net/thauvin/erik/jokeapi/models/Format.kt | 44 +++ .../thauvin/erik/jokeapi/models/IdRange.kt | 37 ++ .../net/thauvin/erik/jokeapi/models/Joke.kt | 45 +++ .../thauvin/erik/jokeapi/models/Language.kt | 55 +++ .../thauvin/erik/jokeapi/models/Parameter.kt | 51 +++ .../net/thauvin/erik/jokeapi/models/Type.kt | 41 +++ .../net/thauvin/erik/jokeapi/ApiCallTest.kt | 87 +++++ .../thauvin/erik/jokeapi/BeforeAllTests.kt | 47 +++ .../thauvin/erik/jokeapi/ExceptionsTest.kt | 90 +++++ .../net/thauvin/erik/jokeapi/GetJokeTest.kt | 211 ++++++++++++ .../net/thauvin/erik/jokeapi/GetJokesTest.kt | 84 +++++ .../thauvin/erik/jokeapi/GetRawJokesTest.kt | 79 +++++ .../thauvin/erik/jokeapi/JokeConfigTest.kt | 182 ++++++++++ .../net/thauvin/erik/jokeapi/JokeUtilTest.kt | 60 ++++ bld | 2 + bld.bat | 4 + build.gradle.kts | 185 ---------- gradle.properties | 1 - gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 7 - gradlew | 249 -------------- gradlew.bat | 92 ----- lib/bld/bld-wrapper.jar | Bin 0 -> 27321 bytes lib/bld/bld-wrapper.properties | 8 + settings.gradle.kts | 18 - sonar-project.properties | 7 + .../java/net/thauvin/erik/JokeApiBuild.java | 153 +++++++++ .../net/thauvin/erik/jokeapi/JokeConfig.kt | 7 +- .../net/thauvin/erik/jokeapi/JokeUtil.kt | 9 +- .../jokeapi/exceptions/HttpErrorException.kt | 1 + .../erik/jokeapi/exceptions/JokeException.kt | 2 + .../thauvin/erik/jokeapi/ExceptionsTest.kt | 11 +- .../net/thauvin/erik/jokeapi/GetJokeTest.kt | 29 +- .../net/thauvin/erik/jokeapi/GetJokesTest.kt | 10 +- .../thauvin/erik/jokeapi/JokeConfigTest.kt | 19 +- .../net/thauvin/erik/jokeapi/JokeUtilTest.kt | 2 +- 58 files changed, 2344 insertions(+), 760 deletions(-) create mode 100644 .idea/app.iml create mode 100644 .idea/bld.iml create mode 100644 .idea/libraries/bld.xml create mode 100644 .idea/libraries/compile.xml create mode 100644 .idea/libraries/runtime.xml create mode 100644 .idea/libraries/test.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations/Run Tests.xml create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 bin/main/net/thauvin/erik/jokeapi/JokeApi.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/JokeConfig.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/exceptions/JokeException.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/models/Category.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/models/Flag.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/models/Format.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/models/IdRange.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/models/Joke.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/models/Language.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/models/Parameter.kt create mode 100644 bin/main/net/thauvin/erik/jokeapi/models/Type.kt create mode 100644 bin/test/net/thauvin/erik/jokeapi/ApiCallTest.kt create mode 100644 bin/test/net/thauvin/erik/jokeapi/BeforeAllTests.kt create mode 100644 bin/test/net/thauvin/erik/jokeapi/ExceptionsTest.kt create mode 100644 bin/test/net/thauvin/erik/jokeapi/GetJokeTest.kt create mode 100644 bin/test/net/thauvin/erik/jokeapi/GetJokesTest.kt create mode 100644 bin/test/net/thauvin/erik/jokeapi/GetRawJokesTest.kt create mode 100644 bin/test/net/thauvin/erik/jokeapi/JokeConfigTest.kt create mode 100644 bin/test/net/thauvin/erik/jokeapi/JokeUtilTest.kt create mode 100755 bld create mode 100644 bld.bat delete mode 100644 build.gradle.kts delete mode 100644 gradle.properties delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat create mode 100644 lib/bld/bld-wrapper.jar create mode 100644 lib/bld/bld-wrapper.properties delete mode 100644 settings.gradle.kts create mode 100644 sonar-project.properties create mode 100644 src/bld/java/net/thauvin/erik/JokeApiBuild.java diff --git a/.circleci/config.yml b/.circleci/config.yml index 2922277..77889be 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,50 +4,41 @@ defaults: &defaults environment: JVM_OPTS: -Xmx3200m TERM: dumb - CI: true + CI_NAME: "CircleCI" -defaults_gradle: &defaults_gradle +defaults_gradle: &defaults_bld steps: - checkout - - restore_cache: - keys: - - gradle-dependencies-{{ checksum "build.gradle.kts" }} - # fallback to using the latest cache if no exact match is found - - gradle-dependencies- - run: - name: Gradle Dependencies - command: ./gradlew dependencies - - save_cache: - paths: ~/.m2 - key: gradle-dependencies-{{ checksum "build.gradle.kts" }} + name: Download the bld dependencies + command: ./bld download - run: - name: Run All Checks - command: ./gradlew check - - store_artifacts: - path: build/reports/ - destination: reports - - store_test_results: - path: build/reports/ + name: Compile source with bld + command: ./bld compile + - run: + name: Run tests with bld + command: ./bld test + jobs: - build_gradle_jdk17: + bld_jdk17: <<: *defaults docker: - image: cimg/openjdk:17.0 - <<: *defaults_gradle + <<: *defaults_bld - build_gradle_jdk11: + bld_jdk20: <<: *defaults docker: - - image: cimg/openjdk:11.0 + - image: cimg/openjdk:20.0 - <<: *defaults_gradle + <<: *defaults_bld workflows: version: 2 - gradle: + bld: jobs: - - build_gradle_jdk11 - - build_gradle_jdk17 + - bld_jdk17 + - bld_jdk20 diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 658abb4..ba51eb1 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,21 +1,21 @@ -name: gradle-ci +name: bld-ci on: [ push, pull_request, workflow_dispatch ] jobs: - build: + build-bld-project: runs-on: ubuntu-latest env: - GRADLE_OPTS: "-Dorg.gradle.jvmargs=-XX:MaxMetaspaceSize=512m" - SONAR_JDK: "17" + COVERAGE_SDK: "17" strategy: matrix: - java-version: [ 11, 17, 20 ] + java-version: [ 17, 20 ] steps: - - uses: actions/checkout@v3 + - name: Checkout source repository + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -25,25 +25,25 @@ jobs: distribution: 'zulu' java-version: ${{ matrix.java-version }} - - name: Grant execute permission for gradlew - run: chmod +x gradlew + - name: Grant bld execute permission + run: chmod +x bld - - name: Cache SonarCloud packages - if: matrix.java-version == env.SONAR_JDK - uses: actions/cache@v3 - with: - path: ~/.sonar/cache - key: ${{ runner.os }}-sonar - restore-keys: ${{ runner.os }}-sonar + - name: Download the bld dependencies + run: ./bld download - - name: Test with Gradle - uses: gradle/gradle-build-action@v2 - with: - arguments: build check --stacktrace --scan + - name: Compile source with bld + run: ./bld compile - - name: SonarCloud - if: success() && matrix.java-version == env.SONAR_JDK + - name: Run tests with bld + run: ./bld jacoco + + - name: Remove pom.xml + if: success() && matrix.java-version == env.COVERAGE_SDK + run: rm -rf pom.xml + + - name: SonarCloud Scan + uses: sonarsource/sonarcloud-github-action@master + if: success() && matrix.java-version == env.COVERAGE_SDK env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: ./gradlew sonar --info diff --git a/.gitignore b/.gitignore index 0742f86..ea86fe8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,84 +1,57 @@ -!.vscode/extensions.json -!.vscode/launch.json -!.vscode/settings.json -!.vscode/tasks.json -*.class -*.code-workspace -*.ctxt -*.iws -*.log -*.nar -*.rar -*.sublime-* -*.tar.gz -*.zip -.DS_Store -.classpath .gradle -.history -.kobalt -.mtj.tmp/ -.mvn/timing.properties -.mvn/wrapper/maven-wrapper.jar -.nb-gradle -.project -.scannerwork -.settings -.vscode/* -/**/.idea/$CACHE_FILE$ -/**/.idea/$PRODUCT_WORKSPACE_FILE$ -/**/.idea/**/caches/build_file_checksums.ser -/**/.idea/**/contentModel.xml -/**/.idea/**/dataSources.ids -/**/.idea/**/dataSources.local.xml -/**/.idea/**/dataSources/ -/**/.idea/**/dbnavigator.xml -/**/.idea/**/dictionaries -/**/.idea/**/dynamic.xml -/**/.idea/**/gradle.xml -/**/.idea/**/httpRequests -/**/.idea/**/libraries -/**/.idea/**/mongoSettings.xml -/**/.idea/**/replstate.xml -/**/.idea/**/shelf -/**/.idea/**/shelf/ -/**/.idea/**/sqlDataSources.xml -/**/.idea/**/tasks.xml -/**/.idea/**/uiDesigner.xml -/**/.idea/**/usage.statistics.xml -/**/.idea/**/workspace.xml -/**/.idea/sonarlint* -/**/.idea_modules/ -Thumbs.db -__pycache__ +.DS_Store +build +lib/bld/** +!lib/bld/bld-wrapper.jar +!lib/bld/bld-wrapper.properties +lib/compile/ +lib/runtime/ +lib/standalone/ +lib/test/ + +# IDEA ignores + +# User-specific +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin atlassian-ide-plugin.xml -bin/ -build/ -cmake-build-*/ -com_crashlytics_export_strings.xml -crashlytics-build.properties -crashlytics.properties -dependency-reduced-pom.xml -deploy/ -dist/ -ehthumbs.db -fabric.properties -gen/ -hs_err_pid* -kobaltBuild -kobaltw*-test -lib/kotlin* -libs/ + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Editor-based Rest Client +.idea/httpRequests + local.properties -out/ -pom.xml.asc -pom.xml.next -pom.xml.releaseBackup -pom.xml.tag -pom.xml.versionsBackup -proguard-project.txt -project.properties -release.properties -target/ -test-output -venv diff --git a/.idea/app.iml b/.idea/app.iml new file mode 100644 index 0000000..2c1fe21 --- /dev/null +++ b/.idea/app.iml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/bld.iml b/.idea/bld.iml new file mode 100644 index 0000000..e63e11e --- /dev/null +++ b/.idea/bld.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml new file mode 100644 index 0000000..cf75013 --- /dev/null +++ b/.idea/libraries/bld.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/compile.xml b/.idea/libraries/compile.xml new file mode 100644 index 0000000..9bd86aa --- /dev/null +++ b/.idea/libraries/compile.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/runtime.xml b/.idea/libraries/runtime.xml new file mode 100644 index 0000000..2ae5c4b --- /dev/null +++ b/.idea/libraries/runtime.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/test.xml b/.idea/libraries/test.xml new file mode 100644 index 0000000..b80486a --- /dev/null +++ b/.idea/libraries/test.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index caf34dd..542659b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,9 +1,9 @@ + - - - + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..55adcb9 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Run Tests.xml b/.idea/runConfigurations/Run Tests.xml new file mode 100644 index 0000000..df4d7d6 --- /dev/null +++ b/.idea/runConfigurations/Run Tests.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9f84d53 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Run Tests", + "request": "launch", + "mainClass": "net.thauvin.erik.JokeapiTest" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..133aa45 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "java.project.sourcePaths": [ + "src/main/java", + "src/main/resources", + "src/test/java", + "src/bld/java" + ], + "java.configuration.updateBuildConfiguration": "automatic", + "java.project.referencedLibraries": [ + "${HOME}/.bld/dist/bld-1.7.5.jar", + "lib/compile/*.jar", + "lib/runtime/*.jar", + "lib/test/*.jar" + ] +} diff --git a/README.md b/README.md index 3627830..5d9f28d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.10-7f52ff)](https://kotlinlang.org/) -[![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/jokeapi?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/) +[![Kotlin](https://img.shields.io/badge/kotlin-1.9.20-7f52ff)](https://kotlinlang.org/) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) +[![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/jokeapi?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_jokeapi&metric=alert_status)](https://sonarcloud.io/dashboard?id=ethauvin_jokeapi) [![GitHub CI](https://github.com/ethauvin/jokeapi/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/jokeapi/actions/workflows/gradle.yml) @@ -88,6 +88,19 @@ var config = new JokeConfig.Builder() var joke = JokeApi.joke(config); joke.getJoke().forEach(System.out::println); ``` + +## bld + +To use with [bld](https://rife2.com/bld), include the following dependency in your build file: + +```java +repositories = List.of(MAVEN_CENTRAL); + +scope(compile) + .include(dependency("net.thauvin.erik:cryptoprice:1.0.1")); +``` +Be sure to use the [bld Kotlin extension](https://github.com/rife2/bld-kotlin) in your project. + ## Gradle, Maven, etc. To use with [Gradle](https://gradle.org/), include the following dependency in your build file: diff --git a/bin/main/net/thauvin/erik/jokeapi/JokeApi.kt b/bin/main/net/thauvin/erik/jokeapi/JokeApi.kt new file mode 100644 index 0000000..b4df9aa --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/JokeApi.kt @@ -0,0 +1,318 @@ +/* + * JokeApi.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import net.thauvin.erik.jokeapi.exceptions.HttpErrorException +import net.thauvin.erik.jokeapi.exceptions.JokeException +import net.thauvin.erik.jokeapi.models.* +import net.thauvin.erik.urlencoder.UrlEncoderUtil +import org.json.JSONObject +import java.util.logging.Logger +import java.util.stream.Collectors + +/** + * Implements the [Sv443's JokeAPI](https://jokeapi.dev/). + */ +object JokeApi { + private const val API_URL = "https://v2.jokeapi.dev/" + + @JvmStatic + val logger: Logger by lazy { Logger.getLogger(JokeApi::class.java.simpleName) } + + /** + * Makes a direct API call. + * + * Sse the [JokeAPI Documentation](https://jokeapi.dev/#endpoints) for more details. + */ + @JvmStatic + @JvmOverloads + @Throws(HttpErrorException::class) + fun apiCall( + endPoint: String, + path: String = "", + params: Map = emptyMap(), + auth: String = "" + ): String { + val urlBuilder = StringBuilder("$API_URL$endPoint") + + if (path.isNotEmpty()) { + if (!urlBuilder.endsWith(('/'))) { + urlBuilder.append('/') + } + urlBuilder.append(path) + } + + if (params.isNotEmpty()) { + urlBuilder.append('?') + val it = params.iterator() + while (it.hasNext()) { + val param = it.next() + urlBuilder.append(param.key) + if (param.value.isNotEmpty()) { + urlBuilder.append("=").append(UrlEncoderUtil.encode(param.value)) + } + if (it.hasNext()) { + urlBuilder.append("&") + } + } + } + return fetchUrl(urlBuilder.toString(), auth) + } + + /** + * Returns one or more jokes using a [configuration][JokeConfig]. + * + * See the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. + */ + @JvmStatic + @Throws(HttpErrorException::class) + fun getRawJokes(config: JokeConfig): String { + return rawJokes( + categories = config.categories, + lang = config.language, + blacklistFlags = config.flags, + type = config.type, + format = config.format, + contains = config.contains, + idRange = config.idRange, + amount = config.amount, + safe = config.safe, + auth = config.auth + ) + } + + /** + * Retrieve a [Joke] instance using a [configuration][JokeConfig]. + * + * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. + */ + @JvmStatic + @JvmOverloads + @Throws(HttpErrorException::class, JokeException::class) + fun joke(config: JokeConfig = JokeConfig.Builder().build()): Joke { + return joke( + categories = config.categories, + lang = config.language, + blacklistFlags = config.flags, + type = config.type, + contains = config.contains, + idRange = config.idRange, + safe = config.safe, + auth = config.auth, + splitNewLine = config.splitNewLine + ) + } + + /** + * Returns an array of [Joke] instances using a [configuration][JokeConfig]. + * + * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. + */ + @JvmStatic + @Throws(HttpErrorException::class, JokeException::class) + fun jokes(config: JokeConfig): Array { + return jokes( + categories = config.categories, + lang = config.language, + blacklistFlags = config.flags, + type = config.type, + contains = config.contains, + idRange = config.idRange, + amount = config.amount, + safe = config.safe, + auth = config.auth, + splitNewLine = config.splitNewLine + ) + } +} + + +/** + * Returns a [Joke] instance. + * + * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. + * + * @param splitNewLine Split newline within [Type.SINGLE] joke. + */ +fun joke( + categories: Set = setOf(Category.ANY), + lang: Language = Language.EN, + blacklistFlags: Set = emptySet(), + type: Type = Type.ALL, + contains: String = "", + idRange: IdRange = IdRange(), + safe: Boolean = false, + auth: String = "", + splitNewLine: Boolean = false +): Joke { + val json = JSONObject( + rawJokes( + categories = categories, + lang = lang, + blacklistFlags = blacklistFlags, + type = type, + contains = contains, + idRange = idRange, + safe = safe, + auth = auth + ) + ) + if (json.getBoolean("error")) { + throw parseError(json) + } else { + return parseJoke(json, splitNewLine) + } +} + +/** + * Returns an array of [Joke] instances. + * + * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. + * + * @param amount The required amount of jokes to return. + * @param splitNewLine Split newline within [Type.SINGLE] joke. + */ +fun jokes( + amount: Int, + categories: Set = setOf(Category.ANY), + lang: Language = Language.EN, + blacklistFlags: Set = emptySet(), + type: Type = Type.ALL, + contains: String = "", + idRange: IdRange = IdRange(), + safe: Boolean = false, + auth: String = "", + splitNewLine: Boolean = false +): Array { + val json = JSONObject( + rawJokes( + categories = categories, + lang = lang, + blacklistFlags = blacklistFlags, + type = type, + contains = contains, + idRange = idRange, + amount = amount, + safe = safe, + auth = auth + ) + ) + if (json.getBoolean("error")) { + throw parseError(json) + } else { + return if (json.has("amount")) { + val jokes = json.getJSONArray("jokes") + Array(jokes.length()) { i -> parseJoke(jokes.getJSONObject(i), splitNewLine) } + } else { + arrayOf(parseJoke(json, splitNewLine)) + } + } +} + +/** + * Returns one or more jokes. + * + * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. + */ +fun rawJokes( + categories: Set = setOf(Category.ANY), + lang: Language = Language.EN, + blacklistFlags: Set = emptySet(), + type: Type = Type.ALL, + format: Format = Format.JSON, + contains: String = "", + idRange: IdRange = IdRange(), + amount: Int = 1, + safe: Boolean = false, + auth: String = "" +): String { + val params = mutableMapOf() + + // Categories + val path = if (categories.isEmpty() || categories.contains(Category.ANY)) { + Category.ANY.value + } else { + categories.stream().map(Category::value).collect(Collectors.joining(",")) + } + + // Language + if (lang != Language.EN) { + params[Parameter.LANG] = lang.value + } + + // Flags + if (blacklistFlags.isNotEmpty()) { + if (blacklistFlags.contains(Flag.ALL)) { + params[Parameter.FLAGS] = Flag.ALL.value + } else { + params[Parameter.FLAGS] = blacklistFlags.stream().map(Flag::value).collect(Collectors.joining(",")) + } + } + + // Type + if (type != Type.ALL) { + params[Parameter.TYPE] = type.value + } + + // Format + if (format != Format.JSON) { + params[Parameter.FORMAT] = format.value + } + + // Contains + if (contains.isNotBlank()) { + params[Parameter.CONTAINS] = contains + } + + // Range + if (idRange.start >= 0) { + if (idRange.end == -1 || idRange.start == idRange.end) { + params[Parameter.RANGE] = idRange.start.toString() + } else { + require(idRange.end > idRange.start) { "Invalid ID Range: ${idRange.start}, ${idRange.end}" } + params[Parameter.RANGE] = "${idRange.start}-${idRange.end}" + } + } + + // Amount + require(amount > 0) { "Invalid Amount: $amount" } + if (amount > 1) { + params[Parameter.AMOUNT] = amount.toString() + } + + // Safe + if (safe) { + params[Parameter.SAFE] = "" + } + + return JokeApi.apiCall("joke", path, params, auth) +} diff --git a/bin/main/net/thauvin/erik/jokeapi/JokeConfig.kt b/bin/main/net/thauvin/erik/jokeapi/JokeConfig.kt new file mode 100644 index 0000000..544383c --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/JokeConfig.kt @@ -0,0 +1,96 @@ +/* + * JokeConfig.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import net.thauvin.erik.jokeapi.JokeConfig.Builder +import net.thauvin.erik.jokeapi.models.Category +import net.thauvin.erik.jokeapi.models.Flag +import net.thauvin.erik.jokeapi.models.Format +import net.thauvin.erik.jokeapi.models.IdRange +import net.thauvin.erik.jokeapi.models.Language +import net.thauvin.erik.jokeapi.models.Type + +/** + * Joke Configuration. + * + * Use the [Builder] to create a new configuration. + */ +class JokeConfig private constructor( + val categories: Set, + val language: Language, + val flags: Set, + val type: Type, + val format: Format, + val contains: String, + val idRange: IdRange, + val amount: Int, + val safe: Boolean, + val splitNewLine: Boolean, + val auth: String +) { + /** + * [Builds][build] a new configuration. + * + * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. + * + * @param splitNewLine Split newline within [Type.SINGLE] joke. + */ + data class Builder( + var categories: Set = setOf(Category.ANY), + var lang: Language = Language.EN, + var blacklistFlags: Set = emptySet(), + var type: Type = Type.ALL, + var format: Format = Format.JSON, + var contains: String = "", + var idRange: IdRange = IdRange(), + var amount: Int = 1, + var safe: Boolean = false, + var splitNewLine: Boolean = false, + var auth: String = "" + ) { + fun categories(categories: Set) = apply { this.categories = categories } + fun lang(language: Language) = apply { lang = language } + fun blacklistFlags(flags: Set) = apply { blacklistFlags = flags } + fun type(type: Type) = apply { this.type = type } + fun format(format: Format) = apply { this.format = format } + fun contains(search: String) = apply { contains = search } + fun idRange(idRange: IdRange) = apply { this.idRange = idRange } + fun amount(amount: Int) = apply { this.amount = amount } + fun safe(safe: Boolean) = apply { this.safe = safe } + fun splitNewLine(splitNewLine: Boolean) = apply { this.splitNewLine = splitNewLine } + fun auth(auth: String) = apply { this.auth = auth } + + fun build() = JokeConfig( + categories, lang, blacklistFlags, type, format, contains, idRange, amount, safe, splitNewLine, auth + ) + } +} diff --git a/bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt b/bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt new file mode 100644 index 0000000..9d838f8 --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -0,0 +1,173 @@ +/* + * JokeUtil.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +@file:JvmName("JokeUtil") + +package net.thauvin.erik.jokeapi + +import net.thauvin.erik.jokeapi.exceptions.HttpErrorException +import net.thauvin.erik.jokeapi.exceptions.JokeException +import net.thauvin.erik.jokeapi.models.Category +import net.thauvin.erik.jokeapi.models.Flag +import net.thauvin.erik.jokeapi.models.Joke +import net.thauvin.erik.jokeapi.models.Language +import net.thauvin.erik.jokeapi.models.Parameter +import net.thauvin.erik.jokeapi.models.Type +import org.json.JSONObject +import java.io.IOException +import java.net.HttpURLConnection +import java.net.URL +import java.util.logging.Level + +internal fun fetchUrl(url: String, auth: String = ""): String { + if (JokeApi.logger.isLoggable(Level.FINE)) { + JokeApi.logger.fine(url) + } + + val connection = URL(url).openConnection() as HttpURLConnection + connection.setRequestProperty( + "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" + ) + if (auth.isNotEmpty()) { + connection.setRequestProperty("Authentication", auth) + } + + if (connection.responseCode in 200..399) { + val body = connection.inputStream.bufferedReader().use { it.readText() } + if (JokeApi.logger.isLoggable(Level.FINE)) { + JokeApi.logger.fine(body) + } + return body + } else { + throw httpError(connection.responseCode) + } +} + +private fun httpError(responseCode: Int): HttpErrorException { + val httpException: HttpErrorException + when (responseCode) { + 400 -> httpException = HttpErrorException( + responseCode, "Bad Request", IOException( + "The request you have sent to JokeAPI is formatted incorrectly and cannot be processed." + ) + ) + + 403 -> httpException = HttpErrorException( + responseCode, "Forbidden", IOException( + "You have been added to the blacklist due to malicious behavior and are not allowed" + + " to send requests to JokeAPI anymore." + ) + ) + + 404 -> httpException = HttpErrorException( + responseCode, "Not Found", IOException("The URL you have requested couldn't be found.") + ) + + 413 -> httpException = HttpErrorException( + responseCode, "URI Too Long", IOException("The URL exceeds the maximum length of 250 characters.") + ) + + 414 -> httpException = HttpErrorException( + responseCode, + "Payload Too Large", + IOException("The payload data sent to the server exceeds the maximum size of 5120 bytes.") + ) + + 429 -> httpException = HttpErrorException( + responseCode, "Too Many Requests", IOException( + "You have exceeded the limit of 120 requests per minute and have to wait a bit" + + " until you are allowed to send requests again." + ) + ) + + 500 -> httpException = HttpErrorException( + responseCode, "Internal Server Error", IOException( + "There was a general internal error within JokeAPI. You can get more info from" + + " the properties in the response text." + ) + ) + + 523 -> httpException = HttpErrorException( + responseCode, "Origin Unreachable", IOException( + "The server is temporarily offline due to maintenance or a dynamic IP update." + + " Please be patient in this case." + ) + ) + + else -> httpException = HttpErrorException(responseCode, "Unknown HTTP Error") + } + + return httpException +} + +internal fun parseError(json: JSONObject): JokeException { + val causedBy = json.getJSONArray("causedBy") + val causes = List(causedBy.length()) { i -> causedBy.getString(i) } + return JokeException( + internalError = json.getBoolean("internalError"), + code = json.getInt("code"), + message = json.getString("message"), + causedBy = causes, + additionalInfo = json.getString("additionalInfo"), + timestamp = json.getLong("timestamp") + ) +} + +internal fun parseJoke(json: JSONObject, splitNewLine: Boolean): Joke { + val jokes = mutableListOf() + if (json.has("setup")) { + jokes.add(json.getString("setup")) + jokes.add(json.getString(("delivery"))) + } else { + if (splitNewLine) { + jokes.addAll(json.getString("joke").split("\n")) + } else { + jokes.add(json.getString("joke")) + } + } + val enabledFlags = mutableSetOf() + val jsonFlags = json.getJSONObject("flags") + Flag.values().filter { it != Flag.ALL }.forEach { + if (jsonFlags.has(it.value) && jsonFlags.getBoolean(it.value)) { + enabledFlags.add(it) + } + } + return Joke( + category = Category.valueOf(json.getString("category").uppercase()), + type = Type.valueOf(json.getString(Parameter.TYPE).uppercase()), + joke = jokes, + flags = enabledFlags, + safe = json.getBoolean("safe"), + id = json.getInt("id"), + lang = Language.valueOf(json.getString(Parameter.LANG).uppercase()) + ) +} + diff --git a/bin/main/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt b/bin/main/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt new file mode 100644 index 0000000..cd17ca8 --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt @@ -0,0 +1,49 @@ +/* + * HttpErrorException.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.exceptions + +import java.io.IOException + +/** + * Signals that a server error has occurred. + * + * Sse the [JokeAPI Documentation](https://jokeapi.dev/#status-codes) for more details. + */ +class HttpErrorException @JvmOverloads constructor( + val statusCode: Int, + message: String, + cause: Throwable? = null +) : IOException(message, cause) { + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/bin/main/net/thauvin/erik/jokeapi/exceptions/JokeException.kt b/bin/main/net/thauvin/erik/jokeapi/exceptions/JokeException.kt new file mode 100644 index 0000000..919216e --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/exceptions/JokeException.kt @@ -0,0 +1,56 @@ +/* + * JokeException.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.exceptions + +/** + * Signals that an error has occurred. + * + * Sse the [JokeAPI Documentation](https://jokeapi.dev/#errors) for more details. + */ +class JokeException @JvmOverloads constructor( + val internalError: Boolean, + val code: Int, + message: String, + val causedBy: List, + val additionalInfo: String, + val timestamp: Long, + cause: Throwable? = null +) : RuntimeException(message, cause) { + companion object { + private const val serialVersionUID = 1L + } + + fun debug(): String { + return "JokeException(message=$message, internalError=$internalError, code=$code," + + " causedBy=$causedBy, additionalInfo='$additionalInfo', timestamp=$timestamp)" + } +} diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Category.kt b/bin/main/net/thauvin/erik/jokeapi/models/Category.kt new file mode 100644 index 0000000..4951d4a --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/models/Category.kt @@ -0,0 +1,45 @@ +/* + * Category.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.models + +/** + * The supported [categories](https://jokeapi.dev/#categories), use [ANY] for all. + */ +enum class Category(val value: String) { + ANY("Any"), + CHRISTMAS("Christmas"), + DARK("Dark"), + MISC("Misc"), + PROGRAMMING("Programming"), + PUN("Pun"), + SPOOKY("Spooky") +} diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Flag.kt b/bin/main/net/thauvin/erik/jokeapi/models/Flag.kt new file mode 100644 index 0000000..af92e90 --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/models/Flag.kt @@ -0,0 +1,45 @@ +/* + * Flag.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.models + +/** + * The supported [blacklist flags](https://jokeapi.dev/#flags-param), use [ALL] to prevent all. + */ +enum class Flag(val value: String) { + EXPLICIT("explicit"), + NSFW("nsfw"), + POLITICAL("political"), + RACIST("racist"), + RELIGIOUS("religious"), + SEXIST("sexist"), + ALL("${NSFW.value},${RELIGIOUS.value},${POLITICAL.value},${RACIST.value},${SEXIST.value},${EXPLICIT.value}") +} diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Format.kt b/bin/main/net/thauvin/erik/jokeapi/models/Format.kt new file mode 100644 index 0000000..2678a21 --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/models/Format.kt @@ -0,0 +1,44 @@ +/* + * Format.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.models + +/** + * The supported response [formats](https://jokeapi.dev/#format-param). + */ +enum class Format(val value: String) { + JSON("json"), + + /** Plain Text */ + TXT("txt"), + XML("xml"), + YAML("yaml") +} diff --git a/bin/main/net/thauvin/erik/jokeapi/models/IdRange.kt b/bin/main/net/thauvin/erik/jokeapi/models/IdRange.kt new file mode 100644 index 0000000..62a6eb6 --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/models/IdRange.kt @@ -0,0 +1,37 @@ +/* + * IdRange.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.models + +/** + * Specifies a joke [ID or range of IDs](https://jokeapi.dev/#idrange-param). + */ +data class IdRange(val start: Int = -1, val end: Int = -1) diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Joke.kt b/bin/main/net/thauvin/erik/jokeapi/models/Joke.kt new file mode 100644 index 0000000..0309977 --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/models/Joke.kt @@ -0,0 +1,45 @@ +/* + * Joke.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.models + +/** + * Stores a joke's data. + */ +data class Joke( + val category: Category, + val type: Type, + val joke: List, + val flags: Set, + val id: Int, + val safe: Boolean, + val lang: Language +) diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Language.kt b/bin/main/net/thauvin/erik/jokeapi/models/Language.kt new file mode 100644 index 0000000..10c00fb --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/models/Language.kt @@ -0,0 +1,55 @@ +/* + * Language.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.models + +/** + * The supported [languages](https://jokeapi.dev/#lang). + */ +enum class Language(val value: String) { + /** Czech */ + CS("cs"), + + /** German */ + DE("de"), + + /** English */ + EN("en"), + + /** Spanish */ + ES("es"), + + /** French */ + FR("fr"), + + /** Portuguese */ + PT("pt") +} diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Parameter.kt b/bin/main/net/thauvin/erik/jokeapi/models/Parameter.kt new file mode 100644 index 0000000..b9e1106 --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/models/Parameter.kt @@ -0,0 +1,51 @@ +/* + * Parameter.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.models + +/** + * The available [URL Parameters](https://jokeapi.dev/#url-parameters). + */ +object Parameter { + const val AMOUNT = "amount" + const val CONTAINS = "contains" + const val FLAGS = "blacklistFlags" + const val FORMAT = "format" + const val RANGE = "idRange" + const val LANG = "lang" + const val SAFE = "safe-mode" + const val TYPE = "type" + + const val BLACKLIST_FLAGS = FLAGS + const val ID_RANGE = RANGE + const val SAFE_MODE = SAFE + const val SEARCH = CONTAINS +} diff --git a/bin/main/net/thauvin/erik/jokeapi/models/Type.kt b/bin/main/net/thauvin/erik/jokeapi/models/Type.kt new file mode 100644 index 0000000..59126b4 --- /dev/null +++ b/bin/main/net/thauvin/erik/jokeapi/models/Type.kt @@ -0,0 +1,41 @@ +/* + * Type.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi.models + +/** + * The supported [types](https://jokeapi.dev/#type-param), use [ALL] for all. + */ +enum class Type(val value: String) { + SINGLE("single"), + TWOPART("twopart"), + ALL("${SINGLE.value},${TWOPART.value}") +} diff --git a/bin/test/net/thauvin/erik/jokeapi/ApiCallTest.kt b/bin/test/net/thauvin/erik/jokeapi/ApiCallTest.kt new file mode 100644 index 0000000..d9f9b30 --- /dev/null +++ b/bin/test/net/thauvin/erik/jokeapi/ApiCallTest.kt @@ -0,0 +1,87 @@ +/* + * ApiCallTest.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import assertk.assertThat +import assertk.assertions.isGreaterThan +import assertk.assertions.startsWith +import net.thauvin.erik.jokeapi.JokeApi.apiCall +import net.thauvin.erik.jokeapi.models.Format +import net.thauvin.erik.jokeapi.models.Language +import net.thauvin.erik.jokeapi.models.Parameter +import org.json.JSONObject +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertAll +import org.junit.jupiter.api.extension.ExtendWith +import kotlin.test.assertContains + +@ExtendWith(BeforeAllTests::class) +internal class ApiCallTest { + @Test + fun `Get Flags`() { + // See https://v2.jokeapi.dev/#flags-endpoint + val response = apiCall(endPoint = "flags") + val json = JSONObject(response) + assertAll("Validate JSON", + { assertFalse(json.getBoolean("error"), "apiCall(flags).error") }, + { assertThat(json.getJSONArray("flags").length(), "apiCall(flags).flags").isGreaterThan(0) }, + { assertThat(json.getLong("timestamp"), "apiCall(flags).timestamp").isGreaterThan(0) }) + } + + @Test + fun `Get Language Code`() { + // See https://v2.jokeapi.dev/#langcode-endpoint + val lang = apiCall( + endPoint = "langcode", path = "french", + params = mapOf(Parameter.FORMAT to Format.YAML.value) + ) + assertContains(lang, "code: \"fr\"", false, "apiCall(langcode, french, yaml)") + } + + @Test + fun `Get Ping Response`() { + // See https://v2.jokeapi.dev/#ping-endpoint + val ping = apiCall(endPoint = "ping", params = mapOf(Parameter.FORMAT to Format.TXT.value)) + assertThat(ping, "apiCall(ping, txt)").startsWith("Pong!") + } + + @Test + fun `Get Supported Language`() { + // See https://v2.jokeapi.dev/languages + val lang = apiCall( + endPoint = "languages", + params = mapOf(Parameter.FORMAT to Format.XML.value, Parameter.LANG to Language.FR.value) + ) + assertThat(lang).startsWith("") + } +} diff --git a/bin/test/net/thauvin/erik/jokeapi/BeforeAllTests.kt b/bin/test/net/thauvin/erik/jokeapi/BeforeAllTests.kt new file mode 100644 index 0000000..de9d48a --- /dev/null +++ b/bin/test/net/thauvin/erik/jokeapi/BeforeAllTests.kt @@ -0,0 +1,47 @@ +/* + * BeforeAllTests.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import org.junit.jupiter.api.extension.BeforeAllCallback +import org.junit.jupiter.api.extension.ExtensionContext +import java.util.logging.ConsoleHandler +import java.util.logging.Level + +class BeforeAllTests : BeforeAllCallback { + override fun beforeAll(context: ExtensionContext?) { + with(JokeApi.logger) { + addHandler(ConsoleHandler().apply { level = Level.FINE }) + level = Level.FINE + } + } +} + diff --git a/bin/test/net/thauvin/erik/jokeapi/ExceptionsTest.kt b/bin/test/net/thauvin/erik/jokeapi/ExceptionsTest.kt new file mode 100644 index 0000000..adacf75 --- /dev/null +++ b/bin/test/net/thauvin/erik/jokeapi/ExceptionsTest.kt @@ -0,0 +1,90 @@ +/* + * ExceptionsTest.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import assertk.all +import assertk.assertThat +import assertk.assertions.index +import assertk.assertions.isEqualTo +import assertk.assertions.isFalse +import assertk.assertions.isGreaterThan +import assertk.assertions.isNotEmpty +import assertk.assertions.isNotNull +import assertk.assertions.isNull +import assertk.assertions.prop +import assertk.assertions.size +import assertk.assertions.startsWith +import net.thauvin.erik.jokeapi.JokeApi.logger +import net.thauvin.erik.jokeapi.exceptions.HttpErrorException +import net.thauvin.erik.jokeapi.exceptions.JokeException +import net.thauvin.erik.jokeapi.models.Category +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +@ExtendWith(BeforeAllTests::class) +internal class ExceptionsTest { + @Test + fun `Validate Joke Exception`() { + val e = assertThrows { + joke(categories = setOf(Category.CHRISTMAS), contains = "foo") + } + logger.fine(e.debug()) + assertThat(e, "joke(${Category.CHRISTMAS},foo)").all { + prop(JokeException::code).isEqualTo(106) + prop(JokeException::internalError).isFalse() + prop(JokeException::message).isEqualTo("No matching joke found") + prop(JokeException::causedBy).size().isEqualTo(1) + prop(JokeException::causedBy).index(0).startsWith("No jokes") + prop(JokeException::additionalInfo).isNotEmpty() + prop(JokeException::timestamp).isGreaterThan(0) + } + } + + @ParameterizedTest + @ValueSource(ints = [400, 404, 403, 413, 414, 429, 500, 523, 666]) + fun `Validate HTTP Exceptions`(code: Int) { + val e = assertThrows { + fetchUrl("https://httpstat.us/$code") + } + assertThat(e, "fetchUrl($code)").all { + prop(HttpErrorException::statusCode).isEqualTo(code) + prop(HttpErrorException::message).isNotNull().isNotEmpty() + if (code < 600) + prop(HttpErrorException::cause).isNotNull().assertThat(Throwable::message).isNotNull() + else + prop(HttpErrorException::cause).isNull() + } + } +} diff --git a/bin/test/net/thauvin/erik/jokeapi/GetJokeTest.kt b/bin/test/net/thauvin/erik/jokeapi/GetJokeTest.kt new file mode 100644 index 0000000..a2b06db --- /dev/null +++ b/bin/test/net/thauvin/erik/jokeapi/GetJokeTest.kt @@ -0,0 +1,211 @@ +/* + * GetJokeTest.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import assertk.all +import assertk.assertThat +import assertk.assertions.any +import assertk.assertions.contains +import assertk.assertions.containsNone +import assertk.assertions.each +import assertk.assertions.isBetween +import assertk.assertions.isEmpty +import assertk.assertions.isEqualTo +import assertk.assertions.isGreaterThan +import assertk.assertions.isGreaterThanOrEqualTo +import assertk.assertions.isIn +import assertk.assertions.isNotEmpty +import assertk.assertions.isNotNull +import assertk.assertions.isTrue +import assertk.assertions.prop +import assertk.assertions.size +import net.thauvin.erik.jokeapi.JokeApi.logger +import net.thauvin.erik.jokeapi.exceptions.JokeException +import net.thauvin.erik.jokeapi.models.Category +import net.thauvin.erik.jokeapi.models.Flag +import net.thauvin.erik.jokeapi.models.IdRange +import net.thauvin.erik.jokeapi.models.Joke +import net.thauvin.erik.jokeapi.models.Language +import net.thauvin.erik.jokeapi.models.Type +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(BeforeAllTests::class) +internal class GetJokeTest { + @Test + fun `Get Joke`() { + val joke = joke() + logger.fine(joke.toString()) + assertThat(joke, "joke()").all { + prop(Joke::joke).isNotEmpty() + prop(Joke::type).isIn(Type.SINGLE, Type.TWOPART) + prop(Joke::id).isGreaterThanOrEqualTo(0) + prop(Joke::lang).isEqualTo(Language.EN) + } + } + + @Test + fun `Get Joke without Blacklist Flags`() { + val joke = joke(blacklistFlags = setOf(Flag.ALL)) + assertThat(joke::flags).isEmpty() + } + + @Test + fun `Get Joke without any Blacklist Flags`() { + val allFlags = Flag.values().filter { it != Flag.ALL }.toSet() + val joke = joke(blacklistFlags = allFlags) + assertThat(joke::flags).isEmpty() + } + + @Test + fun `Get Joke with ID`() { + val id = 172 + val joke = joke(idRange = IdRange(id)) + logger.fine(joke.toString()) + assertThat(joke, "joke($id)").all { + prop(Joke::flags).all { + contains(Flag.EXPLICIT) + contains(Flag.NSFW) + } + prop(Joke::id).isEqualTo(172) + prop(Joke::category).isEqualTo(Category.PUN) + } + } + + @Test + fun `Get Joke with ID Range`() { + val idRange = IdRange(1, 100) + val joke = joke(idRange = idRange) + logger.fine(joke.toString()) + assertThat(joke::id).isBetween(idRange.start, idRange.end) + } + + @Test + fun `Get Joke with invalid ID Range`() { + val idRange = IdRange(100, 1) + val e = assertThrows { joke(idRange = idRange, lang = Language.DE) } + assertThat(e::message).isNotNull().contains("100, 1") + } + + @Test + fun `Get Joke with max ID Range`() { + val idRange = IdRange(1, 30000) + val e = assertThrows { joke(idRange = idRange) } + assertThat(e, "joke{${idRange})").all { + prop(JokeException::additionalInfo).contains("ID range") + } + } + + @Test + fun `Get Joke with two Categories`() { + val joke = joke(categories = setOf(Category.PROGRAMMING, Category.MISC)) + logger.fine(joke.toString()) + assertThat(joke.category, "joke(${Category.PROGRAMMING},${Category.MISC})").isIn( + Category.PROGRAMMING, + Category.MISC + ) + } + + @Test + fun `Get Joke with each Categories`() { + Category.values().filter { it != Category.ANY }.forEach { + val joke = joke(categories = setOf(it)) + logger.fine(joke.toString()) + assertThat(joke::category, "joke($it)").prop(Category::value).isEqualTo(it.value) + } + } + + @Test + fun `Get Joke with each Languages`() { + Language.values().forEach { + val joke = joke(lang = it) + logger.fine(joke.toString()) + assertThat(joke::lang, "joke($it)").prop(Language::value).isEqualTo(it.value) + } + } + + @Test + fun `Get Joke with Split Newline`() { + val joke = joke( + categories = setOf(Category.DARK), type = Type.SINGLE, idRange = IdRange(178), splitNewLine = true + ) + logger.fine(joke.toString()) + assertThat(joke::joke, "joke(splitNewLine=true)").all { + size().isEqualTo(2) + each { + containsNone("\n") + } + } + } + + @Test + fun `Get Safe Joke`() { + val joke = joke(safe = true) + logger.fine(joke.toString()) + assertThat(joke, "joke(safe)").all { + prop(Joke::safe).isTrue() + } + } + + @Test + fun `Get Single Joke`() { + val joke = joke(type = Type.SINGLE) + logger.fine(joke.toString()) + assertThat(joke::type).assertThat(Type.SINGLE) + } + + @Test + fun `Get Two-Parts Joke`() { + val joke = joke(type = Type.TWOPART) + logger.fine(joke.toString()) + assertThat(joke, "joke(${Type.TWOPART})").all { + prop(Joke::type).isEqualTo(Type.TWOPART) + prop(Joke::joke).size().isGreaterThan(1) + } + } + + @Test + fun `Get Joke using Search`() { + val id = 265 + val search = "his wife" + val joke = + joke(contains = search, categories = setOf(Category.PROGRAMMING), idRange = IdRange(id), safe = true) + logger.fine(joke.toString()) + assertThat(joke, "joke($search)").all { + prop(Joke::id).isEqualTo(id) + prop(Joke::joke).any { + it.contains(search) + } + } + } +} diff --git a/bin/test/net/thauvin/erik/jokeapi/GetJokesTest.kt b/bin/test/net/thauvin/erik/jokeapi/GetJokesTest.kt new file mode 100644 index 0000000..1ab8b60 --- /dev/null +++ b/bin/test/net/thauvin/erik/jokeapi/GetJokesTest.kt @@ -0,0 +1,84 @@ +/* + * GetJokesTest.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import assertk.all +import assertk.assertThat +import assertk.assertions.contains +import assertk.assertions.each +import assertk.assertions.index +import assertk.assertions.isEqualTo +import assertk.assertions.isGreaterThanOrEqualTo +import assertk.assertions.isNotNull +import assertk.assertions.isTrue +import assertk.assertions.prop +import assertk.assertions.size +import net.thauvin.erik.jokeapi.models.Joke +import net.thauvin.erik.jokeapi.models.Language +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(BeforeAllTests::class) +internal class GetJokesTest { + @Test + fun `Get Multiple Jokes`() { + val amount = 2 + val jokes = jokes(amount = amount, safe = true, lang = Language.FR) + assertThat(jokes, "jokes").all { + size().isEqualTo(amount) + each { + it.prop(Joke::id).isGreaterThanOrEqualTo(0) + it.prop(Joke::safe).isTrue() + it.prop(Joke::lang).isEqualTo(Language.FR) + } + } + } + + @Test + fun `Get Jokes with Invalid Amount`() { + val e = assertThrows { jokes(amount = -1) } + assertThat(e::message).isNotNull().contains("-1") + } + + @Test + fun `Get One Joke as Multiple`() { + val jokes = jokes(amount = 1, safe = true) + assertThat(jokes, "jokes").all { + size().isEqualTo(1) + index(0).all { + prop(Joke::id).isGreaterThanOrEqualTo(0) + prop(Joke::safe).isTrue() + } + } + } +} diff --git a/bin/test/net/thauvin/erik/jokeapi/GetRawJokesTest.kt b/bin/test/net/thauvin/erik/jokeapi/GetRawJokesTest.kt new file mode 100644 index 0000000..7bcf1c6 --- /dev/null +++ b/bin/test/net/thauvin/erik/jokeapi/GetRawJokesTest.kt @@ -0,0 +1,79 @@ +/* + * GetRawJokesTest.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import assertk.all +import assertk.assertThat +import assertk.assertions.doesNotContain +import assertk.assertions.isNotEmpty +import assertk.assertions.startsWith +import net.thauvin.erik.jokeapi.models.Format +import net.thauvin.erik.jokeapi.models.IdRange +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import kotlin.test.assertContains + +@ExtendWith(BeforeAllTests::class) +internal class GetRawJokesTest { + @Test + fun `Get Raw Joke with TXT`() { + val response = rawJokes(format = Format.TXT) + assertThat(response, "rawJoke(txt)").all { + isNotEmpty() + doesNotContain("Error") + } + } + + @Test + fun `Get Raw Joke with XML`() { + val response = rawJokes(format = Format.XML) + assertThat(response, "rawJoke(xml)").startsWith("\n\n false") + } + + @Test + fun `Get Raw Joke with YAML`() { + val response = rawJokes(format = Format.YAML) + assertThat(response, "rawJoke(yaml)").startsWith("error: false") + } + + @Test + fun `Get Raw Jokes`() { + val response = rawJokes(amount = 2) + assertContains(response, "\"amount\": 2", false, "rawJoke(2)") + } + + @Test + fun `Get Raw Invalid Jokes`() { + val response = rawJokes(contains = "foo", safe = true, amount = 2, idRange = IdRange(160, 161)) + assertContains(response, "\"error\": true", false, "getRawJokes(foo)") + } +} diff --git a/bin/test/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/bin/test/net/thauvin/erik/jokeapi/JokeConfigTest.kt new file mode 100644 index 0000000..92de2e0 --- /dev/null +++ b/bin/test/net/thauvin/erik/jokeapi/JokeConfigTest.kt @@ -0,0 +1,182 @@ +/* + * JokeConfigTest.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import assertk.all +import assertk.assertThat +import assertk.assertions.each +import assertk.assertions.isBetween +import assertk.assertions.isEmpty +import assertk.assertions.isEqualTo +import assertk.assertions.isGreaterThanOrEqualTo +import assertk.assertions.isTrue +import assertk.assertions.prop +import assertk.assertions.size +import net.thauvin.erik.jokeapi.JokeApi.joke +import net.thauvin.erik.jokeapi.JokeApi.jokes +import net.thauvin.erik.jokeapi.JokeApi.getRawJokes +import net.thauvin.erik.jokeapi.JokeApi.logger +import net.thauvin.erik.jokeapi.models.Category +import net.thauvin.erik.jokeapi.models.Flag +import net.thauvin.erik.jokeapi.models.Format +import net.thauvin.erik.jokeapi.models.IdRange +import net.thauvin.erik.jokeapi.models.Joke +import net.thauvin.erik.jokeapi.models.Language +import net.thauvin.erik.jokeapi.models.Type +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import kotlin.test.assertContains + +@ExtendWith(BeforeAllTests::class) +internal class JokeConfigTest { + @Test + fun `Get Joke with Default Builder`() { + val joke = joke() + assertThat(joke, "joke").all { + prop(Joke::id).isGreaterThanOrEqualTo(0) + prop(Joke::lang).isEqualTo(Language.EN) + } + } + + @Test + fun `Get Joke with Builder`() { + val id = 266 + val config = JokeConfig.Builder().apply { + categories(setOf(Category.PROGRAMMING)) + lang(Language.EN) + blacklistFlags(setOf(Flag.ALL)) + type(Type.TWOPART) + idRange(IdRange(id - 2, id + 2)) + safe(true) + }.build() + val joke = joke(config) + logger.fine(joke.toString()) + assertThat(joke, "config").all { + prop(Joke::type).isEqualTo(Type.TWOPART) + prop(Joke::category).isEqualTo(Category.PROGRAMMING) + prop(Joke::joke).size().isEqualTo(2) + prop(Joke::lang).isEqualTo(Language.EN) + prop(Joke::flags).isEmpty() + prop(Joke::id).isBetween(id - 2, id + 2) + } + } + + @Test + fun `Get joke with Builder and Split Newline`() { + val id = 5 + val config = JokeConfig.Builder().apply { + categories(setOf(Category.PROGRAMMING)) + idRange(IdRange(id)) + splitNewLine(true) + }.build() + val joke = joke(config) + logger.fine(joke.toString()) + assertThat(joke, "config").all { + prop(Joke::id).isEqualTo(id) + prop(Joke::joke).size().isEqualTo(2) + } + } + + @Test + fun `Get Raw Joke with Builder`() { + val config = JokeConfig.Builder().apply { + categories(setOf(Category.PROGRAMMING)) + format(Format.TXT) + contains("bar") + amount(2) + safe(true) + }.build() + val joke = getRawJokes(config) + assertContains(joke, "----------------------------------------------", false, "config.amount(2)") + } + + @Test + fun `Get Multiple Jokes with Builder`() { + val amount = 2 + val config = JokeConfig.Builder().apply { + amount(amount) + safe(true) + lang(Language.FR) + }.build() + val jokes = jokes(config) + assertThat(jokes, "jokes").all { + size().isEqualTo(amount) + each { + it.prop(Joke::id).isGreaterThanOrEqualTo(0) + it.prop(Joke::safe).isTrue() + it.prop(Joke::flags).isEmpty() + it.prop(Joke::lang).isEqualTo(Language.FR) + } + } + } + + @Test + fun `Validate Config`() { + val categories = setOf(Category.ANY) + val language = Language.CS + val flags = setOf(Flag.POLITICAL, Flag.RELIGIOUS) + val type = Type.TWOPART + val format = Format.XML + val search = "foo" + val idRange = IdRange(1, 20) + val amount = 10 + val safe = true + val splitNewLine = true + val auth = "token" + val config = JokeConfig.Builder().apply { + categories(categories) + lang(language) + blacklistFlags(flags) + type(type) + format(format) + contains(search) + idRange(idRange) + amount(amount) + safe(safe) + splitNewLine(splitNewLine) + auth(auth) + }.build() + assertThat(config, "config").all { + prop(JokeConfig::categories).isEqualTo(categories) + prop(JokeConfig::language).isEqualTo(language) + prop(JokeConfig::flags).isEqualTo(flags) + prop(JokeConfig::type).isEqualTo(type) + prop(JokeConfig::format).isEqualTo(format) + prop(JokeConfig::contains).isEqualTo(search) + prop(JokeConfig::idRange).isEqualTo(idRange) + prop(JokeConfig::amount).isEqualTo(amount) + prop(JokeConfig::safe).isEqualTo(safe) + prop(JokeConfig::splitNewLine).isEqualTo(splitNewLine) + prop(JokeConfig::auth).isEqualTo(auth) + } + } +} diff --git a/bin/test/net/thauvin/erik/jokeapi/JokeUtilTest.kt b/bin/test/net/thauvin/erik/jokeapi/JokeUtilTest.kt new file mode 100644 index 0000000..8f8d936 --- /dev/null +++ b/bin/test/net/thauvin/erik/jokeapi/JokeUtilTest.kt @@ -0,0 +1,60 @@ +/* + * UtilTest.kt + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.jokeapi + +import assertk.assertThat +import assertk.assertions.contains +import org.json.JSONException +import org.json.JSONObject +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(BeforeAllTests::class) +internal class JokeUtilTest { + @Test + fun `Invalid JSON Error`() { + assertThrows { parseError(JSONObject("{}")) } + } + + @Test + fun `Invalid JSON Joke`() { + assertThrows { parseJoke(JSONObject("{}"), false) } + } + + @Test + fun `Validate Authentication Header`() { + val token = "AUTH-TOKEN" + val body = fetchUrl("https://postman-echo.com/get", token) + assertThat(body, "body").contains("\"authentication\": \"$token\"") + } +} diff --git a/bld b/bld new file mode 100755 index 0000000..bfff52f --- /dev/null +++ b/bld @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +java -jar "$(dirname "$0")/lib/bld/bld-wrapper.jar" "$0" --build net.thauvin.erik.JokeApiBuild "$@" diff --git a/bld.bat b/bld.bat new file mode 100644 index 0000000..9f7473c --- /dev/null +++ b/bld.bat @@ -0,0 +1,4 @@ +@echo off +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +java -jar "%DIRNAME%/lib/bld/bld-wrapper.jar" "%0" --build net.thauvin.erik.JokeApiBuild %* diff --git a/build.gradle.kts b/build.gradle.kts deleted file mode 100644 index 1ed612b..0000000 --- a/build.gradle.kts +++ /dev/null @@ -1,185 +0,0 @@ -import org.gradle.api.tasks.testing.logging.TestExceptionFormat -import org.gradle.api.tasks.testing.logging.TestLogEvent -import org.jetbrains.dokka.gradle.DokkaTask -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - id("com.github.ben-manes.versions") version "0.49.0" - id("io.gitlab.arturbosch.detekt") version "1.23.1" - id("java") - id("maven-publish") - id("org.jetbrains.dokka") version "1.9.10" - id("org.jetbrains.kotlinx.kover") version "0.7.4" - id("org.sonarqube") version "4.4.1.3373" - id("signing") - kotlin("jvm") version "1.9.10" -} - -description = "Retrieve jokes from Sv443's JokeAPI" -group = "net.thauvin.erik" -version = "0.9.1-SNAPSHOT" - -val deployDir = "deploy" -val gitHub = "ethauvin/$name" -val mavenUrl = "https://github.com/$gitHub" -val publicationName = "mavenJava" - -repositories { - mavenCentral() - maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } -} - -dependencies { - implementation(platform(kotlin("bom"))) - - implementation("net.thauvin.erik.urlencoder:urlencoder-lib:1.4.0") - implementation("org.json:json:20231013") - - testImplementation(kotlin("test")) - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") - testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.27.0") -} - -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - withSourcesJar() -} - -koverReport { - defaults { - xml { - onCheck = true - } - html { - onCheck = true - } - } -} - -sonarqube { - properties { - property("sonar.projectKey", "ethauvin_$name") - property("sonar.organization", "ethauvin-github") - property("sonar.host.url", "https://sonarcloud.io") - property("sonar.sourceEncoding", "UTF-8") - property("sonar.coverage.jacoco.xmlReportPaths", "${layout.buildDirectory.get()}/reports/kover/report.xml") - } -} - -val javadocJar by tasks.creating(Jar::class) { - dependsOn(tasks.dokkaJavadoc) - from(tasks.dokkaJavadoc) - archiveClassifier.set("javadoc") -} - -tasks { - test { - useJUnitPlatform() - } - - withType().configureEach { - kotlinOptions.jvmTarget = java.targetCompatibility.toString() - } - - withType { - testLogging { - exceptionFormat = TestExceptionFormat.FULL - events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED) - } - } - - withType().configureEach { - this.jvmTarget = java.targetCompatibility.toString() - } - - withType().configureEach { - this.jvmTarget = java.targetCompatibility.toString() - } - - withType { - destination = file("$projectDir/pom.xml") - } - - clean { - doLast { - project.delete(fileTree(deployDir)) - } - } - - withType().configureEach { - dokkaSourceSets { - named("main") { - moduleName.set("Joke API") - } - } - } - - val copyToDeploy by registering(Copy::class) { - from(configurations.runtimeClasspath) { - exclude("annotations-*.jar") - } - from(jar) - into(deployDir) - } - - register("deploy") { - description = "Copies all needed files to the $deployDir directory." - group = PublishingPlugin.PUBLISH_TASK_GROUP - dependsOn(clean, build, jar) - outputs.dir(deployDir) - inputs.files(copyToDeploy) - mustRunAfter(clean) - } -} - -publishing { - publications { - create(publicationName) { - from(components["java"]) - artifact(javadocJar) - pom { - name.set(project.name) - description.set(project.description) - url.set(mavenUrl) - licenses { - license { - name.set("BSD 3-Clause") - url.set("https://opensource.org/licenses/BSD-3-Clause") - } - } - developers { - developer { - id.set("ethauvin") - name.set("Erik C. Thauvin") - email.set("erik@thauvin.net") - url.set("https://erik.thauvin.net/") - } - } - scm { - connection.set("scm:git:https://github.com/$gitHub.git") - developerConnection.set("scm:git:git@github.com:$gitHub.git") - url.set(mavenUrl) - } - issueManagement { - system.set("GitHub") - url.set("$mavenUrl/issues") - } - } - } - } - repositories { - maven { - name = "ossrh" - url = if (project.version.toString().contains("SNAPSHOT")) - uri("https://oss.sonatype.org/content/repositories/snapshots/") else - uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/") - credentials(PasswordCredentials::class) - } - } -} - -signing { - useGpgCmd() - sign(publishing.publications[publicationName]) -} diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 7fc6f1f..0000000 --- a/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -kotlin.code.style=official diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 3fa8f86..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew deleted file mode 100755 index 1aa94a4..0000000 --- a/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# 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 - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - 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. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 93e3f59..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..431fce99cf1e9d4da73b68a446b92aab039be9e9 GIT binary patch literal 27321 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 Kus>-qu>S(o%Zd*G literal 0 HcmV?d00001 diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties new file mode 100644 index 0000000..32712c6 --- /dev/null +++ b/lib/bld/bld-wrapper.properties @@ -0,0 +1,8 @@ +bld.downloadExtensionJavadoc=false +bld.downloadExtensionSources=true +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.1 +bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.0-SNAPSHOT +bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES +bld.downloadLocation= +bld.sourceDirectories= +bld.version=1.7.5 diff --git a/settings.gradle.kts b/settings.gradle.kts deleted file mode 100644 index 44c4276..0000000 --- a/settings.gradle.kts +++ /dev/null @@ -1,18 +0,0 @@ -plugins { - id("com.gradle.enterprise").version("3.15") -} - -gradleEnterprise { - buildScan { - link("GitHub", "https://github.com/ethauvin/jokeapi/tree/master") - if (!System.getenv("CI").isNullOrEmpty()) { - isUploadInBackground = false - publishOnFailure() - tag("CI") - } - termsOfServiceUrl = "https://gradle.com/terms-of-service" - termsOfServiceAgree = "yes" - } -} - -rootProject.name = "jokeapi" diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..170f57b --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,7 @@ +sonar.organization=ethauvin-github +sonar.projectKey=ethauvin_readingtime +sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml +sonar.sources=src/main/kotlin/ +sonar.tests=src/test/kotlin/ +sonar.java.binaries=build/main,build/test +sonar.java.libraries=lib/compile/*.jar diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java new file mode 100644 index 0000000..bc4d902 --- /dev/null +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -0,0 +1,153 @@ +/* + * JokeApiBuild.java + * + * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik; + +import rife.bld.BuildCommand; +import rife.bld.Project; +import rife.bld.extension.CompileKotlinOperation; +import rife.bld.extension.CompileKotlinOptions; +import rife.bld.extension.JacocoReportOperation; +import rife.bld.extension.dokka.DokkaOperation; +import rife.bld.extension.dokka.LoggingLevel; +import rife.bld.extension.dokka.OutputFormat; +import rife.bld.operations.exceptions.ExitStatusException; +import rife.bld.publish.PomBuilder; +import rife.bld.publish.PublishDeveloper; +import rife.bld.publish.PublishLicense; +import rife.bld.publish.PublishScm; +import rife.tools.exceptions.FileUtilsErrorException; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import static rife.bld.dependencies.Repository.*; +import static rife.bld.dependencies.Scope.compile; +import static rife.bld.dependencies.Scope.test; + +public class JokeApiBuild extends Project { + public JokeApiBuild() { + pkg = "net.thauvin.erik"; + name = "jokeapi"; + version = version(0, 9, 1, "SNAPSHOT"); + + javaRelease = 11; + downloadSources = true; + autoDownloadPurge = true; + repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); + + scope(compile) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", version(1, 9, 20))) + .include(dependency("org.json", "json", "20231013")) + .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 4, 0))); + scope(test) + .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 20))) + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1))) + .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 27, 0))); + + publishOperation() + .repository(version.isSnapshot() ? repository(SONATYPE_SNAPSHOTS_LEGACY.location()) + .withCredentials(property("sonatype.user"), property("sonatype.password")) + : repository(SONATYPE_RELEASES_LEGACY.location()) + .withCredentials(property("sonatype.user"), property("sonatype.password"))) + .info() + .groupId(pkg) + .artifactId(name) + .description("Retrieve jokes from Sv443's JokeAPI") + .url("https://github.com/ethauvin/" + name) + .developer(new PublishDeveloper() + .id("ethauvin") + .name("Erik C. Thauvin") + .email("erik@thauvin.net") + .url("https://erik.thauvin.net/")) + .license(new PublishLicense() + .name("BSD 3-Clause") + .url("https://opensource.org/licenses/BSD-3-Clause")) + .scm(new PublishScm() + .connection("scm:git:https://github.com/ethauvin/" + name) + .developerConnection("scm:git:git@github.com:ethauvin/" + name + ".git") + .url("https://github.com/ethauvin/" + name)) + .signKey(property("sign.key")) + .signPassphrase(property("sign.passphrase")); + + jarSourcesOperation().sourceDirectories(new File(srcMainDirectory(), "kotlin")); + } + + public static void main(String[] args) { + new JokeApiBuild().start(args); + } + + @BuildCommand(summary = "Compiles the Kotlin project") + @Override + public void compile() throws IOException { + new CompileKotlinOperation() + .fromProject(this) + .compileOptions( + new CompileKotlinOptions() + .jdkRelease(javaRelease) + .verbose(true) + ) + .execute(); + } + + @BuildCommand(summary = "Generates JaCoCo Reports") + public void jacoco() throws IOException { + new JacocoReportOperation() + .fromProject(this) + .execute(); + } + + @Override + public void javadoc() throws ExitStatusException, IOException, InterruptedException { + new DokkaOperation() + .fromProject(this) + .loggingLevel(LoggingLevel.INFO) + .moduleName("JokeApi") + .moduleVersion(version.toString()) + .outputDir(new File(buildDirectory(), "javadoc")) + .outputFormat(OutputFormat.JAVADOC) + .execute(); + } + + @Override + public void publish() throws Exception { + super.publish(); + pomRoot(); + } + + @BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory") + public void pomRoot() throws FileUtilsErrorException { + PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(), + new File(workDirectory, "pom.xml")); + } +} diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt index 544383c..4537d13 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt @@ -32,12 +32,7 @@ package net.thauvin.erik.jokeapi import net.thauvin.erik.jokeapi.JokeConfig.Builder -import net.thauvin.erik.jokeapi.models.Category -import net.thauvin.erik.jokeapi.models.Flag -import net.thauvin.erik.jokeapi.models.Format -import net.thauvin.erik.jokeapi.models.IdRange -import net.thauvin.erik.jokeapi.models.Language -import net.thauvin.erik.jokeapi.models.Type +import net.thauvin.erik.jokeapi.models.* /** * Joke Configuration. diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index 9d838f8..ff9f3e6 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -35,12 +35,7 @@ package net.thauvin.erik.jokeapi import net.thauvin.erik.jokeapi.exceptions.HttpErrorException import net.thauvin.erik.jokeapi.exceptions.JokeException -import net.thauvin.erik.jokeapi.models.Category -import net.thauvin.erik.jokeapi.models.Flag -import net.thauvin.erik.jokeapi.models.Joke -import net.thauvin.erik.jokeapi.models.Language -import net.thauvin.erik.jokeapi.models.Parameter -import net.thauvin.erik.jokeapi.models.Type +import net.thauvin.erik.jokeapi.models.* import org.json.JSONObject import java.io.IOException import java.net.HttpURLConnection @@ -155,7 +150,7 @@ internal fun parseJoke(json: JSONObject, splitNewLine: Boolean): Joke { } val enabledFlags = mutableSetOf() val jsonFlags = json.getJSONObject("flags") - Flag.values().filter { it != Flag.ALL }.forEach { + Flag.entries.filter { it != Flag.ALL }.forEach { if (jsonFlags.has(it.value) && jsonFlags.getBoolean(it.value)) { enabledFlags.add(it) } diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt index cd17ca8..815afcc 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt @@ -44,6 +44,7 @@ class HttpErrorException @JvmOverloads constructor( cause: Throwable? = null ) : IOException(message, cause) { companion object { + @Suppress("ConstPropertyName") private const val serialVersionUID = 1L } } diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt index 919216e..16d4ec8 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt @@ -29,6 +29,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +@file:Suppress("ConstPropertyName") + package net.thauvin.erik.jokeapi.exceptions /** diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt index adacf75..3932afd 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt @@ -33,16 +33,7 @@ package net.thauvin.erik.jokeapi import assertk.all import assertk.assertThat -import assertk.assertions.index -import assertk.assertions.isEqualTo -import assertk.assertions.isFalse -import assertk.assertions.isGreaterThan -import assertk.assertions.isNotEmpty -import assertk.assertions.isNotNull -import assertk.assertions.isNull -import assertk.assertions.prop -import assertk.assertions.size -import assertk.assertions.startsWith +import assertk.assertions.* import net.thauvin.erik.jokeapi.JokeApi.logger import net.thauvin.erik.jokeapi.exceptions.HttpErrorException import net.thauvin.erik.jokeapi.exceptions.JokeException diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt index a2b06db..c08ce39 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt @@ -33,29 +33,10 @@ package net.thauvin.erik.jokeapi import assertk.all import assertk.assertThat -import assertk.assertions.any -import assertk.assertions.contains -import assertk.assertions.containsNone -import assertk.assertions.each -import assertk.assertions.isBetween -import assertk.assertions.isEmpty -import assertk.assertions.isEqualTo -import assertk.assertions.isGreaterThan -import assertk.assertions.isGreaterThanOrEqualTo -import assertk.assertions.isIn -import assertk.assertions.isNotEmpty -import assertk.assertions.isNotNull -import assertk.assertions.isTrue -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* import net.thauvin.erik.jokeapi.JokeApi.logger import net.thauvin.erik.jokeapi.exceptions.JokeException -import net.thauvin.erik.jokeapi.models.Category -import net.thauvin.erik.jokeapi.models.Flag -import net.thauvin.erik.jokeapi.models.IdRange -import net.thauvin.erik.jokeapi.models.Joke -import net.thauvin.erik.jokeapi.models.Language -import net.thauvin.erik.jokeapi.models.Type +import net.thauvin.erik.jokeapi.models.* import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith @@ -82,7 +63,7 @@ internal class GetJokeTest { @Test fun `Get Joke without any Blacklist Flags`() { - val allFlags = Flag.values().filter { it != Flag.ALL }.toSet() + val allFlags = Flag.entries.filter { it != Flag.ALL }.toSet() val joke = joke(blacklistFlags = allFlags) assertThat(joke::flags).isEmpty() } @@ -138,7 +119,7 @@ internal class GetJokeTest { @Test fun `Get Joke with each Categories`() { - Category.values().filter { it != Category.ANY }.forEach { + Category.entries.filter { it != Category.ANY }.forEach { val joke = joke(categories = setOf(it)) logger.fine(joke.toString()) assertThat(joke::category, "joke($it)").prop(Category::value).isEqualTo(it.value) @@ -147,7 +128,7 @@ internal class GetJokeTest { @Test fun `Get Joke with each Languages`() { - Language.values().forEach { + Language.entries.forEach { val joke = joke(lang = it) logger.fine(joke.toString()) assertThat(joke::lang, "joke($it)").prop(Language::value).isEqualTo(it.value) diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt index 1ab8b60..2e07a2d 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt @@ -33,15 +33,7 @@ package net.thauvin.erik.jokeapi import assertk.all import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.each -import assertk.assertions.index -import assertk.assertions.isEqualTo -import assertk.assertions.isGreaterThanOrEqualTo -import assertk.assertions.isNotNull -import assertk.assertions.isTrue -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* import net.thauvin.erik.jokeapi.models.Joke import net.thauvin.erik.jokeapi.models.Language import org.junit.jupiter.api.Test diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt index 92de2e0..e617dfc 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt @@ -33,25 +33,12 @@ package net.thauvin.erik.jokeapi import assertk.all import assertk.assertThat -import assertk.assertions.each -import assertk.assertions.isBetween -import assertk.assertions.isEmpty -import assertk.assertions.isEqualTo -import assertk.assertions.isGreaterThanOrEqualTo -import assertk.assertions.isTrue -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* +import net.thauvin.erik.jokeapi.JokeApi.getRawJokes import net.thauvin.erik.jokeapi.JokeApi.joke import net.thauvin.erik.jokeapi.JokeApi.jokes -import net.thauvin.erik.jokeapi.JokeApi.getRawJokes import net.thauvin.erik.jokeapi.JokeApi.logger -import net.thauvin.erik.jokeapi.models.Category -import net.thauvin.erik.jokeapi.models.Flag -import net.thauvin.erik.jokeapi.models.Format -import net.thauvin.erik.jokeapi.models.IdRange -import net.thauvin.erik.jokeapi.models.Joke -import net.thauvin.erik.jokeapi.models.Language -import net.thauvin.erik.jokeapi.models.Type +import net.thauvin.erik.jokeapi.models.* import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import kotlin.test.assertContains diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt index 8f8d936..4b390c8 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt @@ -1,5 +1,5 @@ /* - * UtilTest.kt + * JokeUtilTest.kt * * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) * From aad1b0a4865bfccbed3c318b1b9a5c5b84de9737 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 8 Nov 2023 22:51:23 -0800 Subject: [PATCH 03/60] Fixed sonar properties --- .idea/misc.xml | 3 ++ pom.xml | 67 ++++++++++++++-------------------------- sonar-project.properties | 2 +- 3 files changed, 28 insertions(+), 44 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 542659b..eac42a1 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,8 @@ + + + diff --git a/pom.xml b/pom.xml index fcf6fe4..79c01bc 100644 --- a/pom.xml +++ b/pom.xml @@ -1,16 +1,12 @@ - - - - - - + 4.0.0 net.thauvin.erik jokeapi 0.9.1-SNAPSHOT jokeapi - Retrieve jokes from Sv443's JokeAPI + Retrieve jokes from Sv443's JokeAPI https://github.com/ethauvin/jokeapi @@ -18,6 +14,26 @@ https://opensource.org/licenses/BSD-3-Clause + + + org.jetbrains.kotlin + kotlin-stdlib + 1.9.20 + compile + + + org.json + json + 20231013 + compile + + + net.thauvin.erik.urlencoder + urlencoder-lib-jvm + 1.4.0 + compile + + ethauvin @@ -27,43 +43,8 @@ - scm:git:https://github.com/ethauvin/jokeapi.git + scm:git:https://github.com/ethauvin/jokeapi scm:git:git@github.com:ethauvin/jokeapi.git https://github.com/ethauvin/jokeapi - - GitHub - https://github.com/ethauvin/jokeapi/issues - - - - - org.jetbrains.kotlin - kotlin-bom - 1.9.10 - pom - import - - - - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - 1.9.10 - compile - - - net.thauvin.erik.urlencoder - urlencoder-lib-jvm - 1.4.0 - runtime - - - org.json - json - 20231013 - runtime - - diff --git a/sonar-project.properties b/sonar-project.properties index 170f57b..5fe9b51 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,5 +1,5 @@ sonar.organization=ethauvin-github -sonar.projectKey=ethauvin_readingtime +sonar.projectKey=ethauvin_jokeapi sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml sonar.sources=src/main/kotlin/ sonar.tests=src/test/kotlin/ From 2dd3f59fd54566972f9fc700d2c13e9851c4234d Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 12 Nov 2023 01:09:49 -0800 Subject: [PATCH 04/60] Minor cleanup --- .github/workflows/{gradle.yml => bld.yml} | 0 .idea/libraries/bld.xml | 3 ++- .idea/misc.xml | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{gradle.yml => bld.yml} (100%) diff --git a/.github/workflows/gradle.yml b/.github/workflows/bld.yml similarity index 100% rename from .github/workflows/gradle.yml rename to .github/workflows/bld.yml diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index cf75013..ca84ff0 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -6,6 +6,7 @@ + @@ -14,4 +15,4 @@ - \ No newline at end of file + diff --git a/.idea/misc.xml b/.idea/misc.xml index eac42a1..d303503 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - From 0216c11e0e92e14e4c2a8d057ece22849ae347fd Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 12 Nov 2023 16:07:31 -0800 Subject: [PATCH 05/60] Fixed bld-ci badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5d9f28d..c2f6c09 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/jokeapi?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_jokeapi&metric=alert_status)](https://sonarcloud.io/dashboard?id=ethauvin_jokeapi) -[![GitHub CI](https://github.com/ethauvin/jokeapi/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/jokeapi/actions/workflows/gradle.yml) +[![GitHub CI](https://github.com/ethauvin/jokeapi/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/jokeapi/actions/workflows/bld.yml) [![CircleCI](https://circleci.com/gh/ethauvin/jokeapi/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/jokeapi/tree/master) # JokeAPI for Kotlin, Java and Android From 21fffc19a23ac813658d4cd7766726c8f6c816de Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 23 Nov 2023 18:00:16 -0800 Subject: [PATCH 06/60] Upgraded to Kotlin 1.9.21 --- .idea/misc.xml | 12 ++++++ README.md | 2 +- pom.xml | 4 +- .../java/net/thauvin/erik/JokeApiBuild.java | 40 +++++++++---------- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index d303503..7408350 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,8 +1,20 @@ + + diff --git a/README.md b/README.md index c2f6c09..5308277 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.20-7f52ff)](https://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/kotlin-1.9.21-7f52ff)](https://kotlinlang.org/) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) [![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/jokeapi?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/) diff --git a/pom.xml b/pom.xml index 79c01bc..ed4ed5d 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ org.jetbrains.kotlin kotlin-stdlib - 1.9.20 + 1.9.21 compile @@ -43,7 +43,7 @@ - scm:git:https://github.com/ethauvin/jokeapi + scm:git:https://github.com/ethauvin/jokeapi.git scm:git:git@github.com:ethauvin/jokeapi.git https://github.com/ethauvin/jokeapi diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index bc4d902..5469163 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -34,7 +34,6 @@ package net.thauvin.erik; import rife.bld.BuildCommand; import rife.bld.Project; import rife.bld.extension.CompileKotlinOperation; -import rife.bld.extension.CompileKotlinOptions; import rife.bld.extension.JacocoReportOperation; import rife.bld.extension.dokka.DokkaOperation; import rife.bld.extension.dokka.LoggingLevel; @@ -66,11 +65,11 @@ public class JokeApiBuild extends Project { repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); scope(compile) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", version(1, 9, 20))) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", version(1, 9, 21))) .include(dependency("org.json", "json", "20231013")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 4, 0))); scope(test) - .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 20))) + .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 21))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 27, 0))); @@ -85,18 +84,24 @@ public class JokeApiBuild extends Project { .artifactId(name) .description("Retrieve jokes from Sv443's JokeAPI") .url("https://github.com/ethauvin/" + name) - .developer(new PublishDeveloper() - .id("ethauvin") - .name("Erik C. Thauvin") - .email("erik@thauvin.net") - .url("https://erik.thauvin.net/")) - .license(new PublishLicense() - .name("BSD 3-Clause") - .url("https://opensource.org/licenses/BSD-3-Clause")) - .scm(new PublishScm() - .connection("scm:git:https://github.com/ethauvin/" + name) - .developerConnection("scm:git:git@github.com:ethauvin/" + name + ".git") - .url("https://github.com/ethauvin/" + name)) + .developer( + new PublishDeveloper() + .id("ethauvin") + .name("Erik C. Thauvin") + .email("erik@thauvin.net") + .url("https://erik.thauvin.net/") + ) + .license( + new PublishLicense() + .name("BSD 3-Clause") + .url("https://opensource.org/licenses/BSD-3-Clause") + ) + .scm( + new PublishScm() + .connection("scm:git:https://github.com/ethauvin/" + name + ".git") + .developerConnection("scm:git:git@github.com:ethauvin/" + name + ".git") + .url("https://github.com/ethauvin/" + name) + ) .signKey(property("sign.key")) .signPassphrase(property("sign.passphrase")); @@ -112,11 +117,6 @@ public class JokeApiBuild extends Project { public void compile() throws IOException { new CompileKotlinOperation() .fromProject(this) - .compileOptions( - new CompileKotlinOptions() - .jdkRelease(javaRelease) - .verbose(true) - ) .execute(); } From bddd116090fda190794f57912e690d96671199f8 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 25 Nov 2023 21:23:05 -0800 Subject: [PATCH 07/60] Added detekt extension --- detekt-baseline.xml | 8 +++++++ lib/bld/bld-wrapper.properties | 1 + pom.xml | 18 +++++++++++++++ .../java/net/thauvin/erik/JokeApiBuild.java | 23 ++++++++++++++++++- 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/detekt-baseline.xml b/detekt-baseline.xml index a53ce7c..50acbf1 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -18,6 +18,14 @@ MagicNumber:JokeUtil.kt$500 MagicNumber:JokeUtil.kt$523 TooManyFunctions:JokeConfig.kt$JokeConfig$Builder + WildcardImport:ExceptionsTest.kt$import assertk.assertions.* + WildcardImport:GetJokeTest.kt$import assertk.assertions.* + WildcardImport:GetJokeTest.kt$import net.thauvin.erik.jokeapi.models.* + WildcardImport:GetJokesTest.kt$import assertk.assertions.* WildcardImport:JokeApi.kt$import net.thauvin.erik.jokeapi.models.* + WildcardImport:JokeConfig.kt$import net.thauvin.erik.jokeapi.models.* + WildcardImport:JokeConfigTest.kt$import assertk.assertions.* + WildcardImport:JokeConfigTest.kt$import net.thauvin.erik.jokeapi.models.* + WildcardImport:JokeUtil.kt$import net.thauvin.erik.jokeapi.models.* diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 32712c6..d2d7adf 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -2,6 +2,7 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.1 bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.0-SNAPSHOT +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.0-SNAPSHOT bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= diff --git a/pom.xml b/pom.xml index ed4ed5d..1930c31 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,24 @@ 1.9.21 compile + + org.jetbrains.kotlin + kotlin-stdlib-common + 1.9.21 + compile + + + org.jetbrains.kotlin + kotlin-stdlib-jdk7 + 1.9.21 + compile + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + 1.9.21 + compile + org.json json diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 5469163..c507607 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -34,6 +34,7 @@ package net.thauvin.erik; import rife.bld.BuildCommand; import rife.bld.Project; import rife.bld.extension.CompileKotlinOperation; +import rife.bld.extension.DetektOperation; import rife.bld.extension.JacocoReportOperation; import rife.bld.extension.dokka.DokkaOperation; import rife.bld.extension.dokka.LoggingLevel; @@ -64,8 +65,12 @@ public class JokeApiBuild extends Project { autoDownloadPurge = true; repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); + final var kotlin = version(1, 9, 21); scope(compile) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", version(1, 9, 21))) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) + .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin)) .include(dependency("org.json", "json", "20231013")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 4, 0))); scope(test) @@ -120,6 +125,22 @@ public class JokeApiBuild extends Project { .execute(); } + @BuildCommand(summary = "Checks source with Detekt") + public void detekt() throws ExitStatusException, IOException, InterruptedException { + new DetektOperation() + .fromProject(this) + .execute(); + } + + @BuildCommand(value = "detekt-baseline", summary = "Creates the Detekt baseline") + public void detektBaseline() throws ExitStatusException, IOException, InterruptedException { + new DetektOperation() + .fromProject(this) + .baseline("detekt-baseline.xml") + .createBaseline(true) + .execute(); + } + @BuildCommand(summary = "Generates JaCoCo Reports") public void jacoco() throws IOException { new JacocoReportOperation() From 79ab2287d3df1e921a22b1fe144f229db1441364 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 26 Nov 2023 00:13:19 -0800 Subject: [PATCH 08/60] Version 0.9.1 --- pom.xml | 2 +- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1930c31..f2be8ba 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik jokeapi - 0.9.1-SNAPSHOT + 0.9.1 jokeapi Retrieve jokes from Sv443's JokeAPI https://github.com/ethauvin/jokeapi diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index c507607..2d216a8 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -58,7 +58,7 @@ public class JokeApiBuild extends Project { public JokeApiBuild() { pkg = "net.thauvin.erik"; name = "jokeapi"; - version = version(0, 9, 1, "SNAPSHOT"); + version = version(0, 9, 1); javaRelease = 11; downloadSources = true; From 2b4a7e553422a2dac1e6cab98ba49482c63a0ae1 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 26 Nov 2023 00:37:31 -0800 Subject: [PATCH 09/60] Updated version in README --- README.md | 4 ++-- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5308277..db277f8 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ To use with [bld](https://rife2.com/bld), include the following dependency in yo repositories = List.of(MAVEN_CENTRAL); scope(compile) - .include(dependency("net.thauvin.erik:cryptoprice:1.0.1")); + .include(dependency("net.thauvin.erik:jokeapi:0.9.1")); ``` Be sure to use the [bld Kotlin extension](https://github.com/rife2/bld-kotlin) in your project. @@ -111,7 +111,7 @@ repositories { } dependencies { - implementation("net.thauvin.erik:jokeapi:0.9.0") + implementation("net.thauvin.erik:jokeapi:0.9.1") } ``` diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 2d216a8..2f60162 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -58,7 +58,7 @@ public class JokeApiBuild extends Project { public JokeApiBuild() { pkg = "net.thauvin.erik"; name = "jokeapi"; - version = version(0, 9, 1); + version = version(0, 9, 2, "SNAPSHOT"); javaRelease = 11; downloadSources = true; From 89b51307b3c6183e7b8becd6e0c3ff46b586bce6 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 31 Jan 2024 15:50:19 -0800 Subject: [PATCH 10/60] Bumped bld to 1.8.0 --- .idea/intellij-javadocs-4.0.1.xml | 204 ++++++++++++++++++ .idea/libraries/bld.xml | 4 +- .vscode/settings.json | 2 +- README.md | 1 + lib/bld/bld-wrapper.jar | Bin 27321 -> 27293 bytes lib/bld/bld-wrapper.properties | 8 +- .../java/net/thauvin/erik/JokeApiBuild.java | 9 +- 7 files changed, 215 insertions(+), 13 deletions(-) create mode 100644 .idea/intellij-javadocs-4.0.1.xml diff --git a/.idea/intellij-javadocs-4.0.1.xml b/.idea/intellij-javadocs-4.0.1.xml new file mode 100644 index 0000000..4b17413 --- /dev/null +++ b/.idea/intellij-javadocs-4.0.1.xml @@ -0,0 +1,204 @@ + + + + + UPDATE + false + true + + TYPE + METHOD + FIELD + + + DEFAULT + PROTECTED + PUBLIC + + + + + + ^.*(public|protected|private)*.+interface\s+\w+.* + /**\n + * The interface ${name}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> + */ + + + ^.*(public|protected|private)*.+enum\s+\w+.* + /**\n + * The enum ${name}.\n + */ + + + ^.*(public|protected|private)*.+class\s+\w+.* + /**\n + * The type ${name}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> + */ + + + .+ + /**\n + * The type ${name}.\n + */ + + + + + .+ + /**\n + * Instantiates a new ${name}.\n +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + + + ^.*(public|protected|private)*\s*.*(\w(\s*<.+>)*)+\s+get\w+\s*\(.*\).+ + /**\n + * Gets ${partName}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if isNotVoid> + *\n + * @return the ${partName}\n +</#if> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + ^.*(public|protected|private)*\s*.*(void|\w(\s*<.+>)*)+\s+set\w+\s*\(.*\).+ + /**\n + * Sets ${partName}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if isNotVoid> + *\n + * @return the ${partName}\n +</#if> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + ^.*((public\s+static)|(static\s+public))\s+void\s+main\s*\(\s*String\s*(\[\s*\]|\.\.\.)\s+\w+\s*\).+ + /**\n + * The entry point of application.\n + + <#if element.parameterList.parameters?has_content> + *\n +</#if> + * @param ${element.parameterList.parameters[0].name} the input arguments\n +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + .+ + /**\n + * ${name}<#if isNotVoid> ${return}</#if>.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if isNotVoid> + *\n + * @return the ${return}\n +</#if> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + + + ^.*(public|protected|private)*.+static.*(\w\s\w)+.+ + /**\n + * The constant ${element.getName()}.\n + */ + + + ^.*(public|protected|private)*.*(\w\s\w)+.+ + /**\n + <#if element.parent.isInterface()> + * The constant ${element.getName()}.\n +<#else> + * The ${name}.\n +</#if> */ + + + .+ + /**\n + <#if element.parent.isEnum()> + *${name} ${typeName}.\n +<#else> + * The ${name}.\n +</#if>*/ + + + + + \ No newline at end of file diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index ca84ff0..bff4f62 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/.vscode/settings.json b/.vscode/settings.json index 133aa45..5633e79 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,7 @@ ], "java.configuration.updateBuildConfiguration": "automatic", "java.project.referencedLibraries": [ - "${HOME}/.bld/dist/bld-1.7.5.jar", + "${HOME}/.bld/dist/bld-1.8.0.jar", "lib/compile/*.jar", "lib/runtime/*.jar", "lib/test/*.jar" diff --git a/README.md b/README.md index db277f8..869c58c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) [![Kotlin](https://img.shields.io/badge/kotlin-1.9.21-7f52ff)](https://kotlinlang.org/) +[![bld](https://img.shields.io/badge/1.8.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) [![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/jokeapi?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/) diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 431fce99cf1e9d4da73b68a446b92aab039be9e9..1ae4f55822672a66d89f6c692ffc7f10b2d438c9 100644 GIT binary patch delta 25301 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 diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index d2d7adf..826f8dd 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,9 +1,9 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.1 -bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.0-SNAPSHOT -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.0-SNAPSHOT +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.2 +bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.0 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.0 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= -bld.version=1.7.5 +bld.version=1.8.0 diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 2f60162..d7b5d75 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -65,19 +65,16 @@ public class JokeApiBuild extends Project { autoDownloadPurge = true; repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); - final var kotlin = version(1, 9, 21); + final var kotlin = version(1, 9, 22); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin)) .include(dependency("org.json", "json", "20231013")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 4, 0))); scope(test) - .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 21))) + .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 22))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1))) - .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 27, 0))); + .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 0))); publishOperation() .repository(version.isSnapshot() ? repository(SONATYPE_SNAPSHOTS_LEGACY.location()) From 1a3c7fbac2ad6d340e8b5633e1823ca52df39ec3 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 31 Jan 2024 18:05:32 -0800 Subject: [PATCH 11/60] Minor cleanups --- pom.xml | 22 ++----------------- .../net/thauvin/erik/jokeapi/JokeApi.kt | 3 +++ .../net/thauvin/erik/jokeapi/JokeUtil.kt | 6 +++++ 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/pom.xml b/pom.xml index f2be8ba..61f1be6 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik jokeapi - 0.9.1 + 0.9.2-SNAPSHOT jokeapi Retrieve jokes from Sv443's JokeAPI https://github.com/ethauvin/jokeapi @@ -18,25 +18,7 @@ org.jetbrains.kotlin kotlin-stdlib - 1.9.21 - compile - - - org.jetbrains.kotlin - kotlin-stdlib-common - 1.9.21 - compile - - - org.jetbrains.kotlin - kotlin-stdlib-jdk7 - 1.9.21 - compile - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - 1.9.21 + 1.9.22 compile diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt index b4df9aa..a4dbda1 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt @@ -45,6 +45,9 @@ import java.util.stream.Collectors object JokeApi { private const val API_URL = "https://v2.jokeapi.dev/" + /** + * The logger instance. + */ @JvmStatic val logger: Logger by lazy { Logger.getLogger(JokeApi::class.java.simpleName) } diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index ff9f3e6..21006d5 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -123,6 +123,9 @@ private fun httpError(responseCode: Int): HttpErrorException { return httpException } +/** + * Parse Error. + */ internal fun parseError(json: JSONObject): JokeException { val causedBy = json.getJSONArray("causedBy") val causes = List(causedBy.length()) { i -> causedBy.getString(i) } @@ -136,6 +139,9 @@ internal fun parseError(json: JSONObject): JokeException { ) } +/** + * Parse Joke. + */ internal fun parseJoke(json: JSONObject, splitNewLine: Boolean): Joke { val jokes = mutableListOf() if (json.has("setup")) { From cdeb91c7d4f90f9b66fe0f46e5a67cfa75f87fac Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 31 Jan 2024 18:05:53 -0800 Subject: [PATCH 12/60] Added contributing section --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 869c58c..e2dbad4 100644 --- a/README.md +++ b/README.md @@ -165,3 +165,22 @@ error: false code: "fr" ``` - View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt#L48)... + +## Contributing + +If you want to contribute to this project, all you have to do is clone the GitHub +repository: + +```console +git clone git@github.com:ethauvin/jokeapi.git +``` + +Then use [bld](https://rife2.com/bld) to build: + +```console +cd jokeapi +./bld compile +``` + +The project has an [IntelliJ IDEA](https://www.jetbrains.com/idea/) project structure. You can just open it after all +the dependencies were downloaded and peruse the code. From cb0c2efd4fd44fd4fbe14b88257af43aa55e63ea Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 26 Feb 2024 17:41:33 -0800 Subject: [PATCH 13/60] Bumped bld to 1.9.0 --- .circleci/config.yml | 2 +- .idea/libraries/bld.xml | 4 ++-- .vscode/launch.json | 11 ----------- .vscode/settings.json | 15 --------------- README.md | 2 +- lib/bld/bld-wrapper.jar | Bin 27293 -> 27319 bytes lib/bld/bld-wrapper.properties | 8 ++++---- pom.xml | 2 +- .../java/net/thauvin/erik/JokeApiBuild.java | 6 +++--- 9 files changed, 12 insertions(+), 38 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json diff --git a/.circleci/config.yml b/.circleci/config.yml index 77889be..09d8896 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ defaults: &defaults TERM: dumb CI_NAME: "CircleCI" -defaults_gradle: &defaults_bld +defaults_bld: &defaults_bld steps: - checkout - run: diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index bff4f62..0b615c1 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 9f84d53..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "type": "java", - "name": "Run Tests", - "request": "launch", - "mainClass": "net.thauvin.erik.JokeapiTest" - } - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 5633e79..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "java.project.sourcePaths": [ - "src/main/java", - "src/main/resources", - "src/test/java", - "src/bld/java" - ], - "java.configuration.updateBuildConfiguration": "automatic", - "java.project.referencedLibraries": [ - "${HOME}/.bld/dist/bld-1.8.0.jar", - "lib/compile/*.jar", - "lib/runtime/*.jar", - "lib/test/*.jar" - ] -} diff --git a/README.md b/README.md index e2dbad4..3f4f787 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) [![Kotlin](https://img.shields.io/badge/kotlin-1.9.21-7f52ff)](https://kotlinlang.org/) -[![bld](https://img.shields.io/badge/1.8.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![bld](https://img.shields.io/badge/1.9.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) [![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/jokeapi?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/) diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 1ae4f55822672a66d89f6c692ffc7f10b2d438c9..c2adfe8730e64fdc0c51dc7994d0d143787eb1e2 100644 GIT binary patch delta 25244 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

^*a+>tbBpHE+pL~3DbtKbopH&MqggYR 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 diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 826f8dd..d824691 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,9 +1,9 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.2 -bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.0 -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.0 +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.3 +bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.1 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.2 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= -bld.version=1.8.0 +bld.version=1.9.0 diff --git a/pom.xml b/pom.xml index 61f1be6..f826f1e 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.json json - 20231013 + 20240205 compile diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index d7b5d75..1479469 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -68,12 +68,12 @@ public class JokeApiBuild extends Project { final var kotlin = version(1, 9, 22); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) - .include(dependency("org.json", "json", "20231013")) + .include(dependency("org.json", "json", "20240205")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 4, 0))); scope(test) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 22))) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1))) + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 2))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 2))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 0))); publishOperation() From ca04776f8b523ce22c79f0dc9221cc87a27c1342 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 10 May 2024 11:01:13 -0700 Subject: [PATCH 14/60] Bumped workflow actions to latest versions --- .github/workflows/bld.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index ba51eb1..19a51fd 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -1,6 +1,6 @@ name: bld-ci -on: [ push, pull_request, workflow_dispatch ] +on: [push, pull_request, workflow_dispatch] jobs: build-bld-project: @@ -11,18 +11,18 @@ jobs: strategy: matrix: - java-version: [ 17, 20 ] + java-version: [17, 21, 22] steps: - name: Checkout source repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up JDK ${{ matrix.java-version }} - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: - distribution: 'zulu' + distribution: "zulu" java-version: ${{ matrix.java-version }} - name: Grant bld execute permission From 7fecaa8f8229aecc86a79a5fd62cc205d887d5f4 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 10 May 2024 11:02:57 -0700 Subject: [PATCH 15/60] Bumped bld to version 1.9.1 --- .idea/libraries/bld.xml | 4 ++-- README.md | 2 +- lib/bld/bld-wrapper.jar | Bin 27319 -> 27319 bytes lib/bld/bld-wrapper.properties | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index 0b615c1..a2969be 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/README.md b/README.md index 3f4f787..faf7263 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) [![Kotlin](https://img.shields.io/badge/kotlin-1.9.21-7f52ff)](https://kotlinlang.org/) -[![bld](https://img.shields.io/badge/1.9.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![bld](https://img.shields.io/badge/1.9.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) [![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/jokeapi?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/) diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index c2adfe8730e64fdc0c51dc7994d0d143787eb1e2..ab2efd8985452cb4f800f9274e3ce17765c8bd90 100644 GIT binary patch delta 166 zcmdmfm2vx3M&1B#W)=|!4h{~6mcGRkdFz;g)W$v~V-UT0vvD^QnBi!~t_Nm#r<`X5 zGi1{Y!BUe0GZYnB7y`W6IrKB%X0tOeFt7q~fHxzP2m{>U$&)jjLE0wY%VOdrXNgNSGOa{$#vfXtd)lVuG6^&2^s delta 166 zcmdmfm2vx3M&1B#W)=|!4h{~6Cu<`o^42i}sf~R~#vpq0X5(%qFvHP|T@TFgPC3sA zX2_-)f~6)0W+*B$Fa&tBbL@1t7e9P b>6%PeFnuI54kDiA&jC~y0WxcHO_ntP^9?-6 diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index d824691..315d0e7 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -6,4 +6,4 @@ bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.2 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= -bld.version=1.9.0 +bld.version=1.9.1 From 185836c91aca374b243f87a1a033ba80c1b1a538 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 10 May 2024 11:05:16 -0700 Subject: [PATCH 16/60] Bumped Kotlin to version 1.9.24 --- README.md | 2 +- lib/bld/bld-wrapper.properties | 2 +- pom.xml | 2 +- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 8 +++++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index faf7263..c002abf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.21-7f52ff)](https://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/kotlin-1.9.24-7f52ff)](https://kotlinlang.org/) [![bld](https://img.shields.io/badge/1.9.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 315d0e7..3b10d0a 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,8 +1,8 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.3 -bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.1 bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.2 +bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.4 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= diff --git a/pom.xml b/pom.xml index f826f1e..41092ba 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ org.jetbrains.kotlin kotlin-stdlib - 1.9.22 + 1.9.24 compile diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 1479469..d880b09 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -55,6 +55,7 @@ import static rife.bld.dependencies.Scope.compile; import static rife.bld.dependencies.Scope.test; public class JokeApiBuild extends Project { + final File srcMainKotlin = new File(srcMainDirectory(), "kotlin"); public JokeApiBuild() { pkg = "net.thauvin.erik"; name = "jokeapi"; @@ -65,13 +66,13 @@ public class JokeApiBuild extends Project { autoDownloadPurge = true; repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); - final var kotlin = version(1, 9, 22); + final var kotlin = version(1, 9, 24); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.json", "json", "20240205")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 4, 0))); scope(test) - .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 22))) + .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 2))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 2))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 0))); @@ -107,7 +108,7 @@ public class JokeApiBuild extends Project { .signKey(property("sign.key")) .signPassphrase(property("sign.passphrase")); - jarSourcesOperation().sourceDirectories(new File(srcMainDirectory(), "kotlin")); + jarSourcesOperation().sourceDirectories(srcMainKotlin); } public static void main(String[] args) { @@ -142,6 +143,7 @@ public class JokeApiBuild extends Project { public void jacoco() throws IOException { new JacocoReportOperation() .fromProject(this) + .sourceFiles(srcMainKotlin) .execute(); } From e3c7146d061b727a325cc7acd85c44c70a3f8971 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 10 May 2024 11:05:57 -0700 Subject: [PATCH 17/60] Bumped JaCoCo extension to version 0.9.5 --- lib/bld/bld-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 3b10d0a..2895a28 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,7 +1,7 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.3 bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.2 +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.5 bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.4 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= From ab15abe11f32303f01448c08217578f439e4d94e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 10 May 2024 11:06:51 -0700 Subject: [PATCH 18/60] Bumped org.json to version 20240303 --- pom.xml | 2 +- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 41092ba..0d669f2 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.json json - 20240205 + 20240303 compile diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index d880b09..c6405d9 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -69,8 +69,8 @@ public class JokeApiBuild extends Project { final var kotlin = version(1, 9, 24); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) - .include(dependency("org.json", "json", "20240205")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 4, 0))); + .include(dependency("org.json", "json", "20240303")) scope(test) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 2))) From e8deffa5efee5f9bc615f19bffca90b3198cafbe Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 10 May 2024 11:07:51 -0700 Subject: [PATCH 19/60] Bumped UrlEncoder to version 1.5.0 --- pom.xml | 2 +- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0d669f2..cfa8eb9 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ net.thauvin.erik.urlencoder urlencoder-lib-jvm - 1.4.0 + 1.5.0 compile diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index c6405d9..e99f424 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -69,8 +69,8 @@ public class JokeApiBuild extends Project { final var kotlin = version(1, 9, 24); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) - .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 4, 0))); .include(dependency("org.json", "json", "20240303")) + .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 5, 0))); scope(test) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 2))) From e81c6a0492a72e96a93e151a903c0911bc88fec3 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 10 May 2024 11:12:41 -0700 Subject: [PATCH 20/60] Bumped AssertK to version 0.28.1 --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index e99f424..7b2f318 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -56,6 +56,7 @@ import static rife.bld.dependencies.Scope.test; public class JokeApiBuild extends Project { final File srcMainKotlin = new File(srcMainDirectory(), "kotlin"); + public JokeApiBuild() { pkg = "net.thauvin.erik"; name = "jokeapi"; @@ -75,7 +76,7 @@ public class JokeApiBuild extends Project { .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 2))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 2))) - .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 0))); + .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))); publishOperation() .repository(version.isSnapshot() ? repository(SONATYPE_SNAPSHOTS_LEGACY.location()) From e925f7a1c203f952c3a87d9160775d664b69b97e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 23 May 2024 22:12:13 -0700 Subject: [PATCH 21/60] Bumped Kotlin to version 2.0.0 --- README.md | 2 +- lib/bld/bld-wrapper.properties | 3 ++- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c002abf..2452985 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.24-7f52ff)](https://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/kotlin-2.0.0-7f52ff)](https://kotlinlang.org/) [![bld](https://img.shields.io/badge/1.9.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 2895a28..747e03c 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -2,7 +2,8 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.2 bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.5 -bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.4 +bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.7 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.4 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= bld.sourceDirectories= diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 7b2f318..a01fa8e 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -67,7 +67,7 @@ public class JokeApiBuild extends Project { autoDownloadPurge = true; repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); - final var kotlin = version(1, 9, 24); + final var kotlin = version(2, 0, 0); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.json", "json", "20240303")) From 8332db1a801072d07c80bf84d1833f6e2138bb3e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 25 May 2024 13:18:32 -0700 Subject: [PATCH 22/60] Bumped Detekt extension to version 0.9.4 --- lib/bld/bld-wrapper.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 747e03c..3bec20e 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,6 +1,5 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.2 bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.5 bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.7 bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.4 From e6bfcdad80c7d8b48ef6ed3981196a60393a94fd Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 25 May 2024 20:15:32 -0700 Subject: [PATCH 23/60] Reworked config builder. Added parameters' documentation. --- .idea/misc.xml | 16 +-- detekt-baseline.xml | 15 +- pom.xml | 2 +- .../net/thauvin/erik/jokeapi/JokeApi.kt | 103 ++++++++++++-- .../net/thauvin/erik/jokeapi/JokeConfig.kt | 132 ++++++++++++++---- .../net/thauvin/erik/jokeapi/JokeUtil.kt | 3 + .../thauvin/erik/jokeapi/JokeConfigTest.kt | 4 +- 7 files changed, 217 insertions(+), 58 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 7408350..a57f655 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -2,20 +2,8 @@ - - - - diff --git a/detekt-baseline.xml b/detekt-baseline.xml index 50acbf1..42699a3 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -1,12 +1,13 @@ - + - + - LongParameterList:JokeApi.kt$( amount: Int, categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, contains: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, auth: String = "", splitNewLine: Boolean = false ) - LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, contains: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, auth: String = "", splitNewLine: Boolean = false ) - LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, contains: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, auth: String = "" ) - LongParameterList:JokeConfig.kt$JokeConfig$( val categories: Set<Category>, val language: Language, val flags: Set<Flag>, val type: Type, val format: Format, val contains: String, val idRange: IdRange, val amount: Int, val safe: Boolean, val splitNewLine: Boolean, val auth: String ) - LongParameterList:JokeException.kt$JokeException$( val internalError: Boolean, val code: Int, message: String, val causedBy: List<String>, val additionalInfo: String, val timestamp: Long, cause: Throwable? = null ) + LongParameterList:JokeApi.kt$( amount: Int, categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, contains: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, auth: String = "", splitNewLine: Boolean = false ) + LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, contains: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, auth: String = "", splitNewLine: Boolean = false ) + LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, contains: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, auth: String = "" ) + LongParameterList:JokeConfig.kt$JokeConfig$( val categories: Set<Category>, val language: Language, val flags: Set<Flag>, val type: Type, val format: Format, val contains: String, val idRange: IdRange, val amount: Int, val safe: Boolean, val splitNewLine: Boolean, val auth: String ) + LongParameterList:JokeConfig.kt$JokeConfig$( var categories: Set<Category> = setOf(Category.ANY), var lang: Language = Language.EN, var blacklistFlags: Set<Flag> = emptySet(), var type: Type = Type.ALL, var format: Format = Format.JSON, var contains: String = "", var idRange: IdRange = IdRange(), var amount: Int = 1, var safe: Boolean = false, var splitNewLine: Boolean = false, var auth: String = "" ) + LongParameterList:JokeException.kt$JokeException$( val internalError: Boolean, val code: Int, message: String, val causedBy: List<String>, val additionalInfo: String, val timestamp: Long, cause: Throwable? = null ) MagicNumber:JokeUtil.kt$200 MagicNumber:JokeUtil.kt$399 MagicNumber:JokeUtil.kt$400 diff --git a/pom.xml b/pom.xml index cfa8eb9..1fd22ca 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ org.jetbrains.kotlin kotlin-stdlib - 1.9.24 + 2.0.0 compile diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt index a4dbda1..f1bc14a 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt @@ -101,8 +101,8 @@ object JokeApi { fun getRawJokes(config: JokeConfig): String { return rawJokes( categories = config.categories, - lang = config.language, - blacklistFlags = config.flags, + lang = config.lang, + blacklistFlags = config.blacklistFlags, type = config.type, format = config.format, contains = config.contains, @@ -124,8 +124,8 @@ object JokeApi { fun joke(config: JokeConfig = JokeConfig.Builder().build()): Joke { return joke( categories = config.categories, - lang = config.language, - blacklistFlags = config.flags, + lang = config.lang, + blacklistFlags = config.blacklistFlags, type = config.type, contains = config.contains, idRange = config.idRange, @@ -145,8 +145,8 @@ object JokeApi { fun jokes(config: JokeConfig): Array { return jokes( categories = config.categories, - lang = config.language, - blacklistFlags = config.flags, + lang = config.lang, + blacklistFlags = config.blacklistFlags, type = config.type, contains = config.contains, idRange = config.idRange, @@ -164,6 +164,32 @@ object JokeApi { * * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. * + * @param categories JokeAPI has a first, coarse filter that just categorizes the jokes depending on what the joke is + * about or who the joke is directed at. A joke about programming will be in the [Category.PROGRAMMING] category, dark + * humor will be in the [Category.DARK] category and so on. If you want jokes from all categories, you can instead use + * [Category.ANY], which will make JokeAPI randomly choose a category. + * @param lang There are two types of languages; system languages and joke languages. Both are separate from each other. + * All system messages like errors can have a certain system language, while jokes can only have a joke language. + * It is possible, that system languages don't yet exist for your language while jokes already do. + * If no suitable system language is found, JokeAPI will default to English. + * @param blacklistFlags Blacklist Flags (or just "Flags") are a more fine layer of filtering. Multiple flags can be + * set on each joke, and they tell you something about the offensiveness of each joke. + * @param type Each joke comes with one of two types: [Type.SINGLE] or [Type.TWOPART]. If a joke is of type + * [Type.TWOPART], it has a setup string and a delivery string, which are both part of the joke. They are separated + * because you might want to present the users the delivery after a timeout or in a different section of the UI. + * A joke of type [Type.SINGLE] only has a single string, which is the entire joke. + * @param contains If the search string filter is used, only jokes that contain the specified string will be returned. + * @param idRange If this filter is used, you will only get jokes that are within the provided range of IDs. + * You don't necessarily need to provide an ID range though, a single ID will work just fine as well. + * For example, an ID range of 0-9 will mean you will only get one of the first 10 jokes, while an ID range of 5 will + * mean you will only get the 6th joke. + * @param safe Safe Mode. If enabled, JokeAPI will try its best to serve only jokes that are considered safe for + * everyone. Unsafe jokes are those who can be considered explicit in any way, either through the used language, its + * references or its [flags][blacklistFlags]. Jokes from the category [Category.DARK] are also generally marked as + * unsafe. + * @param auth JokeAPI has a way of whitelisting certain clients. This is achieved through an API token. + * At the moment, you will only receive one of these tokens temporarily if something breaks or if you are a business + * and need more than 120 requests per minute. * @param splitNewLine Split newline within [Type.SINGLE] joke. */ fun joke( @@ -201,7 +227,35 @@ fun joke( * * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. * - * @param amount The required amount of jokes to return. + * @param amount This filter allows you to set a certain amount of jokes to receive in a single call. Setting the + * filter to an invalid number will result in the API defaulting to serving a single joke. Setting it to a number + * larger than 10 will make JokeAPI default to the maximum (10). + * @param categories JokeAPI has a first, coarse filter that just categorizes the jokes depending on what the joke is + * about or who the joke is directed at. A joke about programming will be in the [Category.PROGRAMMING] category, dark + * humor will be in the [Category.DARK] category and so on. If you want jokes from all categories, you can instead use + * [Category.ANY], which will make JokeAPI randomly choose a category. + * @param lang There are two types of languages; system languages and joke languages. Both are separate from each other. + * All system messages like errors can have a certain system language, while jokes can only have a joke language. + * It is possible, that system languages don't yet exist for your language while jokes already do. + * If no suitable system language is found, JokeAPI will default to English. + * @param blacklistFlags Blacklist Flags (or just "Flags") are a more fine layer of filtering. Multiple flags can be + * set on each joke, and they tell you something about the offensiveness of each joke. + * @param type Each joke comes with one of two types: [Type.SINGLE] or [Type.TWOPART]. If a joke is of type + * [Type.TWOPART], it has a setup string and a delivery string, which are both part of the joke. They are separated + * because you might want to present the users the delivery after a timeout or in a different section of the UI. + * A joke of type [Type.SINGLE] only has a single string, which is the entire joke. + * @param contains If the search string filter is used, only jokes that contain the specified string will be returned. + * @param idRange If this filter is used, you will only get jokes that are within the provided range of IDs. + * You don't necessarily need to provide an ID range though, a single ID will work just fine as well. + * For example, an ID range of 0-9 will mean you will only get one of the first 10 jokes, while an ID range of 5 will + * mean you will only get the 6th joke. + * @param safe Safe Mode. If enabled, JokeAPI will try its best to serve only jokes that are considered safe for + * everyone. Unsafe jokes are those who can be considered explicit in any way, either through the used language, its + * references or its [flags][blacklistFlags]. Jokes from the category [Category.DARK] are also generally marked as + * unsafe. + * @param auth JokeAPI has a way of whitelisting certain clients. This is achieved through an API token. + * At the moment, you will only receive one of these tokens temporarily if something breaks or if you are a business + * and need more than 120 requests per minute. * @param splitNewLine Split newline within [Type.SINGLE] joke. */ fun jokes( @@ -244,7 +298,40 @@ fun jokes( /** * Returns one or more jokes. * - * Sse the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. + * See the [JokeAPI Documentation](https://jokeapi.dev/#joke-endpoint) for more details. + * + * @param categories JokeAPI has a first, coarse filter that just categorizes the jokes depending on what the joke is + * about or who the joke is directed at. A joke about programming will be in the [Category.PROGRAMMING] category, dark + * humor will be in the [Category.DARK] category and so on. If you want jokes from all categories, you can instead use + * [Category.ANY], which will make JokeAPI randomly choose a category. + * @param lang There are two types of languages; system languages and joke languages. Both are separate from each other. + * All system messages like errors can have a certain system language, while jokes can only have a joke language. + * It is possible, that system languages don't yet exist for your language while jokes already do. + * If no suitable system language is found, JokeAPI will default to English. + * @param blacklistFlags Blacklist Flags (or just "Flags") are a more fine layer of filtering. Multiple flags can be + * set on each joke, and they tell you something about the offensiveness of each joke. + * @param type Each joke comes with one of two types: [Type.SINGLE] or [Type.TWOPART]. If a joke is of type + * [Type.TWOPART], it has a setup string and a delivery string, which are both part of the joke. They are separated + * because you might want to present the users the delivery after a timeout or in a different section of the UI. + * A joke of type [Type.SINGLE] only has a single string, which is the entire joke. + * @param contains If the search string filter is used, only jokes that contain the specified string will be returned. + * @param format Response Formats (or just "Formats") are a way to get your data in a different file format. + * Maybe your environment or language doesn't support JSON natively. In that case, JokeAPI is able to convert the + * JSON-formatted joke to a different format for you. + * @param idRange If this filter is used, you will only get jokes that are within the provided range of IDs. + * You don't necessarily need to provide an ID range though, a single ID will work just fine as well. + * For example, an ID range of 0-9 will mean you will only get one of the first 10 jokes, while an ID range of 5 will + * mean you will only get the 6th joke. + * @param amount This filter allows you to set a certain amount of jokes to receive in a single call. Setting the + * filter to an invalid number will result in the API defaulting to serving a single joke. Setting it to a number + * larger than 10 will make JokeAPI default to the maximum (10). + * @param safe Safe Mode. If enabled, JokeAPI will try its best to serve only jokes that are considered safe for + * everyone. Unsafe jokes are those who can be considered explicit in any way, either through the used language, its + * references or its [flags][blacklistFlags]. Jokes from the category [Category.DARK] are also generally marked as + * unsafe. + * @param auth JokeAPI has a way of whitelisting certain clients. This is achieved through an API token. + * At the moment, you will only receive one of these tokens temporarily if something breaks or if you are a business + * and need more than 120 requests per minute. */ fun rawJokes( categories: Set = setOf(Category.ANY), diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt index 4537d13..d1e1cfa 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt @@ -39,19 +39,33 @@ import net.thauvin.erik.jokeapi.models.* * * Use the [Builder] to create a new configuration. */ -class JokeConfig private constructor( - val categories: Set, - val language: Language, - val flags: Set, - val type: Type, - val format: Format, - val contains: String, - val idRange: IdRange, - val amount: Int, - val safe: Boolean, - val splitNewLine: Boolean, - val auth: String +class JokeConfig( + var categories: Set = setOf(Category.ANY), + var lang: Language = Language.EN, + var blacklistFlags: Set = emptySet(), + var type: Type = Type.ALL, + var format: Format = Format.JSON, + var contains: String = "", + var idRange: IdRange = IdRange(), + var amount: Int = 1, + var safe: Boolean = false, + var splitNewLine: Boolean = false, + var auth: String = "" ) { + constructor(builder: Builder) : this() { + categories = builder.categories + lang = builder.lang + blacklistFlags = builder.blacklistFlags + type = builder.type + format = builder.format + contains = "${builder.safe}:${builder.splitNewLine}" + idRange = builder.idRange + amount = builder.amount + safe = builder.safe + splitNewLine = builder.splitNewLine + auth = builder.auth + } + /** * [Builds][build] a new configuration. * @@ -72,20 +86,86 @@ class JokeConfig private constructor( var splitNewLine: Boolean = false, var auth: String = "" ) { - fun categories(categories: Set) = apply { this.categories = categories } - fun lang(language: Language) = apply { lang = language } - fun blacklistFlags(flags: Set) = apply { blacklistFlags = flags } - fun type(type: Type) = apply { this.type = type } - fun format(format: Format) = apply { this.format = format } - fun contains(search: String) = apply { contains = search } - fun idRange(idRange: IdRange) = apply { this.idRange = idRange } - fun amount(amount: Int) = apply { this.amount = amount } - fun safe(safe: Boolean) = apply { this.safe = safe } - fun splitNewLine(splitNewLine: Boolean) = apply { this.splitNewLine = splitNewLine } - fun auth(auth: String) = apply { this.auth = auth } + /** + * JokeAPI has a first, coarse filter that just categorizes the jokes depending on what the joke is + * about or who the joke is directed at. A joke about programming will be in the [Category.PROGRAMMING] + * category, dark humor will be in the [Category.DARK] category and so on. If you want jokes from all + * categories, you can instead use [Category.ANY], which will make JokeAPI randomly choose a category. + */ + fun categories(categories: Set): Builder = apply { this.categories = categories } - fun build() = JokeConfig( - categories, lang, blacklistFlags, type, format, contains, idRange, amount, safe, splitNewLine, auth - ) + /** + * There are two types of languages; system languages and joke languages. Both are separate from each other. + * All system messages like errors can have a certain system language, while jokes can only have a joke + * language. It is possible, that system languages don't yet exist for your language while jokes already do. + * If no suitable system language is found, JokeAPI will default to English. + */ + fun lang(language: Language): Builder = apply { lang = language } + + /** + * Blacklist Flags (or just "Flags") are a more fine layer of filtering. Multiple flags can be + * set on each joke, and they tell you something about the offensiveness of each joke. + */ + fun blacklistFlags(flags: Set): Builder = apply { blacklistFlags = flags } + + /** + * Each joke comes with one of two types: [Type.SINGLE] or [Type.TWOPART]. If a joke is of type + * [Type.TWOPART], it has a setup string and a delivery string, which are both part of the joke. They are + * separated because you might want to present the users the delivery after a timeout or in a different section + * of the UI. A joke of type [Type.SINGLE] only has a single string, which is the entire joke. + */ + fun type(type: Type): Builder = apply { this.type = type } + + /** + * Response Formats (or just "Formats") are a way to get your data in a different file format. + * Maybe your environment or language doesn't support JSON natively. In that case, JokeAPI is able to convert + * the JSON-formatted joke to a different format for you. + */ + fun format(format: Format): Builder = apply { this.format = format } + + /** + * If the search string filter is used, only jokes that contain the specified string will be returned. + */ + fun contains(search: String): Builder = apply { contains = search } + + /** + * If this filter is used, you will only get jokes that are within the provided range of IDs. + * You don't necessarily need to provide an ID range though, a single ID will work just fine as well. + * For example, an ID range of 0-9 will mean you will only get one of the first 10 jokes, while an ID range + * of 5 will mean you will only get the 6th joke. + */ + fun idRange(idRange: IdRange): Builder = apply { this.idRange = idRange } + + /** + * This filter allows you to set a certain amount of jokes to receive in a single call. Setting the + * filter to an invalid number will result in the API defaulting to serving a single joke. Setting it to a + * number larger than 10 will make JokeAPI default to the maximum (10). + */ + fun amount(amount: Int): Builder = apply { this.amount = amount } + + /** + * Safe Mode. If enabled, JokeAPI will try its best to serve only jokes that are considered safe for + * everyone. Unsafe jokes are those who can be considered explicit in any way, either through the used language, + * its references or its [flags][blacklistFlags]. Jokes from the category [Category.DARK] are also generally + * marked as unsafe. + */ + fun safe(safe: Boolean): Builder = apply { this.safe = safe } + + /** + * Split newline within [Type.SINGLE] joke. + */ + fun splitNewLine(splitNewLine: Boolean): Builder = apply { this.splitNewLine = splitNewLine } + + /** + * JokeAPI has a way of whitelisting certain clients. This is achieved through an API token. + * At the moment, you will only receive one of these tokens temporarily if something breaks or if you are a + * business and need more than 120 requests per minute. + */ + fun auth(auth: String): Builder = apply { this.auth = auth } + + /** + * Builds a new comment configuration. + */ + fun build() = JokeConfig(this) } } diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index 21006d5..be2d1d2 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -42,6 +42,9 @@ import java.net.HttpURLConnection import java.net.URL import java.util.logging.Level +/** + * Fetch a URL. + */ internal fun fetchUrl(url: String, auth: String = ""): String { if (JokeApi.logger.isLoggable(Level.FINE)) { JokeApi.logger.fine(url) diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt index e617dfc..8349c4c 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt @@ -154,8 +154,8 @@ internal class JokeConfigTest { }.build() assertThat(config, "config").all { prop(JokeConfig::categories).isEqualTo(categories) - prop(JokeConfig::language).isEqualTo(language) - prop(JokeConfig::flags).isEqualTo(flags) + prop(JokeConfig::lang).isEqualTo(language) + prop(JokeConfig::blacklistFlags).isEqualTo(flags) prop(JokeConfig::type).isEqualTo(type) prop(JokeConfig::format).isEqualTo(format) prop(JokeConfig::contains).isEqualTo(search) From a7db176830c3e36bf6d7ae242fa5564e83ff3a5d Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 26 May 2024 00:27:45 -0700 Subject: [PATCH 24/60] Make config constructor private --- .../net/thauvin/erik/jokeapi/JokeConfig.kt | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt index d1e1cfa..a03b2dd 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt @@ -39,32 +39,18 @@ import net.thauvin.erik.jokeapi.models.* * * Use the [Builder] to create a new configuration. */ -class JokeConfig( - var categories: Set = setOf(Category.ANY), - var lang: Language = Language.EN, - var blacklistFlags: Set = emptySet(), - var type: Type = Type.ALL, - var format: Format = Format.JSON, - var contains: String = "", - var idRange: IdRange = IdRange(), - var amount: Int = 1, - var safe: Boolean = false, - var splitNewLine: Boolean = false, - var auth: String = "" -) { - constructor(builder: Builder) : this() { - categories = builder.categories - lang = builder.lang - blacklistFlags = builder.blacklistFlags - type = builder.type - format = builder.format - contains = "${builder.safe}:${builder.splitNewLine}" - idRange = builder.idRange - amount = builder.amount - safe = builder.safe - splitNewLine = builder.splitNewLine - auth = builder.auth - } +class JokeConfig private constructor(builder: Builder) { + val categories = builder.categories + val lang = builder.lang + val blacklistFlags = builder.blacklistFlags + val type = builder.type + val format = builder.format + val contains = builder.contains + val idRange = builder.idRange + val amount = builder.amount + val safe = builder.safe + val splitNewLine = builder.splitNewLine + val auth = builder.auth /** * [Builds][build] a new configuration. @@ -164,7 +150,7 @@ class JokeConfig( fun auth(auth: String): Builder = apply { this.auth = auth } /** - * Builds a new comment configuration. + * Builds a new configuration. */ fun build() = JokeConfig(this) } From 3d684d86c62f3b6ae12f70bf4ef1207c99705dd2 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 27 May 2024 18:07:41 -0700 Subject: [PATCH 25/60] Bumped Kotlin extension to version 0.9.8 --- lib/bld/bld-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 3bec20e..2472505 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,7 +1,7 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.5 -bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.7 +bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.8 bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.4 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= From da0af8552e732069019d5b39484b0d076d6f2ee4 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 12 Jul 2024 15:01:40 -0700 Subject: [PATCH 26/60] Updated various SNAPSHOT dependencies --- .circleci/config.yml | 7 +++++++ .github/workflows/bld.yml | 4 ++++ .idea/libraries/bld.xml | 4 ++-- lib/bld/bld-wrapper.jar | Bin 27319 -> 29229 bytes lib/bld/bld-wrapper.properties | 11 ++++++----- .../java/net/thauvin/erik/JokeApiBuild.java | 10 +++++----- 6 files changed, 24 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 09d8896..18f0f1b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,9 +6,16 @@ defaults: &defaults TERM: dumb CI_NAME: "CircleCI" +orbs: + sdkman: joshdholtz/sdkman@0.2.0 + defaults_bld: &defaults_bld steps: - checkout + - sdkman/setup-sdkman + - sdkman/sdkman-install: + candidate: kotlin + version: 2.0.0 - run: name: Download the bld dependencies command: ./bld download diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 19a51fd..283cde3 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -2,6 +2,9 @@ name: bld-ci on: [push, pull_request, workflow_dispatch] +env: + KOTLIN_HOME: /usr/share/kotlinc + jobs: build-bld-project: runs-on: ubuntu-latest @@ -12,6 +15,7 @@ jobs: strategy: matrix: java-version: [17, 21, 22] + kotlin-version: [1.9.24, 2.0.0] steps: - name: Checkout source repository diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index a2969be..2fb5ff0 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index ab2efd8985452cb4f800f9274e3ce17765c8bd90..81fc0dd691582c1d59737a67330c6400f7d7faf2 100644 GIT binary patch delta 27205 zcmV)EK)}DZ)d8*K0S!<~0|XQR2nYxOD|hUX4SoYFckGdlFn_!WcvRK-KmML`ZgMA+ z3)$ELB9S$F1QnG48bXj@7EA&d7Q>JXB#_L+nF)()t@~EB*0$iTRjjoxC_?}hySa6D zsoH95Yxm__Yiq66mfz<+_s*R=$pq;0fByP#?>*al&UyFuJ!kUre-AuML<@`$Op<~o zM0z#`t2Xp@Rex=Z1p51fk*Zbp+fN2%n3QReNj^cjn*&<|RlR}GrmE%*n}eM(L7DS= zLOrpCf>d$IN|XG8EZwOmT(zX9H|QfvkZ&Lwj8t~@0NiNGF)7!gJjzc2*SaGb3-$@h z-V}^2kAyLGY=@wk#SNY=u}Dv7Q+3JkDnDh>7+&I7L4RY@4Oy8*g2r1kfeJB2=RhP9 z48<1rL^=eGZtyO*I*TUJaVAZ+=y;kUXxd1Kncff>2z7QhhP#5;dTnoypcxIv(7Bpd za)L!u8G3fFTi;>QbU|bES_Wc0y;TkpdV*0uO`{ARHp`-7DiM_LfKPV8KE^eq8>^=) zv#6XmK7Vf5INma5t^{(DqZ@icTY_Cn1JUl*V9ZYy_T;lInnNcE8Wjolhoe2QaKxTB z$1^Yb>j_V>XfF574sMSHL(!gaDB8jGr&)A5%@b7E72X!=4F|gF678+wfk>x@CsuRM z`4%lm-*Xve>k4;jcxPC2Ce;WsHwET|4W%m>w>Xur(+LGbT4T{#T8BlYKw1`v2+A7*qGY9yfa0v)o(+)zQ{SXO zstjwuKI&wO^mbKl@9WK`AZ;{hlSSPG5y{t`Lx8vu5UZ94V%WS4ZxmFWMr_xNDEui9 zs(F$v7WESJhc6bkyF!?XM^F`ECRaOuoqumpgqY^QZ!{LwN^G^C2575E+br5n&_QFg zRL8>M-l)dI3eX5W{lHgOVydY_Q8j#G=GO}?x`-}@%q(hH+_9{trDJ(bTU%XA6FA31 z|449Ca69iT7L0_j;7jQV;f?m7>U>y(D=oT;)$;hhz?NWbIMf-4t?G$&;|u&6ia`-wL)V&gokiE{ZX>|b zxasc=bOvjBdwJV8TJ$;I_ITcQYx9bh+PYTn_Vdx_O73`zMW5%6c`fxz>gIU6aO)Q= zx{X^4?bbAam~vmT=*zSdx@TLYCw~@95NKK&_8Q9FCfzQm!b9!g_Re5G3$Taqb&*Io zQkQ5j>CS|j0i60~x4}<$(A~^t_rSP%=WgqcgtrAYIO234^l3C0i(xs@%FWSm$VXp+ zo`&#LIJ&yB-xX>fJ%~15-<-;XT5Je|NIg96A#f@S-Ov_4t*3`A`Wig~7JqT*B53i5 zEOHdq8OqX+TJ#tb^@G@Wp>>;{(YcRsIE|`9y^L4S`NBbZ&o(ia@ z{T3adgU}Ulh-x-O!@UEsAafx!ZbGjmSeLs$W6`s82%0PwwzcZG;t_S_H!S)l_swEo zE5NRhN#BOOOYIK566x81S@k3}iISh5rx#3m(V~~=nhD`esgdefx0Ecz+^OwiWi+)A#LCuUb488jY;60pHJlvfb z(ZTUn@t%HT(QkP}{>GYmaD78fYb(bFzqjZQ^hcOo;HkDZ5RI}g;{~BBL8w2|UrhQx zi~h<+I%h~bG!w@2?o9gIFr>j5XS3s5`3K%Yr}Pi)o^0Do_*k3Ix^uL1=KKYc(S zu{K`kr}yb&{`v$SZPI9aAyhY{=MBeU`qZNT(0`$~16^Hu@oi!4EuB={aKvR-4?_wp z4&2?5Lk!)k0eUMKF$IFO<2|OSJ`{2~xF*LZ3|Ku@!wxH9wIb6Jra<6kVYQ4ZXR#;$ z4~zAxw}0UJa{UF$%9 ze~G8n=gG{!HA#0jRDYKduLdLm+VxL06e59d-AJ+P>e0NM1?^7H5!|#54i+j^_A4}o`z~uoH$H< zfqHeJSY(G^RAFx*%1M?uS)77dF|G-QPPYo0g=EYOdAu;139Z&_k zJTv>nTz_#oL`Td^x->)9##@>z=38QcScpBchYZFjUbBd!nfJw+mZ%YnP@`Ql2t8Wr z>uttbY>7H%Bfn-NXE$@jD8E=LMwz1C>t-cq^og^v$to|?gR+g5XkwiDnU0CYFBQuz zagJy~e_j_{(?vUCHYrNhEXopXVudMIT4I$r7k>e|YdJdM1A%nls6ePI5b3J5%NUoj zqHRgXX<&|qVV#{$)y&$f8D(pr*0I@eJ|L_yuC4B{s1ek;@7?5DJHSIs?6|2~2@_Y+`au%RngB z(|;FCda$CK?q&$R>@5J(9AZ>dY#8Y2?cz1`TjG3PgWAMNg7qS5iI^DRQ0n}F00&58 z)0mqQ1oxA~HcM>h^hd^`1h5M%aiO>fw21ax5Y$mvy-!>MU=m_;G&70 zme|E>ggd9RXyOjEMI)U)aTid)llTNQX;#G1e^H-6ETIsZ`vf8gSy|~5h!%2(dVj4x zfjD7GcP!Q)omW-GEwd~80$YQj%5Y>;mHwJj#R;c(ed23Su^xw&QS)_6JSrZ;HZakm z-mZjyx8sQFH-R!!Jdwx%I8`k{Hg10LIDLdU#Z#8pE8^H6JL}1$2s+yxZ3`?0EwP^$ zVPO&O3V8fMOFYdinB5r;#Xz;_*?&QTjB@2j!`L@F^~s#kJtGlOZ-^8 z0;eg+YEC!hrTCPbM`Kv8S>ko^6Lf^Sj0CVvk6W)h);sm+{ib-!6hF1Z&wqG9`NO+l zmED0T8w2k9jwOCBeu1roP%$)B;s~oLewmU(YYg;H*NQn?yerO@h?++Y>7{J;d#jpi{O0)18mRxS#di>pZIj7 z6*}>%Przl&s%UMhS>C#|xeaKMWJ$r$!3A9!DL$zLEjWs7c82?^2Da@8Rp~r{b{ms% zBP3VI3`=HeboWGCLxKKicR1#gu&k>SkfSHgt_(+`h)+X-*pB|727k{Y19q(PDvPS9 zGd_9@)A}u$%}5{Z?Ab?1c8m<)?kqnmlQc0DGCkrZGS*u<&*Fj$tO<-el&Mh z^aW#qu0SlnnO~l(+LH5`C$bY_u_Dq72aSDHA2& zD|*39y*xMLcd;ewIMpmuoMCJjaqP%=c_X+1zn}%k^!RT*39s zRgMNrH0L8Uz0xP)f~v;Fr}*V+xyF=hExAsfm+;P`!Oj8r&pWCb5k3Vr1sC^h3bKQk zts@A|)N(j9dt^>e4*)A3kn1fOkQ=mL5$JOKxGT6cxV<5~EvW4oMh#!8DZ_$hrY^TB+&a+N zUDLY>$|=^}=k>4T`IfX3`F0kFr;J&0fX_(AB$zMN&pWJ-wd8h7?vNKiQad@A?$yzD z$C1wRJbzI+JJ|9fOI|GDs%FH(D_ZJ3**Tkg>!C$HBQG=MXDxZTydpK$tapYr3>($} z*oP&2*&oQOlP58*K&)gPajhk<(>fwN5X&c@tqX3noRXl0BSd)(!+#;LgT`S#^NcedJNQ6;$&z1|J8dW3 zg?mDAIuOiUiJ_*vJrM$Fu4o8{Hf3CT*#6Hi@0RzN@?J~cC+|;Wi$($kgvTO*P!!SZ zl1LaFSYCXL%U`yvWSLJs00q$%4uPXSKrjjfKg62WXUc~YGdpt86pk$k4}`js`55^K z1b-`h4)pqkO=!!zUjHeS&I-pb)O*OTB>NAFfX zl0Pi>S~4#8@mU-g(Mh4rIErnvlTN1GpK{EcJf+MMAIXE3d|Ez(Ew{BVuLIwuOXSHz zmV8cr!%kV~v!Td9r*<$;N;xofl3bpeNPlo6&sF6a1Vs*KJlEDC?pC8b&37#MynMmV zQa1);-C-E|GmmmgIP#n}1lY`MP5}w|G9no|2uDwT&ywGlKY)?k%Fbrz%vbv4|9?SCR&@6JBq9l;LT7}9{J@fbm;V4CL+X|#4}aL= zr90)9|Fq;s@?Y$Bc5(XX2*>@aP5DU*?UqNvF!E8?pZ!>VYLO}bllJ6)CAS~86e$7j z?+JAWVejgjJqHhIV1jWzR?1R_%HZIZBQ17K(hR8fD^vMQm1QYE=UnoJ^?!gYYzy>2 zoiUn}WvNk|nahjV3dk#^LgiR0mlG9vI)~xS3BaFF`Iai++XXqcS@yJLsj-$Cr%iU> zmad+N1~$P`g-j7nTWC@455&5cA<*I+5p#n&&QgxV6gBx#)(hi?SD9X^D?1Oi!D{h7|U_g zRN_dQncyr-EmigQ@qbxcAi71+-lWgAinHtv9lhM)CCRZdK`OS6wQghvo^F3Q7ACp{ z41Kn0Fjb?aniLdW@v#nsHV0?+4%Kw7#TFl_b1c=uYR1}NSL&1!XsOyPwL)_uaF^V< zRyD7g>RjiLWjJp9G+M2;)EW+=NA*IzvnYxmRbiFPk(#}c4lw!W3}E=0mT7T zS29&vIy9gfS*iOJ482vcxVWTZ3-u6engP;<9&jk?!T_c0fl@MH#hW6^xd zQD0$3d4GV9=Z?%0KDFCc!QOj9KJ`_Ewkx8+NJY)2US!y~4I(@y(tM`5~`6cZQQ)K8q@JV95uGdcWCOT9I0I7{Q==Gx>f$N}{;OTEqga=D*ZP<`s> zg37DbR@y0gCW@V{ufWEuPFPn~e8&6}oPSl9=y`n#VO;SMMx<=gr+x*7t}N9()+SB` zD@%Rq*ESSRmT4HA6d!rc-@=C;q4$vaeve&NmZCjnwm+iw#MyIBI{B2jr=E6tU_)nD za3fpAKU?ZA3V~jBEX;1HzRqo*?$^S|FIrI#zO89FYei#SQyVrioa!*=iL0*KNq<0j zS!;8XXV9pWJAVLz<{D0wxQXIcpZceu`Tt*zTKGtyc~w(GbIoF%v2N41!X^%@bLVtq zl6j%2rm+s8viF{CvU)UE+jv-7)4J5B{$so0_L+WVcOcr0id8K&%a=pCm$%d{sXy0e zke$CyT&KdOlRfn9&H6gH6xoSNaDSz+pzD=sP0IfK@t<`7v?cICsfgd_E%mH;{%~Gi2yQlN^^a3>8h_xUHt8dq zHulSz_gNpW3`Bak>{J@D?w%;$W*I5*%@F(aU5IhTX%5IsR$`5T$fkil@HSrqOw$Kb zr~J&oiPXk)!9Mncv{&!BQeZkl4-@Mqp!iwylpetD46%4>TYS6z%*rCmdmMcL5 z+o@{!pDuD&>vJH+!zhHCoqt;z1N{zO64R}W^1(%`b6H!E&zX+bpS+{pu>p!hr{3Wl zZsx0YL$7lVy=ezXea;O-MDjyAyLS)a$!@XJycwP00li6teUhm$+4afNT-vJU8&#fb zXcI=d$Hp0H`;yquH6$*VF^WR^(yA}w-ntu|dNAQVs!Ux)#s)r3GJpBkI-V}gUIJLo z@3J~eU*I${p%a@=u{s_#1lHq2=@;eMbUX`qu^yQ2O$tnw3G!_0*(9hsT?g;XBc=@&R-48|U;>6P0Kc}Q*Gb-D ze$VGd=ZH~X8)N_1{eRU-8o!YBfxa0cgL9xl97*hOe_}HH_bQ1Wk^ljGAltzwvK$~Y zDU#zRAMps1iS8WMb@X+e!ax7gdBYAbD`@tJ@^%wlT|JTA6YWSCQoc14)u`x&MI8o! zVSDQw&%OT@ReQ(1)U+UNNpeDbo4pr6B9>1g>h5}&z9%NMxWt7EIz)&?!g02spB; zz?!3}YQX(bB7YW<({E>fIyTr6n2Nt4X(4^1!%5W_q{;9LDoHoZ2s~$+JAV~ ztD1k*kxagI41{{L=}VXR;|m|jgc`!a5n#HhRo+lIVc&DT)5LU=uk_e6iBKUdi_kbu zl6b~3rKb7b8Y36>y9?STV&7x4MZwnbS)OlSr<-7(IDc}Mp3eIg`fUzRpO z>#BA^C#Avh(MO$eG^Ecz8ibat{SE+j&C|fpn81VRHJv#myO4G;JFtU z5jv)+9)VNOJ|@F_OcDui)dZb80vn>5PLYIJnL6z7Z`i)Uqqe!|@MLu-4XI*hFlqhs zhqv-?0)OmEXXY74kXi5KGe=tCP;_P57qx)>4fwZ6(D>d!--fQh^whJL>9Yl$c=VqO zr*?q-Oae=ZumVZ0=$Y{d4W zu7My|*H<+c^+clsK@9jV7+C16gwOasHYNo4;fH?XN5+p$;}y$z)p!lkItVHOHE83 z&y(o>3-mjm|GbE%(GGb5&%=M7K)-Ku-cLI3i=6l8ocCk;UC4(wc$b3HOn>rWCjK)E z_Y)^oiB^>EBUO5kvfA^r2WiwkD%eZoO83yjy;OwiY3=)H#$K9PD)v$-$`vSA?WGfw zpC^~9y>u!+s!Q_>dfK;_7Cxc3QlKaG<2enJHPIMqrb%=T&7>A8qgHIY4I5iQOK2sX zP3Ib8(9^OPWsEh(;hklSH-9EL3qH$PaN$7`n0e7bs%yXm8E5ITAhS5TDOHMllm!}&eyPt?EcOI z`Rh1PRp_tD;3sJuk8fV;9hhlKVkR*Un9o4V^^EGW{PT=wXnniN-+$0LNL~ABv!Hzx zYO07+|4!OmF-Wm_#vZz$(1_C|z zq&wORjeT_2p(prvzjPs8Lc2)m4bK6p2yl+0E75W_*!CKlPuGHO*8!c^(*WIo{x@O7 zjr19?*>!Y_M#@5=ca7a4~8EpN!Ghhc6+G#yXN!LSK5*-U*W zjii9Vo!(0qI4+ z`Yxco1WtXKcGCAX5n3RC6X;Z9rY1t0ON5)8uM9w#ZOqcGz?w^#T`pmEIfTikn>>U$ zg^a@ho`x`osgnN&RI(aR-SP>g5^XK5bBMMci)5nRc7Kq52qpL9MxgeUJ@k|Ox8wBl zRd(UmrE&UQoc_c$2kHIxgY-eWP2+!n#{1}><@@MgO{Eq2B2NFtYm)ssY`+HV*Dn1k z5W;z@xX7r8i!A)JV2YWV{9(<@fZEK6i@ZWZ)2oKI)1@MZE`x@+25*~Q3n>TBA7k;a z&{%qvW`EJ^==l>`N^gKxZ$iJng)RP+y69)rOK($*-T|DS)1~P51^R`iPbtt*L#;-! zQKD7sZ7v0Fb12}W8;w$<45)JPerXc#KQsx}+!Q&7S<`xJQKuVxAE#(%$$vt@u>&J_I&a- z)Um1^WLlOV5EFQw!lsHBD39d>HIs?ZlCLucT-*&7u8r_T%57{@NdfEqPEbCizU0MaGuZk zvVZ1f75WOZn8?0Eg~szV9g;83+D*sJ%h*lh=lQvAlv9^6FT2nWR>*`QkJ5!e?Zxz2 zx)Sd%((TZPcR)~YfgU7!7=pV8<@=!txooq_W?~!sd)U@LK(zk|4E_Zp{tEN)K2_1* zAmSgu-}yV7f)6pnM--rc!2*ARx&95)^M4^={|7T2rrU)$K4I9bcxpi9X?my(0V zDO&7D)5FGG<5W<58r`P08K;q<8Sy2uKBXd46dfl1O$IaG`z-GQbxTb#(-c*vn14(3 zDNPoKp*%+JVsmd6^KJSbE+-$xdNPLeB5E+{j>Q_rXv!YeivR5KbcaYkK80DYpgu=9 z-asAe#0AW(1!5UEH7*(&z)Q`I2jRt(?-8y0M0-=&^JJp(tcu4Q@tIqu`6a8V91NUS zen?|*3YB09m2fmpah1nJ#=OX;(SO3C0x^oFh|x3)?-G&i%2)v?cskSr!>9rUPt%lH zU{gy|VGbGprCE$DV;;727#$>U5c{&xnoY_sCy>u?H2(_&(V4~$#D^E+)bmJ4vOyfihW}9A?-q!$Hf-ggDwz#+&?TK*ME_nbW-Ua zu@xS*17j6HBgo9SmnIg7i_45;M?X4V%C2{5TzobzuEgsaOqAIqA1N&dMz4RQk*6%@ zDY43IU}qZEe+8Vh8}PmePT3d5O)zS=>9?UV+yd8|L_TGS0?HO+sR;UJnixmZq2DS* zAzv(3a)c3>>XL3P*XGBpE9Yl4ug+ulCR^(O-?|y2*F)09dx3IWq%NO23`cUI4&-3 z$A=0+f!m%@ zAnqIy`e`2MGhOJD|0n2oj|hE!I_Uhvqod&D-lO2;%yc;6zlz|%WuwYOo<3yN_iMO- zo>4X;?8O@PID5RyB!AP5S`OKH^+%oMUKckb&$9F=vs?{BZyW5ZAZ%F}u@1A$ED#SA zh~07V)m3)s;WGW5e}7y&!X6uZ?1`o295AE#pm?0cbx&M8xtnI_PWzlr}+DxRHdsJR(qGsYVCQEA24j5+f%*#-Ev{eOC47v*5giG`W_#mmq$ zS7eCYhhJwXaq+|b;#EOS75l{-0$y<+KHe5^*575%e!uvYfCl+$!pD>Amoxdvg+6C;6O+HT`|!=B_BQ@nApRB? ze;*Y87ELF6vriiNWaykUzmB_oTM2`Ay(V43AU`V0$Bu1O&tpAZciNL1-0D4N0t+GOa607HoL3;gH-x4 z_O3m0dYqn4BpVQ`H0+VHxKiA5K$an+M>EWT=H}S7?Gs8niEoHSz+MBVgx@h+EOh6`5F4jK{)6^o})HTT)y z34(hP4?z2WmGZ=clrKO9@es`rUw@}k@dT{Eqf`k8;8gKAoi3iFYVj1+h`qE}#A&J6 z2g|UZI>k3>qc}+2;u*R`e1k3%hv;(g99<>8MK_CY!-xG2=6{|Zgunl&c#-ys@6+?* z2lR$`h29gd((lA;^k?xpR``a<6K{%1;w@N?pJKi5ze+-BQ%wit?MLR zj=FR3Wdcjb>$*%Rq#UEgXyrffjkvW9BQoe_nqjO!U8cyR$+E{-3I9HeN{v<8YWxFPKTz4FX1~gOaO-|q9@d+89P~~CT?u5CC4k%^m z@wCX4p-)JBLKDWX=3q6&MhzqqoU#{qflEg3z>*XpYI=ai?vdA&AAgY7v*6!=@3_2) zWu_cb(ggd`Feq>4)a3{5W&7x#?9jyJ7g=ZvjjS>9j<~$*To;su;RW(5fWy5WAA4+{oR~rbz+sDChsm7S!1)B2o_9EEp{lf8L>et$szOut`nvk5xcE03pKSwwkq zIv8sPHOZN@TF#;`%MvilEP6zi!ZuYATj7JU9L!QdFUm^#u{=>T%2MF%IJ({Fmd^mE zP1Ixb7@INUYFcM(F?zuYk3b*x86n{OAX#9KF#5gdWDb}qUUB@_GaW}nLo@naXy-c& zlS3J~^nVdOWXhj4nBt}^I1)F)DO1`z+2MF66SU;f#0SaG31IolNA&C0kGKJeJ_?j4 zLz+&(rcd=aEfZXhonS;9j-8;B8Pb!?n4psx_LAVM=V^ZO;qwk7O1qp?#Q^l%dx^z~ zY_zfk?c|free!or6$RqXxcvR9@`^$E2Y8}?;eP^LWpRuCD3E_mtpHQ}EiOM?RZ-5* zgYsi`V*kz2UR?f{Jys>P5>%OwxLRW_jlxRilTR)Hffv$Pc_xfY4b7Cb&>V~DRJnxC zlxNWrSx?L5GFmCmrggHx4WO`G7ayH2K00lDV8d&St;RNNY&lHec4G&~yAHr; zaDPc@_pfpLUxc+CuN_9o=<*=zw+Upazks1e18EPH##J`{jdsqu{QNzr^7s{3V^-lk zo-t6iUrj`aT4->C=X;X{q8q zn&&&Hs@wOe1@p3)R0V3Go=w~W62To)XMgUav*-B>c`3C_34kdy;i>rrB4xG2qS*xS`1R?3oX;KCI&Uaq1kvK{toHMkH?id+j0Tt};92d$OssapnUKyIK*WG8G^7u_#| zK*L7*mfS=?lHK%y>=7Aqv+&7Yk$)}2Vm#gx@h*|;#S(eGXqFLiu8fNFDw~Dab zE_TQr;xqC>alO1q+$Jv;x64b!eeyG!)9*u2_5nEfV&f9X%K$xKTxxs<+T59_13kN^(l?lnbvR9D91SJY^;8+H&unH=9>KkbgQGb&*#<{LB9u9ZtDc(?Z;O9Tl<0M3Wgf`9x%q`WT(^&2Z zPI0*{H?$twRCUHxa3|%JRoFsbzF&1i5)Qwf%tK8DvPfP*ro0l2coj{QSJQNP4VBAl zX$~CCQ{)Y9_F*EF{1!p}Jh z6G$wT&MtSt`zVzEaCUhuW@R|D+5E?8u%T>^+Pp`F2G#kEEWy~&fS|GiY6sDNb+N?b za=sgJb}~_6+qIja?{A?3`2~+%o9%F@k4g~EGKUr*9JxKkuGuwg*X-rN!{>LxL$KCe+!XdF?8%O7_+VG($f zdyto!dWGvl}~vxlBar3^R$a( zuj@V%{1>v)uj|1y>w55iSl2uId(5Z3h^*7Xgn>zi2Dp<`K>*(p4PYXIeN2wV#=2*o_{BwK3Ol!c-$_IaSqxo4mg?5 z^9nQg@N_a_r)ucHMRXP|a}Q5#1@!`DAQte;mtZMhhQIb*Sjq1p%KI)=%a`4R<77Hr zADuFbt#rM#m2T>BrH;`gdY+??#_dGuVm??sO&>uo)e(Q<$Q(I?l&p{ zHH-hQrvvjz$8D}I1y;o4oV(qpo@^*>EPs~MePfNu_tE6?vBpVrGs?zhm=_GHr|`z} z3InR+y|R=%u8rQGz!`aiGUZ#C`lmD%5mBjpn}1Hk_gwjNS7lDca=v0bpyR=6eOk@x zwL&k}KE<3sD)TT$Bz#6KbMR!z{1;8h_46fZX9Eizr1*8HSGJErLvp6_VGlC=T5FL0 zn#P0#tcU&wSYJqiwJQ}C`HZi+v2MO*9HM6#R)HEEq)`Rxz&`c#lS)_ZQO_2rZ(xci z<$v@7^{w2ggX%j^%Gv_;lJi+#puRh(zW=1Uvq1eQgR9gl1?qMC>kZ=>y0l&GQ9o^c zQfFbUK7<5!F)zEz_4$JMnc1Md@ma(amt6 zcG6Zjf7|G5w4I)kKZI>~SmX0+#v=}cPcpuauNdVSk7Ayu^fRuXgZg@ z6aWYa2mmX0?31%IDSsqPVRdd}XiaZqWiDfEVRLhhQ}0jHP!v6ncI#FjGAA;a;13wA z1EruM;*bmpM$Cl7=?w8xHwu)Lj&v>lTQU+M8V#TQqm1`Gs!XS5ZSrpKednBedi(nA z`=_q}o}j3qhhfZjwr#WKZkg|W>)^ol&9~<|g!s}+WccU|f0NaL!86h}X< zQH#3U@N9;Dqfp+n4lUEQyd86+wrAG^!e%h2VTdD(>(uiCuU4WD56=s$D~rm&6~iJ495;%kE53iWyw;W^wr4beVUPob9gA@JQn067$n{EcwEZ<08mQ@2z28o-Ejf{0Llaa z08mQ<1QY-W2nYZxckHvXGm8QPD|hUZK{hde+4lRMJCi$^+$Xmr_j68s>C~|kM6^KrgqH+qI=KvTQx;Rf4*xEH z|FkZDXxp@v?K=V;F{Z5ZgP~w-A(K`l6(jy2a#$xx?L3Dd~IXQ)#t zQ&HlpqAy4D(g@PLG>S&+G{&H@bPki@1O#{mqf3Gjj1rDqu5jKc+mAD7JWXJ7b*VWQ zmnThYbu1DLZL5_H&oyWgO=ijm?2Fo?;jZ3T0MptI{*+Hi?~;u!Qw*x0N~Y|8XrRX* z@nc}7!t|zv5Rz(xrqVQE-R<8Qs1Jua{IT`H*mk@{WByPK>|S1;-t%l~GR#dbXNHu; znR3Ayx~!9|oo&z@n#<$~0(x`uCFM>DX|n2Tb7(%Dr&EnVwG#Kj^d=C7?f&SBz@C_F zyTG7@bOA6Ap&}JOTM`x}DT+CNHK`f(1}&imsLa-27sxX;Wmv-hjrf}avDBbtlFvH$ zyu#ldkdn3BpbM!P6OIP=29)eH$?6pbt)x{bqp3u)DZ@IvR7b4_t)?}QgN|@F1R<~{ zJP7WJ>NaYLK7W zvAk}7tYf=`ZOnzK&T^7J0%UO7PAvp)ky)Jwi>ie(oeGxEpg)3Fj1X? zOyd*dG<9_aw)wjjMYi>J2STxiJsp9bSTG#&&`vBU8t#pB1j;)6p~+2LHEkp=bN*) zdwJ+SnDJn!r#A+S0{-q4R(a?XOryfRvB4U6=>UCFr%xI506iGD_<*A+K@u?Iffc&T zH!YT$^J)5wP7fP@^jZ2GY)ZVxO2;5*yE_7F2C+n+rlu+Dbo#uL`bvi!KEgCnAyn4c zE7@EY+YX5YW955zYgts0j82u@|AI88Uu3En+D5P09trQ3e5sWqe<{uti_OlNdg%~7 zCW&4pVSYl&)nTTo3Au0pk&r7V1tnjH=qZD~B0~;$M^`w13XMGyUvBb*ywp!e4LU~0 zApo#Dt9yHTA^`{r@GUJLWC?}jqF$X&#P#1=hhu79dYT@SKTj26Exm=5MbAs!`Wn;x zvvOw{w9P{=U{0omfWW0m);I9gv=8ZDz4Q`&OQ&y3yZv$;i4f)uR}zqZU_0zZ?cnYt z!_<;`!)twimuXD$2Z_nLU^Ez8sU*uwuh92(`hh|JMgN^P2iX{NaP9VY!4R%2&os!U z<{<}2GTWwhzjHKc`$heXZ;pWI|J6FGU#BtMc#@|=@^4RN=gJ|3hN(u6No>yrJgBBL9j zT&%rDL6{CAR*HC8pkYNc0A zQ_z_vcx%@)BUAtG<~~+3zF_L)P>*cabMdpw1l{sH`t1}NG#f!n^0iGpL6xL{gd|Wu z+s2XPMBe!N>~k=GiQ1t&^X(F6&LN#>I=zI82PwQo`sb%s8FTmWUn zoFg+;cNr~F1ROu1II;2fSxhgpp(=GzEtUh|wVS}|B9y=CBKD?${kRD6_cObuvCPnP}OoT{^KG;29k4 z|AcZ?8Snh{WmZkvUZhtrLOTdmmo`l5@tc6@o9FSZn(e4ORZ1vq%5%OY{$lThJgUJc zU_8szc(YgbCB4zAp%_#!FthcuSbCq4P}I{msK3j~i5!3V+?Yz9I(4*|-`+li*F#+T zCwX5oXqt1)FMN%x{h&o-n0AQJz~KfSXUF#PcZ@x&r2kUYU8yIMHFTT7sBb+Hp*fSv zSlZWaDH<1T{lNLwb@$~aLoE9=NHSUo3buLHLt?)w$qrH;^R~VB~=TIJprN|@VD zMl)mMFe$R9S6H*50I!*2y3aJH3!r{;njy^+#GKiAZ9OPr5X+w0IJLLkP5VO%P$hNA zXC`ITIka85mMA`X(4#UcOmR1IH1&;5?Idn+hvvAE=id%*S}$WB;tMCFA^W0YRkvq@ z(wka0)ZJewJ8xFG^uZHc9Hl{2IrHoM1wO}t^O>gOVn4bjo|x>xA+P~>iZrgr%Fwk9 zGPxN$#1)O*`cyA`>Z`l;gYRTLAVQC&%sq?~#)AXkB8@&P-4dh))0>its{;LC5%m3u z;LS@2v>`EG>MQy5ao+{kl{fd4Cw1ZI+5_fX%$7_tPz53IKg`wJoB%$ zjM*t($HL1!N_mDp?q{Ai-SnjL$nWvVY3MrxLk^;VZi9E2zKT0i)OYL;e4)imT|Fe3 zekwm1-mfZUgq+ zAacMW4{+MP6uL#Va&mL=*lM=`XEH-qaq5SH?DfPELZVTTr3%;W z%m*(&LS14C)K#yBB7R}@nv`;Vg#KED3MLE394D5dUkd();ASmOiP;;W9Ffirr*9cX z#4a7ZGQyWgYW^K5qZOPiH1llXG-_wVzJq~%`0k8*xU-9s(!{@p0ZIzyT(c%+CQ(=9 zy+a%1*H;MCqAhKmCJlKU=`PG}wpFICbYow^Sb~LwOq!{ps!(>JZ{G2QqPk!h2hsZ(^Kpv_sRGWoFr}Y8>ozmdMUe2uyOT=eW)Z zxjC2Xxcag!!wFtSKwZslM__epS8cyua$Gubix$A?Cy8Zxaf_ayc@v4{EQvbp)%i|v z>9SF{w6=rR19ydaC@_%}QjLzw+%Di$K%OZTrB>(&`JCcspVXZ|rGLm)r$x=OC{;zS z5yi!(hL%O^p)*}A-@_d?a}Q2yj@o~Q6bvuj8o$g#J zav1~1qjAb>FJ0a+1elfTNe{rE6#90!JX$0CQT>an>Wx|!T& zE{Z`G&b^aQWTKZS;wO;AP3WnW0lV>LAIiY{oKQ7}lQI`;;~GJHG&k1=_sRAJ>~(C= z_NzmjC_H|z{Y~KVqUscWJ-uul!*`3JBOxaZHH%#J(3h!+ZI1iH(BE(5nYq*|n;$UB zGh`C%3VOB80ubR5+`Dc;-PE?=H|I1;T^i7vZYu-wp1R$kG)!V`A&MnaJgBLJ5esc> zKe#%JAogW_O?2LLe`Cf)uJkIXc_u{re0^j8S~)R4iZ=b{N5naI5K7%sI`Lu1=a7Oi z!On!qRGgWkJMFItx_QC0KAt zH>u@PUS=v?RKFvLPnr*&lTB5FDmSj&BMVx?eE0 zU4vhCgvXy7tYFnuk659IX9<=b%HEo-GL!NuMs0M=%FbSh=*tyhgm7 z7GB*?L-$K18Nx+P*lM|O3691cv@t75E0w(y-r0H~EkT;(EMfZ1GZjx{RsD?W`%2dl za4`$RZZofbuB(kM!Iq1ycu}#L*aHIMP!fM8;Z*tr8=I{iou_u)dMX+@za*Thxt*ag`GF zXv7vZ8-7o(MILk)J!Rb&l8XkJu{nM9st3VDr9jZ!Pr#E zS|6vAZ+=@re-Iif{PvB@&F6GiRE_0m@#7@^B^tPWLrT0aQSCMo77d?6DO8)#&A zQ?RgquVce)*`Y|wFJx<8GWzE{$ui5 z`+S6?I9$tg3Grz2c%>~}--&2iw7bf0lDmM8ZmKYM=f_6qBJ0Jp61!)5or~9G$>gZv zFOsKkIHew0!Y-rL;(kVR8D%G%hKmKxMurHUc(`hV?0)IjID)uL>jiyGrR;PIu1(Bx z5LN#QF$b`!jRB!ul2*_%0NA@r<}Q zBUtXj_%YWNY|+9z9v@NsN<=D(wlc@(1(ytUij&HpJltxe?{&@>2r%;5n`Cq&m277o zMKj#~=;%AAPlJ-C_=f_4_=Ra4ZWZ2@GBzd*9-PewiPJT#lD;&$=quAjEusNAX*K&i zcB(8BDIbm;>QZ@D=#U5F-LrS^|>Mz7X&tgIJ+0(t z6kQ>fO;~ztqkUYnkZgO)v&|1LXx=|@$MF(R#BxBSW>8Gf+r|KYe#?eD$)$-zR@n^e zd@GgxN-;y3Oi=91uE(uP|m)t1khgJxyq)_yYt9}@Y*?n+_Pq#d~e%jE&AU?iHZRRkCsCG2oxYQ*H7a_6X`L7t2 z1{!;BG{`Ep$*NuGSaa;S(k}6h(tu92qi_XB!_(TYy{$^s;8sbZ*qXpoA2(WR>d-Kk z>_#-t;9h&b-HKW_1H@*`&E0TMdzwFIU+SXr2e!yrDI#bKPl9s%Hl zg5Zwg_$J#5eY1*u1tvXsCp`*%(~5j~CZBjGp9GQFx4C?$fF*!9XB6I?IyI3skq?TLf2RedPp2Az0sIJu#T612ce>eO?Ud z`Y^>J_Dka`4@<;CePpFJ`OqSnO z&^>Wp7tK_fn@Mf$%)=L-$cM1AcGjx(Z%s6Rcw?+3rXs>Bw$l8fE5l>w?+NPWbhS&2 z!CZX3*+s#0-J>`7GFBu@{$R%4S&$`}j%Jd8g$T~GGh-Dz@D`fkOyDm=IG3DBN2C^@ zc5X!x;Bwd8@iOu<;)T9smRH5wm!~tonYO8jCnWpw@7km8vgpF^Wy|ArtWwo!r;L8= zB+(GO`jpe_o`;Z^dcS~z(%>bcKAvE`l`dK_S3^^uCpW)UlUbGfd*vi?9n|&ZQFD>+ zxd-;yu0YQk;h%%3P=2dVa6lxx5^u0Hp_PEO`@CB-cI67dLpl7aWa`xAOA)IIt6zxw zLR52BuZ+(r0^LWjuy|i7<7r&}JKp@WfWAc8sgC=C@ZHu_E2nph*pZn+3u{6a>fXvbqP zM=MC|>5=#A=_Ndy%n%*&zM11XD4H-6q&OCM%K5?phmSUh3P>r_cVqW9p?bIFy*kRQ z8sB^_mHBZFKB|`x^@&D4@P`$b1Se;n0cHH^hWSgrg-=#k3=olgThMXDb>bgl0(XKT zv>&U0t73=vr>8T$dCxRgdBRxe4C-Yg0s#XAXOiVzhL(XE;zeBNBQc0tF0Uxb+MsZz zq4oi!NLT2S)b^TAO9gxUc~K!C(H7B>Sy|2SQ9t@6=cr7 z-_-&(v9n>ej7>iyZ$Lggscz_JuB6Xxq+AH)$-;0vcThPp=!+)ai03by%u@Quez~iQ zl<^%hU>fmj{@M`&lB7=8-L@83qbZ5PzPHF%{?`aW0=4B zCsJ-r+L%5?-#`=iXH!g;5(SO+XI}_wEAxr^Fu{gd5-d}`eU#%Rw zGOG6=#M!LMGlIa*>5s(uZ{b z)=BvL!)&||w=58TDcz-{dWNAok8_QGmy8>rc_@0Xx(D@%zFxP!Z9$Q~GtDnAEYju< zWg+;bMV^q0Xk+mcK3D>l*#`~Q!)T!zhCx{7Fdx}Z6|k8;k%Dp{MP(PgKQcW4?f60} z_-$k>ZhTH$l*G3WS)`yvUgtDw(LHgOBjjbZ4HY+&0`4{S3xYeg6%Cv&i`Dj=@-92i zU)Nu{`9QtZ(4Adzf)K9}VZ8jm-W<&?#?B?BhfM*P%RmlGWgLY$*Ys=ZY(N%o82@^H zPPU9t`R2%w6)PSi9bflfv&w))Ru>&Bk| zi_HEWiCVSg$3g%)-V-U-0WtkLHb@}hIzsMu$VdaRkz6v5j zW~=u(@A9NaZL;yme=1|=i)h&e5LYOsKk`E+6krL54+1A(38s>O6pE$a1>xG&7Ex*o zU-SS`p71vr(x`$t8n+4|W46_P6fu~F*oI+{ABD>MaJ)RIqx>@6biD;%UMX$?w~1Ia zQJ~?r;WlQo$N+^Mgd6&ObN{eV*3~nk9~@}=0;%`W(mBDNclo?@55hmfzzlKoX}Sy; zM1rv;A{#OzjMJ7sVyblD@nKeI|CCD_D_6i?RqdsJ{tOE}odtK9fhwaBb)v;&nt`ee z*Nt%t7f_Cdu_9sH?{6?@%VH!8!&64X$H@f7&d#{0P-%55 z|2<;lHn927P+F8G3jZNz*F~6Kg=vcEx5Z}LM49IP)WqC>VPfR|nXQZSbJKMcX)(wc zw@opNSp0Ap<I@8a(09@4}%kNqA#h6m_No_lO2tjgWMq!_$uj zeK7^)4$I9f=fWF$^Oqw%;j3N03j*l6)c&dj<63;Yb8PkC43V{@UaoXimnnWgIvZ|n zlc{}&yp?bwp6RRUFCn>K#A$kQI9u8+PSTz`nXnd*=AO(V4yB)ck#ojKi$Z*%9wEXy(@!vWib{mnWn`emQSVPo zN1!1WL`UveM?##v%P^#K;(Zz1Re|9+yK0w-oV+zO;Og1Ew^-trkEC~VuNZWux`j*= z=9DZTE^_QrmR$;M?0lYvnh|K@4_^3!Cep!OWz?TaC(o zKm&w4Jcgd)2{H9UYB(Vb2n&iBy*0(?q0K)DD>zXUzkfY4v>tFHDv}odA^%dvjWWV1 z(SattB?9O`6FWH7yT!g$t@o@rk~CA>v<54{4beFtYXEBnw}nS-Obkkb1))+72} z7OHabd#*eH6pL|;hXLwY`_%}NQhi=?TXmqUYjR`J*a-eOntmU0HH|*pk#OC!X_lq=YqC zQ?2r@9dQ^x{woghrA~Ca7X4KXU;UJr@tDBWDi-zeMPcFLaa&Q zDS7Zg3U}>9`&LO8Y0b`(1wUI84xW)#|F36?Se5yOLole=;6BVGSn-a8UrpxW^ce~ly_#ZWrvoe>a8&L+{W_`T`HNC zO?^;_iZ2&P=s`uMe%Zq3H#fq$1?7II@W7Hm`k~KxcJC8sJhp`!4Y6T*1oK0Mt#;C2 zDv!$g;xsdE4o<2*Ny31}y^Cq2GVUc*#gdrsu#$9#_S=rhyLi;gCB9m3hf1ZddE?}e z!VEBwjmc0MZlzWwR;d?PgMP#vQQSqm2B3QR(_{vure|0zZandqfDR(I+)`Oa>5PHN zRE}rejcnabxU~br)l0OsBhTfT8|Pg0j97!KxlU9U>XU5EnBR(=0_OPV%t%9g(f$`R zxfSe~qH;)y*S`6L9^iMjs+fyH3t;gFHGKUY<&t^6_S?Yzc2{bZ4UuF?W`Wq0E{3w8 z>O(uo`(Bw_+`M1Ie4zB+QtDHON^k-;TS&xwvRud(FBKkwGLO6v;Ba*6QskDs`o;Zp zig-Rv;Me?B{%5*5EDtfotJWSV`hBJfQj{~+W_Iglg^&uItGA_bX+VKuF}jYk(r<3e zKoJEg$!_|0;KT-1S+@2p$Xt-KWfG6Nq*5J(F|gvuc0S9Zf5a{Gn+wj_oupK=h+@gV z`bqp$wb9oPp8aS@jRtM-1w_(Xh~D^sm=gvG*^g=#7nEZh!5e2q+kkMvwT>xhYw|P6 zbvO2+Yg652tz=iKvf5-|iJ zAqw0$lzlGn&7}^$gEA1IsPd+Z3U?bCs= zeFV&4fcaT#jiPPf(F7F07lH8)2~HG9lL)tESWq)uclnd!Df3|v&5QY}@#^?NH;l3E zS_s*uP&O;!-s!AB?Cp`{XGJ4|i@ZdcZtJ8csMx;9zJg@tcb?q24q>RZyZKgn3Gk(v zK-*2^fiIjbvf)M{$7L{PN96cPq8{8`ok4*L@y!R_wJCT`bJ8?|F zx^@`e0Z*_seUGxMb5JXuJ=(Tr_K;9Vqq&%J)D?TXO_t60d5p)^+-;zF$X8Kh*MY>V z;;%uT{nhRM9qrQ+L^5UVL_I6p^zbedW~)5hXQf)i{K|cDaU4eP=ou35B2|hktSBPl z87!ijbUF0#`eLl6L^<4xy_5io^M9`x$xGRm?HX= zl3+p_MHl19@0u_m=HLA`ce&R@byWAJZabPyit^AOa^C$^!dN$mos%0}d|#b^raCuI zbbB(rw_Goq-Ml!_!(0WUh<5wgt2Vi{M>Ax?1A2cxl9Tg|qeF_u712SE@9*?|p(na; z=>CMEf-+yo{DtW%hh2@kzCKbg)ADxu-qPg2^bpg&qdY-y)x~VfBKjz7{t_}{g34%a z6}19EpSzd*pd7dtza zzN#5)KAjl4dE9V{8jUYDCsFiZxI#HyrcxVJlT;1XW1##n2dGAw{#qW9+d?U!(LDX1 z8}OG@WPjAA9e?A#9zu|Wut`hNjBLpV%RBj;@e4Ihui3!&Uc`Hbfhs5v;7vY9*7n45 zWOH1h$%-}) z7}y-St1N(e46-_5R?9@M%5u0CzQy4;tke5*^F%KbBIi6{z~ zhlt5Pj{9||=t0;pigS)KCBcB;gAXwBD6N(KwSu`mXejAtRayK~dZ~Mf`GouuGanb) z&9CHfEnO)%ovNYOw9*Zym%O!x@ZDgBi~>bxjE_i)9gvAsWD7cVSzp8$h?$2zYn}`xYqEpgtVBfC z<_r}P_CN$EzQj=NBv4zTNiBp{rS4HM0UO*<2L(?wP(_PSU(2A{wXy4wGm!$2s*^5J zaaa?D`**_)Z-KSrj!4HYSx=mezS^roF$)mD_R?4NBF)LA(THO}q+w>6QOZAyprk{m z3U|_u=06ifmt)>&0TFq{-j}M&g+iiLN(N;@W*`~PheP$f--t6+7-WwXqIN;Yi~kN^ zsS#_#ngREexbT%Yw))*E_HFzoBSP2{mkCIxt6Xv2nE77QE)BnqrG9z{o zaX`1%@Xt>&FRYM8C4CBKWtkOl8uYZOTB*B{Vb-Nrf*^xMt2{p0q0IMZ`VPDcUb zim=6{(jST4;PY5a=W5KuO~jgIEH-R7?E@Dwk_LF<3V333RDvNnv)D|3@*4gj(6fVa z3aBN7r03#xiKV2X&iO~C=?`k_A3ES{=_`6D7c0SirwIhM=U z%-76x{kKltNh$6s^-}z}lyA5psm73f-Bu2T6m^)waZW*&yeSUB2gpn(nMLj_B^oyM zA}1=MVT{4$Qe5PM+!O}+ln;gpXbT$hdWhMRzV7jQirq?5zO|z+imf*U%&dw(?u;zo z;mX$08)+Wp`nlRAhx4fh$P+WGE=`YI>s{?0i$wj~DqSO#2mMn&KH@wBGxir5>mWaX zg~VIqm)=r{Q&7lcKt;y&l&sOa&+;=%G9ylflTz0$7?v@N*dD)FATA05YNaeJ^rHII z!T6;5hEuOLQ+;HM#eyjgUS*+u3T{Q>CIhoF zb(*>kgFM<&U82sK8l=5cxx$7&rORSoa81G5b*8YTc4PT0Qv!2MuM^A_XYVoN0X)b7 zORn=;UD_|suF&u`FH~oMY_*|y4LWA%ChzWU6z%P6L)7@Px4+a3I*%hW6*sQD5MH=V z(iGZ6n4Vrd+wlYlDHzl$6*Dla$TO+H;mC|QhqCKJAEXBEGa!t7y026Dg3J`Tq2nf~ zvnM~%ZHRMtEUwt6rMfuzasX-$WcAo#5U)9+w#uP# z^=E3+gysAz+0;qu=b3;xzs5K{Mh3(9w3y*ii;Q2trS`G#O@Q(1^zn!OWTv@~1hOY< z>sgplM>tArG+4DWX6-Bm6l*1Wd3mGl-~wi1&XJYRc2;FkdYk$5x&u>WEgkOj)V21% z9YcUw=Nw~a2WmLMpef?EyJeEXW^}Q0j*NUeuo_P5SJwt^K(}!SGoDH-e(RYagp+fn zhT>P}^50>>Nx2uJ>z6)&IQ;10?HA7@A;%~XGV|P?dTS9@DP@QY7@a8lj=_@hLrj69 z?6c0d7H!;`kyZ6mz50tqnBp#|_SE)V%S4~SUxqF%8_p}MAnI=ksPG}NlR z+9ogI+bcV{YrG$z{F+A9k6b$PaEa}}#+X{$$NWt0wImn?4}P55;H|Yy(IbvjpE9=5 z)vQhhGJul;X!|(>cA`>#N9stIKF*=Yq?fp(Kc_k1T1>$kkNLQ(B1y#FkVH2+eomo{ zWFV{S>|)WUG51 z*Q5R;P9)j_Y=vjn0g-RwBThsQ%zh;8i)%u=PH(sk2%Bg7P5}V{2R}^9$2U6z{*x`B zN`3Xj*A6;&4A|U?5qOC8uvzY(Ru6Dak{B`U3U;{dSa;1e8GghoSY~RuoBx zKw+}~RQ*rBI{m+{{~e%t6LJWI{(q(w{|8%3Y63lj=O5wS_8;N>e*;YL{{u+Uvm*X4 zMgMb%1plq&UrtjfNr{_?>Hh*#MU7`UK|?_W{R98@zdESdB>l1y`!7@{LT|DCe?r+X zP*7C=ONhoUiOGT{322QX@t<-2&*?$_UxGRgP*CCul7<>mDyrWVe<;br!T+Zn@n3ZP Mr@H80GZfVS0|)-#IsgCw delta 25278 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 diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 2472505..3164e31 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,9 +1,10 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.5 -bld.extensions=com.uwyn.rife2:bld-kotlin:0.9.8 -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.4 -bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.downloadLocation= +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.4 +bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.0-SNAPSHOT +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.6 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.0-SNAPSHOT +bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= -bld.version=1.9.1 +bld.version=2.0.0-SNAPSHOT diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index a01fa8e..8a3b260 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -35,8 +35,8 @@ import rife.bld.BuildCommand; import rife.bld.Project; import rife.bld.extension.CompileKotlinOperation; import rife.bld.extension.DetektOperation; +import rife.bld.extension.DokkaOperation; import rife.bld.extension.JacocoReportOperation; -import rife.bld.extension.dokka.DokkaOperation; import rife.bld.extension.dokka.LoggingLevel; import rife.bld.extension.dokka.OutputFormat; import rife.bld.operations.exceptions.ExitStatusException; @@ -74,8 +74,8 @@ public class JokeApiBuild extends Project { .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 5, 0))); scope(test) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 2))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 2))) + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 3))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 3))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))); publishOperation() @@ -118,7 +118,7 @@ public class JokeApiBuild extends Project { @BuildCommand(summary = "Compiles the Kotlin project") @Override - public void compile() throws IOException { + public void compile() throws Exception { new CompileKotlinOperation() .fromProject(this) .execute(); @@ -141,7 +141,7 @@ public class JokeApiBuild extends Project { } @BuildCommand(summary = "Generates JaCoCo Reports") - public void jacoco() throws IOException { + public void jacoco() throws Exception { new JacocoReportOperation() .fromProject(this) .sourceFiles(srcMainKotlin) From f653a0be64e0e3de7dfa77f5c5fba567eb7ba80a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Fri, 12 Jul 2024 15:30:59 -0700 Subject: [PATCH 27/60] Cleaned up CI workflows --- .circleci/config.yml | 57 +++++++++++++++++++++++--------------- .github/workflows/bld.yml | 27 ++++++++---------- lib/bld/bld-wrapper.jar | Bin 29229 -> 29578 bytes 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 18f0f1b..17b50f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,8 @@ -version: 2 +version: 2.1 + +orbs: + sdkman: joshdholtz/sdkman@0.2.0 + defaults: &defaults working_directory: ~/repo environment: @@ -6,25 +10,31 @@ defaults: &defaults TERM: dumb CI_NAME: "CircleCI" -orbs: - sdkman: joshdholtz/sdkman@0.2.0 - -defaults_bld: &defaults_bld - steps: - - checkout - - sdkman/setup-sdkman - - sdkman/sdkman-install: - candidate: kotlin - version: 2.0.0 - - run: - name: Download the bld dependencies - command: ./bld download - - run: - name: Compile source with bld - command: ./bld compile - - run: - name: Run tests with bld - command: ./bld test +commands: + build_and_test: + parameters: + reports-dir: + type: string + default: "build/reports/test_results" + steps: + - checkout + - sdkman/setup-sdkman + - sdkman/sdkman-install: + candidate: kotlin + version: 2.0.0 + - run: + name: Download dependencies + command: ./bld download + - run: + name: Compile source + command: ./bld compile + - run: + name: Run tests + command: ./bld jacoco -reports-dir=<< parameters.reports-dir >> + - store_test_results: + path: << parameters.reports-dir >> + - store_artifacts: + path: build/reports/jacoco/test/html jobs: bld_jdk17: @@ -33,7 +43,8 @@ jobs: docker: - image: cimg/openjdk:17.0 - <<: *defaults_bld + steps: + - build_and_test bld_jdk20: <<: *defaults @@ -41,10 +52,10 @@ jobs: docker: - image: cimg/openjdk:20.0 - <<: *defaults_bld + steps: + - build_and_test workflows: - version: 2 bld: jobs: - bld_jdk17 diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 283cde3..d785a99 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -1,21 +1,20 @@ name: bld-ci -on: [push, pull_request, workflow_dispatch] +on: [ push, pull_request, workflow_dispatch ] env: + COVERAGE_JDK: "21" + COVERAGE_KOTLIN: "2.0.0" KOTLIN_HOME: /usr/share/kotlinc jobs: build-bld-project: runs-on: ubuntu-latest - env: - COVERAGE_SDK: "17" - strategy: matrix: - java-version: [17, 21, 22] - kotlin-version: [1.9.24, 2.0.0] + java-version: [ 17, 21, 22 ] + kotlin-version: [ 1.9.24, 2.0.0 ] steps: - name: Checkout source repository @@ -23,31 +22,29 @@ jobs: with: fetch-depth: 0 - - name: Set up JDK ${{ matrix.java-version }} + - name: Set up JDK ${{ matrix.java-version }} with Kotlin ${{ matrix.kotlin-version }} uses: actions/setup-java@v4 with: distribution: "zulu" java-version: ${{ matrix.java-version }} - - name: Grant bld execute permission - run: chmod +x bld - - - name: Download the bld dependencies + - name: Download dependencies run: ./bld download - - name: Compile source with bld + - name: Compile source run: ./bld compile - - name: Run tests with bld + + - name: Run tests run: ./bld jacoco - name: Remove pom.xml - if: success() && matrix.java-version == env.COVERAGE_SDK + if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN run: rm -rf pom.xml - name: SonarCloud Scan uses: sonarsource/sonarcloud-github-action@master - if: success() && matrix.java-version == env.COVERAGE_SDK + if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 81fc0dd691582c1d59737a67330c6400f7d7faf2..0dcc8fe99049d8f7fa462df703709aa0e5776830 100644 GIT binary patch delta 14895 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 delta 14565 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 U;fxQaWuIj3ObAtE{~z#w0R3z|%K!iX From 08780a5c7369b7febac4a63603275501aa8fb5d8 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 11 Sep 2024 01:06:11 -0700 Subject: [PATCH 28/60] Bumped bld to version 2.1.0 --- .circleci/config.yml | 2 +- .idea/bld.xml | 6 ++++++ .idea/libraries/bld.xml | 4 ++-- .idea/libraries/compile.xml | 4 ++-- .idea/libraries/runtime.xml | 4 ++-- .idea/libraries/test.xml | 4 ++-- README.md | 4 ++-- detekt-baseline.xml | 1 - lib/bld/bld-wrapper.jar | Bin 29578 -> 30440 bytes lib/bld/bld-wrapper.properties | 10 +++++----- 10 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 .idea/bld.xml diff --git a/.circleci/config.yml b/.circleci/config.yml index 17b50f1..8dabc3f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ commands: - sdkman/setup-sdkman - sdkman/sdkman-install: candidate: kotlin - version: 2.0.0 + version: 2.0.20 - run: name: Download dependencies command: ./bld download diff --git a/.idea/bld.xml b/.idea/bld.xml new file mode 100644 index 0000000..6600cee --- /dev/null +++ b/.idea/bld.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index 2fb5ff0..5c4010c 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/.idea/libraries/compile.xml b/.idea/libraries/compile.xml index 9bd86aa..99cc0c0 100644 --- a/.idea/libraries/compile.xml +++ b/.idea/libraries/compile.xml @@ -7,7 +7,7 @@ - - + + \ No newline at end of file diff --git a/.idea/libraries/runtime.xml b/.idea/libraries/runtime.xml index 2ae5c4b..d4069f2 100644 --- a/.idea/libraries/runtime.xml +++ b/.idea/libraries/runtime.xml @@ -8,7 +8,7 @@ - - + + \ No newline at end of file diff --git a/.idea/libraries/test.xml b/.idea/libraries/test.xml index b80486a..57ed5ef 100644 --- a/.idea/libraries/test.xml +++ b/.idea/libraries/test.xml @@ -8,7 +8,7 @@ - - + + \ No newline at end of file diff --git a/README.md b/README.md index 2452985..e618d1e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.0.0-7f52ff)](https://kotlinlang.org/) -[![bld](https://img.shields.io/badge/1.9.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![Kotlin](https://img.shields.io/badge/kotlin-2.0.20-7f52ff)](https://kotlinlang.org/) +[![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) [![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/jokeapi?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/) diff --git a/detekt-baseline.xml b/detekt-baseline.xml index 42699a3..79e77da 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -6,7 +6,6 @@ LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, contains: String = "", idRange: IdRange = IdRange(), safe: Boolean = false, auth: String = "", splitNewLine: Boolean = false ) LongParameterList:JokeApi.kt$( categories: Set<Category> = setOf(Category.ANY), lang: Language = Language.EN, blacklistFlags: Set<Flag> = emptySet(), type: Type = Type.ALL, format: Format = Format.JSON, contains: String = "", idRange: IdRange = IdRange(), amount: Int = 1, safe: Boolean = false, auth: String = "" ) LongParameterList:JokeConfig.kt$JokeConfig$( val categories: Set<Category>, val language: Language, val flags: Set<Flag>, val type: Type, val format: Format, val contains: String, val idRange: IdRange, val amount: Int, val safe: Boolean, val splitNewLine: Boolean, val auth: String ) - LongParameterList:JokeConfig.kt$JokeConfig$( var categories: Set<Category> = setOf(Category.ANY), var lang: Language = Language.EN, var blacklistFlags: Set<Flag> = emptySet(), var type: Type = Type.ALL, var format: Format = Format.JSON, var contains: String = "", var idRange: IdRange = IdRange(), var amount: Int = 1, var safe: Boolean = false, var splitNewLine: Boolean = false, var auth: String = "" ) LongParameterList:JokeException.kt$JokeException$( val internalError: Boolean, val code: Int, message: String, val causedBy: List<String>, val additionalInfo: String, val timestamp: Long, cause: Throwable? = null ) MagicNumber:JokeUtil.kt$200 MagicNumber:JokeUtil.kt$399 diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 0dcc8fe99049d8f7fa462df703709aa0e5776830..be0620dc8a742c3f8d48cb54675aa6d64d0ee1b1 100644 GIT binary patch delta 28389 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 T)BgmqTZ*MC5sabRf4cq;Ie|c@ delta 27525 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 k4iFF`vSRvb;!4Ut Date: Wed, 11 Sep 2024 01:07:15 -0700 Subject: [PATCH 29/60] Updated dependencies Bumped Kotlin to version 2.0.20 Bumped Junit to verson 5.11.0 --- .github/workflows/bld.yml | 7 +++---- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 7 ++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index d785a99..7b7a4b9 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -1,6 +1,6 @@ name: bld-ci -on: [ push, pull_request, workflow_dispatch ] +on: [push, pull_request, workflow_dispatch] env: COVERAGE_JDK: "21" @@ -13,8 +13,8 @@ jobs: strategy: matrix: - java-version: [ 17, 21, 22 ] - kotlin-version: [ 1.9.24, 2.0.0 ] + java-version: [17, 21, 22] + kotlin-version: [1.9.24, 2.0.20] steps: - name: Checkout source repository @@ -34,7 +34,6 @@ jobs: - name: Compile source run: ./bld compile - - name: Run tests run: ./bld jacoco diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 8a3b260..c6d24ba 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -67,15 +67,15 @@ public class JokeApiBuild extends Project { autoDownloadPurge = true; repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); - final var kotlin = version(2, 0, 0); + final var kotlin = version(2, 0, 20); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.json", "json", "20240303")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 5, 0))); scope(test) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 3))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 3))) + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 0))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 0))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))); publishOperation() @@ -83,6 +83,7 @@ public class JokeApiBuild extends Project { .withCredentials(property("sonatype.user"), property("sonatype.password")) : repository(SONATYPE_RELEASES_LEGACY.location()) .withCredentials(property("sonatype.user"), property("sonatype.password"))) + .repository(repository("github")) .info() .groupId(pkg) .artifactId(name) From 137201c3e7ff6ad72d3a7f5a8a6642db189f3a30 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 21 Sep 2024 13:10:08 -0700 Subject: [PATCH 30/60] Updated copyright --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt | 4 ++-- .../net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt | 2 +- .../net/thauvin/erik/jokeapi/exceptions/JokeException.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt | 2 +- 22 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index c6d24ba..fc53878 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -1,7 +1,7 @@ /* * JokeApiBuild.java * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt index f1bc14a..8222435 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt @@ -1,7 +1,7 @@ /* * JokeApi.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt index a03b2dd..d8e6ad5 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt @@ -1,7 +1,7 @@ /* * JokeConfig.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index be2d1d2..6338fb5 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -1,7 +1,7 @@ /* * JokeUtil.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -52,7 +52,7 @@ internal fun fetchUrl(url: String, auth: String = ""): String { val connection = URL(url).openConnection() as HttpURLConnection connection.setRequestProperty( - "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" + "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0" ) if (auth.isNotEmpty()) { connection.setRequestProperty("Authentication", auth) diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt index 815afcc..947fe04 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt @@ -1,7 +1,7 @@ /* * HttpErrorException.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt index 16d4ec8..3854116 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt @@ -1,7 +1,7 @@ /* * JokeException.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt index 4951d4a..55021ad 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt @@ -1,7 +1,7 @@ /* * Category.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt index af92e90..2f3b9d4 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt @@ -1,7 +1,7 @@ /* * Flag.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt index 2678a21..7a0e74a 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt @@ -1,7 +1,7 @@ /* * Format.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt index 62a6eb6..a92fdf1 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt @@ -1,7 +1,7 @@ /* * IdRange.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt index 0309977..413e133 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt @@ -1,7 +1,7 @@ /* * Joke.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt index 10c00fb..ddcb462 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt @@ -1,7 +1,7 @@ /* * Language.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt index b9e1106..20bdea3 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt @@ -1,7 +1,7 @@ /* * Parameter.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt index 59126b4..e19ee73 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt @@ -1,7 +1,7 @@ /* * Type.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt index d9f9b30..066f4ca 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt @@ -1,7 +1,7 @@ /* * ApiCallTest.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt index de9d48a..b9d59f5 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt @@ -1,7 +1,7 @@ /* * BeforeAllTests.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt index 3932afd..4570a81 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt @@ -1,7 +1,7 @@ /* * ExceptionsTest.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt index c08ce39..5c86c08 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt @@ -1,7 +1,7 @@ /* * GetJokeTest.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt index 2e07a2d..dffb187 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt @@ -1,7 +1,7 @@ /* * GetJokesTest.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt index 7bcf1c6..cfc7bbe 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt @@ -1,7 +1,7 @@ /* * GetRawJokesTest.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt index 8349c4c..eb01e33 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt @@ -1,7 +1,7 @@ /* * JokeConfigTest.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt index 4b390c8..56839e8 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt @@ -1,7 +1,7 @@ /* * JokeUtilTest.kt * - * Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: From 76f78a868839cabdffc1427e3bc5103323021464 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 22 Dec 2024 15:00:56 -0800 Subject: [PATCH 31/60] Made sure the connection is disconnected --- .../net/thauvin/erik/jokeapi/JokeUtil.kt | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index 6338fb5..3ef3acc 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -51,21 +51,25 @@ internal fun fetchUrl(url: String, auth: String = ""): String { } val connection = URL(url).openConnection() as HttpURLConnection - connection.setRequestProperty( - "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0" - ) - if (auth.isNotEmpty()) { - connection.setRequestProperty("Authentication", auth) - } - - if (connection.responseCode in 200..399) { - val body = connection.inputStream.bufferedReader().use { it.readText() } - if (JokeApi.logger.isLoggable(Level.FINE)) { - JokeApi.logger.fine(body) + try { + connection.setRequestProperty( + "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0" + ) + if (auth.isNotEmpty()) { + connection.setRequestProperty("Authentication", auth) } - return body - } else { - throw httpError(connection.responseCode) + + if (connection.responseCode in 200..399) { + val body = connection.inputStream.bufferedReader().use { it.readText() } + if (JokeApi.logger.isLoggable(Level.FINE)) { + JokeApi.logger.fine(body) + } + return body + } else { + throw httpError(connection.responseCode) + } + } finally { + connection.disconnect() } } From 37517a2845c9c2e4c68cbfec1211d51a09343caf Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 22 Dec 2024 15:10:32 -0800 Subject: [PATCH 32/60] Updated dependencies Bumped Kotlin to version 2.1.0 Bumped Kotlin extension to version 1.0.3 Bumped Dokka extension to version 1.0.2 Bumped JUnit to 5.11.4 Bumped UrlEncoder to version 1.6.0 --- .github/workflows/bld.yml | 4 ++-- .idea/kotlinc.xml | 4 ++-- README.md | 2 +- lib/bld/bld-wrapper.properties | 4 ++-- pom.xml | 4 ++-- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 8 ++++---- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 7b7a4b9..cc397af 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -13,8 +13,8 @@ jobs: strategy: matrix: - java-version: [17, 21, 22] - kotlin-version: [1.9.24, 2.0.20] + java-version: [17, 21, 23] + kotlin-version: [1.9.24, 2.1.0] steps: - name: Checkout source repository diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index f8467b4..a8d9757 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - - \ No newline at end of file + diff --git a/README.md b/README.md index e618d1e..a45b49c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.0.20-7f52ff)](https://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/kotlin-2.1.0-7f52ff)](https://kotlinlang.org/) [![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index ee5e7de..04271d1 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -2,9 +2,9 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.7 -bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.1 +bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.2 bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.8 -bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.2 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.3 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= bld.version=2.1.0 diff --git a/pom.xml b/pom.xml index 1fd22ca..0d3d213 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ org.jetbrains.kotlin kotlin-stdlib - 2.0.0 + 2.1.0 compile @@ -30,7 +30,7 @@ net.thauvin.erik.urlencoder urlencoder-lib-jvm - 1.5.0 + 1.6.0 compile diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index fc53878..ec95df3 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -67,15 +67,15 @@ public class JokeApiBuild extends Project { autoDownloadPurge = true; repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); - final var kotlin = version(2, 0, 20); + final var kotlin = version(2, 1, 0); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.json", "json", "20240303")) - .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 5, 0))); + .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 6, 0))); scope(test) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 0))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 0))) + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 4))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 4))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))); publishOperation() From 5ac8f910b59247cbba2947a0853c8753db46b778 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 22 Dec 2024 20:33:44 -0800 Subject: [PATCH 33/60] Only throw an HTTP error if the response body is empty --- .idea/runConfigurations/Run Tests.xml | 9 ------ .../net/thauvin/erik/jokeapi/JokeUtil.kt | 14 ++++----- .../thauvin/erik/jokeapi/ExceptionsTest.kt | 29 +++++++++---------- 3 files changed, 21 insertions(+), 31 deletions(-) delete mode 100644 .idea/runConfigurations/Run Tests.xml diff --git a/.idea/runConfigurations/Run Tests.xml b/.idea/runConfigurations/Run Tests.xml deleted file mode 100644 index df4d7d6..0000000 --- a/.idea/runConfigurations/Run Tests.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index 3ef3acc..2d1f6cb 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -59,15 +59,15 @@ internal fun fetchUrl(url: String, auth: String = ""): String { connection.setRequestProperty("Authentication", auth) } - if (connection.responseCode in 200..399) { - val body = connection.inputStream.bufferedReader().use { it.readText() } - if (JokeApi.logger.isLoggable(Level.FINE)) { - JokeApi.logger.fine(body) - } - return body - } else { + val stream = if (connection.responseCode in 200..399) connection.inputStream else connection.errorStream + val body = stream.bufferedReader().use { it.readText() } + if (body.isBlank()) { throw httpError(connection.responseCode) } + if (JokeApi.logger.isLoggable(Level.FINE)) { + JokeApi.logger.fine(body) + } + return body } finally { connection.disconnect() } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt index 4570a81..d441189 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt @@ -41,8 +41,6 @@ import net.thauvin.erik.jokeapi.models.Category import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource @ExtendWith(BeforeAllTests::class) internal class ExceptionsTest { @@ -63,19 +61,20 @@ internal class ExceptionsTest { } } - @ParameterizedTest - @ValueSource(ints = [400, 404, 403, 413, 414, 429, 500, 523, 666]) - fun `Validate HTTP Exceptions`(code: Int) { - val e = assertThrows { - fetchUrl("https://httpstat.us/$code") - } - assertThat(e, "fetchUrl($code)").all { - prop(HttpErrorException::statusCode).isEqualTo(code) - prop(HttpErrorException::message).isNotNull().isNotEmpty() - if (code < 600) - prop(HttpErrorException::cause).isNotNull().assertThat(Throwable::message).isNotNull() - else - prop(HttpErrorException::cause).isNull() + @Test + fun `Validate HTTP Exceptions`() { + val locs = ArrayList>() + locs.add(Pair("https://apichallenges.herokuapp.com/secret/note", 401)) + locs.add(Pair("https://apichallenges.herokuapp.com/todo", 404)) + + for ((url, code) in locs) { + val e = assertThrows { + fetchUrl(url) + } + assertThat(e, "fetchUrl($code)").all { + prop(HttpErrorException::statusCode).isEqualTo(code) + prop(HttpErrorException::message).isNotNull().isNotEmpty() + } } } } From b95e1541fbce6884b96e507c181fe92175c094b2 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 25 Dec 2024 18:04:40 -0800 Subject: [PATCH 34/60] Added JokeResponse data class --- .idea/misc.xml | 5 +++ README.md | 9 +++-- .../net/thauvin/erik/jokeapi/JokeApi.kt | 13 ++++--- .../net/thauvin/erik/jokeapi/JokeUtil.kt | 7 ++-- .../jokeapi/exceptions/HttpErrorException.kt | 1 - .../erik/jokeapi/models/JokeResponse.kt | 39 +++++++++++++++++++ .../thauvin/erik/jokeapi/models/Parameter.kt | 1 + .../net/thauvin/erik/jokeapi/ApiCallTest.kt | 15 ++++--- .../thauvin/erik/jokeapi/GetRawJokesTest.kt | 16 +++++--- .../thauvin/erik/jokeapi/JokeConfigTest.kt | 5 ++- .../net/thauvin/erik/jokeapi/JokeUtilTest.kt | 6 ++- 11 files changed, 88 insertions(+), 29 deletions(-) create mode 100644 src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt diff --git a/.idea/misc.xml b/.idea/misc.xml index a57f655..84b848d 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,9 +1,14 @@ + + + + + diff --git a/README.md b/README.md index a45b49c..ad7bac2 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ A simple library to retrieve jokes from [Sv443's JokeAPI](https://v2.jokeapi.dev ## Examples (TL;DR) ```kotlin -import net.thauvin.erik.jokeapi.getJoke +import net.thauvin.erik.jokeapi.joke val joke = joke() val safe = joke(safe = true) @@ -124,8 +124,9 @@ You can also retrieve one or more raw (unprocessed) jokes in all [supported form For example for YAML: ```kotlin -var joke = getRawJokes(format = Format.YAML, idRange = IdRange(22)) -println(joke) +var jokes = getRawJokes(format = Format.YAML, idRange = IdRange(22)) +println(jokes.data) +``` ``` ```yaml error: false @@ -158,7 +159,7 @@ val lang = JokeApi.apiCall( path = "french", params = mapOf(Parameter.FORMAT to Format.YAML.value) ) -println(lang) +println(lang.data) ``` ```yaml error: false diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt index 8222435..c33c75b 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt @@ -54,7 +54,7 @@ object JokeApi { /** * Makes a direct API call. * - * Sse the [JokeAPI Documentation](https://jokeapi.dev/#endpoints) for more details. + * See the [JokeAPI Documentation](https://jokeapi.dev/#endpoints) for more details. */ @JvmStatic @JvmOverloads @@ -64,7 +64,7 @@ object JokeApi { path: String = "", params: Map = emptyMap(), auth: String = "" - ): String { + ): JokeResponse { val urlBuilder = StringBuilder("$API_URL$endPoint") if (path.isNotEmpty()) { @@ -98,7 +98,7 @@ object JokeApi { */ @JvmStatic @Throws(HttpErrorException::class) - fun getRawJokes(config: JokeConfig): String { + fun getRawJokes(config: JokeConfig): JokeResponse { return rawJokes( categories = config.categories, lang = config.lang, @@ -213,7 +213,7 @@ fun joke( idRange = idRange, safe = safe, auth = auth - ) + ).data ) if (json.getBoolean("error")) { throw parseError(json) @@ -281,7 +281,7 @@ fun jokes( amount = amount, safe = safe, auth = auth - ) + ).data ) if (json.getBoolean("error")) { throw parseError(json) @@ -333,6 +333,7 @@ fun jokes( * At the moment, you will only receive one of these tokens temporarily if something breaks or if you are a business * and need more than 120 requests per minute. */ +@Throws(HttpErrorException::class) fun rawJokes( categories: Set = setOf(Category.ANY), lang: Language = Language.EN, @@ -344,7 +345,7 @@ fun rawJokes( amount: Int = 1, safe: Boolean = false, auth: String = "" -): String { +): JokeResponse { val params = mutableMapOf() // Categories diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index 2d1f6cb..a6457bb 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -45,7 +45,7 @@ import java.util.logging.Level /** * Fetch a URL. */ -internal fun fetchUrl(url: String, auth: String = ""): String { +internal fun fetchUrl(url: String, auth: String = ""): JokeResponse { if (JokeApi.logger.isLoggable(Level.FINE)) { JokeApi.logger.fine(url) } @@ -63,11 +63,10 @@ internal fun fetchUrl(url: String, auth: String = ""): String { val body = stream.bufferedReader().use { it.readText() } if (body.isBlank()) { throw httpError(connection.responseCode) - } - if (JokeApi.logger.isLoggable(Level.FINE)) { + } else if (JokeApi.logger.isLoggable(Level.FINE)) { JokeApi.logger.fine(body) } - return body + return JokeResponse(connection.responseCode, body) } finally { connection.disconnect() } diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt index 947fe04..bcf0173 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt @@ -44,7 +44,6 @@ class HttpErrorException @JvmOverloads constructor( cause: Throwable? = null ) : IOException(message, cause) { companion object { - @Suppress("ConstPropertyName") private const val serialVersionUID = 1L } } diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt new file mode 100644 index 0000000..acc129a --- /dev/null +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt @@ -0,0 +1,39 @@ +/* + * JokeResponse.kt + * + * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.jokeapi.models + +/** + * The Joke API response. + * + * @property code The HTTP status code. + * @property data The response text. + */ +data class JokeResponse(val code: Int, val data: String) diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt index 20bdea3..812ca33 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt @@ -34,6 +34,7 @@ package net.thauvin.erik.jokeapi.models /** * The available [URL Parameters](https://jokeapi.dev/#url-parameters). */ +@Suppress("unused") object Parameter { const val AMOUNT = "amount" const val CONTAINS = "contains" diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt index 066f4ca..5c41c7d 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt @@ -32,6 +32,7 @@ package net.thauvin.erik.jokeapi import assertk.assertThat +import assertk.assertions.isEqualTo import assertk.assertions.isGreaterThan import assertk.assertions.startsWith import net.thauvin.erik.jokeapi.JokeApi.apiCall @@ -51,8 +52,9 @@ internal class ApiCallTest { fun `Get Flags`() { // See https://v2.jokeapi.dev/#flags-endpoint val response = apiCall(endPoint = "flags") - val json = JSONObject(response) - assertAll("Validate JSON", + val json = JSONObject(response.data) + assertAll( + "Validate JSON", { assertFalse(json.getBoolean("error"), "apiCall(flags).error") }, { assertThat(json.getJSONArray("flags").length(), "apiCall(flags).flags").isGreaterThan(0) }, { assertThat(json.getLong("timestamp"), "apiCall(flags).timestamp").isGreaterThan(0) }) @@ -65,14 +67,16 @@ internal class ApiCallTest { endPoint = "langcode", path = "french", params = mapOf(Parameter.FORMAT to Format.YAML.value) ) - assertContains(lang, "code: \"fr\"", false, "apiCall(langcode, french, yaml)") + assertThat(lang.code).isEqualTo(200) + assertContains(lang.data, "code: \"fr\"", false, "apiCall(langcode, french, yaml)") } @Test fun `Get Ping Response`() { // See https://v2.jokeapi.dev/#ping-endpoint val ping = apiCall(endPoint = "ping", params = mapOf(Parameter.FORMAT to Format.TXT.value)) - assertThat(ping, "apiCall(ping, txt)").startsWith("Pong!") + assertThat(ping.code).isEqualTo(200) + assertThat(ping.data).startsWith("Pong!") } @Test @@ -82,6 +86,7 @@ internal class ApiCallTest { endPoint = "languages", params = mapOf(Parameter.FORMAT to Format.XML.value, Parameter.LANG to Language.FR.value) ) - assertThat(lang).startsWith("") + assertThat(lang.code).isEqualTo(200) + assertThat(lang.data).startsWith("") } } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt index cfc7bbe..3a96d1b 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt @@ -34,6 +34,7 @@ package net.thauvin.erik.jokeapi import assertk.all import assertk.assertThat import assertk.assertions.doesNotContain +import assertk.assertions.isEqualTo import assertk.assertions.isNotEmpty import assertk.assertions.startsWith import net.thauvin.erik.jokeapi.models.Format @@ -47,7 +48,8 @@ internal class GetRawJokesTest { @Test fun `Get Raw Joke with TXT`() { val response = rawJokes(format = Format.TXT) - assertThat(response, "rawJoke(txt)").all { + assertThat(response.code).isEqualTo(200) + assertThat(response.data, "rawJoke(data)").all { isNotEmpty() doesNotContain("Error") } @@ -56,24 +58,28 @@ internal class GetRawJokesTest { @Test fun `Get Raw Joke with XML`() { val response = rawJokes(format = Format.XML) - assertThat(response, "rawJoke(xml)").startsWith("\n\n false") + assertThat(response.code).isEqualTo(200) + assertThat(response.data, "rawJoke(xml)").startsWith("\n\n false") } @Test fun `Get Raw Joke with YAML`() { val response = rawJokes(format = Format.YAML) - assertThat(response, "rawJoke(yaml)").startsWith("error: false") + assertThat(response.code).isEqualTo(200) + assertThat(response.data, "rawJoke(yaml)").startsWith("error: false") } @Test fun `Get Raw Jokes`() { val response = rawJokes(amount = 2) - assertContains(response, "\"amount\": 2", false, "rawJoke(2)") + assertThat(response.code).isEqualTo(200) + assertContains(response.data, "\"amount\": 2", false, "rawJoke(2)") } @Test fun `Get Raw Invalid Jokes`() { val response = rawJokes(contains = "foo", safe = true, amount = 2, idRange = IdRange(160, 161)) - assertContains(response, "\"error\": true", false, "getRawJokes(foo)") + assertThat(response.code).isEqualTo(400) + assertContains(response.data, "\"error\": true", false, "getRawJokes(foo)") } } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt index eb01e33..d5c37c3 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt @@ -102,8 +102,9 @@ internal class JokeConfigTest { amount(2) safe(true) }.build() - val joke = getRawJokes(config) - assertContains(joke, "----------------------------------------------", false, "config.amount(2)") + val jokes = getRawJokes(config) + assertThat(jokes.code).isEqualTo(200) + assertContains(jokes.data, "----------------------------------------------", false, "config.amount(2)") } @Test diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt index 56839e8..42e47a0 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt @@ -33,6 +33,7 @@ package net.thauvin.erik.jokeapi import assertk.assertThat import assertk.assertions.contains +import assertk.assertions.isEqualTo import org.json.JSONException import org.json.JSONObject import org.junit.jupiter.api.Test @@ -54,7 +55,8 @@ internal class JokeUtilTest { @Test fun `Validate Authentication Header`() { val token = "AUTH-TOKEN" - val body = fetchUrl("https://postman-echo.com/get", token) - assertThat(body, "body").contains("\"authentication\": \"$token\"") + val response = fetchUrl("https://postman-echo.com/get", token) + assertThat(response.code).isEqualTo(200) + assertThat(response.data, "body").contains("\"authentication\": \"$token\"") } } From f0ccff6529512df6b53ad9d9d592edb6eacf222c Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 25 Dec 2024 18:18:14 -0800 Subject: [PATCH 35/60] 1.0.0-SNAPSHOT --- .idea/misc.xml | 5 +++++ README.md | 6 +++--- pom.xml | 2 +- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 84b848d..f2b4c1e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,12 +3,17 @@ + + + + + diff --git a/README.md b/README.md index ad7bac2..d78cbbd 100644 --- a/README.md +++ b/README.md @@ -95,10 +95,10 @@ joke.getJoke().forEach(System.out::println); To use with [bld](https://rife2.com/bld), include the following dependency in your build file: ```java -repositories = List.of(MAVEN_CENTRAL); +repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS_LEGACY); scope(compile) - .include(dependency("net.thauvin.erik:jokeapi:0.9.1")); + .include(dependency("net.thauvin.erik", "jokeapi", "1.0.0-SNAPSHOT")); ``` Be sure to use the [bld Kotlin extension](https://github.com/rife2/bld-kotlin) in your project. @@ -112,7 +112,7 @@ repositories { } dependencies { - implementation("net.thauvin.erik:jokeapi:0.9.1") + implementation("net.thauvin.erik:jokeapi:1.0.0-SNAPSHOT") } ``` diff --git a/pom.xml b/pom.xml index 0d3d213..2f8858d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik jokeapi - 0.9.2-SNAPSHOT + 1.0.0-SNAPSHOT jokeapi Retrieve jokes from Sv443's JokeAPI https://github.com/ethauvin/jokeapi diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index ec95df3..979bb2e 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -60,7 +60,7 @@ public class JokeApiBuild extends Project { public JokeApiBuild() { pkg = "net.thauvin.erik"; name = "jokeapi"; - version = version(0, 9, 2, "SNAPSHOT"); + version = version(1, 0, 0, "SNAPSHOT"); javaRelease = 11; downloadSources = true; From 97e0479ffb1f0d7477b0a0e69e5ad838fce9df0b Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 26 Dec 2024 11:16:24 -0800 Subject: [PATCH 36/60] Renamed JsonResource code to statusCode --- README.md | 7 +++- detekt-baseline.xml | 1 + .../erik/jokeapi/models/JokeResponse.kt | 6 +-- .../net/thauvin/erik/jokeapi/ApiCallTest.kt | 6 +-- .../thauvin/erik/jokeapi/GetRawJokesTest.kt | 41 +++++++++++-------- .../thauvin/erik/jokeapi/JokeConfigTest.kt | 2 +- .../net/thauvin/erik/jokeapi/JokeUtilTest.kt | 2 +- 7 files changed, 38 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index d78cbbd..b289e5c 100644 --- a/README.md +++ b/README.md @@ -154,13 +154,16 @@ A generic `apiCall()` function is available to access other [JokeAPI endpoints]( For example to retrieve the French [language code](https://v2.jokeapi.dev/#langcode-endpoint): ```kotlin -val lang = JokeApi.apiCall( +val response = JokeApi.apiCall( endPoint = "langcode", path = "french", params = mapOf(Parameter.FORMAT to Format.YAML.value) ) -println(lang.data) +if (response.statusCode == 200) { + println(response.data) +} ``` + ```yaml error: false code: "fr" diff --git a/detekt-baseline.xml b/detekt-baseline.xml index 79e77da..1a99819 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -22,6 +22,7 @@ WildcardImport:GetJokeTest.kt$import assertk.assertions.* WildcardImport:GetJokeTest.kt$import net.thauvin.erik.jokeapi.models.* WildcardImport:GetJokesTest.kt$import assertk.assertions.* + WildcardImport:GetRawJokesTest.kt$import assertk.assertions.* WildcardImport:JokeApi.kt$import net.thauvin.erik.jokeapi.models.* WildcardImport:JokeConfig.kt$import net.thauvin.erik.jokeapi.models.* WildcardImport:JokeConfigTest.kt$import assertk.assertions.* diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt index acc129a..11d4c56 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt @@ -33,7 +33,7 @@ package net.thauvin.erik.jokeapi.models /** * The Joke API response. * - * @property code The HTTP status code. - * @property data The response text. + * @property statusCode The HTTP status code. + * @property data The response body text. */ -data class JokeResponse(val code: Int, val data: String) +data class JokeResponse(val statusCode: Int, val data: String) diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt index 5c41c7d..492d829 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt @@ -67,7 +67,7 @@ internal class ApiCallTest { endPoint = "langcode", path = "french", params = mapOf(Parameter.FORMAT to Format.YAML.value) ) - assertThat(lang.code).isEqualTo(200) + assertThat(lang.statusCode).isEqualTo(200) assertContains(lang.data, "code: \"fr\"", false, "apiCall(langcode, french, yaml)") } @@ -75,7 +75,7 @@ internal class ApiCallTest { fun `Get Ping Response`() { // See https://v2.jokeapi.dev/#ping-endpoint val ping = apiCall(endPoint = "ping", params = mapOf(Parameter.FORMAT to Format.TXT.value)) - assertThat(ping.code).isEqualTo(200) + assertThat(ping.statusCode).isEqualTo(200) assertThat(ping.data).startsWith("Pong!") } @@ -86,7 +86,7 @@ internal class ApiCallTest { endPoint = "languages", params = mapOf(Parameter.FORMAT to Format.XML.value, Parameter.LANG to Language.FR.value) ) - assertThat(lang.code).isEqualTo(200) + assertThat(lang.statusCode).isEqualTo(200) assertThat(lang.data).startsWith("") } } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt index 3a96d1b..3466611 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt @@ -33,53 +33,60 @@ package net.thauvin.erik.jokeapi import assertk.all import assertk.assertThat -import assertk.assertions.doesNotContain -import assertk.assertions.isEqualTo -import assertk.assertions.isNotEmpty -import assertk.assertions.startsWith +import assertk.assertions.* import net.thauvin.erik.jokeapi.models.Format import net.thauvin.erik.jokeapi.models.IdRange +import net.thauvin.erik.jokeapi.models.JokeResponse import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import kotlin.test.assertContains @ExtendWith(BeforeAllTests::class) internal class GetRawJokesTest { @Test fun `Get Raw Joke with TXT`() { val response = rawJokes(format = Format.TXT) - assertThat(response.code).isEqualTo(200) - assertThat(response.data, "rawJoke(data)").all { - isNotEmpty() - doesNotContain("Error") + assertThat(response).all { + prop("statusCode", JokeResponse::statusCode).isEqualTo(200) + prop("data", JokeResponse::data).all { + isNotEmpty() + doesNotContain("Error") + } } } @Test fun `Get Raw Joke with XML`() { val response = rawJokes(format = Format.XML) - assertThat(response.code).isEqualTo(200) - assertThat(response.data, "rawJoke(xml)").startsWith("\n\n false") + assertThat(response).all { + prop("statusCode", JokeResponse::statusCode).isEqualTo(200) + prop("data", JokeResponse::data).startsWith("\n\n false") + } } @Test fun `Get Raw Joke with YAML`() { val response = rawJokes(format = Format.YAML) - assertThat(response.code).isEqualTo(200) - assertThat(response.data, "rawJoke(yaml)").startsWith("error: false") + assertThat(response).all { + prop("statusCode", JokeResponse::statusCode).isEqualTo(200) + prop("data", JokeResponse::data).startsWith("error: false") + } } @Test fun `Get Raw Jokes`() { val response = rawJokes(amount = 2) - assertThat(response.code).isEqualTo(200) - assertContains(response.data, "\"amount\": 2", false, "rawJoke(2)") + assertThat(response).all { + prop("statusCode", JokeResponse::statusCode).isEqualTo(200) + prop("data", JokeResponse::data).isNotEmpty() + } } @Test fun `Get Raw Invalid Jokes`() { val response = rawJokes(contains = "foo", safe = true, amount = 2, idRange = IdRange(160, 161)) - assertThat(response.code).isEqualTo(400) - assertContains(response.data, "\"error\": true", false, "getRawJokes(foo)") + assertThat(response).all { + prop("statusCode", JokeResponse::statusCode).isEqualTo(400) + prop("data", JokeResponse::data).contains("\"error\": true") + } } } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt index d5c37c3..a311a71 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt @@ -103,7 +103,7 @@ internal class JokeConfigTest { safe(true) }.build() val jokes = getRawJokes(config) - assertThat(jokes.code).isEqualTo(200) + assertThat(jokes.statusCode).isEqualTo(200) assertContains(jokes.data, "----------------------------------------------", false, "config.amount(2)") } diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt index 42e47a0..7a05c27 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt @@ -56,7 +56,7 @@ internal class JokeUtilTest { fun `Validate Authentication Header`() { val token = "AUTH-TOKEN" val response = fetchUrl("https://postman-echo.com/get", token) - assertThat(response.code).isEqualTo(200) + assertThat(response.statusCode).isEqualTo(200) assertThat(response.data, "body").contains("\"authentication\": \"$token\"") } } From b0631046b9c3f26ecf5503ef41f315b2dc857e6c Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 1 Jan 2025 16:50:07 -0800 Subject: [PATCH 37/60] Bumped Json to version 20241224 --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 979bb2e..5f505c4 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -70,7 +70,7 @@ public class JokeApiBuild extends Project { final var kotlin = version(2, 1, 0); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) - .include(dependency("org.json", "json", "20240303")) + .include(dependency("org.json", "json", "20241224")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 6, 0))); scope(test) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) From ccfe3ac4db0ee7d2e75375521c3711ff650ae989 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 1 Jan 2025 16:51:39 -0800 Subject: [PATCH 38/60] Updated copyright --- LICENSE.txt | 2 +- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt | 2 +- .../net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt | 2 +- .../kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt | 2 +- src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt | 2 +- src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 4331a4d..82ecd17 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright 2022-2023 Erik C. Thauvin (erik@thauvin.net) +Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 5f505c4..9d3c42b 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -1,7 +1,7 @@ /* * JokeApiBuild.java * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt index c33c75b..474aa27 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt @@ -1,7 +1,7 @@ /* * JokeApi.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt index d8e6ad5..a4d4901 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeConfig.kt @@ -1,7 +1,7 @@ /* * JokeConfig.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index a6457bb..460211c 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -1,7 +1,7 @@ /* * JokeUtil.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt index bcf0173..f2e8529 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/HttpErrorException.kt @@ -1,7 +1,7 @@ /* * HttpErrorException.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt index 3854116..ac77344 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/exceptions/JokeException.kt @@ -1,7 +1,7 @@ /* * JokeException.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt index 55021ad..cfb008e 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Category.kt @@ -1,7 +1,7 @@ /* * Category.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt index 2f3b9d4..be2e21f 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Flag.kt @@ -1,7 +1,7 @@ /* * Flag.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt index 7a0e74a..1beb9d3 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Format.kt @@ -1,7 +1,7 @@ /* * Format.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt index a92fdf1..73d45ec 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/IdRange.kt @@ -1,7 +1,7 @@ /* * IdRange.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt index 413e133..c2124ae 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Joke.kt @@ -1,7 +1,7 @@ /* * Joke.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt index 11d4c56..d34f2c3 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/JokeResponse.kt @@ -1,7 +1,7 @@ /* * JokeResponse.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt index ddcb462..3ee166e 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Language.kt @@ -1,7 +1,7 @@ /* * Language.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt index 812ca33..8962b2a 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt @@ -1,7 +1,7 @@ /* * Parameter.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt index e19ee73..4fd80fe 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/models/Type.kt @@ -1,7 +1,7 @@ /* * Type.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt index 492d829..6153825 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ApiCallTest.kt @@ -1,7 +1,7 @@ /* * ApiCallTest.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt index b9d59f5..50ce4b2 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/BeforeAllTests.kt @@ -1,7 +1,7 @@ /* * BeforeAllTests.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt index d441189..eb6837a 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/ExceptionsTest.kt @@ -1,7 +1,7 @@ /* * ExceptionsTest.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt index 5c86c08..78d34a9 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt @@ -1,7 +1,7 @@ /* * GetJokeTest.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt index dffb187..ea49211 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokesTest.kt @@ -1,7 +1,7 @@ /* * GetJokesTest.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt index 3466611..aa85337 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt @@ -1,7 +1,7 @@ /* * GetRawJokesTest.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt index a311a71..a4d4e0c 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeConfigTest.kt @@ -1,7 +1,7 @@ /* * JokeConfigTest.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt index 7a05c27..d50b97a 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/JokeUtilTest.kt @@ -1,7 +1,7 @@ /* * JokeUtilTest.kt * - * Copyright 2022-2024 Erik C. Thauvin (erik@thauvin.net) + * Copyright 2022-2025 Erik C. Thauvin (erik@thauvin.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: From 3afbfb26ed35f0ef6b5a6e68bd9ce11e8b82d031 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 16 Mar 2025 13:12:40 -0700 Subject: [PATCH 39/60] Bump bld to version 2.2.1 --- .idea/libraries/bld.xml | 4 ++-- README.md | 2 +- lib/bld/bld-wrapper.jar | Bin 30440 -> 30440 bytes 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index 5c4010c..153a060 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/README.md b/README.md index b289e5c..ed6f2f8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.1.0-7f52ff)](https://kotlinlang.org/) [![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) [![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/jokeapi?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/jokeapi/) diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index be0620dc8a742c3f8d48cb54675aa6d64d0ee1b1..1eb86cf1499953d882eea146008c67bc5ccdebe2 100644 GIT binary patch delta 203 zcmaFymhr_~M!o=VW)=|!4h{|m-^~$G6ZvXcK=j6b6B{sNa-Y4%=Jz(UnZUfwefC{Y zmW&gd9z;y7;2a}_^`p=LB0E{9L{8*i9|;9^1_lOJAP(?mWD;RO*f%+^ q#0g^0mJ$yzV^V1_L?9f-SXb%-5&2dc3zaJK;{dr5Wb)*-W!3 Date: Sun, 16 Mar 2025 13:13:36 -0700 Subject: [PATCH 40/60] Bump Kotlin to version 2.1.10 --- .github/workflows/bld.yml | 2 +- README.md | 2 +- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index cc397af..08a73b4 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: java-version: [17, 21, 23] - kotlin-version: [1.9.24, 2.1.0] + kotlin-version: [1.9.25, 2.1.10] steps: - name: Checkout source repository diff --git a/README.md b/README.md index ed6f2f8..a4e6631 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) -[![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![Kotlin](https://img.shields.io/badge/kotlin-2.1.10-7f52ff)](https://kotlinlang.org/) [![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 9d3c42b..5191775 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -67,7 +67,7 @@ public class JokeApiBuild extends Project { autoDownloadPurge = true; repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); - final var kotlin = version(2, 1, 0); + final var kotlin = version(2, 1, 10); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.json", "json", "20241224")) From 256903cec10a048aadeef9249c0e4cc0e8c4dd54 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 16 Mar 2025 13:15:40 -0700 Subject: [PATCH 41/60] Update extensions dependencies Bump Detekt extension to version 0.9.9 Bump Dokka extension to version 1.0.3 Bump Jacoco Report extension to version 0.9.9 Bump Kotlin extension to version 1.0.4 --- lib/bld/bld-wrapper.properties | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 04271d1..154abb0 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,10 +1,10 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.7 -bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.2 -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.8 -bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.3 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.9 +bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.3 +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.9 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.4 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= -bld.version=2.1.0 +bld.version=2.2.1 From 427dc1a24833ba7f034a5254a6d6c21d79745a53 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 16 Mar 2025 13:16:42 -0700 Subject: [PATCH 42/60] Bump org.json to version 20250107 --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 5191775..5fec68c 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -70,7 +70,7 @@ public class JokeApiBuild extends Project { final var kotlin = version(2, 1, 10); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) - .include(dependency("org.json", "json", "20241224")) + .include(dependency("org.json", "json", "20250107")) .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 6, 0))); scope(test) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) From 944fbf122842ce341a9c07d8b14ff74edc8f9dd5 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 16 Mar 2025 13:17:08 -0700 Subject: [PATCH 43/60] Bump JUnit to version 5.12.1 --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 5fec68c..3cc16f4 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -74,8 +74,8 @@ public class JokeApiBuild extends Project { .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", version(1, 6, 0))); scope(test) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 4))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 4))) + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 1))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 1))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))); publishOperation() From b17a4fd58814e3fc3a2b85c3a489aa9ceecca24f Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 16 Mar 2025 15:32:14 -0700 Subject: [PATCH 44/60] Cleanup tests --- .../net/thauvin/erik/jokeapi/GetJokeTest.kt | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt index 78d34a9..e5a7d39 100644 --- a/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt @@ -70,15 +70,12 @@ internal class GetJokeTest { @Test fun `Get Joke with ID`() { - val id = 172 + val id = 201 val joke = joke(idRange = IdRange(id)) logger.fine(joke.toString()) assertThat(joke, "joke($id)").all { - prop(Joke::flags).all { - contains(Flag.EXPLICIT) - contains(Flag.NSFW) - } - prop(Joke::id).isEqualTo(172) + prop(Joke::flags).contains(Flag.RELIGIOUS); + prop(Joke::id).isEqualTo(id) prop(Joke::category).isEqualTo(Category.PUN) } } @@ -137,12 +134,10 @@ internal class GetJokeTest { @Test fun `Get Joke with Split Newline`() { - val joke = joke( - categories = setOf(Category.DARK), type = Type.SINGLE, idRange = IdRange(178), splitNewLine = true - ) + val joke = joke(type = Type.SINGLE, idRange = IdRange(18), splitNewLine = true) logger.fine(joke.toString()) assertThat(joke::joke, "joke(splitNewLine=true)").all { - size().isEqualTo(2) + size().isGreaterThanOrEqualTo(2) each { containsNone("\n") } @@ -177,13 +172,12 @@ internal class GetJokeTest { @Test fun `Get Joke using Search`() { - val id = 265 - val search = "his wife" + val search = "UDP joke" val joke = - joke(contains = search, categories = setOf(Category.PROGRAMMING), idRange = IdRange(id), safe = true) + joke(contains = search, categories = setOf(Category.PROGRAMMING), safe = true) logger.fine(joke.toString()) assertThat(joke, "joke($search)").all { - prop(Joke::id).isEqualTo(id) + prop(Joke::id).isEqualTo(0) prop(Joke::joke).any { it.contains(search) } From 4cc92e956f1cfb783a0a5c392ff897b567a5cfc3 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 16 Mar 2025 15:37:59 -0700 Subject: [PATCH 45/60] Update root pom --- pom.xml | 4 ++-- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2f8858d..2a9d9e6 100644 --- a/pom.xml +++ b/pom.xml @@ -18,13 +18,13 @@ org.jetbrains.kotlin kotlin-stdlib - 2.1.0 + 2.1.10 compile org.json json - 20240303 + 20250107 compile diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 3cc16f4..be69f63 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -167,6 +167,12 @@ public class JokeApiBuild extends Project { pomRoot(); } + @Override + public void publishLocal() throws Exception { + super.publishLocal(); + pomRoot(); + } + @BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory") public void pomRoot() throws FileUtilsErrorException { PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(), From 8978b56750290ea928371cf395e20b41ef85724a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 16 Mar 2025 16:54:21 -0700 Subject: [PATCH 46/60] Fix fetchUrl handling of HTTP errors with html content types --- src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index 460211c..9bd8ac1 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -59,9 +59,10 @@ internal fun fetchUrl(url: String, auth: String = ""): JokeResponse { connection.setRequestProperty("Authentication", auth) } - val stream = if (connection.responseCode in 200..399) connection.inputStream else connection.errorStream + val isSuccess = connection.responseCode in 200..399 + val stream = if (isSuccess) connection.inputStream else connection.errorStream val body = stream.bufferedReader().use { it.readText() } - if (body.isBlank()) { + if (!isSuccess && (body.isBlank() || connection.contentType.contains("text/html"))) { throw httpError(connection.responseCode) } else if (JokeApi.logger.isLoggable(Level.FINE)) { JokeApi.logger.fine(body) From 4b4f778490a9ddd20ce2a946d9ac47b7aa76a069 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 16 Mar 2025 17:29:06 -0700 Subject: [PATCH 47/60] Version 1.0.0 --- README.md | 4 ++-- pom.xml | 2 +- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a4e6631..1d5a1f4 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ To use with [bld](https://rife2.com/bld), include the following dependency in yo repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS_LEGACY); scope(compile) - .include(dependency("net.thauvin.erik", "jokeapi", "1.0.0-SNAPSHOT")); + .include(dependency("net.thauvin.erik", "jokeapi", "1.0.0")); ``` Be sure to use the [bld Kotlin extension](https://github.com/rife2/bld-kotlin) in your project. @@ -112,7 +112,7 @@ repositories { } dependencies { - implementation("net.thauvin.erik:jokeapi:1.0.0-SNAPSHOT") + implementation("net.thauvin.erik:jokeapi:1.0.0") } ``` diff --git a/pom.xml b/pom.xml index 2a9d9e6..52e318e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik jokeapi - 1.0.0-SNAPSHOT + 1.0.0 jokeapi Retrieve jokes from Sv443's JokeAPI https://github.com/ethauvin/jokeapi diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index be69f63..1d01225 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -60,7 +60,7 @@ public class JokeApiBuild extends Project { public JokeApiBuild() { pkg = "net.thauvin.erik"; name = "jokeapi"; - version = version(1, 0, 0, "SNAPSHOT"); + version = version(1, 0, 0); javaRelease = 11; downloadSources = true; From f16d54fd5327275c5927e3baccf4c5c4ffb4246a Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 16 Mar 2025 20:43:54 -0700 Subject: [PATCH 48/60] Fix yaml example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1d5a1f4..0539e27 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ For example for YAML: var jokes = getRawJokes(format = Format.YAML, idRange = IdRange(22)) println(jokes.data) ``` -``` + ```yaml error: false category: "Programming" @@ -143,8 +143,8 @@ flags: id: 22 safe: true lang: "en" - ``` + - View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokesTest.kt#L46)... ## Extending From e211159757dfacf6a87629801921188ef8950278 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 04:24:15 -0700 Subject: [PATCH 49/60] Add Junit Platform Launcher dependency --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 1d01225..dfb9478 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -76,6 +76,7 @@ public class JokeApiBuild extends Project { .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 1))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 1))) + .include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 12, 1))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))); publishOperation() From d39542478fc23314b37a6d4a04bc1925ac917324 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Mar 2025 23:51:16 -0700 Subject: [PATCH 50/60] JDK 24 --- .github/workflows/bld.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 08a73b4..36e3f2b 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - java-version: [17, 21, 23] + java-version: [17, 21, 24] kotlin-version: [1.9.25, 2.1.10] steps: From 7ba1b0ecf69ef05936bb08e6eacd368e7bb347d9 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 20 Mar 2025 08:53:06 -0700 Subject: [PATCH 51/60] Bump Kotlin to version 2.1.20 --- .github/workflows/bld.yml | 2 +- README.md | 2 +- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 36e3f2b..64fbb4d 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: java-version: [17, 21, 24] - kotlin-version: [1.9.25, 2.1.10] + kotlin-version: [1.9.25, 2.1.20] steps: - name: Checkout source repository diff --git a/README.md b/README.md index 0539e27..bb86972 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.1.10-7f52ff)](https://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/kotlin-2.1.20-7f52ff)](https://kotlinlang.org/) [![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Release](https://img.shields.io/github/release/ethauvin/jokeapi.svg)](https://github.com/ethauvin/jokeapi/releases/latest) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik/jokeapi?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik/jokeapi) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index dfb9478..5500301 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -67,7 +67,7 @@ public class JokeApiBuild extends Project { autoDownloadPurge = true; repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL); - final var kotlin = version(2, 1, 10); + final var kotlin = version(2, 1, 20); scope(compile) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.json", "json", "20250107")) From b2163c7ee7af7ac43e00e9618b0ef06c30a20f64 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 20 Mar 2025 08:53:29 -0700 Subject: [PATCH 52/60] 1.0.1-SNAPSHOT --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 5500301..b2b0054 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -60,7 +60,7 @@ public class JokeApiBuild extends Project { public JokeApiBuild() { pkg = "net.thauvin.erik"; name = "jokeapi"; - version = version(1, 0, 0); + version = version(1, 0, 1, "SNAPSHOT"); javaRelease = 11; downloadSources = true; From 40568463dd98f8bc67c74003b241b245ec9797db Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 20 Mar 2025 09:19:03 -0700 Subject: [PATCH 53/60] Add Kotlin compile options for JDK 24 --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index b2b0054..ac5db7c 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -39,6 +39,7 @@ import rife.bld.extension.DokkaOperation; import rife.bld.extension.JacocoReportOperation; import rife.bld.extension.dokka.LoggingLevel; import rife.bld.extension.dokka.OutputFormat; +import rife.bld.extension.kotlin.CompileOptions; import rife.bld.operations.exceptions.ExitStatusException; import rife.bld.publish.PomBuilder; import rife.bld.publish.PublishDeveloper; @@ -121,8 +122,11 @@ public class JokeApiBuild extends Project { @BuildCommand(summary = "Compiles the Kotlin project") @Override public void compile() throws Exception { + final var options = new CompileOptions(); + options.jvmOptions().add("--enable-native-access=ALL-UNNAMED"); new CompileKotlinOperation() .fromProject(this) + .compileOptions(options) .execute(); } From f737077b1db190d7af2b9a85000adeaf1934030f Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 20 Mar 2025 09:19:14 -0700 Subject: [PATCH 54/60] Update root POM --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 52e318e..e480d48 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik jokeapi - 1.0.0 + 1.0.1-SNAPSHOT jokeapi Retrieve jokes from Sv443's JokeAPI https://github.com/ethauvin/jokeapi @@ -18,7 +18,7 @@ org.jetbrains.kotlin kotlin-stdlib - 2.1.10 + 2.1.20 compile From 7df1c20e821bd45f9bd8a12ae9c2dc13ae5cc660 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 20 Mar 2025 09:21:50 -0700 Subject: [PATCH 55/60] Replace deprecated URL(url) with URI(url) --- src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index 9bd8ac1..8315010 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -39,6 +39,7 @@ import net.thauvin.erik.jokeapi.models.* import org.json.JSONObject import java.io.IOException import java.net.HttpURLConnection +import java.net.URI import java.net.URL import java.util.logging.Level @@ -50,7 +51,7 @@ internal fun fetchUrl(url: String, auth: String = ""): JokeResponse { JokeApi.logger.fine(url) } - val connection = URL(url).openConnection() as HttpURLConnection + val connection = URI(url).toURL().openConnection() as HttpURLConnection try { connection.setRequestProperty( "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0" From a2ab48e67ca9a6535ed404ef13c0e6f23d1797cc Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 20 Mar 2025 20:42:09 -0700 Subject: [PATCH 56/60] Combine Kotlin compile options --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index ac5db7c..2289949 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -122,8 +122,7 @@ public class JokeApiBuild extends Project { @BuildCommand(summary = "Compiles the Kotlin project") @Override public void compile() throws Exception { - final var options = new CompileOptions(); - options.jvmOptions().add("--enable-native-access=ALL-UNNAMED"); + var options = new CompileOptions().jvmOptions("--enable-native-access=ALL-UNNAMED"); new CompileKotlinOperation() .fromProject(this) .compileOptions(options) From 708550ad5cbfa9ad6f2a448b4295a223a3031648 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 26 Mar 2025 12:19:41 -0700 Subject: [PATCH 57/60] Update to latest snapshot --- lib/bld/bld-wrapper.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 154abb0..fc9463a 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,10 +1,10 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.9 -bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.3 -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.9 -bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.4 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.10-SNAPSHOT +bld.extension-dokka=com.uwyn.rife2:bld-dokka:1.0.4-SNAPSHOT +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.10-SNAPSHOT +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0-SNAPSHOT bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= bld.version=2.2.1 From af753c7ac3afe09aca11a0b447195349eeb1deba Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 26 Mar 2025 12:20:03 -0700 Subject: [PATCH 58/60] Add extensions logging --- src/bld/java/net/thauvin/erik/JokeApiBuild.java | 16 ++++++++++++++-- .../kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt | 1 - 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/bld/java/net/thauvin/erik/JokeApiBuild.java b/src/bld/java/net/thauvin/erik/JokeApiBuild.java index 2289949..62b9d9a 100644 --- a/src/bld/java/net/thauvin/erik/JokeApiBuild.java +++ b/src/bld/java/net/thauvin/erik/JokeApiBuild.java @@ -50,6 +50,9 @@ import rife.tools.exceptions.FileUtilsErrorException; import java.io.File; import java.io.IOException; import java.util.List; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; import static rife.bld.dependencies.Repository.*; import static rife.bld.dependencies.Scope.compile; @@ -116,16 +119,25 @@ public class JokeApiBuild extends Project { } public static void main(String[] args) { + // Enable detailed logging for the extensions + var level = Level.ALL; + var logger = Logger.getLogger("rife.bld.extension"); + var consoleHandler = new ConsoleHandler(); + + consoleHandler.setLevel(level); + logger.addHandler(consoleHandler); + logger.setLevel(level); + logger.setUseParentHandlers(false); + new JokeApiBuild().start(args); } @BuildCommand(summary = "Compiles the Kotlin project") @Override public void compile() throws Exception { - var options = new CompileOptions().jvmOptions("--enable-native-access=ALL-UNNAMED"); new CompileKotlinOperation() .fromProject(this) - .compileOptions(options) + .compileOptions(new CompileOptions().verbose(true)) .execute(); } diff --git a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt index 8315010..651844c 100644 --- a/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt +++ b/src/main/kotlin/net/thauvin/erik/jokeapi/JokeUtil.kt @@ -40,7 +40,6 @@ import org.json.JSONObject import java.io.IOException import java.net.HttpURLConnection import java.net.URI -import java.net.URL import java.util.logging.Level /** From 04e636feb44886f10121a01f1726ef6558df3b5e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 26 Mar 2025 12:20:35 -0700 Subject: [PATCH 59/60] Add OS matrix for Ubuntu, Windows and macOS --- .github/workflows/bld.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 64fbb4d..3b6da13 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -1,20 +1,20 @@ name: bld-ci -on: [push, pull_request, workflow_dispatch] +on: [ push, pull_request, workflow_dispatch ] env: COVERAGE_JDK: "21" - COVERAGE_KOTLIN: "2.0.0" - KOTLIN_HOME: /usr/share/kotlinc + COVERAGE_KOTLIN: "2.1.20" jobs: build-bld-project: - runs-on: ubuntu-latest - strategy: matrix: - java-version: [17, 21, 24] - kotlin-version: [1.9.25, 2.1.20] + java-version: [ 17, 21, 24 ] + kotlin-version: [ 1.9.25, 2.0.21, 2.1.20 ] + os: [ ubuntu-latest, windows-latest, macos-latest ] + + runs-on: ${{ matrix.os }} steps: - name: Checkout source repository @@ -39,11 +39,13 @@ jobs: - name: Remove pom.xml if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN + && matrix.os == 'unbuntu-latest' run: rm -rf pom.xml - name: SonarCloud Scan uses: sonarsource/sonarcloud-github-action@master if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN + && matrix.os == 'unbuntu-latest' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From ad99c4c838f8a5220973b8ed6fb00607d7a575c1 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 26 Mar 2025 12:27:19 -0700 Subject: [PATCH 60/60] Fix typo --- .github/workflows/bld.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 3b6da13..007e63a 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -39,13 +39,13 @@ jobs: - name: Remove pom.xml if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN - && matrix.os == 'unbuntu-latest' + && matrix.os == 'ubuntu-latest' run: rm -rf pom.xml - name: SonarCloud Scan uses: sonarsource/sonarcloud-github-action@master if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN - && matrix.os == 'unbuntu-latest' + && matrix.os == 'ubuntu-latest' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}