From 92e8e36bd932fd00c8728e09bcb710efc1c833d1 Mon Sep 17 00:00:00 2001 From: BREW <81044362+b-re-w@users.noreply.github.com> Date: Sat, 7 Nov 2026 12:00:07 +0900 Subject: [PATCH 1/2] WIP: release readiness fixes (stopped mid-way, not reviewed) --- .github/workflows/test.yml | 6 +- AGENTS.md | 5 +- README.md | 17 ++---- docs/SPEC.md | 19 +++++-- docs/guide/getting-started.html | 18 +++--- docs/guide/guide-tcl.html | 4 +- docs/locale/README_ko.md | 17 ++---- .../python/multiplatform/tcl/Installer.kt | 43 ++++++++++---- .../python/multiplatform/tcl/InstallerTest.kt | 57 ++++++++++++++++++- .../toolchain/typedpython/TypedpythonGate.kt | 2 +- .../TypedpythonGateArtifactTest.kt | 13 +++-- .../typedpython/TypedpythonGateTest.kt | 4 +- usage-example/build.gradle.kts | 4 +- usage-example/gradle/libs.versions.toml | 5 +- usage-example/settings.gradle.kts | 27 ++++----- 15 files changed, 159 insertions(+), 82 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 25dfe74..89e09b5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -121,9 +121,9 @@ jobs: python-version: "3.15" - uses: astral-sh/setup-uv@v6 - # usage-example applies three things from mavenLocal: packpack (through the plugin), the - # toolchain plugin, and python-multiplatform's library and bindings plugin. Versions pinned in - # usage-example/gradle/libs.versions.toml (3.15.0-alpha02). + # usage-example takes packpack (through the plugin) and the toolchain plugin from mavenLocal, and + # python-multiplatform (3.15.0-alpha03, usage-example/gradle/libs.versions.toml) from Maven Central + # only (usage-example/settings.gradle.kts), so its local publish below is not what the build uses. - name: Publish packpack, the toolchain plugin and python-multiplatform to mavenLocal run: | (cd .ci/pypackpack && ./gradlew :packpack:publishToMavenLocal --console=plain) diff --git a/AGENTS.md b/AGENTS.md index 3e924cd..fa76908 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -245,8 +245,9 @@ history removing. Prerequisites: `org.thisisthepy.python.multiplatform:packpack:0.1.0` in `~/.m2` (published from the `pypackpack` repository), `uv` on `PATH`, and network access: `InstallDependenciesTaskTest` and `InstallerTest` run a real `uv add` against PyPI. `usage-example` additionally needs an Android SDK -(`ANDROID_HOME`) and python-multiplatform in `~/.m2`: from a python-multiplatform checkout, -`./gradlew publishAllToMavenLocal` (`org.thisisthepy:python-multiplatform*` and bindings plugin `3.15.0-alpha02`). +(`ANDROID_HOME`) and python-multiplatform `3.15.0-alpha03` (library, KSP processor, bindings plugin), which it +resolves from Maven Central only; only the toolchain plugin and packpack come from `~/.m2`. That version must +equal `DEFAULT_TYPEDPYTHON_GATE` (`toolchain/.../typedpython/TypedpythonGate.kt`): bump both together. Run each module separately (rule 8), with output to a file under `.cache/`: diff --git a/README.md b/README.md index 0e1a225..b63d007 100644 --- a/README.md +++ b/README.md @@ -48,14 +48,9 @@ owns the Gradle vocabulary in between. ## πŸš€ Quick start -> `toolchain` is published to Maven Central (with its Gradle plugin marker, so add `mavenCentral()` to -> `pluginManagement.repositories` in `settings.gradle.kts`). While pre-release, publish `pypackpack`'s -> `packpack` artifact and this plugin to `mavenLocal()` first, and have `uv` on your `PATH`. - -```shell -# in pypackpack: ./gradlew :packpack:publishToMavenLocal -./gradlew :toolchain:publishToMavenLocal -``` +> `toolchain` is published to Maven Central with its Gradle plugin marker, starting with `1.0.0-alpha`: +> add `mavenCentral()` to `pluginManagement.repositories` in `settings.gradle.kts`. The plugin installs +> dependencies with `uv`, so have `uv` on your `PATH`. ```kotlin // settings.gradle.kts @@ -63,7 +58,6 @@ pluginManagement { repositories { mavenCentral() gradlePluginPortal() - mavenLocal() // while using an unreleased local build } } ``` @@ -85,7 +79,7 @@ plugins { } python { - compileSdk = "3.13" + compileSdk = "3.15.0" // the CPython python-multiplatform provides localLibraryPath = "src/commonMain/python" // a pypackpack package: pyproject.toml + src/main/ packaging { fileName = "usage-example" @@ -120,7 +114,8 @@ python { Python only? Skip Gradle builds entirely: ```shell -./gradlew :toolchain:runTcl --args="install pythonx-compose" +uv tool install toolchain-lite +tcl install pythonx-compose ``` ## 🧭 Architecture at a glance diff --git a/docs/SPEC.md b/docs/SPEC.md index 7ea3f22..77c7080 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -61,7 +61,7 @@ Test: `PythonSdkTest` (`a CPython before 3_15 is refused as a GIL build, inside **Temporary exception: `3.15.0` without `t` (`PY3_15_0`).** It names python-multiplatform's GIL build, which is what python-multiplatform publishes today: its `gradle.properties` has `pythonFreeThreaded=false`, -its artifact version (`3.15.0-alpha02`) carries no flavour, and Android and iOS have no 3.15t build yet +its artifact version (`3.15.0-alpha03`) carries no flavour, and Android and iOS have no 3.15t build yet (python-multiplatform #163). Selecting `cp315t` wheels for that runtime would install wheels it cannot load. The exception is removed, and `3.15.0` then means `3.15.0t`, when python-multiplatform publishes free-threaded as its default with the flavour in its version or metadata, and #163 lands; #76 tracks it. @@ -540,10 +540,11 @@ bundled. Every `buildPython` and the single host `buildPytho --find-links typedpython== pyrefly==` (`@Input` versions, defaults `0.1.0` and `1.3.2`). `` must hold both wheels for the platform; nothing comes from an index. 2. The **gate artifact**, by default: the `typedpython-gate` zip python-multiplatform-ksp publishes beside - its processor jar, `org.thisisthepy:python-multiplatform-ksp:3.15.0-alpha02:typedpython-gate@zip` + its processor jar, `org.thisisthepy:python-multiplatform-ksp:3.15.0-alpha03:typedpython-gate@zip` (`DEFAULT_TYPEDPYTHON_GATE`, the one place its group and version are written; `-Ptypedpython.gate= ` overrides it). It is resolved leniently from the project's own - repositories (python-multiplatform's `publishToMavenLocal` puts it in `mavenLocal()`), unzipped into + repositories (Maven Central has it from python-multiplatform 3.15.0-alpha03, its first Central release; + python-multiplatform's `publishToMavenLocal` puts it in `mavenLocal()`), unzipped into `build/typedpython/gate`, and its manifest `typedpython-gate.json` (format 1) gives typedpython's wheel, version and SHA-256 and the SHA-256 of every pyrefly PyPI wheel. The install is `uv pip install --python --require-hashes -r build/typedpython/gate-requirements.txt`, where @@ -671,9 +672,15 @@ task output and `wasmJsProcessResources` wiring). ## 2. `tcl`: toolchain-lite ### 2.1 `tcl install ` -Finds the nearest `pyproject.toml` at or above the working directory. If there is none, runs -`uv init --bare` there first (through `pypackpack`'s `BackendInterface.initProject`), then -`addDependencies` for the package. Exit code 0 on success and the `uv` output on stdout; 1 with a +Finds the project to add to without ever editing an unrelated ancestor (`findProjectRoot`): the working +directory's own `pyproject.toml` always counts; inside a git repository (a directory holding a `.git` +directory, or a `.git` file for a worktree) the search walks up to the nearest `pyproject.toml` and stops at +the repository root; outside any repository no parent is searched. If no project qualifies, runs +`uv init --bare --no-workspace` in the working directory first (through `pypackpack`'s +`BackendInterface.initProject`; `--no-workspace` keeps `uv` from adding the new project as a member of an +ancestor's workspace, which would write into that ancestor's `pyproject.toml`), then `addDependencies` for +the package. Inside a repository whose root has a `pyproject.toml`, a subdirectory without one still adds +to the root's project, as `uv add` itself would. Exit code 0 on success and the `uv` output on stdout; 1 with a message on stderr for a missing argument, an unknown command or a failed install. No arguments prints `Usage: tcl install `. diff --git a/docs/guide/getting-started.html b/docs/guide/getting-started.html index 542960f..90c953d 100644 --- a/docs/guide/getting-started.html +++ b/docs/guide/getting-started.html @@ -28,13 +28,15 @@

