diff --git a/CHANGELOG.md b/CHANGELOG.md index 26d0a376..920c4d28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Import All has been added to public-facing API (#891) - Web UI workspace view now has an option to abort merge in progress (#895) +- New setting lets you treat generated classes as read-only in Studio/VS Code (#712) ## Fixed - Web UI workspace view labels changes as Merge Conflict if there are unmerged changes (#890) diff --git a/cls/SourceControl/Git/Extension.cls b/cls/SourceControl/Git/Extension.cls index 2922e403..6b7d7af3 100644 --- a/cls/SourceControl/Git/Extension.cls +++ b/cls/SourceControl/Git/Extension.cls @@ -474,6 +474,8 @@ Method IsReadOnly(InternalName As %String) As %Boolean set settings = ##class(SourceControl.Git.Settings).%New() quit (##class(SourceControl.Git.Utils).Locked() && '$get(^IRIS.Temp("sscProd",$job,"bypassLock"))) + || (settings.generatedFilesReadOnly + && ##class(SourceControl.Git.Utils).ItemIsGenerated(InternalName)) || (##class(SourceControl.Git.Utils).ItemIsProductionToDecompose($get(InternalName)) && 'settings.decomposeProdAllowIDE && '##class(SourceControl.Git.Production).IsEnsPortal()) @@ -588,3 +590,4 @@ Method CheckBusinessProcessesAndRules(InternalName As %String) As %Status } } + diff --git a/cls/SourceControl/Git/Settings.cls b/cls/SourceControl/Git/Settings.cls index a25579ac..cd2b7d9a 100644 --- a/cls/SourceControl/Git/Settings.cls +++ b/cls/SourceControl/Git/Settings.cls @@ -51,6 +51,9 @@ Property gitUserEmail As %String(MAXLEN = 255) [ InitialExpression = {##class(So /// Whether mapped items should be read-only, preventing them from being added to source control Property mappedItemsReadOnly As %Boolean [ InitialExpression = {##class(SourceControl.Git.Utils).MappedItemsReadOnly()} ]; +/// Whether generated files should be read-only within Studio/VS Code +Property generatedFilesReadOnly As %Boolean [ InitialExpression = {##class(SourceControl.Git.Utils).GeneratedFilesReadOnly()} ]; + /// Whether basic mode should be enabled for user ${username}, greatly simplifying the functionality of the package, requiring no knowledge of git Property basicMode As %String [ InitialExpression = {##class(SourceControl.Git.Utils).BasicMode()} ]; @@ -179,6 +182,7 @@ Method %Save() As %Status set @storage@("settings","percentClassReplace") = ..percentClassReplace set @storage@("settings","settingsUIReadOnly") = ..settingsUIReadOnly set @storage@("settings", "mappedItemsReadOnly") = ..mappedItemsReadOnly + set @storage@("settings", "generatedFilesReadOnly") = ..generatedFilesReadOnly set @storage@("settings", "defaultMergeBranch") = ..defaultMergeBranch set @storage@("settings", "compileOnImport") = ..compileOnImport set @storage@("settings", "warnInstanceWideUncommitted") = ..warnInstanceWideUncommitted @@ -224,6 +228,7 @@ Method ToDynamicObject() As %DynamicObject [ Internal ] set settingsJSON = { "pullEventClass": (..pullEventClass), "percentClassReplace": (..percentClassReplace), + "generatedFilesReadOnly": (..generatedFilesReadOnly), "Mappings": {} } do settingsJSON.%Set("decomposeProductions",..decomposeProductions,"boolean") @@ -248,6 +253,7 @@ Method ImportDynamicObject(pSettingsDyn As %DynamicObject) [ Internal ] set ..pullEventClass = pSettingsDyn.%Get("pullEventClass") set ..percentClassReplace = pSettingsDyn.%Get("percentClassReplace") set ..decomposeProductions = pSettingsDyn.%Get("decomposeProductions") + set ..generatedFilesReadOnly = pSettingsDyn.%Get("generatedFilesReadOnly") kill ..Mappings set mappingsDyn = pSettingsDyn.%Get("Mappings", {}) set i1 = mappingsDyn.%GetIterator() @@ -546,7 +552,7 @@ Method RetrieveDefaults() As %Boolean [ Internal ] Method SaveDefaults() As %Boolean { set defaults = {} - set items = $lb("gitBinPath", "pullEventClass", "percentClassReplace", "environmentName", "systemBasicMode", "defaultMergeBranch", "mappedItemsReadOnly", "compileOnImport") + set items = $lb("gitBinPath", "pullEventClass", "percentClassReplace", "environmentName", "systemBasicMode", "defaultMergeBranch", "mappedItemsReadOnly", "generatedFilesReadOnly", "compileOnImport") for i=1:1:$LISTLENGTH(items) { set property = $listget(items,i) do defaults.%Set(property, $property($this, property)) @@ -555,4 +561,3 @@ Method SaveDefaults() As %Boolean } } - diff --git a/cls/SourceControl/Git/Utils.cls b/cls/SourceControl/Git/Utils.cls index 76c2f3f0..a78d922d 100644 --- a/cls/SourceControl/Git/Utils.cls +++ b/cls/SourceControl/Git/Utils.cls @@ -155,6 +155,11 @@ ClassMethod MappedItemsReadOnly() As %Boolean quit $get(@..#Storage@("settings", "mappedItemsReadOnly"), 1) } +ClassMethod GeneratedFilesReadOnly() As %Boolean +{ + quit $get(@..#Storage@("settings", "generatedFilesReadOnly"), 0) +} + ClassMethod GitUserName() As %String { quit $get(@..#Storage@("settings","user",$username,"gitUserName"),$username) @@ -1103,6 +1108,11 @@ ClassMethod Type(InternalName As %String) As %String quit type } +ClassMethod ItemIsGenerated(InternalName As %String) As %Boolean +{ + return ##class(%RoutineMgr).IsGenerated(..NormalizeInternalName(InternalName)) +} + ClassMethod NameWithoutExtension(InternalName As %String) As %String [ CodeMode = expression ] { $Piece(InternalName, ".", 1, $Length(InternalName,".")-1) @@ -3341,4 +3351,3 @@ ClassMethod IsSchemaStandard(pName As %String = "") As %Boolean [ Internal ] } } - diff --git a/csp/gitprojectsettings.csp b/csp/gitprojectsettings.csp index e070adc8..40296ada 100644 --- a/csp/gitprojectsettings.csp +++ b/csp/gitprojectsettings.csp @@ -130,6 +130,12 @@ body { set settings.mappedItemsReadOnly = 0 } + if ($Get(%request.Data("generatedFilesReadOnly", 1)) = 1) { + set settings.generatedFilesReadOnly = 1 + } else { + set settings.generatedFilesReadOnly = 0 + } + set settings.compileOnImport = ($Get(%request.Data("compileOnImport", 1)) = 1) set settings.decomposeProductions = ($Get(%request.Data("decomposeProductions", 1)) = 1) @@ -502,6 +508,18 @@ body { + +
+ +
+
+ + +
+
+ +
@@ -986,4 +1004,4 @@ $('.mapping-input-group').children('.voca').each(function(){ // ignore; may occur on platform versions without the above properties } quit 1 - \ No newline at end of file + diff --git a/test/UnitTest/SourceControl/Git/Extension.cls b/test/UnitTest/SourceControl/Git/Extension.cls new file mode 100644 index 00000000..971f9528 --- /dev/null +++ b/test/UnitTest/SourceControl/Git/Extension.cls @@ -0,0 +1,35 @@ +Class UnitTest.SourceControl.Git.Extension Extends UnitTest.SourceControl.Git.AbstractTest +{ + +Method TestGeneratedFilesReadOnlyOption() +{ + set sc = $$$OK + set classCreated = 0 + try { + do $System.OBJ.Delete("UnitTest.SourceControl.Git.GeneratedReadOnly") + set classDef = ##class(%Dictionary.ClassDefinition).%New() + set classDef.Name = "UnitTest.SourceControl.Git.GeneratedReadOnly" + set classDef.GeneratedBy = "UnitTest.SourceControl.Git.GeneratedBy" + $$$ThrowOnError(classDef.%Save()) + $$$ThrowOnError($System.OBJ.Compile("UnitTest.SourceControl.Git.GeneratedReadOnly", "ck")) + set classCreated = 1 + + set settings = ##class(SourceControl.Git.Settings).%New() + set settings.generatedFilesReadOnly = 0 + $$$ThrowOnError(settings.%Save()) + set extension = ##class(SourceControl.Git.Extension).%New("") + do $$$AssertNotTrue(extension.IsReadOnly("UnitTest.SourceControl.Git.GeneratedReadOnly.cls")) + + set settings.generatedFilesReadOnly = 1 + $$$ThrowOnError(settings.%Save()) + do $$$AssertTrue(extension.IsReadOnly("UnitTest.SourceControl.Git.GeneratedReadOnly.cls")) + } catch err { + set sc = err.AsStatus() + } + if classCreated { + do $System.OBJ.Delete("UnitTest.SourceControl.Git.GeneratedReadOnly") + } + $$$ThrowOnError(sc) +} + +} \ No newline at end of file diff --git a/test/UnitTest/SourceControl/Git/Settings.cls b/test/UnitTest/SourceControl/Git/Settings.cls index d2ebb34a..d9e47b4f 100644 --- a/test/UnitTest/SourceControl/Git/Settings.cls +++ b/test/UnitTest/SourceControl/Git/Settings.cls @@ -11,6 +11,7 @@ Method SampleSettingsJSON() "pullEventClass": "pull event class", "percentClassReplace": "x", "decomposeProductions": true, + "generatedFilesReadOnly": true, "Mappings": { "TUV": { "*": { @@ -37,10 +38,12 @@ Method TestJSONImportExport() set settings.decomposeProductions = "" set settings.percentClassReplace = "" set settings.pullEventClass = "" + set settings.generatedFilesReadOnly = 0 do settings.ImportDynamicObject(settingsDynObj) do $$$AssertEquals(settings.decomposeProductions, 1) do $$$AssertEquals(settings.percentClassReplace, "x") do $$$AssertEquals(settings.pullEventClass, "pull event class") + do $$$AssertEquals(settings.generatedFilesReadOnly, 1) do $$$AssertEquals($get(settings.Mappings("TUV","*")),"tuv/") do $$$AssertEquals($get(settings.Mappings("TUV","UnitTest")),"tuv2/") do $$$AssertTrue($get(settings.Mappings("TUV","UnitTest","NoFolders"))) @@ -52,6 +55,7 @@ Method TestJSONImportExport() do $$$AssertEquals(settingsDynObj.decomposeProductions, 1) do $$$AssertEquals(settingsDynObj.percentClassReplace, "x") do $$$AssertEquals(settingsDynObj.pullEventClass, "pull event class") + do $$$AssertEquals(settingsDynObj.generatedFilesReadOnly, 1) do $$$AssertEquals(settingsDynObj.Mappings."TUV"."*".directory,"tuv/") do $$$AssertEquals(settingsDynObj.Mappings."TUV"."UnitTest".directory,"tuv2/") do $$$AssertTrue(settingsDynObj.Mappings."TUV"."UnitTest".noFolders) @@ -66,6 +70,7 @@ Method TestSaveAndImportSettings() set settings.pullEventClass = "SourceControl.Git.PullEventHandler.Default" set settings.percentClassReplace = "_" set settings.decomposeProductions = 1 + set settings.generatedFilesReadOnly = 1 $$$ThrowOnError(settings.SaveWithSourceControl()) do $$$AssertStatusOK(##class(SourceControl.Git.Utils).AddToSourceControl("embedded-git-config.GSC")) // settings file should be in source control @@ -78,17 +83,20 @@ Method TestSaveAndImportSettings() do $$$AssertEquals(^SYS("SourceControl","Git","settings","pullEventClass"),"SourceControl.Git.PullEventHandler.Default") do $$$AssertEquals(^SYS("SourceControl","Git","settings","percentClassReplace"),"_") do $$$AssertEquals(^SYS("SourceControl","Git","settings","decomposeProductions"),"1") + do $$$AssertEquals(^SYS("SourceControl","Git","settings","generatedFilesReadOnly"),"1") // change and save settings set settings.Mappings("CLS","Foo") = "foo2/" set settings.pullEventClass = "SourceControl.Git.PullEventHandler.IncrementalLoad" set settings.percentClassReplace = "x" set settings.decomposeProductions = 0 + set settings.generatedFilesReadOnly = 0 $$$ThrowOnError(settings.SaveWithSourceControl()) // new setting should be in the global do $$$AssertEquals(^SYS("SourceControl","Git","settings","mappings","CLS","Foo"),"foo2/") do $$$AssertEquals(^SYS("SourceControl","Git","settings","pullEventClass"),"SourceControl.Git.PullEventHandler.IncrementalLoad") do $$$AssertEquals(^SYS("SourceControl","Git","settings","percentClassReplace"),"x") do $$$AssertEquals(^SYS("SourceControl","Git","settings","decomposeProductions"),"0") + do $$$AssertEquals(^SYS("SourceControl","Git","settings","generatedFilesReadOnly"),"0") // revert change to settings do $$$AssertStatusOK(##class(SourceControl.Git.Utils).Revert("embedded-git-config.GSC")) // old setting should be in the global @@ -96,6 +104,7 @@ Method TestSaveAndImportSettings() do $$$AssertEquals(^SYS("SourceControl","Git","settings","pullEventClass"),"SourceControl.Git.PullEventHandler.Default") do $$$AssertEquals(^SYS("SourceControl","Git","settings","percentClassReplace"),"_") do $$$AssertEquals(^SYS("SourceControl","Git","settings","decomposeProductions"),"1") + do $$$AssertEquals(^SYS("SourceControl","Git","settings","generatedFilesReadOnly"),"1") } Method OnBeforeAllTests() As %Status