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..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(%Studio.SourceControl.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)
@@ -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
}
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
- -
+
-
+ ]]>
}