Getting startedμ‹œμž‘ν•˜κΈ°

1. Prerequisites1. μ€€λΉ„λ¬Ό

-
Needν•„μš”ν•œ 것Why이유
JDK 17+ and Gradle 8.9 (wrapper)JDK 17 이상, Gradle 8.9 (래퍼)The build itself.λΉŒλ“œ 자체.
uv on PATHPATH 의 uvpypackpack installs dependencies with it.pypackpack 이 μ˜μ‘΄μ„± μ„€μΉ˜μ— μ”λ‹ˆλ‹€.
packpack:0.1.0 in Maven LocalMaven Local 의 packpack:0.1.0The plugin depends on pypackpack as a library.ν”ŒλŸ¬κ·ΈμΈμ΄ pypackpack 을 라이브러리둜 μ”λ‹ˆλ‹€.
Android SDK (ANDROID_HOME)Android SDK (ANDROID_HOME)Only if your module has an Android target.λͺ¨λ“ˆμ— Android 타깃이 μžˆμ„ λ•Œλ§Œ.
-
# in a pypackpack checkout
-./gradlew :packpack:publishToMavenLocal
-
-# in this repository
-./gradlew :toolchain:publishToMavenLocal
-

The plugin and its marker are distributed through Maven Central (with mavenLocal() as the fallback while pre-release). Put mavenCentral() in pluginManagement.repositories in your settings.gradle.kts (plus mavenLocal() for local builds).

ν”ŒλŸ¬κ·ΈμΈκ³Ό λ§ˆμ»€λŠ” Maven Central 둜 λ°°ν¬λ©λ‹ˆλ‹€(μΆœμ‹œ μ „μ—λŠ” mavenLocal() 둜 λŒ€μ²΄). settings.gradle.kts 의 pluginManagement.repositories 에 mavenCentral() 을 λ‘μ„Έμš”(둜컬 λΉŒλ“œλ₯Ό μ“Έ λ•ŒλŠ” mavenLocal() 도 ν•¨κ»˜).

+
Needν•„μš”ν•œ 것Why이유
JDK 17+ and Gradle 8.9 (wrapper)JDK 17 이상, Gradle 8.9 (래퍼)The build itself.λΉŒλ“œ 자체.
uv on PATHPATH 의 uvpypackpack installs dependencies with it.pypackpack 이 μ˜μ‘΄μ„± μ„€μΉ˜μ— μ”λ‹ˆλ‹€.
mavenCentral() in pluginManagement.repositoriespluginManagement.repositories 의 mavenCentral()The plugin, its marker and pypackpack (the library it depends on) come from Maven Central.ν”ŒλŸ¬κ·ΈμΈ, 마컀, 그리고 ν”ŒλŸ¬κ·ΈμΈμ΄ μ˜μ‘΄ν•˜λŠ” pypackpack 라이브러리λ₯Ό Maven Central μ—μ„œ λ°›μŠ΅λ‹ˆλ‹€.
Android SDK (ANDROID_HOME)Android SDK (ANDROID_HOME)Only if your module has an Android target.λͺ¨λ“ˆμ— Android 타깃이 μžˆμ„ λ•Œλ§Œ.
+
// settings.gradle.kts
+pluginManagement {
+    repositories {
+        mavenCentral()
+        gradlePluginPortal()
+    }
+}
+

The plugin and its marker are published to Maven Central, starting with 1.0.0-alpha. To try an unreleased change from a checkout, see Contributing.

ν”ŒλŸ¬κ·ΈμΈκ³Ό λ§ˆμ»€λŠ” 1.0.0-alpha λΆ€ν„° Maven Central 에 λ°°ν¬λ©λ‹ˆλ‹€. μ²΄ν¬μ•„μ›ƒμ˜ μΆœμ‹œ μ „ 변경을 써 보렀면 κΈ°μ—¬ν•˜κΈ°λ₯Ό λ³΄μ„Έμš”.

@@ -56,7 +58,7 @@

