diff --git a/CHANGELOG.md b/CHANGELOG.md index a7f30105..e1749419 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Edits to a decomposed production in VS Code fixed after changes to the VS Code ObjectScript extension (#949) - Configure prompt no longer quits out with an unhelpful error if existing boolean settings are null (#962) - Branch names are now constrained to a reasonable set of allowed characters, fixing an issue where branch names with special characters were hidden without explanation (#914) +- PTD documents that are not decomposed production items may now be added to source control (#965) ## [2.16.0] - 2026-03-06 diff --git a/cls/SourceControl/Git/Production.cls b/cls/SourceControl/Git/Production.cls index 3c3adbb8..eb619c6a 100644 --- a/cls/SourceControl/Git/Production.cls +++ b/cls/SourceControl/Git/Production.cls @@ -726,6 +726,12 @@ ClassMethod CreateInternalName(productionName As %String = "", itemName As %Stri ) } +/// Returns true if the PTD document with given internal name should be treated as a decomposed production item. +ClassMethod IsPTDDecomposedProductionItem(internalName) As %Boolean +{ + return internalName [ "||" +} + /// Given an external name for a PTD item, removes that item from the production. ClassMethod RemoveItemByExternalName(externalName As %String, nameMethod As %String) As %Status { diff --git a/cls/SourceControl/Git/PullEventHandler/IncrementalLoad.cls b/cls/SourceControl/Git/PullEventHandler/IncrementalLoad.cls index 3faa6378..3f888277 100644 --- a/cls/SourceControl/Git/PullEventHandler/IncrementalLoad.cls +++ b/cls/SourceControl/Git/PullEventHandler/IncrementalLoad.cls @@ -41,7 +41,7 @@ Method OnPull() As %Status set delList(delIndex, internalName) = tExternalName } else { set nFiles = nFiles + 1 - if (##class(SourceControl.Git.Utils).Type(internalName) = "ptd") { + if (##class(SourceControl.Git.Utils).Type(internalName) = "ptd") && ##class(SourceControl.Git.Production).IsPTDDecomposedProductionItem(internalName) { set ptdList(internalName) = "" } else { set compilelist(internalName) = "" @@ -78,7 +78,9 @@ Method OnPull() As %Status set start = $zhorolog set key = $order(ptdList("")) while (key '= "") { - set sc = $$$ADDSC(sc, ##class(SourceControl.Git.Utils).ImportItem(key,1)) + if ##class(SourceControl.Git.Production).IsPTDDecomposedProductionItem(key) { + set sc = $$$ADDSC(sc, ##class(SourceControl.Git.Utils).ImportItem(key,1)) + } set key = $order(ptdList(key)) } write !,"Production items imported in ",($zhorolog-start),"s" diff --git a/cls/SourceControl/Git/Utils.cls b/cls/SourceControl/Git/Utils.cls index c9c1bf12..78337670 100644 --- a/cls/SourceControl/Git/Utils.cls +++ b/cls/SourceControl/Git/Utils.cls @@ -1481,7 +1481,7 @@ ClassMethod ImportItem(InternalName As %String, force As %Boolean = 0, verbose A set type = ..Type(InternalName) set imported = 1 if ..IsRoutineOutdated(InternalName) || force || (type = "ptd"){ - if (type = "ptd") && settings.decomposeProductions && ##class(%Library.EnsembleMgr).IsEnsembleNamespace() { + if (type = "ptd") && settings.decomposeProductions && ##class(%Library.EnsembleMgr).IsEnsembleNamespace() && ##class(SourceControl.Git.Production).IsPTDDecomposedProductionItem(InternalName) { if ##class(%File).Exists(filename) { // Deployment manager should not reexport because studio project file includes timestamp // ideally we could just new %SourceControl, but Ens portal config pages do not use %SourceControl @@ -1595,9 +1595,11 @@ ClassMethod ListItemsInFiles(ByRef itemList, ByRef err) As %Status if (mappingFileType = "/CSP/") { do ..ListItemsRecursively(mappingFileType,"*",mappedFilePath,.itemList) } elseif ..UserTypeCached("foo."_mappingFileType, .userTypeClass) { - set fileSpec = $select( - userTypeClass="Ens.Util.ProjectTextDocument": "*.xml;*.XML", - 1: "*."_$zcvt(mappingFileType,"L")_";*."_$zconvert(mappingFileType,"U")) + set fileSpec = "*."_$zcvt(mappingFileType,"L")_";*."_$zconvert(mappingFileType,"U") + // PTDs may be decomposed production items, which are represented as xml + if (userTypeClass="Ens.Util.ProjectTextDocument") { + set fileSpec = fileSpec _ ";*.xml;*.XML" + } do ..ListItemsRecursively(mappingFileType, fileSpec, mappedFilePath, .itemList) } else { set res = $system.OBJ.ImportDir(mappedFilePath,,"-d",.err,1, .tempItemList, $$$DoNotLoad) @@ -1795,7 +1797,7 @@ ClassMethod ExportItem(InternalName As %String, expand As %Boolean = 1, force As quit $$$OK } write !, "exporting new version of ", InternalName, " to ", filename - if (type = "ptd") { + if (type = "ptd") && (##class(SourceControl.Git.Production).IsPTDDecomposedProductionItem(InternalName)) { $$$QuitOnError(##class(SourceControl.Git.Production).ExportPTD(InternalName,"FullExternalName")) } elseif (..ItemIsProductionToDecompose(InternalName, .productionName)) { write !, "Production decomposition enabled, skipping export of production class" @@ -2559,7 +2561,7 @@ ClassMethod Name(InternalName As %String, ByRef MappingExists As %Boolean) As %S // If no specific mapping was specified (p=""), then return the whole csp filename; otherwise return the name without the mapped piece set relativeInternalName=$extract(InternalName,$length(p)+2,*) quit $translate(found_$translate(relativeInternalName,"%","_"),"\","/") - } elseif (..Type(InternalName) = "ptd") { + } elseif (..Type(InternalName) = "ptd") && ##class(SourceControl.Git.Production).IsPTDDecomposedProductionItem(InternalName) { do ##class(SourceControl.Git.Production).ParseInternalName(InternalName,'default,.filename) return $translate(found_filename, "\","/") } elseif ext="CLS"||(ext="PRJ")||usertype { @@ -3417,4 +3419,3 @@ ClassMethod IsSchemaStandard(pName As %String = "") As %Boolean [ Internal ] } } - diff --git a/test/UnitTest/SourceControl/Git/ProductionDecomposition.cls b/test/UnitTest/SourceControl/Git/ProductionDecomposition.cls index a3d6eaa6..49ea341e 100644 --- a/test/UnitTest/SourceControl/Git/ProductionDecomposition.cls +++ b/test/UnitTest/SourceControl/Git/ProductionDecomposition.cls @@ -122,6 +122,16 @@ Method TestImportItemsWithError() do $$$AssertStatusOK(##class(SourceControl.Git.Utils).ImportItem("UnitTest.SampleProduction||Settings-a|Ens.Activity.Operation.Local.PTD")) } +/// PTD documents that do not represent decomposed production items may be added to source control as .PTD files +Method TestNonHostPTD() +{ + do ##class(Ens.Util.ProjectTextDocument).Delete("UnitTest.SourceControl.Git.SamplePTD.PTD") + $$$ThrowOnError(##class(Ens.Util.ProjectTextDocument).Create("Some text","UnitTest.SourceControl.Git.SamplePTD","Descriptive text")) + do $$$AssertStatusOK(##class(SourceControl.Git.Utils).AddToSourceControl("UnitTest.SourceControl.Git.SamplePTD.PTD")) + do $$$AssertTrue(##class(SourceControl.Git.Utils).IsInSourceControl("UnitTest.SourceControl.Git.SamplePTD.PTD")) + do $$$AssertEquals(##class(SourceControl.Git.Utils).Name("UnitTest.SourceControl.Git.SamplePTD.PTD"),"ptd/UnitTest/SourceControl/Git/SamplePTD.ptd") +} + ClassMethod ReplaceProductionDefinition(pXDataName) { new %SourceControl