diff --git a/CHANGELOG.md b/CHANGELOG.md index 4793480d..84749d85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.9.0] - Unreleased + +### Added +- Menu option to export production to support migrating to production decomposition (#665) + ## [2.8.0] - 2024-12-06 ### Added diff --git a/cls/SourceControl/Git/Extension.cls b/cls/SourceControl/Git/Extension.cls index c4c4ad9b..03c09fdc 100644 --- a/cls/SourceControl/Git/Extension.cls +++ b/cls/SourceControl/Git/Extension.cls @@ -30,6 +30,7 @@ XData Menu + @@ -148,6 +149,7 @@ Method LocalizeName(name As %String) As %String "Fetch":$$$Text("@Fetch@Fetch from remote"), "Pull":$$$Text("@Pull@Pull changes from remote branch"), "Status": $$$Text("@Status@Status"), + "ExportProduction": $$$Text("@ExportProduction@Export Production"), :name) } @@ -163,7 +165,7 @@ Method OnSourceMenuItem(name As %String, ByRef Enabled As %String, ByRef Display } if ##class(SourceControl.Git.Utils).IsNamespaceInGit() { - if $listfind($listbuild("AddToSC", "RemoveFromSC", "Revert", "Commit"), name) { + if $listfind($listbuild("AddToSC", "RemoveFromSC", "Revert", "Commit", "ExportProduction"), name) { quit ..OnSourceMenuContextItem(InternalName,name,.Enabled,.DisplayName) } @@ -243,6 +245,9 @@ Method OnSourceMenuContextItem(itemName As %String, menuItemName As %String, ByR if '(##class(SourceControl.Git.Change).IsUncommitted(##class(SourceControl.Git.Utils).FullExternalName(itemName))) || ($username '= userCheckedOut) { set Enabled = 0 } + } elseif menuItemName = "ExportProduction" { + set itemNameNoExt = $piece(itemName,".",1,*-1) + set Enabled = (##class(SourceControl.Git.Production).IsProductionClass(itemNameNoExt,"FullExternalName")) } elseif ##class(SourceControl.Git.Utils).IsInSourceControl(itemName) { set Enabled = $case(menuItemName, "AddToSC":-1,:1) } else { diff --git a/cls/SourceControl/Git/Util/Production.cls b/cls/SourceControl/Git/Util/Production.cls index a6692601..fd7f7341 100644 --- a/cls/SourceControl/Git/Util/Production.cls +++ b/cls/SourceControl/Git/Util/Production.cls @@ -4,6 +4,40 @@ Include SourceControl.Git Class SourceControl.Git.Util.Production { +ClassMethod BaselineProduction(productionName, settings As SourceControl.Git.Settings = {##class(SourceControl.Git.Settings).%New()}) +{ + set productionInternalName = productionName _ ".cls" + if '##class(SourceControl.Git.Utils).FileIsMapped(productionInternalName) { + if settings.decomposeProductions { + write !, "Exporting production in decomposed format: " _ productionInternalName + if ##class(SourceControl.Git.Utils).IsInSourceControl(productionInternalName) { + set st = ##class(SourceControl.Git.Utils).RemoveFromSourceControl(productionInternalName) + $$$ThrowOnError(st) + } + set st = ##class(SourceControl.Git.Production).ExportProductionDefinitionShards(productionName,"FullExternalName",.itemInternalNames) + $$$ThrowOnError(st) + set key = $order(itemInternalNames("")) + while (key '= "") { + set st = ##class(SourceControl.Git.Utils).AddToSourceControl(key) + $$$ThrowOnError(st) + set key = $order(itemInternalNames(key)) + } + } else { + write !, "Exporting production in class format: " _ productionInternalName + set st = ##class(SourceControl.Git.Utils).AddToSourceControl(productionInternalName) + $$$ThrowOnError(st) + set key = $order(@##class(SourceControl.Git.Utils).#Storage@("items", "")) + while (key '= "") { + if $match(key,"^"_productionName_"\|\|.*\.(?i)ptd$") { + set st = ##class(SourceControl.Git.Utils).RemoveFromSourceControl(key) + $$$ThrowOnError(st) + } + set key = $order(@##class(SourceControl.Git.Utils).#Storage@("items", key)) + } + } + } +} + /// Baselines all productions in this namespace from single-file to decomposed or vice versa. ClassMethod BaselineProductions() { @@ -13,37 +47,7 @@ ClassMethod BaselineProductions() throw:rs.%SQLCODE<0 ##class(%Exception.SQL).CreateFromSQLCODE(rs.%SQLCODE,rs.%Message) while rs.%Next(.sc) { $$$ThrowOnError(sc) - set productionName = rs.Name - set productionInternalName = productionName _ ".cls" - if '##class(SourceControl.Git.Utils).FileIsMapped(productionInternalName) { - if settings.decomposeProductions { - write !, "Decomposing production: " _ productionInternalName - if ##class(SourceControl.Git.Utils).IsInSourceControl(productionInternalName) { - set st = ##class(SourceControl.Git.Utils).RemoveFromSourceControl(productionInternalName) - $$$ThrowOnError(st) - } - set st = ##class(SourceControl.Git.Production).ExportProductionDefinitionShards(productionName,"FullExternalName",.itemInternalNames) - $$$ThrowOnError(st) - set key = $order(itemInternalNames("")) - while (key '= "") { - set st = ##class(SourceControl.Git.Utils).AddToSourceControl(key) - $$$ThrowOnError(st) - set key = $order(itemInternalNames(key)) - } - } else { - write !, "Recomposing production: " _ productionInternalName - set st = ##class(SourceControl.Git.Utils).AddToSourceControl(productionInternalName) - $$$ThrowOnError(st) - set key = $order(@##class(SourceControl.Git.Utils).#Storage@("items", "")) - while (key '= "") { - if $match(key,"^"_productionName_"\|\|.*\.(?i)ptd$") { - set st = ##class(SourceControl.Git.Utils).RemoveFromSourceControl(key) - $$$ThrowOnError(st) - } - set key = $order(@##class(SourceControl.Git.Utils).#Storage@("items", key)) - } - } - } + do ..BaselineProduction(rs.Name, settings) } } diff --git a/cls/SourceControl/Git/Utils.cls b/cls/SourceControl/Git/Utils.cls index 3760af50..e34a265f 100644 --- a/cls/SourceControl/Git/Utils.cls +++ b/cls/SourceControl/Git/Utils.cls @@ -323,6 +323,8 @@ ClassMethod UserAction(InternalName As %String, MenuName As %String, ByRef Targe do ..RunGitCommand("status", .errStream, .outStream) write !, !, "Git Status: " do ..PrintStreams(outStream, errStream) + } elseif (menuItemName = "ExportProduction") { + do ##class(SourceControl.Git.Util.Production).BaselineProduction($piece(InternalName,".",1,*-1)) } quit ec } diff --git a/docs/production-decomposition.md b/docs/production-decomposition.md index b951fe84..7b5b7ba7 100644 --- a/docs/production-decomposition.md +++ b/docs/production-decomposition.md @@ -4,7 +4,7 @@ Production Decomposition is a feature of Embedded Git that allows multiple devel ## Enabling production decomposition The feature may be enabled by checking the "Decompose Productions" box in the Git Settings page. For deployment of changes to other environments through git to work properly, the value of this setting must match on all namespaces connected to this repository. To assist, settings are automatically exported into a `embedded-git-config.json` file at the root of the repository that may be committed and imported into other environments. -If there are existing productions in the namespace, they should be migrated to the new decomposed format by running `do ##class(SourceControl.Git.API).BaselineProductions()`. You may then use the Git Web UI to view, commit, and push the corresponding changes. This method should be run in a single namespace and then deployed to other namespaces through normal Embedded Git deployment mechanisms. +If there are existing productions in the namespace, they should be migrated to the new decomposed format. Do this by opening the production and selecting the "Export Production" option in the source control menu. You may then use the Git Web UI to view, commit, and push the corresponding changes. This step should be done in a single namespace and then deployed to other namespaces through normal Embedded Git deployment mechanisms. ## Editing productions in the IDE There are a couple of limitations related to editing a production class directly in an integrated development environment (Studio or VS Code). diff --git a/docs/testing.md b/docs/testing.md index 039aa7f0..9c66872f 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -31,5 +31,5 @@ The following is a testing plan that should be followed prior to release of a ne - Test migration of a production to decomposed format: - On the initial namespace, disable production decomposition. Create a new production and add a number of items. Sync and confirm it has been pushed to the remote repository. - On the second namespace, sync and confirm the new production has been created. - - On the initial namespace, turn on production decomposition. From terminal, run `do ##class(SourceControl.Git.API).BaselineProductions()`. Confirm the Web UI includes changes for delete of the old production class and adds for all production items. Commit all items and push the branch. + - On the initial namespace, turn on production decomposition. Open the production page and use the "Export Production" option in the source control menu. Confirm the Web UI includes changes for delete of the old production class and adds for all production items. Commit all items and push the branch. - On the second namespace, turn on production decomposition. Sync. The production should be reloaded with no changes. \ No newline at end of file diff --git a/module.xml b/module.xml index 21eba717..7702e998 100644 --- a/module.xml +++ b/module.xml @@ -3,7 +3,7 @@ git-source-control - 2.8.0 + 2.9.0 Server-side source control extension for use of Git on InterSystems platforms git source control studio vscode module