3. Apply the plugin3. ν”Œ } python { - compileSdk = "3.13" + compileSdk = "3.15.0" localLibraryPath = "src/commonMain/python" packaging { fileName = "usage-example" diff --git a/docs/guide/guide-tcl.html b/docs/guide/guide-tcl.html index ba9df2f..4aba534 100644 --- a/docs/guide/guide-tcl.html +++ b/docs/guide/guide-tcl.html @@ -28,12 +28,12 @@

tcl for Python usersPython

Install a packageνŒ¨ν‚€μ§€ μ„€μΉ˜

-
uv tool install toolchain-lite    # once 0.1.0 is on PyPI
+
uv tool install toolchain-lite
 tcl install pythonx-compose
 tcl --version
 
 ./gradlew :toolchain:runTcl --args="install pythonx-compose"    # from a checkout
-

tcl install <package> looks for a pyproject.toml in the current directory and its parents. If there is none it runs uv init --bare first; then it adds the package with uv add, through the same pypackpack backend the Gradle plugin uses.

tcl install <package> λŠ” ν˜„μž¬ 디렉터리와 κ·Έ μƒμœ„μ—μ„œ pyproject.toml 을 μ°ΎμŠ΅λ‹ˆλ‹€. μ—†μœΌλ©΄ λ¨Όμ € uv init --bare λ₯Ό μ‹€ν–‰ν•˜κ³ , Gradle ν”ŒλŸ¬κ·ΈμΈκ³Ό 같은 pypackpack λ°±μ—”λ“œλ‘œ uv add λ₯Ό ν•΄μ„œ νŒ¨ν‚€μ§€λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.

+

tcl install <package> uses the pyproject.toml in the current directory. Inside a git repository it also looks in the parent directories, up to the repository root and never above it; outside a repository it does not look in parents at all, so an unrelated project above you is never edited. If there is none it runs uv init --bare --no-workspace in the current directory first; then it adds the package with uv add, through the same pypackpack backend the Gradle plugin uses.

tcl install <package> λŠ” ν˜„μž¬ λ””λ ‰ν„°λ¦¬μ˜ pyproject.toml 을 μ”λ‹ˆλ‹€. git μ €μž₯μ†Œ μ•ˆμ΄λ©΄ μƒμœ„ 디렉터리도 μ €μž₯μ†Œ λ£¨νŠΈκΉŒμ§€λ§Œ μ°Ύκ³  κ·Έ μœ„λ‘œλŠ” κ°€μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ €μž₯μ†Œ 밖이면 μƒμœ„ 디렉터리λ₯Ό μ•„μ˜ˆ μ°Ύμ§€ μ•ŠμœΌλ―€λ‘œ, μœ„μ— μžˆλŠ” κ΄€κ³„μ—†λŠ” ν”„λ‘œμ νŠΈλ₯Ό κ³ μΉ˜λŠ” 일이 μ—†μŠ΅λ‹ˆλ‹€. μ—†μœΌλ©΄ λ¨Όμ € ν˜„μž¬ λ””λ ‰ν„°λ¦¬μ—μ„œ uv init --bare --no-workspace λ₯Ό μ‹€ν–‰ν•˜κ³ , Gradle ν”ŒλŸ¬κ·ΈμΈκ³Ό 같은 pypackpack λ°±μ—”λ“œλ‘œ uv add λ₯Ό ν•΄μ„œ νŒ¨ν‚€μ§€λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.

Invocation호좜Result결과
tcl install pkgexit 0, uv output on stdoutμ’…λ£Œ μ½”λ“œ 0, stdout 에 uv 좜λ ₯
tclexit 1, Usage: tcl install <package>μ’…λ£Œ μ½”λ“œ 1, Usage: tcl install <package>
tcl installexit 1, missing argumentμ’…λ£Œ μ½”λ“œ 1, 인자 λˆ„λ½
tcl otherexit 1, unknown commandμ’…λ£Œ μ½”λ“œ 1, μ•Œ 수 μ—†λŠ” λͺ…λ Ή

install is the only command, matching issue #1. tcl needs uv on PATH and network access to PyPI.

λͺ…령은 이슈 #1 κ·ΈλŒ€λ‘œ install ν•˜λ‚˜λΏμž…λ‹ˆλ‹€. tcl 은 PATH 의 uv 와 PyPI λ„€νŠΈμ›Œν¬ 접근이 ν•„μš”ν•©λ‹ˆλ‹€.

diff --git a/docs/locale/README_ko.md b/docs/locale/README_ko.md index 86118b8..224a630 100644 --- a/docs/locale/README_ko.md +++ b/docs/locale/README_ko.md @@ -47,14 +47,9 @@ Python 을 λ‚΄μž₯ν•œ Kotlin Multiplatform μ•±μ—λŠ” 맞물렀 λŒμ•„κ°€μ•Ό ν•˜ ## πŸš€ λΉ λ₯Έ μ‹œμž‘ -> `toolchain` 은 Gradle ν”ŒλŸ¬κ·ΈμΈ λ§ˆμ»€μ™€ ν•¨κ»˜ Maven Central 에 λ°°ν¬λ©λ‹ˆλ‹€(`settings.gradle.kts` 의 -> `pluginManagement.repositories` 에 `mavenCentral()` 을 λ‘μ„Έμš”). 정식 μΆœμ‹œ μ „μ—λŠ” `pypackpack` 의 -> `packpack` μ•„ν‹°νŒ©νŠΈμ™€ 이 ν”ŒλŸ¬κ·ΈμΈμ„ λ¨Όμ € `mavenLocal()` 에 λ°°ν¬ν•˜κ³ , `PATH` 에 `uv` κ°€ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. - -```shell -# pypackpack μ—μ„œ: ./gradlew :packpack:publishToMavenLocal -./gradlew :toolchain:publishToMavenLocal -``` +> `toolchain` 은 `1.0.0-alpha` λΆ€ν„° Gradle ν”ŒλŸ¬κ·ΈμΈ λ§ˆμ»€μ™€ ν•¨κ»˜ Maven Central 에 λ°°ν¬λ©λ‹ˆλ‹€. +> `settings.gradle.kts` 의 `pluginManagement.repositories` 에 `mavenCentral()` 을 λ‘μ„Έμš”. ν”ŒλŸ¬κ·ΈμΈμ΄ +> `uv` 둜 μ˜μ‘΄μ„±μ„ μ„€μΉ˜ν•˜λ―€λ‘œ `PATH` 에 `uv` κ°€ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. ```kotlin // settings.gradle.kts @@ -62,7 +57,6 @@ pluginManagement { repositories { mavenCentral() gradlePluginPortal() - mavenLocal() // μΆœμ‹œ μ „ 둜컬 λΉŒλ“œλ₯Ό μ“Έ λ•Œ } } ``` @@ -84,7 +78,7 @@ plugins { } python { - compileSdk = "3.13" + compileSdk = "3.15.0" // python-multiplatform 이 μ œκ³΅ν•˜λŠ” CPython localLibraryPath = "src/commonMain/python" // pypackpack νŒ¨ν‚€μ§€: pyproject.toml + src/main/ packaging { fileName = "usage-example" @@ -119,7 +113,8 @@ python { Python 만 μ“°λ‚˜μš”? Gradle λΉŒλ“œ 없이: ```shell -./gradlew :toolchain:runTcl --args="install pythonx-compose" +uv tool install toolchain-lite +tcl install pythonx-compose ``` ## 🧭 ν•œλˆˆμ— λ³΄λŠ” ꡬ쑰 diff --git a/toolchain/src/cliMain/kotlin/org/thisisthepy/python/multiplatform/tcl/Installer.kt b/toolchain/src/cliMain/kotlin/org/thisisthepy/python/multiplatform/tcl/Installer.kt index b483bfc..2d19d2c 100644 --- a/toolchain/src/cliMain/kotlin/org/thisisthepy/python/multiplatform/tcl/Installer.kt +++ b/toolchain/src/cliMain/kotlin/org/thisisthepy/python/multiplatform/tcl/Installer.kt @@ -7,16 +7,32 @@ import java.io.File private const val PYPROJECT_FILE = "pyproject.toml" +private const val GIT_ENTRY = ".git" + /** - * Finds the `pypackpack`/`uv` project root by walking up from [startDir] looking for a - * `pyproject.toml` -- mirrors `pypackpack`'s own `findProjectRoot` - * (`packpack/utils/Workspace.kt`), reimplemented here rather than reused because that function is - * `internal` to the `packpack` Gradle module and is not part of its published API surface. + * Finds the project `tcl install` adds to, starting at [startDir], without ever reaching an + * unrelated ancestor project: + * + * - [startDir]'s own `pyproject.toml` always counts. + * - Inside a git repository (a directory holding a `.git` directory, or a `.git` file for a + * worktree), the search walks up to the nearest `pyproject.toml`, and stops at the repository + * root, which is the last directory checked. A `pyproject.toml` above the repository belongs to + * another project. + * - Outside any repository there is no boundary to trust, so only [startDir] counts: a stray + * `pyproject.toml` in a parent or the home directory is never edited. + * + * Returns null when no project qualifies; [Installer.install] then initializes one in [startDir]. */ fun findProjectRoot(startDir: File): File? { - var current: File? = startDir.canonicalFile - while (current != null) { + val start = startDir.canonicalFile + if (File(start, PYPROJECT_FILE).isFile) return start + + val repositoryRoot = generateSequence(start) { it.parentFile }.firstOrNull { File(it, GIT_ENTRY).exists() } + ?: return null + var current: File? = start.parentFile + while (current != null && current.path.length >= repositoryRoot.path.length) { if (File(current, PYPROJECT_FILE).isFile) return current + if (current == repositoryRoot) break current = current.parentFile } return null @@ -45,7 +61,7 @@ class Installer( ) { /** * Adds [packageName] as a dependency of the project rooted at (or above) [workingDir], - * initializing a fresh `pyproject.toml` there first via `uv init --bare` if [findProjectRoot] + * initializing a fresh `pyproject.toml` there first via `uv init --bare --no-workspace` if [findProjectRoot] * finds none. Returns the same `Result` `pypackpack`'s backend does: `uv`'s own * combined stdout/stderr on success, or the failure it hit -- including a failed `initProject`, * which short-circuits before `addDependencies` is ever attempted. @@ -58,9 +74,16 @@ class Installer( val existingRoot = findProjectRoot(workingDir) if (existingRoot == null) { - // `--bare` matches what `pypackpack init` itself does (`docs/SPEC.md` "Project - // creation"): only `pyproject.toml` is generated by `uv`, nothing else assumed. - val initResult = backend.initProject(path = null, extraArgs = mapOf("bare" to ""), workingDir = workingDir) + // `--bare` matches what `pypackpack init` itself does (pypackpack's `docs/SPEC.md` + // "Project creation"): only `pyproject.toml` is generated by `uv`, nothing else assumed. + // `--no-workspace` keeps `uv` from registering the new project as a member of an + // ancestor's workspace, which would write `[tool.uv.workspace]` into that ancestor. + val initResult = + backend.initProject( + path = null, + extraArgs = mapOf("bare" to "", "no-workspace" to ""), + workingDir = workingDir, + ) if (initResult.isFailure) return initResult } diff --git a/toolchain/src/cliTest/kotlin/org/thisisthepy/python/multiplatform/tcl/InstallerTest.kt b/toolchain/src/cliTest/kotlin/org/thisisthepy/python/multiplatform/tcl/InstallerTest.kt index a6f42cd..1d1d623 100644 --- a/toolchain/src/cliTest/kotlin/org/thisisthepy/python/multiplatform/tcl/InstallerTest.kt +++ b/toolchain/src/cliTest/kotlin/org/thisisthepy/python/multiplatform/tcl/InstallerTest.kt @@ -3,7 +3,9 @@ package org.thisisthepy.python.multiplatform.tcl import java.io.File import kotlin.io.path.createTempDirectory import kotlin.test.Test +import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNull import kotlin.test.assertTrue /** @@ -61,14 +63,67 @@ class InstallerTest { } @Test - fun `findProjectRoot walks up from a nested directory to the pyproject toml`() { + fun `findProjectRoot walks up from a nested directory to the pyproject toml of the same repository`() { val root = createTempDirectory("tcl-find-root").toFile() + File(root, ".git").mkdirs() File(root, "pyproject.toml").writeText("[project]\nname = \"x\"\n") val nested = File(root, "a/b/c").apply { mkdirs() } assertTrue(findProjectRoot(nested) == root.canonicalFile) } + @Test + fun `findProjectRoot uses the working directory's own pyproject toml`() { + val dir = createTempDirectory("tcl-find-root-cwd").toFile() + File(dir, "pyproject.toml").writeText("[project]\nname = \"x\"\n") + + assertTrue(findProjectRoot(dir) == dir.canonicalFile) + } + + @Test + fun `findProjectRoot does not cross a git boundary into an unrelated parent project`() { + val parent = createTempDirectory("tcl-find-root-git-boundary").toFile() + File(parent, "pyproject.toml").writeText("[project]\nname = \"unrelated\"\n") + val repo = File(parent, "repo").apply { mkdirs() } + // A worktree's `.git` is a file, not a directory: both mark the boundary. + File(repo, ".git").writeText("gitdir: elsewhere\n") + val nested = File(repo, "src").apply { mkdirs() } + + assertNull(findProjectRoot(nested), "the parent's pyproject.toml lies outside the repository") + } + + @Test + fun `findProjectRoot outside any repository does not take an ancestor's pyproject toml`() { + val parent = createTempDirectory("tcl-find-root-no-repo").toFile() + File(parent, "pyproject.toml").writeText("[project]\nname = \"unrelated\"\n") + val child = File(parent, "child").apply { mkdirs() } + + assertNull(findProjectRoot(child), "with no repository boundary, only the working directory counts") + } + + @Test + fun `install below an unrelated project creates its own project and leaves the ancestor untouched`() { + val parent = createTempDirectory("tcl-install-unrelated-ancestor").toFile() + val parentPyproject = + """ + [project] + name = "unrelated-ancestor" + version = "0.0.1" + requires-python = ">=3.13" + dependencies = [] + """.trimIndent() + File(parent, "pyproject.toml").writeText(parentPyproject) + val child = File(parent, "child").apply { mkdirs() } + + val result = installBlocking("six", child) + + assertTrue(result.isSuccess, "install should succeed: ${result.exceptionOrNull()}") + assertEquals(parentPyproject, File(parent, "pyproject.toml").readText(), "the ancestor project must not be edited") + val own = File(child, "pyproject.toml") + assertTrue(own.isFile, "install should have initialized a project in the working directory") + assertTrue(own.readText().contains("six"), "the new project should record the dependency") + } + @Test fun `findProjectRoot returns null when nothing is found above it`() { val dir = createTempDirectory("tcl-find-root-none").toFile() diff --git a/toolchain/src/main/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGate.kt b/toolchain/src/main/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGate.kt index fdce0ac..ba311f7 100644 --- a/toolchain/src/main/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGate.kt +++ b/toolchain/src/main/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGate.kt @@ -10,7 +10,7 @@ import java.io.File * uses the same). This is the one place both are written; `-Ptypedpython.gate=` * overrides it. */ -const val DEFAULT_TYPEDPYTHON_GATE = "org.thisisthepy:python-multiplatform-ksp:3.15.0-alpha02" +const val DEFAULT_TYPEDPYTHON_GATE = "org.thisisthepy:python-multiplatform-ksp:3.15.0-alpha03" /** Project property overriding [DEFAULT_TYPEDPYTHON_GATE]. */ const val TYPEDPYTHON_GATE_PROPERTY = "typedpython.gate" diff --git a/toolchain/src/test/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGateArtifactTest.kt b/toolchain/src/test/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGateArtifactTest.kt index ef36566..4229335 100644 --- a/toolchain/src/test/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGateArtifactTest.kt +++ b/toolchain/src/test/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGateArtifactTest.kt @@ -20,11 +20,14 @@ import kotlin.test.assertTrue * comes from PyPI). Without the zip these tests are skipped with that reason, as on CI. */ class TypedpythonGateArtifactTest { - private val mavenLocalZip = File( - System.getProperty("user.home"), - ".m2/repository/org/thisisthepy/python-multiplatform-ksp/3.15.0-alpha02/" + - "python-multiplatform-ksp-3.15.0-alpha02-typedpython-gate.zip", - ) + // Derived from DEFAULT_TYPEDPYTHON_GATE so a version bump cannot leave this test probing an old path. + private val mavenLocalZip = DEFAULT_TYPEDPYTHON_GATE.split(':').let { (group, artifact, version) -> + File( + System.getProperty("user.home"), + ".m2/repository/${group.replace('.', '/')}/$artifact/$version/" + + "$artifact-$version-$TYPEDPYTHON_GATE_CLASSIFIER.zip", + ) + } @BeforeTest fun requireGate() { diff --git a/toolchain/src/test/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGateTest.kt b/toolchain/src/test/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGateTest.kt index 285cde8..327c204 100644 --- a/toolchain/src/test/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGateTest.kt +++ b/toolchain/src/test/kotlin/org/thisisthepy/python/multiplatform/toolchain/typedpython/TypedpythonGateTest.kt @@ -41,9 +41,9 @@ class TypedpythonGateTest { @Test fun `the gate is the typedpython-gate zip of python-multiplatform-ksp, from one constant`() { - assertEquals("org.thisisthepy:python-multiplatform-ksp:3.15.0-alpha02", DEFAULT_TYPEDPYTHON_GATE) + assertEquals("org.thisisthepy:python-multiplatform-ksp:3.15.0-alpha03", DEFAULT_TYPEDPYTHON_GATE) assertEquals( - "org.thisisthepy:python-multiplatform-ksp:3.15.0-alpha02:typedpython-gate@zip", + "org.thisisthepy:python-multiplatform-ksp:3.15.0-alpha03:typedpython-gate@zip", typedpythonGateNotation(DEFAULT_TYPEDPYTHON_GATE), ) assertEquals("typedpython.gate", TYPEDPYTHON_GATE_PROPERTY) diff --git a/usage-example/build.gradle.kts b/usage-example/build.gradle.kts index 9d38ac3..3dd656a 100644 --- a/usage-example/build.gradle.kts +++ b/usage-example/build.gradle.kts @@ -15,8 +15,8 @@ plugins { alias(libs.plugins.kotlin.native.desktop).apply(false) alias(libs.plugins.compose.compiler) // usage-example is its own build (settings.gradle.kts here). The toolchain plugin is resolved by - // coordinate from mavenLocal (`./gradlew :toolchain:publishToMavenLocal` in ../), as is - // python-multiplatform's bindings plugin, which stages and packages the CPython stdlib (#22). + // coordinate from mavenLocal (`./gradlew :toolchain:publishToMavenLocal` in ../); python-multiplatform's + // bindings plugin, which stages and packages the CPython stdlib (#22), comes from Maven Central. alias(libs.plugins.toolchain) alias(libs.plugins.python.multiplatform.bindings) } diff --git a/usage-example/gradle/libs.versions.toml b/usage-example/gradle/libs.versions.toml index 8c67728..cc85147 100644 --- a/usage-example/gradle/libs.versions.toml +++ b/usage-example/gradle/libs.versions.toml @@ -12,8 +12,9 @@ compose-multiplatform = "1.11.1-ext.2" compose-plugin = "1.11.1-ext.3" kotlin = "2.4.20-Beta2" kotlinx-coroutines = "1.10.1" -# python-multiplatform's library, KSP and bindings plugin share one version (its #70, #95, #318, #333). -python-multiplatform = "3.15.0-alpha02" +# python-multiplatform's library, KSP and bindings plugin share one version (its #70, #95, #318, #333), +# resolved from Maven Central. Keep it equal to the toolchain plugin's DEFAULT_TYPEDPYTHON_GATE. +python-multiplatform = "3.15.0-alpha03" # The toolchain plugin, from ../toolchain via mavenLocal (`./gradlew :toolchain:publishToMavenLocal`). toolchain = "1.0.0-alpha" diff --git a/usage-example/settings.gradle.kts b/usage-example/settings.gradle.kts index a065f3c..8a11f0d 100644 --- a/usage-example/settings.gradle.kts +++ b/usage-example/settings.gradle.kts @@ -1,10 +1,19 @@ // usage-example/ is its own Gradle build (toolchain#22, #62), run with the repository's wrapper: // ./gradlew -p usage-example …. It consumes python-multiplatform, which is built with Kotlin 2.4, so it uses // that toolchain (gradle/libs.versions.toml here); the plugin in ../toolchain stays on -// its own Kotlin for its consumers. Plugins and libraries resolve from Maven Central once published, -// and fall back to mavenLocal while unreleased (publish them locally first; see AGENTS.md Β§16). +// its own Kotlin for its consumers. python-multiplatform (library, KSP processor, bindings plugin and +// the typedpython-gate zip) resolves from Maven Central only: 3.15.0-alpha03 is its first Central +// release, so this build resolves once that upload is published. Only the toolchain plugin under test +// and packpack (group org.thisisthepy.python.multiplatform) come from mavenLocal, checked first, so the +// build exercises this checkout's plugin (`./gradlew :toolchain:publishToMavenLocal`; AGENTS.md Β§15-16) +// even after a version of it is on Central. pluginManagement { repositories { + mavenLocal { + content { + includeGroup("org.thisisthepy.python.multiplatform") + } + } google { mavenContent { includeGroupAndSubgroups("androidx") @@ -22,13 +31,6 @@ pluginManagement { } } gradlePluginPortal() - mavenLocal { - content { - includeGroupAndSubgroups("org.thisisthepy") - excludeGroupAndSubgroups("org.thisisthepy.compose") - excludeGroupAndSubgroups("org.thisisthepy.kotlin") - } - } } } @@ -50,13 +52,6 @@ dependencyResolutionManagement { mavenPom() } } - mavenLocal { - content { - includeGroupAndSubgroups("org.thisisthepy") - excludeGroupAndSubgroups("org.thisisthepy.compose") - excludeGroupAndSubgroups("org.thisisthepy.kotlin") - } - } } } From c8881ea1804884e28709954cbc8345056d2aaee6 Mon Sep 17 00:00:00 2001 From: BREW <81044362+b-re-w@users.noreply.github.com> Date: Sun, 8 Nov 2026 03:37:35 +0900 Subject: [PATCH 2/2] Review release-readiness WIP: keep the tcl fix and gate bump, drop Central-only claims (#125) Kept: findProjectRoot stops at the git repository root and searches no parent outside a repository, uv init --no-workspace, the new InstallerTest cases (red on the old Installer, green now), DEFAULT_TYPEDPYTHON_GATE and usage-example at 3.15.0-alpha03, compileSdk = "3.15.0" in the README and guide, tcl via uv tool install toolchain-lite (0.1.0 is on PyPI). Dropped: usage-example resolving python-multiplatform from Maven Central only, and the README/guide/SPEC text saying the plugin and python-multiplatform are already on Central. repo1.maven.org has no org/thisisthepy artefacts yet, so that would break the usage-example build; mavenLocal stays. --- .github/workflows/test.yml | 6 +++--- AGENTS.md | 6 +++--- README.md | 12 ++++++++--- docs/SPEC.md | 3 +-- docs/guide/getting-started.html | 16 +++++++-------- docs/locale/README_ko.md | 12 ++++++++--- usage-example/build.gradle.kts | 4 ++-- usage-example/gradle/libs.versions.toml | 4 ++-- usage-example/settings.gradle.kts | 27 +++++++++++++++---------- 9 files changed, 52 insertions(+), 38 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 89e09b5..b216b1f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -121,9 +121,9 @@ jobs: python-version: "3.15" - uses: astral-sh/setup-uv@v6 - # usage-example takes packpack (through the plugin) and the toolchain plugin from mavenLocal, and - # python-multiplatform (3.15.0-alpha03, usage-example/gradle/libs.versions.toml) from Maven Central - # only (usage-example/settings.gradle.kts), so its local publish below is not what the build uses. + # usage-example applies three things from mavenLocal: packpack (through the plugin), the + # toolchain plugin, and python-multiplatform's library and bindings plugin. Versions pinned in + # usage-example/gradle/libs.versions.toml (3.15.0-alpha03). - name: Publish packpack, the toolchain plugin and python-multiplatform to mavenLocal run: | (cd .ci/pypackpack && ./gradlew :packpack:publishToMavenLocal --console=plain) diff --git a/AGENTS.md b/AGENTS.md index fa76908..e067b6a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -245,9 +245,9 @@ history removing. Prerequisites: `org.thisisthepy.python.multiplatform:packpack:0.1.0` in `~/.m2` (published from the `pypackpack` repository), `uv` on `PATH`, and network access: `InstallDependenciesTaskTest` and `InstallerTest` run a real `uv add` against PyPI. `usage-example` additionally needs an Android SDK -(`ANDROID_HOME`) and python-multiplatform `3.15.0-alpha03` (library, KSP processor, bindings plugin), which it -resolves from Maven Central only; only the toolchain plugin and packpack come from `~/.m2`. That version must -equal `DEFAULT_TYPEDPYTHON_GATE` (`toolchain/.../typedpython/TypedpythonGate.kt`): bump both together. +(`ANDROID_HOME`) and python-multiplatform in `~/.m2`: from a python-multiplatform checkout, +`./gradlew publishAllToMavenLocal` (`org.thisisthepy:python-multiplatform*` and bindings plugin `3.15.0-alpha03`). +That version must equal `DEFAULT_TYPEDPYTHON_GATE` (`toolchain/.../typedpython/TypedpythonGate.kt`): bump both together. Run each module separately (rule 8), with output to a file under `.cache/`: diff --git a/README.md b/README.md index b63d007..4057a1a 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,14 @@ owns the Gradle vocabulary in between. ## πŸš€ Quick start -> `toolchain` is published to Maven Central with its Gradle plugin marker, starting with `1.0.0-alpha`: -> add `mavenCentral()` to `pluginManagement.repositories` in `settings.gradle.kts`. The plugin installs -> dependencies with `uv`, so have `uv` on your `PATH`. +> `toolchain` is published to Maven Central (with its Gradle plugin marker, so add `mavenCentral()` to +> `pluginManagement.repositories` in `settings.gradle.kts`). While pre-release, publish `pypackpack`'s +> `packpack` artifact and this plugin to `mavenLocal()` first, and have `uv` on your `PATH`. + +```shell +# in pypackpack: ./gradlew :packpack:publishToMavenLocal +./gradlew :toolchain:publishToMavenLocal +``` ```kotlin // settings.gradle.kts @@ -58,6 +63,7 @@ pluginManagement { repositories { mavenCentral() gradlePluginPortal() + mavenLocal() // while using an unreleased local build } } ``` diff --git a/docs/SPEC.md b/docs/SPEC.md index 77c7080..249f1f4 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -543,8 +543,7 @@ bundled. Every `buildPython` and the single host `buildPytho its processor jar, `org.thisisthepy:python-multiplatform-ksp:3.15.0-alpha03:typedpython-gate@zip` (`DEFAULT_TYPEDPYTHON_GATE`, the one place its group and version are written; `-Ptypedpython.gate= ` overrides it). It is resolved leniently from the project's own - repositories (Maven Central has it from python-multiplatform 3.15.0-alpha03, its first Central release; - python-multiplatform's `publishToMavenLocal` puts it in `mavenLocal()`), unzipped into + repositories (python-multiplatform's `publishToMavenLocal` puts it in `mavenLocal()`), unzipped into `build/typedpython/gate`, and its manifest `typedpython-gate.json` (format 1) gives typedpython's wheel, version and SHA-256 and the SHA-256 of every pyrefly PyPI wheel. The install is `uv pip install --python --require-hashes -r build/typedpython/gate-requirements.txt`, where diff --git a/docs/guide/getting-started.html b/docs/guide/getting-started.html index 90c953d..3da9e8c 100644 --- a/docs/guide/getting-started.html +++ b/docs/guide/getting-started.html @@ -28,15 +28,13 @@

Getting startedμ‹œμž‘ν•˜κΈ°

1. Prerequisites1. μ€€λΉ„λ¬Ό

-
Needν•„μš”ν•œ 것Why이유
JDK 17+ and Gradle 8.9 (wrapper)JDK 17 이상, Gradle 8.9 (래퍼)The build itself.λΉŒλ“œ 자체.
uv on PATHPATH 의 uvpypackpack installs dependencies with it.pypackpack 이 μ˜μ‘΄μ„± μ„€μΉ˜μ— μ”λ‹ˆλ‹€.
mavenCentral() in pluginManagement.repositoriespluginManagement.repositories 의 mavenCentral()The plugin, its marker and pypackpack (the library it depends on) come from Maven Central.ν”ŒλŸ¬κ·ΈμΈ, 마컀, 그리고 ν”ŒλŸ¬κ·ΈμΈμ΄ μ˜μ‘΄ν•˜λŠ” pypackpack 라이브러리λ₯Ό Maven Central μ—μ„œ λ°›μŠ΅λ‹ˆλ‹€.
Android SDK (ANDROID_HOME)Android SDK (ANDROID_HOME)Only if your module has an Android target.λͺ¨λ“ˆμ— Android 타깃이 μžˆμ„ λ•Œλ§Œ.
-
// settings.gradle.kts
-pluginManagement {
-    repositories {
-        mavenCentral()
-        gradlePluginPortal()
-    }
-}
-

The plugin and its marker are published to Maven Central, starting with 1.0.0-alpha. To try an unreleased change from a checkout, see Contributing.

ν”ŒλŸ¬κ·ΈμΈκ³Ό λ§ˆμ»€λŠ” 1.0.0-alpha λΆ€ν„° Maven Central 에 λ°°ν¬λ©λ‹ˆλ‹€. μ²΄ν¬μ•„μ›ƒμ˜ μΆœμ‹œ μ „ 변경을 써 보렀면 κΈ°μ—¬ν•˜κΈ°λ₯Ό λ³΄μ„Έμš”.

+
Needν•„μš”ν•œ 것Why이유
JDK 17+ and Gradle 8.9 (wrapper)JDK 17 이상, Gradle 8.9 (래퍼)The build itself.λΉŒλ“œ 자체.
uv on PATHPATH 의 uvpypackpack installs dependencies with it.pypackpack 이 μ˜μ‘΄μ„± μ„€μΉ˜μ— μ”λ‹ˆλ‹€.
packpack:0.1.0 in Maven LocalMaven Local 의 packpack:0.1.0The plugin depends on pypackpack as a library.ν”ŒλŸ¬κ·ΈμΈμ΄ pypackpack 을 라이브러리둜 μ”λ‹ˆλ‹€.
Android SDK (ANDROID_HOME)Android SDK (ANDROID_HOME)Only if your module has an Android target.λͺ¨λ“ˆμ— Android 타깃이 μžˆμ„ λ•Œλ§Œ.
+
# in a pypackpack checkout
+./gradlew :packpack:publishToMavenLocal
+
+# in this repository
+./gradlew :toolchain:publishToMavenLocal
+

The plugin and its marker are distributed through Maven Central (with mavenLocal() as the fallback while pre-release). Put mavenCentral() in pluginManagement.repositories in your settings.gradle.kts (plus mavenLocal() for local builds).

ν”ŒλŸ¬κ·ΈμΈκ³Ό λ§ˆμ»€λŠ” Maven Central 둜 λ°°ν¬λ©λ‹ˆλ‹€(μΆœμ‹œ μ „μ—λŠ” mavenLocal() 둜 λŒ€μ²΄). settings.gradle.kts 의 pluginManagement.repositories 에 mavenCentral() 을 λ‘μ„Έμš”(둜컬 λΉŒλ“œλ₯Ό μ“Έ λ•ŒλŠ” mavenLocal() 도 ν•¨κ»˜).

diff --git a/docs/locale/README_ko.md b/docs/locale/README_ko.md index 224a630..bbc7a49 100644 --- a/docs/locale/README_ko.md +++ b/docs/locale/README_ko.md @@ -47,9 +47,14 @@ Python 을 λ‚΄μž₯ν•œ Kotlin Multiplatform μ•±μ—λŠ” 맞물렀 λŒμ•„κ°€μ•Ό ν•˜ ## πŸš€ λΉ λ₯Έ μ‹œμž‘ -> `toolchain` 은 `1.0.0-alpha` λΆ€ν„° Gradle ν”ŒλŸ¬κ·ΈμΈ λ§ˆμ»€μ™€ ν•¨κ»˜ Maven Central 에 λ°°ν¬λ©λ‹ˆλ‹€. -> `settings.gradle.kts` 의 `pluginManagement.repositories` 에 `mavenCentral()` 을 λ‘μ„Έμš”. ν”ŒλŸ¬κ·ΈμΈμ΄ -> `uv` 둜 μ˜μ‘΄μ„±μ„ μ„€μΉ˜ν•˜λ―€λ‘œ `PATH` 에 `uv` κ°€ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. +> `toolchain` 은 Gradle ν”ŒλŸ¬κ·ΈμΈ λ§ˆμ»€μ™€ ν•¨κ»˜ Maven Central 에 λ°°ν¬λ©λ‹ˆλ‹€(`settings.gradle.kts` 의 +> `pluginManagement.repositories` 에 `mavenCentral()` 을 λ‘μ„Έμš”). 정식 μΆœμ‹œ μ „μ—λŠ” `pypackpack` 의 +> `packpack` μ•„ν‹°νŒ©νŠΈμ™€ 이 ν”ŒλŸ¬κ·ΈμΈμ„ λ¨Όμ € `mavenLocal()` 에 λ°°ν¬ν•˜κ³ , `PATH` 에 `uv` κ°€ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. + +```shell +# pypackpack μ—μ„œ: ./gradlew :packpack:publishToMavenLocal +./gradlew :toolchain:publishToMavenLocal +``` ```kotlin // settings.gradle.kts @@ -57,6 +62,7 @@ pluginManagement { repositories { mavenCentral() gradlePluginPortal() + mavenLocal() // μΆœμ‹œ μ „ 둜컬 λΉŒλ“œλ₯Ό μ“Έ λ•Œ } } ``` diff --git a/usage-example/build.gradle.kts b/usage-example/build.gradle.kts index 3dd656a..9d38ac3 100644 --- a/usage-example/build.gradle.kts +++ b/usage-example/build.gradle.kts @@ -15,8 +15,8 @@ plugins { alias(libs.plugins.kotlin.native.desktop).apply(false) alias(libs.plugins.compose.compiler) // usage-example is its own build (settings.gradle.kts here). The toolchain plugin is resolved by - // coordinate from mavenLocal (`./gradlew :toolchain:publishToMavenLocal` in ../); python-multiplatform's - // bindings plugin, which stages and packages the CPython stdlib (#22), comes from Maven Central. + // coordinate from mavenLocal (`./gradlew :toolchain:publishToMavenLocal` in ../), as is + // python-multiplatform's bindings plugin, which stages and packages the CPython stdlib (#22). alias(libs.plugins.toolchain) alias(libs.plugins.python.multiplatform.bindings) } diff --git a/usage-example/gradle/libs.versions.toml b/usage-example/gradle/libs.versions.toml index cc85147..d00bb42 100644 --- a/usage-example/gradle/libs.versions.toml +++ b/usage-example/gradle/libs.versions.toml @@ -12,8 +12,8 @@ compose-multiplatform = "1.11.1-ext.2" compose-plugin = "1.11.1-ext.3" kotlin = "2.4.20-Beta2" kotlinx-coroutines = "1.10.1" -# python-multiplatform's library, KSP and bindings plugin share one version (its #70, #95, #318, #333), -# resolved from Maven Central. Keep it equal to the toolchain plugin's DEFAULT_TYPEDPYTHON_GATE. +# python-multiplatform's library, KSP and bindings plugin share one version (its #70, #95, #318, #333). +# Keep it equal to the toolchain plugin's DEFAULT_TYPEDPYTHON_GATE. python-multiplatform = "3.15.0-alpha03" # The toolchain plugin, from ../toolchain via mavenLocal (`./gradlew :toolchain:publishToMavenLocal`). toolchain = "1.0.0-alpha" diff --git a/usage-example/settings.gradle.kts b/usage-example/settings.gradle.kts index 8a11f0d..a065f3c 100644 --- a/usage-example/settings.gradle.kts +++ b/usage-example/settings.gradle.kts @@ -1,19 +1,10 @@ // usage-example/ is its own Gradle build (toolchain#22, #62), run with the repository's wrapper: // ./gradlew -p usage-example …. It consumes python-multiplatform, which is built with Kotlin 2.4, so it uses // that toolchain (gradle/libs.versions.toml here); the plugin in ../toolchain stays on -// its own Kotlin for its consumers. python-multiplatform (library, KSP processor, bindings plugin and -// the typedpython-gate zip) resolves from Maven Central only: 3.15.0-alpha03 is its first Central -// release, so this build resolves once that upload is published. Only the toolchain plugin under test -// and packpack (group org.thisisthepy.python.multiplatform) come from mavenLocal, checked first, so the -// build exercises this checkout's plugin (`./gradlew :toolchain:publishToMavenLocal`; AGENTS.md Β§15-16) -// even after a version of it is on Central. +// its own Kotlin for its consumers. Plugins and libraries resolve from Maven Central once published, +// and fall back to mavenLocal while unreleased (publish them locally first; see AGENTS.md Β§16). pluginManagement { repositories { - mavenLocal { - content { - includeGroup("org.thisisthepy.python.multiplatform") - } - } google { mavenContent { includeGroupAndSubgroups("androidx") @@ -31,6 +22,13 @@ pluginManagement { } } gradlePluginPortal() + mavenLocal { + content { + includeGroupAndSubgroups("org.thisisthepy") + excludeGroupAndSubgroups("org.thisisthepy.compose") + excludeGroupAndSubgroups("org.thisisthepy.kotlin") + } + } } } @@ -52,6 +50,13 @@ dependencyResolutionManagement { mavenPom() } } + mavenLocal { + content { + includeGroupAndSubgroups("org.thisisthepy") + excludeGroupAndSubgroups("org.thisisthepy.compose") + excludeGroupAndSubgroups("org.thisisthepy.kotlin") + } + } } }