From a0c8254ec9f3b1c6d7f2bb9af54aebd75535c329 Mon Sep 17 00:00:00 2001
From: Pravin Barton <9560941+isc-pbarton@users.noreply.github.com>
Date: Fri, 13 Dec 2024 11:32:42 -0500
Subject: [PATCH 1/3] fix: parsing of nested CDATA in PTD items
---
CHANGELOG.md | 3 ++
cls/SourceControl/Git/Production.cls | 48 ++++++++++++++++------------
2 files changed, 30 insertions(+), 21 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 84749d85..68177c39 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Menu option to export production to support migrating to production decomposition (#665)
+### Fixed
+- Fixed errors on production page when item settings need to be XML escaped (#667)
+
## [2.8.0] - 2024-12-06
### Added
diff --git a/cls/SourceControl/Git/Production.cls b/cls/SourceControl/Git/Production.cls
index 1ffbe553..23c48471 100644
--- a/cls/SourceControl/Git/Production.cls
+++ b/cls/SourceControl/Git/Production.cls
@@ -62,7 +62,7 @@ ClassMethod DeleteProductionDefinitionShards(productionClass As %String, deleteM
while rs.%Next(.sc) {
quit:$$$ISERR(sc)
set ptdFilename = rs.Data("Name")
- set sc = ##class(%Studio.SourceControl.Production).ParseExternalName(ptdFilename, .ptdInternalName)
+ set sc = ##class(SourceControl.Git.Production).ParseExternalName(ptdFilename, .ptdInternalName)
quit:$$$ISERR(sc)
// TODO: Consider reverting delete if any ptd is not editable by current user
set sc = $method(%SourceControl, deleteMethod, ptdInternalName)
@@ -371,26 +371,32 @@ ClassMethod IsProductionClass(className As %String, nameMethod As %String) As %B
ClassMethod ParseExternalName(externalName, Output internalName = "", Output productionName = "") As %Status
{
set sc = $$$OK
- set extNameNormalized = $replace(externalName, "\", "/")
- set file = $piece(extNameNormalized, "/", *)
- if $extract(file,1,9) = "ProdStgs-" {
- set productionName = $replace($extract(file,10,*-4), "_", ".")
- set internalName = ..CreateInternalName(productionName,,,1)
- } else {
- if ##class(%File).Exists(externalName) {
- // Special case for Config Item Settings PTD, requires checking PTD CDATA for Item and Class name
- set deployDoc = ##class(EnsLib.EDI.XML.Document).%New(externalName)
- set exportNotesPTDText = $ZCVT(deployDoc.GetValueAt("/Export/Document[1]/1"),"I","XML")
- set exportNotesPTD = ##class(EnsLib.EDI.XML.Document).%New(exportNotesPTDText)
- set productionName = exportNotesPTD.GetValueAt("/Deployment/Creation/SourceProduction")
- set settingsPTDText = $zconvert(deployDoc.GetValueAt("/Export/Document[2]/1"),"I","XML")
- set settingsPTD = ##class(EnsLib.EDI.XML.Document).%New(settingsPTDText)
- set itemClass = settingsPTD.GetValueAt("/Item/@ClassName")
- set itemName = settingsPTD.GetValueAt("/Item/@Name")
- set internalName = ..CreateInternalName(productionName, itemName, itemClass, 0)
- } else {
- set sc = $$$ERROR($$$GeneralError, "Item settings PTD file " _ externalName _ " does not exist. Cannot parse external name.")
- }
+ try {
+ set extNameNormalized = $replace(externalName, "\", "/")
+ set file = $piece(extNameNormalized, "/", *)
+ if $extract(file,1,9) = "ProdStgs-" {
+ set productionName = $replace($extract(file,10,*-4), "_", ".")
+ set internalName = ..CreateInternalName(productionName,,,1)
+ } else {
+ if ##class(%File).Exists(externalName) {
+ // Special case for Config Item Settings PTD, requires checking PTD CDATA for Item and Class name
+ set deployDoc = ##class(EnsLib.EDI.XML.Document).%New(externalName)
+ set exportNotesPTDText = $ZCVT(deployDoc.GetValueAt("/Export/Document[1]/1"),"I","XML")
+ set exportNotesPTD = ##class(EnsLib.EDI.XML.Document).%New(exportNotesPTDText)
+ set productionName = exportNotesPTD.GetValueAt("/Deployment/Creation/SourceProduction")
+ set settingsPTDText = $zconvert(deployDoc.GetValueAt("/Export/Document[2]/1"),"I","XML")
+ // unquote embedded CDATA close markers - see Ens.Util.ProjectTextDocument StreamToGbl method
+ set settingsPTDText = $replace(settingsPTDText,"]*]>", "]]>")
+ set settingsPTD = ##class(EnsLib.EDI.XML.Document).%New(settingsPTDText)
+ set itemClass = settingsPTD.GetValueAt("/Item/@ClassName")
+ set itemName = settingsPTD.GetValueAt("/Item/@Name")
+ set internalName = ..CreateInternalName(productionName, itemName, itemClass, 0)
+ } else {
+ set sc = $$$ERROR($$$GeneralError, "Item settings PTD file " _ externalName _ " does not exist. Cannot parse external name.")
+ }
+ }
+ } catch err {
+ set sc = err.AsStatus()
}
return sc
}
From db1e65fede3d9957f9902fd5c7fc522f020bcad8 Mon Sep 17 00:00:00 2001
From: Pravin Barton <9560941+isc-pbarton@users.noreply.github.com>
Date: Fri, 13 Dec 2024 11:46:32 -0500
Subject: [PATCH 2/3] test: production decomp with escaped CDATA
---
.../SourceControl/Git/ProductionDecomposition.cls | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/test/UnitTest/SourceControl/Git/ProductionDecomposition.cls b/test/UnitTest/SourceControl/Git/ProductionDecomposition.cls
index 3ca53fe2..1a4d5fef 100644
--- a/test/UnitTest/SourceControl/Git/ProductionDecomposition.cls
+++ b/test/UnitTest/SourceControl/Git/ProductionDecomposition.cls
@@ -82,10 +82,10 @@ Method TestEditProduction()
$$$ThrowOnError(%SourceControl.OnBeforeSave(..#ProductionName_".cls"))
do ..ReplaceProductionDefinition("ProductionDefinition3")
$$$ThrowOnError(%SourceControl.OnAfterSave(..#ProductionName_".cls"))
- do $$$AssertTrue(##class(SourceControl.Git.Utils).IsInSourceControl("UnitTest.SampleProduction||Settings-b|Ens.Activity.Operation.Local.PTD"))
+ do $$$AssertTrue(##class(SourceControl.Git.Utils).IsInSourceControl("UnitTest.SampleProduction||Settings-b|EnsLib.SOAP.GenericOperation.PTD"))
do ##class(SourceControl.Git.Utils).RunGitCommand("add",,,".")
do ##class(SourceControl.Git.Utils).Commit("UnitTest.SampleProduction||Settings-a|Ens.Activity.Operation.Local.PTD")
- do ##class(SourceControl.Git.Utils).Commit("UnitTest.SampleProduction||Settings-b|Ens.Activity.Operation.Local.PTD")
+ do ##class(SourceControl.Git.Utils).Commit("UnitTest.SampleProduction||Settings-b|EnsLib.SOAP.GenericOperation.PTD")
$$$ThrowOnError(production.%Reload())
do $$$AssertEquals(production.Items.Count(), 2)
do $$$AssertEquals(production.Items.GetAt(1).Settings.GetAt(1).Name, "RecordStatsInterval")
@@ -135,7 +135,8 @@ XData ProductionDefinition2
-
61
- -
+
-
+ ]]>
}
@@ -147,7 +148,8 @@ XData ProductionDefinition3
-
71
- -
+
-
+ ]]>
}
From 13b474da912ce4f1d609f453f833f1d8b978d84a Mon Sep 17 00:00:00 2001
From: Pravin Barton <9560941+isc-pbarton@users.noreply.github.com>
Date: Tue, 17 Dec 2024 11:13:14 -0500
Subject: [PATCH 3/3] refactor: compatibility with
%Studio.SourceControl.Production
---
cls/SourceControl/Git/Production.cls | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cls/SourceControl/Git/Production.cls b/cls/SourceControl/Git/Production.cls
index 23c48471..1d2f98be 100644
--- a/cls/SourceControl/Git/Production.cls
+++ b/cls/SourceControl/Git/Production.cls
@@ -62,7 +62,7 @@ ClassMethod DeleteProductionDefinitionShards(productionClass As %String, deleteM
while rs.%Next(.sc) {
quit:$$$ISERR(sc)
set ptdFilename = rs.Data("Name")
- set sc = ##class(SourceControl.Git.Production).ParseExternalName(ptdFilename, .ptdInternalName)
+ set sc = ..ParseExternalName(ptdFilename, .ptdInternalName)
quit:$$$ISERR(sc)
// TODO: Consider reverting delete if any ptd is not editable by current user
set sc = $method(%SourceControl, deleteMethod, ptdInternalName)