diff --git a/.github/scripts/replace_string.py b/.github/scripts/replace_string.py old mode 100644 new mode 100755 index f398e8e11..9835ccdc7 --- a/.github/scripts/replace_string.py +++ b/.github/scripts/replace_string.py @@ -2,6 +2,9 @@ import argparse from pathlib import Path +import sys +import git + def main() -> None: parser = argparse.ArgumentParser() @@ -13,11 +16,20 @@ def main() -> None: def replace_string(path: Path, old_string: str, new_string: str) -> None: + repo = git.Repo(path, search_parent_directories=True) for file in path.glob('**/*'): - if file.is_file(): + if not should_replace(repo, file): + continue + try: text = file.read_text() text = text.replace(old_string, new_string) file.write_text(text) + except UnicodeError as e: + print(f'Error processing file {file}:', e, file=sys.stderr) + + +def should_replace(repo, file): + return file.is_file() and not repo.ignored(file) and file.parts[0] != '.git' if __name__ == "__main__": diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt new file mode 100644 index 000000000..239991ab1 --- /dev/null +++ b/.github/scripts/requirements.txt @@ -0,0 +1 @@ +GitPython==3.1.31 diff --git a/.github/scripts/test_replace_string.py b/.github/scripts/test_replace_string.py old mode 100644 new mode 100755 index 6099b990f..29f94f43a --- a/.github/scripts/test_replace_string.py +++ b/.github/scripts/test_replace_string.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import unittest +from unittest import mock from pathlib import Path from shutil import copytree from tempfile import TemporaryDirectory @@ -10,7 +11,9 @@ class TestReplaceString(unittest.TestCase): - def test_replace_string(self): + @mock.patch('git.Repo') + def test_replace_string(self, repo): + repo.return_value.ignored.return_value = False old = '0.17.0' new = '0.17.1' files = ('README.md', 'build.gradle.kts', 'notebook.ipynb') diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index f0362a6c7..eb0b56d33 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -26,6 +26,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + - run: pip install -r .github/scripts/requirements.txt - name: 'unittest discover' run: python3 -m unittest discover -bs .github/scripts diff --git a/.github/workflows/update-examples.yml b/.github/workflows/update-examples.yml index ba891e993..592805704 100644 --- a/.github/workflows/update-examples.yml +++ b/.github/workflows/update-examples.yml @@ -16,6 +16,7 @@ jobs: steps: - name: 'Checkout' uses: actions/checkout@v3 + - run: pip install -r .github/scripts/requirements.txt - name: 'Get versions' run: | old_version="$(git tag --sort=-v:refname | head -n 2 | tail -n 1)" diff --git a/README.md b/README.md index 2fa4d8e12..f8c08fe37 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Gradle Enterprise API Kotlin -[![Maven Central](https://img.shields.io/badge/Maven%20Central-0.16.2-blue)][14] -[![Javadoc](https://img.shields.io/badge/Javadoc-0.16.2-orange)][7] +[![Maven Central](https://img.shields.io/badge/Maven%20Central-0.17.0-blue)][14] +[![Javadoc](https://img.shields.io/badge/Javadoc-0.17.0-orange)][7] A Kotlin library to access the [Gradle Enterprise API][1], easy to use from: @@ -9,10 +9,9 @@ A Kotlin library to access the [Gradle Enterprise API][1], easy to use from: - [Kotlin scripts (`kts`)][27] - [Kotlin projects][28] -Using the API is as easy as this: - ```kotlin -GradleEnterpriseApi.buildsApi.getBuilds(since = yesterdayMilli).forEach { +val api = GradleEnterpriseApi.newInstance() +api.buildsApi.getBuilds(since = yesterdayMilli).forEach { println(it) } ``` @@ -53,7 +52,7 @@ recommended over JitPack. ``` %useLatestDescriptors -%use gradle-enterprise-api-kotlin(version=0.16.2) +%use gradle-enterprise-api-kotlin(version=0.17.0) ``` @@ -62,7 +61,7 @@ recommended over JitPack. Add to a Kotlin script ```kotlin -@file:DependsOn("com.gabrielfeo:gradle-enterprise-api-kotlin:0.16.2") +@file:DependsOn("com.gabrielfeo:gradle-enterprise-api-kotlin:0.17.0") ``` @@ -72,7 +71,7 @@ recommended over JitPack. ```kotlin dependencies { - implementation("com.gabrielfeo:gradle-enterprise-api-kotlin:0.16.2") + implementation("com.gabrielfeo:gradle-enterprise-api-kotlin:0.17.0") } ``` @@ -101,11 +100,13 @@ For example, [`BuildsApi`][20] contains all endpoints under `/api/builds/`: ### Calling the APIs -For simple use cases, you may use the companion instance ([DefaultInstance][23]) directly, as if -calling static methods: +API methods are generated as suspend functions. +For most cases like scripts and notebooks, simply use [runBlocking][30]: ```kotlin -GradleEnterpriseApi.buildsApi.getBuilds(since = yesterdayMilli) +runBlocking { + val builds: List = api.buildsApi.getBuilds(since = yesterdayMilli) +} ``` It's recommended to call [`GradleEnterpriseApi.shutdown()`][11] at the end of scripts to release @@ -130,7 +131,7 @@ also takes care of paging under-the-hood, returning a [`Flow`][26] of all builds date, so you don't have to worry about the REST API's limit of 1000 builds per request: ```kotlin -val builds = GradleEnterpriseApi.buildsApi.getGradleAttributesFlow(since = lastYear) +val builds: Flow = api.buildsApi.getGradleAttributesFlow(since = lastYear) builds.collect { // ... } @@ -189,7 +190,7 @@ import com.gabrielfeo.gradle.enterprise.api.model.extension.* [11]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/library/com.gabrielfeo.gradle.enterprise.api/-gradle-enterprise-api/shutdown.html [12]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/library/com.gabrielfeo.gradle.enterprise.api/-config/-cache-config/cache-enabled.html [13]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/library/com.gabrielfeo.gradle.enterprise.api/-config/-cache-config/index.html -[14]: https://central.sonatype.com/artifact/com.gabrielfeo/gradle-enterprise-api-kotlin/0.16.2 +[14]: https://central.sonatype.com/artifact/com.gabrielfeo/gradle-enterprise-api-kotlin/0.17.0 [16]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/library/com.gabrielfeo.gradle.enterprise.api/-config/api-url.html [17]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/library/com.gabrielfeo.gradle.enterprise.api/-config/api-token.html [18]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/library/com.gabrielfeo.gradle.enterprise.api/-builds-api/index.html @@ -204,3 +205,4 @@ import com.gabrielfeo.gradle.enterprise.api.model.extension.* [27]: ./examples/example-script.main.kts [28]: ./examples/example-project [29]: https://nbviewer.org/github/gabrielfeo/gradle-enterprise-api-kotlin/blob/main/examples/example-notebooks/MostFrequentBuilds.ipynb +[30]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html diff --git a/examples/example-notebooks/MostFrequentBuilds.ipynb b/examples/example-notebooks/MostFrequentBuilds.ipynb index ef21c547d..9ddadc789 100644 --- a/examples/example-notebooks/MostFrequentBuilds.ipynb +++ b/examples/example-notebooks/MostFrequentBuilds.ipynb @@ -35,7 +35,7 @@ "Add libraries to use, via line magics. `%use` is a [line magic](https://github.com/Kotlin/kotlin-jupyter#line-magics) of the Kotlin kernel that can do much more than adding the library. To illustrate, this setup can be replaced with a single line magic.\n", "\n", "```kotlin\n", - "@file:DependsOn(\"com.gabrielfeo:gradle-enterprise-api-kotlin:0.16.2\")\n", + "@file:DependsOn(\"com.gabrielfeo:gradle-enterprise-api-kotlin:0.17.0\")\n", "\n", "import com.gabrielfeo.gradle.enterprise.api.*\n", "import com.gabrielfeo.gradle.enterprise.api.model.*\n", @@ -45,7 +45,7 @@ "is the same as:\n", "\n", "```\n", - "%use gradle-enterprise-api-kotlin(version=0.16.2)\n", + "%use gradle-enterprise-api-kotlin(version=0.17.0)\n", "```" ] }, @@ -57,7 +57,7 @@ "outputs": [], "source": [ "%useLatestDescriptors\n", - "%use gradle-enterprise-api-kotlin(version=0.16.2)\n", + "%use gradle-enterprise-api-kotlin(version=0.17.0)\n", "%use coroutines(v=1.7.1)" ] }, @@ -112,9 +112,10 @@ "import java.time.temporal.*\n", "import java.util.LinkedList\n", "\n", + "val api = GradleEnterpriseApi.newInstance()\n", "val builds: List = runBlocking {\n", " val startMilli = startDate.atStartOfDay(ZoneId.of(\"UTC\")).toInstant().toEpochMilli()\n", - " GradleEnterpriseApi.buildsApi.getGradleAttributesFlow(since = startMilli)\n", + " api.buildsApi.getGradleAttributesFlow(since = startMilli)\n", " .filter(buildFilter)\n", " .toList(LinkedList())\n", "}" diff --git a/examples/example-project/app/build.gradle.kts b/examples/example-project/app/build.gradle.kts index 4989d92b9..bc23c0fd0 100644 --- a/examples/example-project/app/build.gradle.kts +++ b/examples/example-project/app/build.gradle.kts @@ -14,5 +14,5 @@ java { } dependencies { - implementation("com.gabrielfeo:gradle-enterprise-api-kotlin:0.16.2") + implementation("com.gabrielfeo:gradle-enterprise-api-kotlin:0.17.0") } diff --git a/examples/example-script.main.kts b/examples/example-script.main.kts index 8f6789ad6..24c63b6b0 100644 --- a/examples/example-script.main.kts +++ b/examples/example-script.main.kts @@ -15,7 +15,7 @@ * legacy tests. We should suggest they run test instead, leaving check for CI to run." */ -@file:DependsOn("com.gabrielfeo:gradle-enterprise-api-kotlin:0.16.2") +@file:DependsOn("com.gabrielfeo:gradle-enterprise-api-kotlin:0.17.0") import com.gabrielfeo.gradle.enterprise.api.* import com.gabrielfeo.gradle.enterprise.api.model.* @@ -32,9 +32,10 @@ val buildFilter: (GradleAttributes) -> Boolean = { build -> } // Fetch builds from the API +val api = GradleEnterpriseApi.newInstance() val builds: List = runBlocking { val startMilli = startDate.atStartOfDay(ZoneId.of("UTC")).toInstant().toEpochMilli() - GradleEnterpriseApi.buildsApi.getGradleAttributesFlow(since = startMilli) + api.buildsApi.getGradleAttributesFlow(since = startMilli) .filter(buildFilter) .toList(LinkedList()) } diff --git a/library/src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/GradleEnterpriseApi.kt b/library/src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/GradleEnterpriseApi.kt index 01074faec..1bbb1f163 100644 --- a/library/src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/GradleEnterpriseApi.kt +++ b/library/src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/GradleEnterpriseApi.kt @@ -3,6 +3,7 @@ package com.gabrielfeo.gradle.enterprise.api import com.gabrielfeo.gradle.enterprise.api.internal.buildOkHttpClient import com.gabrielfeo.gradle.enterprise.api.internal.buildRetrofit import com.gabrielfeo.gradle.enterprise.api.internal.infrastructure.Serializer +import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.create @@ -15,15 +16,14 @@ import retrofit2.create * - [metaApi] * - [testDistributionApi] * - * For simple use cases, you may use the companion instance ([DefaultInstance]) directly, as if - * calling static methods: + * Create an instance with [newInstance]: * * ```kotlin - * GradleEnterpriseApi.buildsApi.getBuilds(...) + * val api = GradleEnterpriseApi.newInstance() + * api.buildsApi.getBuilds(...) * ``` * - * However, if you need to change [config] at runtime or own the instance's lifecycle (e.g. - * with an IoC container like Dagger), create a new instance: + * You may pass a default [Config], e.g. for sharing [OkHttpClient] resources: * * ```kotlin * val options = Options(clientBuilder = myOwnOkHttpClient.newBuilder()) @@ -48,10 +48,6 @@ interface GradleEnterpriseApi { */ fun shutdown() - /** - * The default, companion instance of the Gradle Enterprise API client. See - * [GradleEnterpriseApi]. - */ companion object { /**