Skip to content

[bugfix] repo:install-and-deploy respect explicitly-requested version#6433

Open
joewiz wants to merge 1 commit into
eXist-db:developfrom
joewiz:bugfix/install-and-deploy-respect-version
Open

[bugfix] repo:install-and-deploy respect explicitly-requested version#6433
joewiz wants to merge 1 commit into
eXist-db:developfrom
joewiz:bugfix/install-and-deploy-respect-version

Conversation

@joewiz
Copy link
Copy Markdown
Member

@joewiz joewiz commented Jun 2, 2026

[This PR was co-authored with Claude Code. -Joe]

Summary

When a higher version of a package is already installed in the EXPath registry, calling repo:install-and-deploy($name, $version, $url) with an explicit lower $version reports success but silently deploys the existing higher version instead of the one the user asked for. This PR makes the deploy step use the freshly-installed package directly, so the explicit version request is honored.

This was surfaced by Craig Berry on Slack while attempting to downgrade tei-publisher-lib from 6.1.0 to 6.0.2. A companion fix for the related silent-failure on repo:remove is in #6432.

What changed

exist-core/src/main/java/org/exist/repo/Deployment.java

  • Added a Package-based overload deploy(DBBroker, Txn, Package, String). The body is the prior deploy(... String pkgName, Optional<ExistRepository> repo, ...) lifted to take a Package directly, so the package-dir / abbrev / version lookups all flow from one consistent source instead of re-resolving by name halfway through.
  • The original by-name overload is kept (for repo:deploy(name) callers) and delegates to the new one via getPackage(pkgName, repo).
  • installAndDeploy(...) now resolves the just-installed package by the version extracted from the XAR descriptor (Packages.version(requestedVersion)) rather than relying on what installPackage() returns — which, for the higher-version-already-present case, was packages.latest(). The lookup is in a small resolveInstalledVersion() helper to keep installAndDeploy's NPath complexity at its prior level.

extensions/modules/expathrepo/src/test/xquery/modules/expathrepo/deployment.xql

  • New regression test deploy:install-lower-version-after-higher: installs version 1.0.0, then installs version 0.5.0 (using fresh fixtures with name http://exist-db.org/apps/dtest-versioning to avoid polluting other tests), and asserts that the expath-pkg.xml written to the deployed target collection /db/apps/dtest-versioning/ reports version 0.5.0. Before the fix this returned 1.0.0.
  • The assertion reads doc("/db/apps/<target>/expath-pkg.xml") rather than repo:get-resource(name, "expath-pkg.xml") — the latter returns from packages.latest()'s repo dir and so reports 1.0.0 even after a correct deploy of 0.5.0; only the deployed target collection shows what was actually delivered to the user.

Root cause

In Deployment.installAndDeploy:

  1. repo.getParentRepo().installPackage(xar, ...) is called, which installs the XAR into the registry and returns some Package — but for an EXPath name with multiple versions present, it returns packages.latest(), not necessarily the just-installed one.
  2. The follow-up deploy(pkgName, ...) then calls getPackage(pkgName, repo), which also returns packages.latest(), and deploys from that package's dir.

So even though the right XAR was unpacked into data/expathrepo/<abbrev>-<requested>/, the deploy step copies files out of data/expathrepo/<abbrev>-<latest>/ into /db/apps/<target>/. Result: install OK, but deploy installs the wrong version, with no error.

Test plan

  • mvn test -pl extensions/modules/expathrepo -Dtest='ExpathRepoTests' — 9/9 pass (8 prior + new regression)
  • Codacy / PMD on changed Java file — no new warnings introduced (NPath, cleanup() unused, parameter reassignment warnings are pre-existing on this file)
  • Manually reproduced Craig's scenario (install 1.0.0, then repo:install-and-deploy(name, "0.5.0", url) against local copy of the XAR) — before this commit, deployed expath-pkg.xml reports 1.0.0; after, 0.5.0.

Related

When a higher version of a package is already in the EXPath registry,
calling repo:install-and-deploy(name, "<lower>", url) would correctly
fetch the requested XAR and install it into the registry, but the
subsequent deploy() step would re-resolve by name via packages.latest()
and deploy the existing higher version's directory instead. The user
sees a successful "ok" status, but the deployed application is the
higher version, not the one they asked for.

Two changes:

1. Deployment.deploy(...) now has a Package-based overload that takes
   the freshly-installed Package directly. The by-name overload is kept
   and delegates to the new one via getPackage(pkgName, repo).

2. installAndDeploy(...) looks up the package by the version extracted
   from the XAR descriptor (via Packages.version(...)) and passes it to
   the Package-based deploy overload, bypassing packages.latest().

Includes XQSuite regression test (deploy:install-lower-version-after-higher):
install 1.0.0, then install 0.5.0 over it, and verify the deployed
expath-pkg.xml in the target collection is 0.5.0's, not 1.0.0's.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@joewiz joewiz requested a review from a team as a code owner June 2, 2026 19: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