Skip to content

Phase 1: Multi-platform support — Python implementation + compatibility test harness - #49

Merged
loesak merged 29 commits into
masterfrom
feature/multi-platform-phase1
Jun 23, 2026
Merged

Phase 1: Multi-platform support — Python implementation + compatibility test harness#49
loesak merged 29 commits into
masterfrom
feature/multi-platform-phase1

Conversation

@loesak

@loesak loesak commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds a Python implementation of esque (implementations/python/) mirroring the JVM structure: class-based Esque orchestrator, EsqueConfiguration, elasticsearch-py client, distributed locking, template resolution, and canonical checksum
  • Adds a black-box compatibility test harness (tests/) that runs all registered implementations via CLI against a shared Elasticsearch testcontainer and asserts behavioral equivalency across 35 scenarios
  • Restructures the JVM build into implementations/jvm/ as a single-project Gradle build and replaces the monolithic CI with split ci.yml + release.yml
  • Fixes the canonical checksum algorithm so JVM and Python produce identical values for the same migration content (explicit map serialization to guarantee alphabetical key order)
  • Adds cross-implementation record equivalency test asserting JVM and Python write identical checksums, versions, descriptions, and order values

Test plan

  • All 35 compatibility tests pass (JVM + Python, including cross-implementation equivalency)
  • Pre-commit hook runs JVM checks, Python lint/typecheck, and full compatibility suite
  • uv run esque --help works from implementations/python/
  • ./gradlew run --args="--help" works from implementations/jvm/

🤖 Generated with Claude Code

Aaron Loes and others added 29 commits June 13, 2026 21:38
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the Gradle application plugin and Clikt 4.4.0 so the JVM
implementation can be invoked as a subprocess via ./gradlew :esque-core:run
--args="...". CLI accepts --es-url, --migrations-dir, --migration-key,
--migration-user, --lock-timeout-minutes, and repeatable --property flags.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
17 test scenarios covering initialization, execution, idempotency, key
independence, history metadata, user recording, template substitution,
integrity verification, and numeric version ordering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…f get_url

ElasticSearchContainer in testcontainers-python 4.x has no get_url().
Construct the URL from get_container_host_ip() and get_exposed_port(9200).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- requires-python bumped to >=3.14
- ruff (0.11+) and ty (0.0.49) added as dev dependencies
- ruff configured with E/W/F/I/N/UP/B/RUF rules, line-length 120
- subprocess.CompletedProcess[str], list[dict[str, Any]] type params added
- Iterator[str] return type on es_url fixture
- Guard added for impl.task None case in run()
- Unused assert_index_absent import removed from test file
- zip() given strict=True, bare f-string prefix removed
- Import blocks sorted per isort

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ty has no --strict flag; warn-level rules are explicitly set to error
in [tool.ty.rules] to match the strictness intent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- pyright 1.1.410 added as dev dependency with typeCheckingMode = "strict"
- reportMissingTypeStubs disabled (testcontainers has no py.typed)
- default_factory=list -> lambda: [] to resolve list[Unknown] in strict mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves esque-core/ to implementations/jvm/ and updates settings.gradle.kts
to remap the :esque-core project directory. Removes esque-examples/ (not
published, not needed for the multi-platform effort). Maven artifact ID
org.loesak:esque-core is unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switches checksum serialization from YAML to compact JSON with
alphabetically sorted keys and nulls omitted. Both produce identical
MD5-first-4-bytes integers, but JSON canonical form is language-neutral
and precisely replicable in any implementation without a YAML dependency.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ests

Python implementation in implementations/python/ uses Click for CLI,
httpx for ES REST calls, and PyYAML for migration file parsing. Implements
the full Esque behavioral contract: initialization, file loading, template
resolution, checksum (JSON canonical matching the JVM), distributed locking
via ES op_type=create, integrity verification, and idempotent execution.

All 34 compatibility tests pass (17 scenarios × 2 implementations).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ci.yml runs on every push and PR: build-jvm (ktfmtCheck + detekt + test),
build-python (ruff + pyright), and compatibility-tests (34 scenarios via
testcontainers, parametrized over both implementations). Jobs build-jvm and
build-python run in parallel; compatibility-tests gates on both.

release.yml runs only on published GitHub releases: publish-jvm to Maven
Central (unchanged) and publish-python to PyPI via UV_PUBLISH_TOKEN.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Relocates gradlew, gradlew.bat, gradle/, gradle.properties, detekt.yml,
and settings.gradle.kts from the repo root into implementations/jvm/.
Merges the root build.gradle.kts (plugin declarations, group/version,
kotlin toolchain, detekt config, repositories) into implementations/jvm/
build.gradle.kts so it stands as a self-contained single-project build.

Updates .githooks/pre-commit, CI workflows, and the test harness
implementations.yml/helpers.py to cd into implementations/jvm (or use
gradle_dir) when invoking Gradle. All 34 compatibility tests still pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pre-commit now runs three stages in sequence:
  [1/3] JVM: ktfmtCheck + detekt + test
  [2/3] Python: ruff check + ruff format --check + pyright
  [3/3] Compatibility tests: pytest (34 scenarios × 2 implementations)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Python)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, classifiers, URLs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@loesak
loesak merged commit 13e1826 into master Jun 23, 2026
3 checks passed
@loesak
loesak deleted the feature/multi-platform-phase1 branch June 23, 2026 04:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant