There are 2 updates, 1 comment.
 
 
XWiki Platform / cid:jira-generated-image-avatar-d6dc3a43-84e2-40f5-a324-ae5babca6c17 XWIKI-10330 Open

Allow forcing the redeployment of an already-installed extension version

 
View issue   ·   Add comment
 

2 updates

 
cid:jira-generated-image-avatar-6fa05028-0fdf-4fd9-a3b8-1f97b16628e3 Changes by Vincent Massol on 25/Aug/26 14:58
 
Summary: Allow reinstalling forcing the redeployment of an already-installed extension from an extension repository in the extension manager version
Description: This should be helpful in different use case: h2. Scope

- reinstall an upgraded snapshot Allow forcing the redeployment of an extension version that is *already installed*: re-run the same extension while testing
handlers for that same version, so that a JAR is re - repair deployed and the pages of a broken XAR are re-imported. This covers repairing an extension that have whose deployed content has been locally corrupted , modified or partly deleted, and it applies to released extensions as much as to SNAPSHOTs.

Refreshing an installed SNAPSHOT extension with a more recent build while developing -- the first use case of the original description, kept in the first comment of this issue -- is *out of scope* here and is handled by XCOMMONS-2748 instead. That is an upgrade rather than a reinstall: with timestamped SNAPSHOT versions the two builds are different versions, so the normal upgrade path applies and the XAR three-way merge keeps working.

h2. Why the existing features do not cover this

*
The workaround "Repair" action only rewrites the installed-extensions index. {{Action.REPAIR}} calls {{ExtensionHandler#initialize()}}, a no-op in {{AbstractExtensionHandler}} that {{XarExtensionHandler}} does not override, so no content is to use http redeployed -- as the UI itself states : // {{ extensions. xwiki actions . org/xwiki/bin/view/Extension/Extension+Tweak repairXAR.hint=Mark this XAR extension as installed without importing its wiki pages}}. It is moreover gated on {{!isValid(namespace)}}, and do validity is computed purely from the following: dependency graph recorded in the index, so a corrupted artifact or a modified or deleted page never marks an extension invalid and never surfaces a Repair button.
*
uninstall Installing the same id and version again short-circuits in {{AbstractInstallPlanJob#checkInstalledExtension()}}, with {{InstallException("Extension [%s] is already installed on namespace [%s]")}} when {{failOnExist}} is set (the default) and an empty plan plus a warning otherwise. {{RepairXarJob}} short-circuits the same way. There is no {{force}} or {{reinstall}} property on {{InstallRequest}}.
*
clean "Compute changes" ({{DiffXarJob}}) plus the local per-page "Reset" button ({{XarExtensionScriptService#reset()}}, {{Packager#reset()}}) does reset a page to its packaged state, and does recreate a page that was deleted, but it is one page per click, it requires a full diff job to run first, and there is no bulk operation for all the pages of an extension using Extension Tweak .
*
The remaining workaround is still uninstall followed by install , which deletes the pages and loses any customisation.

h2. Expected behaviour

* An explicit action on an already-installed extension which computes a plan and, once that plan has been validated by the user, re-runs the handlers for the same version. Computing the plan must stay read-only: nothing may be uninstalled, deleted or downloaded before the user has accepted the plan.
* For a XAR, the pages must be merged the way a newly installed page is: ignore the previous version entirely and compare the current (database) version against the next (packaged) version, raising a conflict when the two differ, so that customisations are never silently discarded.
 
 

1 comment

 
cid:jira-generated-image-avatar-6fa05028-0fdf-4fd9-a3b8-1f97b16628e3 Vincent Massol on 25/Aug/26 14:58
 

Re-scoping this issue

Following the review of the pull requests attached to this issue (both now closed: https://github.com/xwiki/xwiki-platform/pull/5383 and https://github.com/xwiki/xwiki-commons/pull/1703), the SNAPSHOT use case is removed from this issue and handled by XCOMMONS-2748 instead.

Thomas Mortagne is right that refreshing an installed SNAPSHOT with a more recent build is an upgrade, not a reinstall. Framed that way, the XAR problem the pull request was stuck on disappears on its own: with timestamped SNAPSHOT versions the two builds are genuinely different versions, so the extension handler gets a distinct previous version and the three-way merge works as designed, with no need for any "force overwrite" flag.

What the existing features actually cover

I checked the code before deciding what was left here, because two of the candidate answers turned out to be wrong.

The "Repair" action does not redeploy anything. It only rewrites the installed-extensions index: Action.REPAIR calls ExtensionHandler#initialize(), which is a no-op in AbstractExtensionHandler and is not overridden by XarExtensionHandler, so no page is ever touched. The UI string says so outright: extensions.actions.repairXAR.hint=Mark this XAR extension as installed without importing its wiki pages. It is also gated on the extension being invalid, and validity (DefaultInstalledExtensionRepository#validateExtension()) is computed purely from the dependency graph recorded in the index – a corrupted artifact or a modified or deleted wiki page never makes an extension invalid, so the Repair affordance never even appears for those. Reusing the repair semantics is therefore not an option: repair is the opposite of redeploying.

Restoring a deleted or modified extension page, on the other hand, is already possible today, which I had not realised: "Compute changes" (DiffXarJob) followed by the per-page "Reset" button (XarExtensionScriptService#reset() then Packager#reset(), available since 9.3RC1) resets a page to its packaged state, and because getDocument() returns a fresh empty document when the page is absent, it also recreates a page that was deleted. Its limits are ergonomic rather than functional: one page per click, a full diff job has to run first, and there is no bulk "restore all the pages of this extension" operation.

What is left

Forcing a clean redeploy of an already-installed version – which covers the "repair a broken extension that have been locally corrupted" use case of the original description, and applies to released extensions just as much as to SNAPSHOTs. XCOMMONS-2748 does not address it: there is no SNAPSHOT special-casing anywhere in the plan or install pipeline, and the same-version short-circuit applies to SNAPSHOTs too. It is blocked three separate ways today, which the updated description lists.

Original description, for the record

This should be helpful in different use case:

  • reinstall an upgraded snapshot of the same extension while testing
  • repair a broken extension that have been locally corrupted

The workaround is to use http://extensions.xwiki.org/xwiki/bin/view/Extension/Extension+Tweak and do the following:

  • uninstall
  • clean the local extension using Extension Tweak
  • install