From 9d4977f3d3d143746f96f8480f55def85f96a7d1 Mon Sep 17 00:00:00 2001 From: isc-dchui Date: Wed, 27 May 2026 13:29:25 -0400 Subject: [PATCH 1/6] feat: implement 'locate' command for resource-to-module mapping - Added 'locate' (alias 'loc') to identify the owning module of a resource. - Uses %IPM.ExtensionBase.Utils:GetHomeModuleName for reliable lookup. - Formatted output to match 'list' command (Name + Version). - Added unit tests for various resource types (.cls, .inc). - Validated handling of various resource types (.inc, .cls). - Confirmed graceful error handling for missing arguments and non-existent resources. --- src/cls/IPM/Main.cls | 26 ++++++++++++++++++++++++++ tests/unit_tests/Test/PM/Unit/CLI.cls | 19 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/cls/IPM/Main.cls b/src/cls/IPM/Main.cls index 98d1fd40..3a6e9c1d 100644 --- a/src/cls/IPM/Main.cls +++ b/src/cls/IPM/Main.cls @@ -810,6 +810,13 @@ generate /my/path -export 00000,PacketName2,IgnorePacket2^00000,PacketName3,Igno config get HistoryRetain + + Find the module that owns a specific resource. + + locate %IPM.Main.cls + loc %IPM.Common.inc + + } @@ -1098,6 +1105,8 @@ ClassMethod ShellInternal( do ..Information(.tCommandInfo) } elseif (tCommandInfo = "history") { do ..History(.tCommandInfo) + } elseif (tCommandInfo = "locate") { + do ..Locate(.tCommandInfo) } } catch pException { if (pException.Code = $$$ERCTRLC) { @@ -4325,6 +4334,23 @@ ClassMethod Update(ByRef pCommandInfo) } } +ClassMethod Locate(ByRef CommandInfo) +{ + set resource = $get(CommandInfo("parameters","resource")) + if resource="" { + $$$ThrowOnError($$$ERROR($$$GeneralError,"Resource name is required.")) + } + set moduleName = ##class(%IPM.ExtensionBase.Utils).GetHomeModuleName(resource) + if (moduleName="") { + write $$$FormattedLine($$$Red, "Resource '"_ resource_"' is not currently mapped to an installed module.") + quit + } + set showFields = "" + write ! + do ..GetListModules(,moduleName, .list) + do ..DisplayModules(.list,,,, .tModifiers) +} + ClassMethod GetPythonInstalledLibs(Output list) { set target = ##class(%File).NormalizeDirectory("python", $system.Util.ManagerDirectory()) diff --git a/tests/unit_tests/Test/PM/Unit/CLI.cls b/tests/unit_tests/Test/PM/Unit/CLI.cls index 04f45ed3..875bb2ba 100644 --- a/tests/unit_tests/Test/PM/Unit/CLI.cls +++ b/tests/unit_tests/Test/PM/Unit/CLI.cls @@ -658,4 +658,23 @@ Method TestSortListVersionPrerelease() do $$$AssertEquals($listget(sorted(6),1), "snap", "version desc: snap (1.0.0-SNAPSHOT)") } +Method TestLocateCommand() +{ + do $$$LogMessage("Testing 'loc' alias with .inc resource") + set status = ..RunCommand("loc %IPM.Common.inc") + do $$$AssertStatusOK(status, "Alias 'loc' executed successfully") + + do $$$LogMessage("Testing 'locate' command with .cls resource") + set status = ..RunCommand("locate %IPM.Main.cls") + do $$$AssertStatusOK(status, "Command 'locate' executed successfully") + + do $$$LogMessage("Testing locate with non-existing resource") + set status = ..RunCommand("locate Test.Sample.inc") + do $$$AssertStatusOK(status, "Gracefully handled non-existing resource") + + do $$$LogMessage("Testing locate without required argument") + set status = ..RunCommand("locate") + do $$$AssertStatusNotOK(status, "Handled missing argument") +} + } From a7917f572439a516c657168c87ea1364ef4e2fc1 Mon Sep 17 00:00:00 2001 From: AshokThangavel Date: Sat, 28 Feb 2026 00:55:16 +0530 Subject: [PATCH 2/6] docs: Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5c4c8a7..5e7dc6ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ modules are. ### Added - #1024: Added flag -export-python-deps to publish command +- #1081: implement locate command for resource-to-module mapping ### Fixed - #996: Ensure COS commands execute in exec under a dedicated, isolated context From bda56a53c323b22de49567c00d82a6b2184caaeb Mon Sep 17 00:00:00 2001 From: AshokThangavel Date: Tue, 3 Mar 2026 14:52:53 +0530 Subject: [PATCH 3/6] # Refactor: rename locate command and clarify error messaging * **Rename** `locate` command to `locate-resource` and **remove alias** per maintainer feedback to avoid ambiguity with system commands. * **Update** error message to use "part of" instead of "mapped to" to avoid confusion with InterSystems IRIS mapping terminology. --- src/cls/IPM/Main.cls | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/cls/IPM/Main.cls b/src/cls/IPM/Main.cls index 3a6e9c1d..e553a0c3 100644 --- a/src/cls/IPM/Main.cls +++ b/src/cls/IPM/Main.cls @@ -810,11 +810,11 @@ generate /my/path -export 00000,PacketName2,IgnorePacket2^00000,PacketName3,Igno config get HistoryRetain - + Find the module that owns a specific resource. - - locate %IPM.Main.cls - loc %IPM.Common.inc + + locate-resource %IPM.Main.cls + locate-resource %IPM.Common.inc @@ -1105,7 +1105,7 @@ ClassMethod ShellInternal( do ..Information(.tCommandInfo) } elseif (tCommandInfo = "history") { do ..History(.tCommandInfo) - } elseif (tCommandInfo = "locate") { + } elseif (tCommandInfo = "locate-resource") { do ..Locate(.tCommandInfo) } } catch pException { @@ -4337,12 +4337,9 @@ ClassMethod Update(ByRef pCommandInfo) ClassMethod Locate(ByRef CommandInfo) { set resource = $get(CommandInfo("parameters","resource")) - if resource="" { - $$$ThrowOnError($$$ERROR($$$GeneralError,"Resource name is required.")) - } set moduleName = ##class(%IPM.ExtensionBase.Utils).GetHomeModuleName(resource) if (moduleName="") { - write $$$FormattedLine($$$Red, "Resource '"_ resource_"' is not currently mapped to an installed module.") + write $$$FormattedLine($$$Red, "Resource '"_ resource_"' is not currently part of an installed module.") quit } set showFields = "" From bd7d5a877744655c732061ba14635a6dd81900c3 Mon Sep 17 00:00:00 2001 From: AshokThangavel Date: Tue, 3 Mar 2026 14:55:32 +0530 Subject: [PATCH 4/6] refactor: Method name updated --- src/cls/IPM/Main.cls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cls/IPM/Main.cls b/src/cls/IPM/Main.cls index e553a0c3..b563bc6b 100644 --- a/src/cls/IPM/Main.cls +++ b/src/cls/IPM/Main.cls @@ -1106,7 +1106,7 @@ ClassMethod ShellInternal( } elseif (tCommandInfo = "history") { do ..History(.tCommandInfo) } elseif (tCommandInfo = "locate-resource") { - do ..Locate(.tCommandInfo) + do ..LocateResource(.tCommandInfo) } } catch pException { if (pException.Code = $$$ERCTRLC) { @@ -4334,7 +4334,7 @@ ClassMethod Update(ByRef pCommandInfo) } } -ClassMethod Locate(ByRef CommandInfo) +ClassMethod LocateResource(ByRef CommandInfo) { set resource = $get(CommandInfo("parameters","resource")) set moduleName = ##class(%IPM.ExtensionBase.Utils).GetHomeModuleName(resource) From 24e77149eb5fb0794eaa4a8cafbedcb8b0c53376 Mon Sep 17 00:00:00 2001 From: isc-dchui Date: Thu, 9 Jul 2026 09:27:43 -0400 Subject: [PATCH 5/6] Update unit test code and changelog --- CHANGELOG.md | 2 +- src/cls/IPM/Main.cls | 2 +- tests/unit_tests/Test/PM/Unit/CLI.cls | 48 +++++++++++++++++++++------ 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e7dc6ec..fd5f7fe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - #1178: Add `-password-env` and `-token-env` modifiers to the `repo` command to read the password/token from a named environment variable (secure alternatives to `-password` and `-token`). +- #1081: Implement locate-resource command for resource-to-module mapping ## [0.10.8] - 2026-07-08 @@ -66,7 +67,6 @@ modules are. ### Added - #1024: Added flag -export-python-deps to publish command -- #1081: implement locate command for resource-to-module mapping ### Fixed - #996: Ensure COS commands execute in exec under a dedicated, isolated context diff --git a/src/cls/IPM/Main.cls b/src/cls/IPM/Main.cls index b563bc6b..3f1ee058 100644 --- a/src/cls/IPM/Main.cls +++ b/src/cls/IPM/Main.cls @@ -810,7 +810,7 @@ generate /my/path -export 00000,PacketName2,IgnorePacket2^00000,PacketName3,Igno config get HistoryRetain - + Find the module that owns a specific resource. locate-resource %IPM.Main.cls diff --git a/tests/unit_tests/Test/PM/Unit/CLI.cls b/tests/unit_tests/Test/PM/Unit/CLI.cls index 875bb2ba..cf137bfd 100644 --- a/tests/unit_tests/Test/PM/Unit/CLI.cls +++ b/tests/unit_tests/Test/PM/Unit/CLI.cls @@ -660,20 +660,46 @@ Method TestSortListVersionPrerelease() Method TestLocateCommand() { - do $$$LogMessage("Testing 'loc' alias with .inc resource") - set status = ..RunCommand("loc %IPM.Common.inc") - do $$$AssertStatusOK(status, "Alias 'loc' executed successfully") - - do $$$LogMessage("Testing 'locate' command with .cls resource") - set status = ..RunCommand("locate %IPM.Main.cls") - do $$$AssertStatusOK(status, "Command 'locate' executed successfully") + set ipmModule = ##class(%IPM.Storage.Module).NameOpen("zpm",,.sc) + do $$$AssertStatusOK(sc, "Opened zpm module to get version") + set ipmVersion = ipmModule.VersionString + + do $$$LogMessage("Testing locate-resource with .inc resource") + do ##class(%IPM.Utils.Module).BeginCaptureOutput(.cookie) + set status = ##class(%IPM.Main).Shell("locate-resource %IPM.Common.inc") + do ##class(%IPM.Utils.Module).EndCaptureOutput(cookie, .output) + do $$$AssertStatusOK(status, "locate-resource %IPM.Common.inc executed successfully") + set content = "" + set i = "" + for { + set i = $order(output(i)) + quit:i="" + set content = content _ output(i) _ $char(10) + } + do $$$AssertTrue(content [ "zpm", "output contains module name 'zpm'") + do $$$AssertTrue(content [ ipmVersion, "output contains IPM version "_ipmVersion) + + do $$$LogMessage("Testing locate-resource with .cls resource") + do ##class(%IPM.Utils.Module).BeginCaptureOutput(.cookie) + set status = ##class(%IPM.Main).Shell("locate-resource %IPM.Main.cls") + do ##class(%IPM.Utils.Module).EndCaptureOutput(cookie, .output) + do $$$AssertStatusOK(status, "locate-resource %IPM.Main.cls executed successfully") + set content = "" + set i = "" + for { + set i = $order(output(i)) + quit:i="" + set content = content _ output(i) _ $char(10) + } + do $$$AssertTrue(content [ "zpm", "output contains module name 'zpm'") + do $$$AssertTrue(content [ ipmVersion, "output contains IPM version "_ipmVersion) - do $$$LogMessage("Testing locate with non-existing resource") - set status = ..RunCommand("locate Test.Sample.inc") + do $$$LogMessage("Testing locate-resource with non-existing resource") + set status = ..RunCommand("locate-resource Test.Sample.inc") do $$$AssertStatusOK(status, "Gracefully handled non-existing resource") - do $$$LogMessage("Testing locate without required argument") - set status = ..RunCommand("locate") + do $$$LogMessage("Testing locate-resource without required argument") + set status = ..RunCommand("locate-resource") do $$$AssertStatusNotOK(status, "Handled missing argument") } From 41878326d73a06b2908afc034b8a775094970159 Mon Sep 17 00:00:00 2001 From: isc-dchui Date: Tue, 18 Aug 2026 11:09:24 -0400 Subject: [PATCH 6/6] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d2ee80e..9fd8aedd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - #1117: Add `sync` command for incremental loading of changed files in dev-mode modules. Detects modified files since last sync using SHA-1 hash and recompiles only what is stale. Supports `-delete` for processing removed files and `-test` for running changed test-phase unit tests. +- #1081: Implement `locate-resource` command for resource-to-module mapping ## [0.10.9] - 2026-08-05 ### Added - #1178: Add `-password-env` and `-token-env` modifiers to the `repo` command to read the password/token from a named environment variable (secure alternatives to `-password` and `-token`). -- #1081: Implement locate-resource command for resource-to-module mapping ### Changed - #1186: Change %IPM.Main:ShellScript() to return a status.