From 65f582692d9294111fa936d1bc6262fde9d13506 Mon Sep 17 00:00:00 2001 From: James Lechtner Date: Fri, 10 Apr 2026 12:27:29 -0400 Subject: [PATCH 1/4] Update should check version requirements using post-update values instead of what's currently installed --- src/cls/IPM/Storage/Module.cls | 2 +- src/cls/IPM/Utils/Module.cls | 89 ++++++++++++++----- .../Test/PM/Integration/Update.cls | 61 +++++++++++++ .../module-a/cls/ModuleA/Class1.cls | 9 ++ .../post-update/module-a/module.xml | 16 ++++ .../module-b/cls/ModuleB/Class1.cls | 9 ++ .../post-update/module-b/module.xml | 16 ++++ .../module-c/cls/ModuleC/Class1.cls | 9 ++ .../post-update/module-c/module.xml | 10 +++ .../module-a/cls/ModuleA/Class1.cls | 9 ++ .../pre-update/module-a/module.xml | 16 ++++ .../module-b/cls/ModuleB/Class1.cls | 9 ++ .../pre-update/module-b/module.xml | 16 ++++ .../module-c/cls/ModuleC/Class1.cls | 9 ++ .../pre-update/module-c/module.xml | 10 +++ .../module-d/cls/ModuleD/Class1.cls | 9 ++ .../pre-update/module-d/module.xml | 16 ++++ 17 files changed, 290 insertions(+), 25 deletions(-) create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-a/cls/ModuleA/Class1.cls create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-a/module.xml create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-b/cls/ModuleB/Class1.cls create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-b/module.xml create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-c/cls/ModuleC/Class1.cls create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-c/module.xml create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-a/cls/ModuleA/Class1.cls create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-a/module.xml create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-b/cls/ModuleB/Class1.cls create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-b/module.xml create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-c/cls/ModuleC/Class1.cls create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-c/module.xml create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-d/cls/ModuleD/Class1.cls create mode 100644 tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-d/module.xml diff --git a/src/cls/IPM/Storage/Module.cls b/src/cls/IPM/Storage/Module.cls index c5b402a58..80406b687 100644 --- a/src/cls/IPM/Storage/Module.cls +++ b/src/cls/IPM/Storage/Module.cls @@ -1074,7 +1074,7 @@ Method ProcessSingleDependencyIterative( } set sc = ##class(%IPM.Utils.Module).GetRequiredVersionExpression( - pDep.Name,otherDepsList,.installedReqExpr,.installedConstraintList + pDep.Name,otherDepsList,,.installedReqExpr,.installedConstraintList ) $$$ThrowOnError(sc) set searchExpr = searchExpr.And(installedReqExpr) diff --git a/src/cls/IPM/Utils/Module.cls b/src/cls/IPM/Utils/Module.cls index b2903e36d..144393e9d 100644 --- a/src/cls/IPM/Utils/Module.cls +++ b/src/cls/IPM/Utils/Module.cls @@ -114,7 +114,7 @@ ClassMethod LoadModuleReference( // Ensure requested versions match those required by other modules in the namespace, excluding versions currently being installed // (the requirements of such modules are already known to be satisfied) - set tSC = ..GetRequiredVersionExpression(pModuleName,,.tExpression,.tSourceList) + set tSC = ..GetRequiredVersionExpression(pModuleName,,.pDependencyGraph,.tExpression,.tSourceList) if $$$ISERR(tSC) { quit } @@ -350,35 +350,76 @@ ClassMethod GetModuleObjectFromString( /// Returns a semantic version expression capturing all version requirements for a given module name in the current namespace. /// A list of modules to exclude may be provided (for example, if these modules would be updated at the same time). ClassMethod GetRequiredVersionExpression( - pModuleName As %String, - pExcludeModules As %List = "", - Output pExpression As %IPM.General.SemanticVersionExpression, - Output pSourceList As %List) As %Status + moduleName As %String, + excludeModules As %List = "", + ByRef dependencyGraph, + Output expression As %IPM.General.SemanticVersionExpression, + Output sourceList As %List) As %Status { - set tSC = $$$OK + set sc = $$$OK try { - set pExpression = ##class(%IPM.General.SemanticVersionExpression).%New() - set pSourceList = "" + // Add modules from the dependency graph to the excludeModules list + if ($data(dependencyGraph)) { + do ..ConstructInvertedDependencyGraph(.dependencyGraph, .invertedDependencyGraph) + set flatDepList = ..GetFlatDependencyListFromInvertedDependencyGraph(.invertedDependencyGraph) + for i = 1:1:flatDepList.Count() { + set excludeModules = excludeModules _ $listbuild(flatDepList.GetAt(i).Name) + } + } - set tResult = ##class(%IPM.Storage.Module).VersionRequirementsFunc(pModuleName,pExcludeModules) - if (tResult.%SQLCODE < 0) { - $$$ThrowStatus($$$ERROR($$$SQLCode,tResult.%SQLCODE,tResult.%Message)) + set expression = ##class(%IPM.General.SemanticVersionExpression).%New() + set sourceList = "" + + set result = ##class(%IPM.Storage.Module).VersionRequirementsFunc(moduleName,excludeModules) + if (result.%SQLCODE < 0) { + $$$ThrowStatus($$$ERROR($$$SQLCode,result.%SQLCODE,result.%Message)) } - while tResult.%Next(.tSC) { - $$$ThrowOnError(tSC) - set tVersion = tResult.%Get("Version") - $$$ThrowOnError(##class(%IPM.General.SemanticVersionExpression).FromString(tVersion,.tVersionExpr)) - set pExpression = pExpression.And(tVersionExpr) - set pSourceList = pSourceList_$listbuild($listtostring(tResult.%Get("ModuleNames"),", ")_": "_tVersion) + while result.%Next(.sc) { + $$$ThrowOnError(sc) + set version = result.%Get("Version") + $$$ThrowOnError(##class(%IPM.General.SemanticVersionExpression).FromString(version,.versionExpr)) + set expression = expression.And(versionExpr) + set sourceList = sourceList_$listbuild($listtostring(result.%Get("ModuleNames"),", ")_": "_version) } - $$$ThrowOnError(tSC) + + // Add modules from the dependency graph to the expression and sourceList objects + if ($data(dependencyGraph)) { + set key = "" + for { + set key = $order(dependencyGraph(moduleName, key)) + if (key = "") { + quit + } + // Name of module which requires this one + the version expression string it requires + set requiringModuleName = $piece(key, " ") + set version = dependencyGraph(moduleName, key) + + // Iterate over sourceList; if the required version expression is equivalent to this one, add this module name to that version + set newVersion = 1 + for i=1:1:$listlength(sourceList) { + if $find($listget(sourceList, i), version) { + set $list(sourceList, i) = requiringModuleName _ ", " _ $list(sourceList, i) + set newVersion = 0 + quit + } + } + // If this is a new required version expression, add a new item to the list + if (newVersion) { + $$$ThrowOnError(##class(%IPM.General.SemanticVersionExpression).FromString(version, .versionExpr)) + set expression = expression.And(versionExpr) + set sourceList = sourceList _ $listbuild(requiringModuleName _ ": " _ version) + } + } + } + + $$$ThrowOnError(sc) } catch e { - set pExpression = $$$NULLOREF - set pSourceList = "" - set tSC = e.AsStatus() + set expression = $$$NULLOREF + set sourceList = "" + set sc = e.AsStatus() } - quit tSC + quit sc } /// Returns a flat list of dependents for a given module name (and optional version)
@@ -1251,7 +1292,7 @@ ClassMethod LoadDependencies( set reloadSnapshots = +$get(pParams("UpdateSnapshots")) set permitDowngrade = +$get(pParams("PermitDowngrade")) - set ignoreInstalled = +$get(pParams("IgnoreInstalled")) + set ignoreInstalled = +$get(pParams("zpm", "IgnoreInstalled")) write !, "Building dependency graph..." // Intentionally always write even in non-verbose mode set sc = pModule.BuildDependencyGraph(.dependencyGraph,,reloadSnapshots,,phaseList,,,,ignoreInstalled,,permitDowngrade) $$$ThrowOnError(sc) @@ -1278,7 +1319,7 @@ ClassMethod LoadDependencies( // Ignore modules already installed that do not need to be installed again continue } - set sc = ..LoadModuleReference(moduleReference.ServerName, moduleReference.Name, moduleReference.VersionString, moduleReference.Deployed, moduleReference.PlatformVersion, .pParams) + set sc = ..LoadModuleReference(moduleReference.ServerName, moduleReference.Name, moduleReference.VersionString, moduleReference.Deployed, moduleReference.PlatformVersion, .pParams, .dependencyGraph) $$$ThrowOnError(sc) } diff --git a/tests/integration_tests/Test/PM/Integration/Update.cls b/tests/integration_tests/Test/PM/Integration/Update.cls index 9fe4a9a6f..58fb97356 100644 --- a/tests/integration_tests/Test/PM/Integration/Update.cls +++ b/tests/integration_tests/Test/PM/Integration/Update.cls @@ -662,4 +662,65 @@ Method TestDevModePropagation() do $$$AssertEquals(dep.DeveloperMode, 0) } +/// Test case to make sure that update doesn't fail due to version errors that get resolved as a part of update +/// i.e. - Module A 1.0.0 requires Module B ^1.0.0 +/// - Module A 2.0.0 requires Module B ^2.0.0 +/// - Pre-Update: Module A 1.0.0, Module B 1.3.0 +/// - Post-Update: Module A 2.0.0, Module B 2.0.1 +/// - Don't want a version error to be thrown in flight when Module A is 2.0.0 and Module B is still 1.3.0 +Method TestDependencyVersionsUpdated() +{ + // Define variables for this test + set modA = "module-a" + set modB = "module-b" + set modC = "module-c" + set modD = "module-d" + + set modAPreVersion = "2.0.0" + set modBPreVersion = "1.0.0" + set modCPreVersion = "5.6.45+snapshot" + + set modAPostVersion = "2.1.0+snapshot" + set modBPostVersion = "2.0.0+snapshot" + set modCPostVersion = "6.2.0+snapshot" + + // Install base module module-a + set sc = ##class(%IPM.Main).Shell("install -v " _ modA _ " " _ modAPreVersion) + do $$$AssertStatusOK(sc, "Successfully installed " _ modA _ " " _ modAPreVersion) + + // Confirm that module-a and dependencies were installed with the correct versions + set mod = ##class(%IPM.Storage.Module).NameOpen(modA) + do $$$AssertEquals(mod.Version.ToString(), modAPreVersion, "Module " _ modA _ " correctly installed as " _ modAPreVersion) + set mod = ##class(%IPM.Storage.Module).NameOpen(modB) + do $$$AssertEquals(mod.Version.ToString(), modBPreVersion, "Module " _ modB _ " correctly installed as " _ modBPreVersion) + set mod = ##class(%IPM.Storage.Module).NameOpen(modC) + do $$$AssertEquals(mod.Version.ToString(), modCPreVersion, "Module " _ modC _ " correctly installed as " _ modCPreVersion) + + // Install module-d prior to update + set sc = ##class(%IPM.Main).Shell("install -v " _ modD) + do $$$AssertStatusOK(sc, "Successfully installed " _ modD) + + // Update base module module-a. Update should error due to version incompatabilities caused by module-d + set sc = ##class(%IPM.Main).Shell("update -v " _ modA _ " " _ modAPostVersion) + do $$$AssertStatusNotOK(sc, "Updating " _ modA _ " fails due to version errors with previously installed " _ modD) + + // Uninstall module-d then try the update again + set sc = ##class(%IPM.Main).Shell("uninstall -v " _ modD) + do $$$AssertStatusOK(sc, "Successfully uninstalled " _ modD) + set sc = ##class(%IPM.Main).Shell("update -v " _ modA _ " " _ modAPostVersion) + do $$$AssertStatusOK(sc, "Successfully updated " _ modA _ " and its dependencies") + + // Confirm that module-a and dependencies were updated to the correct versions + set mod = ##class(%IPM.Storage.Module).NameOpen(modA) + do $$$AssertEquals(mod.Version.ToString(), modAPostVersion, "Module " _ modA _ " correctly installed as " _ modAPostVersion) + set mod = ##class(%IPM.Storage.Module).NameOpen(modB) + do $$$AssertEquals(mod.Version.ToString(), modBPostVersion, "Module " _ modB _ " correctly installed as " _ modBPostVersion) + set mod = ##class(%IPM.Storage.Module).NameOpen(modC) + do $$$AssertEquals(mod.Version.ToString(), modCPostVersion, "Module " _ modC _ " correctly installed as " _ modCPostVersion) + + // Uninstall module-a and dependencies + set sc = ##class(%IPM.Main).Shell("uninstall -r " _ modA) + do $$$AssertStatusOK(sc, "Successfully uninstalled " _ modA _ " and dependencies") +} + } diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-a/cls/ModuleA/Class1.cls b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-a/cls/ModuleA/Class1.cls new file mode 100644 index 000000000..20027a563 --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-a/cls/ModuleA/Class1.cls @@ -0,0 +1,9 @@ +Class ModuleA.Class1 +{ + +ClassMethod MethodA() +{ + write !, "This is ##class(ModuleA.Class1).MethodA()" +} + +} diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-a/module.xml b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-a/module.xml new file mode 100644 index 000000000..d5f02ab07 --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-a/module.xml @@ -0,0 +1,16 @@ + + + + + module-a + 2.1.0+snapshot + + + + module-b + ^2.0.0 + + + + + \ No newline at end of file diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-b/cls/ModuleB/Class1.cls b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-b/cls/ModuleB/Class1.cls new file mode 100644 index 000000000..6b96fe0bd --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-b/cls/ModuleB/Class1.cls @@ -0,0 +1,9 @@ +Class ModuleB.Class1 +{ + +ClassMethod MethodA() +{ + write !, "This is ##class(ModuleB.Class1).MethodA()" +} + +} diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-b/module.xml b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-b/module.xml new file mode 100644 index 000000000..d85acd61f --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-b/module.xml @@ -0,0 +1,16 @@ + + + + + module-b + 2.0.0+snapshot + + + + module-c + ^6.1.15 + + + + + \ No newline at end of file diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-c/cls/ModuleC/Class1.cls b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-c/cls/ModuleC/Class1.cls new file mode 100644 index 000000000..3d8712188 --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-c/cls/ModuleC/Class1.cls @@ -0,0 +1,9 @@ +Class ModuleC.Class1 +{ + +ClassMethod MethodA() +{ + write !, "This is ##class(ModuleC.Class1).MethodA()" +} + +} diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-c/module.xml b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-c/module.xml new file mode 100644 index 000000000..7c0928fff --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/post-update/module-c/module.xml @@ -0,0 +1,10 @@ + + + + + module-c + 6.2.0+snapshot + + + + \ No newline at end of file diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-a/cls/ModuleA/Class1.cls b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-a/cls/ModuleA/Class1.cls new file mode 100644 index 000000000..20027a563 --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-a/cls/ModuleA/Class1.cls @@ -0,0 +1,9 @@ +Class ModuleA.Class1 +{ + +ClassMethod MethodA() +{ + write !, "This is ##class(ModuleA.Class1).MethodA()" +} + +} diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-a/module.xml b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-a/module.xml new file mode 100644 index 000000000..3d7525cca --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-a/module.xml @@ -0,0 +1,16 @@ + + + + + module-a + 2.0.0 + + + + module-b + 1.0.0 + + + + + \ No newline at end of file diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-b/cls/ModuleB/Class1.cls b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-b/cls/ModuleB/Class1.cls new file mode 100644 index 000000000..6b96fe0bd --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-b/cls/ModuleB/Class1.cls @@ -0,0 +1,9 @@ +Class ModuleB.Class1 +{ + +ClassMethod MethodA() +{ + write !, "This is ##class(ModuleB.Class1).MethodA()" +} + +} diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-b/module.xml b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-b/module.xml new file mode 100644 index 000000000..c5376a6f5 --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-b/module.xml @@ -0,0 +1,16 @@ + + + + + module-b + 1.0.0 + + + + module-c + ^5.4.1 + + + + + \ No newline at end of file diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-c/cls/ModuleC/Class1.cls b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-c/cls/ModuleC/Class1.cls new file mode 100644 index 000000000..3d8712188 --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-c/cls/ModuleC/Class1.cls @@ -0,0 +1,9 @@ +Class ModuleC.Class1 +{ + +ClassMethod MethodA() +{ + write !, "This is ##class(ModuleC.Class1).MethodA()" +} + +} diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-c/module.xml b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-c/module.xml new file mode 100644 index 000000000..293705f51 --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-c/module.xml @@ -0,0 +1,10 @@ + + + + + module-c + 5.6.45+snapshot + + + + \ No newline at end of file diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-d/cls/ModuleD/Class1.cls b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-d/cls/ModuleD/Class1.cls new file mode 100644 index 000000000..47801f80f --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-d/cls/ModuleD/Class1.cls @@ -0,0 +1,9 @@ +Class ModuleD.Class1 +{ + +ClassMethod MethodA() +{ + write !, "This is ##class(ModuleD.Class1).MethodA()" +} + +} diff --git a/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-d/module.xml b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-d/module.xml new file mode 100644 index 000000000..ac813f17f --- /dev/null +++ b/tests/integration_tests/Test/PM/Integration/_data/update-test/dependency-versions-updated/pre-update/module-d/module.xml @@ -0,0 +1,16 @@ + + + + + module-d + 1.0.0 + + + + module-c + ^5.3.0 + + + + + \ No newline at end of file From c74ed861e8a4fb198aa1bb2ff537392ad0f825a1 Mon Sep 17 00:00:00 2001 From: James Lechtner Date: Fri, 10 Apr 2026 12:29:30 -0400 Subject: [PATCH 2/4] Adding changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64e8ba38b..6df8e80d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #1052: In a namespace with mapped IPM, the `info` command works again and the intro message displays the IPM version and where its mapped from - #1102: %IPM.Storage.QualifiedModuleInfo:%New() will now copy over version properties when passed in a resolvedReference - #1112: Packaging a module with a globals resource now respects SourcesRoot, placing the exported file at the correct path in the tarball +- #1119: Update should check version requirements using post-update values instead of what's currently installed ## [0.10.6] - 2026-02-24 From e69852099bac7edba961c88c39c4ee2e93d9a888 Mon Sep 17 00:00:00 2001 From: James Lechtner Date: Tue, 14 Apr 2026 13:54:15 -0400 Subject: [PATCH 3/4] First round of changes. Describing the addition of the dependency graph --- src/cls/IPM/Utils/Module.cls | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cls/IPM/Utils/Module.cls b/src/cls/IPM/Utils/Module.cls index 144393e9d..1b480331a 100644 --- a/src/cls/IPM/Utils/Module.cls +++ b/src/cls/IPM/Utils/Module.cls @@ -349,6 +349,9 @@ ClassMethod GetModuleObjectFromString( /// Returns a semantic version expression capturing all version requirements for a given module name in the current namespace. /// A list of modules to exclude may be provided (for example, if these modules would be updated at the same time). +/// +/// If provided a dependency graph, will use versions defined there instead of what the SQL call returns. +/// This is especially important for update, where we want to check requirements with post-update versions as opposed to what's currently installed. ClassMethod GetRequiredVersionExpression( moduleName As %String, excludeModules As %List = "", @@ -382,6 +385,7 @@ ClassMethod GetRequiredVersionExpression( set expression = expression.And(versionExpr) set sourceList = sourceList_$listbuild($listtostring(result.%Get("ModuleNames"),", ")_": "_version) } + $$$ThrowOnError(sc) // Add modules from the dependency graph to the expression and sourceList objects if ($data(dependencyGraph)) { @@ -412,8 +416,6 @@ ClassMethod GetRequiredVersionExpression( } } } - - $$$ThrowOnError(sc) } catch e { set expression = $$$NULLOREF set sourceList = "" @@ -1292,7 +1294,7 @@ ClassMethod LoadDependencies( set reloadSnapshots = +$get(pParams("UpdateSnapshots")) set permitDowngrade = +$get(pParams("PermitDowngrade")) - set ignoreInstalled = +$get(pParams("zpm", "IgnoreInstalled")) + set ignoreInstalled = +$get(pParams("IgnoreInstalled")) write !, "Building dependency graph..." // Intentionally always write even in non-verbose mode set sc = pModule.BuildDependencyGraph(.dependencyGraph,,reloadSnapshots,,phaseList,,,,ignoreInstalled,,permitDowngrade) $$$ThrowOnError(sc) From 7c30ac54d9b91dc1d3287d4783da15fc314b55bf Mon Sep 17 00:00:00 2001 From: James Lechtner Date: Wed, 15 Apr 2026 17:10:17 -0400 Subject: [PATCH 4/4] Specifying "the update command" instead of just saying update --- CHANGELOG.md | 2 +- src/cls/IPM/Utils/Module.cls | 2 +- tests/integration_tests/Test/PM/Integration/Update.cls | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6df8e80d4..dfad33363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #1052: In a namespace with mapped IPM, the `info` command works again and the intro message displays the IPM version and where its mapped from - #1102: %IPM.Storage.QualifiedModuleInfo:%New() will now copy over version properties when passed in a resolvedReference - #1112: Packaging a module with a globals resource now respects SourcesRoot, placing the exported file at the correct path in the tarball -- #1119: Update should check version requirements using post-update values instead of what's currently installed +- #1119: The update command should check version requirements using post-update values instead of what's currently installed ## [0.10.6] - 2026-02-24 diff --git a/src/cls/IPM/Utils/Module.cls b/src/cls/IPM/Utils/Module.cls index 1b480331a..d41928965 100644 --- a/src/cls/IPM/Utils/Module.cls +++ b/src/cls/IPM/Utils/Module.cls @@ -351,7 +351,7 @@ ClassMethod GetModuleObjectFromString( /// A list of modules to exclude may be provided (for example, if these modules would be updated at the same time). /// /// If provided a dependency graph, will use versions defined there instead of what the SQL call returns. -/// This is especially important for update, where we want to check requirements with post-update versions as opposed to what's currently installed. +/// This is especially important for the update command, where we want to check requirements with post-update versions as opposed to what's currently installed. ClassMethod GetRequiredVersionExpression( moduleName As %String, excludeModules As %List = "", diff --git a/tests/integration_tests/Test/PM/Integration/Update.cls b/tests/integration_tests/Test/PM/Integration/Update.cls index 58fb97356..b00907917 100644 --- a/tests/integration_tests/Test/PM/Integration/Update.cls +++ b/tests/integration_tests/Test/PM/Integration/Update.cls @@ -663,11 +663,11 @@ Method TestDevModePropagation() } /// Test case to make sure that update doesn't fail due to version errors that get resolved as a part of update -/// i.e. - Module A 1.0.0 requires Module B ^1.0.0 -/// - Module A 2.0.0 requires Module B ^2.0.0 -/// - Pre-Update: Module A 1.0.0, Module B 1.3.0 -/// - Post-Update: Module A 2.0.0, Module B 2.0.1 -/// - Don't want a version error to be thrown in flight when Module A is 2.0.0 and Module B is still 1.3.0 +/// i.e. - Module A 2.0.0 requires Module B ^1.0.0 +/// - Module A 2.1.0 requires Module B ^2.0.0 +/// - Pre-Update: Module A 2.0.0, Module B 1.0.0 +/// - Post-Update: Module A 2.1.0, Module B 2.0.0 +/// - Don't want a version error to be thrown in flight when Module A is 2.1.0 and Module B is still 1.0.0 Method TestDependencyVersionsUpdated() { // Define variables for this test