Skip to content

Commit c12ef63

Browse files
authored
Merge branch 'main' into basic-export-modes
2 parents a7d4179 + 33ed837 commit c12ef63

File tree

13 files changed

+186
-2
lines changed

13 files changed

+186
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- New setting to configure whether mapped items should be should be treated as read-only
1515
- Added a basic mode to automatically perform functionality expected in basic use cases (#349)
1616
- New sync operation for basic mode that fetches, pulls, commits and then pushes (#349)
17+
- Now skips files belonging to other git enabled packages in `##class(SourceControl.Git.Change).RefreshUncommitted()` (#347)
18+
- Added a new "Branch" parameter to `##class(SourceControl.Git.PullEventHandler)` (#351)
19+
- Command-line utility to do a baseline export of items in a namespace
20+
1721

1822
## [2.3.1] - 2024-04-30
1923

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ This might look like:
5858
5959
![Example of mapping configuration](docs/images/settings.PNG "Example of mapping configuration")
6060
61+
### Pull Event Handlers
62+
63+
The ##class(SourceControl.Git.PullEventHandler) is a base class that can be extended in order to develop functionality that should be run when the repository pulls from remote. The code placed inside the subclass' OnPull() method will be executed any time a pull occurs.
64+
65+
A recommended way to implement CI/CD would be to use one of the pre-defined subclasses of PullEventHandler that are placed inside the PullEventHandler package. Additionally, custom load logic can be placed in that package following the model of the existing subclasses.
66+
6167
### Security
6268
6369
#### Unsecured (http) connections
@@ -99,6 +105,8 @@ Assuming you have the local and remote repositories created,
99105
`git config core.sshCommand 'ssh -i ~/.ssh/<private key name>'`
100106
8. Test the refresh button for the remote branches on the WebUI, fetch from the source control menu in Studio or VS Code, and `git fetch` in Git Bash. All 3 should work without any issues.
101107
108+
109+
102110
## During Development
103111
104112
:warning: Whenever any code in this project is updated outside the server (e.g. after every `git pull`), you _have_ to run `zpm "load <absolute path to git-source-control>"`. Otherwise, the changes won't be reflected on the server. However, if you load git-source-control via the InterSystems package manager and run `git pull` via the extension itself with the default pull event handler configured, it'll just work.

cls/SourceControl/Git/API.cls

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,12 @@ ClassMethod Unlock()
5656
quit ##class(SourceControl.Git.Utils).Locked(0)
5757
}
5858

59+
/// Run in terminal to baseline a namespace by adding all items to source control.
60+
/// - pCommitMessage: if defined, all changes in namespace context will be committed.
61+
/// - pPushToRemote: if defined, will run a git push to the specified remote
62+
ClassMethod BaselineExport(pCommitMessage = "", pPushToRemote = "") As %Status
63+
{
64+
quit ##class(SourceControl.Git.Utils).BaselineExport(pCommitMessage, pPushToRemote)
5965
}
6066

67+
}

cls/SourceControl/Git/Change.cls

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,13 @@ ClassMethod RefreshUncommitted(Display = 0, IncludeRevert = 0, Output gitFiles,
131131
set examine=$select(action="add":1,action="edit":1,action="delete":1, IncludeRevert&&(action="revert"):1,1:0)
132132
if 'examine set filename=$order(tFileList(filename),1,action) continue
133133

134+
set packageRoot = ##class(SourceControl.Git.Utils).TempFolder()
134135
set InternalName = ##class(SourceControl.Git.Utils).NameToInternalName(filename,0,0)
135136

137+
// skip files belonging to other git enabled packages
138+
if ($EXTRACT(filename, 1, $LENGTH(packageRoot)) '= packageRoot) continue
139+
140+
136141
if (('##class(%File).Exists(filename)) || (InternalName = "") || ((InternalName '= "") && ('$data(gitFiles(InternalName), found)) &&
137142
(($data($$$TrackedItems(InternalName))) || ##class(SourceControl.Git.Utils).NormalizeExtension($data($$$TrackedItems(InternalName)))))) {
138143
set sc=..RemoveUncommitted(filename,Display,0,0)

cls/SourceControl/Git/PullEventHandler.cls

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ Property LocalRoot As %String(MAXLEN = "");
1313
/// Modified files (integer-subscripted array storing objects of class SourceControl.Git.Modification)
1414
Property ModifiedFiles [ MultiDimensional ];
1515

16+
/// The branch that is checked out before OnPull() is called
17+
Property Branch [ InitialExpression = {##class(SourceControl.Git.Utils).GetCurrentBranch()} ];
18+
1619
Method OnPull() As %Status [ Abstract ]
1720
{
1821
}

cls/SourceControl/Git/Utils.cls

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,12 @@ ClassMethod Fetch(ByRef diffFiles) As %Status
432432
quit $$$OK
433433
}
434434

435+
ClassMethod GetCurrentBranch() As %String{
436+
do ##class(SourceControl.Git.Utils).RunGitCommandWithInput("branch",,.errStream,.outStream,"--show-current")
437+
set branchName = outStream.ReadLine(outStream.Size)
438+
quit branchName
439+
}
440+
435441
ClassMethod Pull(remote As %String = "origin", preview As %Boolean = 0) As %Status
436442
{
437443
#define Force 1
@@ -601,6 +607,7 @@ ClassMethod AddToServerSideSourceControl(InternalName As %String) As %Status
601607

602608
ClassMethod AddToSourceControl(InternalName As %String) As %Status
603609
{
610+
do ##class(SourceControl.Git.PackageManagerContext).ForInternalName(InternalName)
604611
set settings = ##class(SourceControl.Git.Settings).%New()
605612
#dim i as %Integer
606613
#dim ec as %Status = $$$OK
@@ -2066,6 +2073,13 @@ ClassMethod CheckInitialization()
20662073
}
20672074
}
20682075

2076+
ClassMethod GetPackageVersion() As %String
2077+
{
2078+
do ##class(%ZPM.PackageManager).GetVersion("git-source-control",.out)
2079+
set scVersion = out("git-source-control")
2080+
quit $LIST(scVersion, 2)
2081+
}
2082+
20692083
ClassMethod GetSourceControlInclude() As %String
20702084
{
20712085
quit $select(##class(%Library.EnsembleMgr).IsEnsembleInstalled():
@@ -2218,5 +2232,47 @@ ClassMethod ResetSourceControlClass()
22182232
do ##class(%Studio.SourceControl.Interface).SourceControlClassSet("")
22192233
}
22202234

2235+
ClassMethod BaselineExport(pCommitMessage = "", pPushToRemote = "") As %Status
2236+
{
2237+
set sc = $$$OK
2238+
try {
2239+
write !, "Exporting items..."
2240+
set rs = ##class(%Library.RoutineMgr).StudioOpenDialogFunc(
2241+
"*.mac,*.int,*.inc,*.cls,*.csp" // Spec
2242+
, , ,0 // SystemFiles
2243+
,1 // Flat
2244+
,0 // NotStudio
2245+
,0 // ShowGenerated
2246+
, , ,0 // Mapped
2247+
)
2248+
throw:rs.%SQLCODE<0 ##class(%Exception.SQL).CreateFromSQLCODE(rs.%SQLCODE,rs.%Message)
2249+
while rs.%Next(.sc) {
2250+
$$$ThrowOnError(sc)
2251+
set internalName = rs.Name
2252+
// exclude items in a non-default IPM package
2253+
set context = ##class(SourceControl.Git.PackageManagerContext).ForInternalName(internalName)
2254+
continue:($isobject(context.Package) && 'context.IsInDefaultPackage)
2255+
$$$ThrowOnError(..AddToSourceControl(internalName))
2256+
}
2257+
if pCommitMessage '= "" {
2258+
// switch to default context
2259+
do ##class(SourceControl.Git.PackageManagerContext).ForInternalName("")
2260+
do ..RunGitWithArgs(.errStream, .outStream, "add", "--all")
2261+
do ..PrintStreams(errStream, outStream)
2262+
set username = ..GitUserName()
2263+
set email = ..GitUserEmail()
2264+
set author = username_" <"_email_">"
2265+
do ..RunGitWithArgs(.errStream, .outStream, "commit", "--author", author, "-m", pCommitMessage)
2266+
do ..PrintStreams(errStream, outStream)
2267+
$$$ThrowOnError(##class(SourceControl.Git.Change).RefreshUncommitted(,,,1))
2268+
if (pPushToRemote '= "") {
2269+
$$$ThrowOnError(..Push(pPushToRemote))
2270+
}
2271+
}
2272+
} catch err {
2273+
set sc = err.AsStatus()
2274+
}
2275+
return sc
22212276
}
22222277

2278+
}

cls/SourceControl/Git/WebUIDriver.cls

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ ClassMethod HandleRequest(pagePath As %String, InternalName As %String = "", Out
1818
set responseJSON = ..Uncommitted()
1919
} elseif $extract(pagePath,6,*) = "settings" {
2020
set responseJSON = ..GetSettingsURL(%request)
21+
} elseif $extract(pagePath, 6, *) = "get-package-version"{
22+
set responseJSON = ..GetPackageVersion()
2123
} else {
2224
set %response.Status = ##class(%CSP.REST).#HTTP404NOTFOUND
2325
set responseJSON = {"error":("invalid URI: " _ pagePath)}
@@ -231,5 +233,11 @@ ClassMethod GetSettingsURL(%request As %CSP.Request) As %SystemBase
231233
quit {"url": (settingsURL)}
232234
}
233235

236+
ClassMethod GetPackageVersion() As %Library.DynamicObject
237+
{
238+
set version = ##class(SourceControl.Git.Utils).GetPackageVersion()
239+
quit {"version": (version)}
240+
}
241+
234242
}
235243

csp/gitprojectsettings.csp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ body {
7070
<body>
7171
<server>
7272
set namespace = $namespace
73+
set version = ##class(SourceControl.Git.Utils).GetPackageVersion()
7374
set webuiURL = "/isc/studio/usertemplates/gitsourcecontrol/webuidriver.csp/"_namespace_"/?CSPSHARE=1"
7475
set webuiURL = ##class(SourceControl.Git.WebUIDriver).GetURLPrefix(%request, webuiURL)
7576

@@ -127,7 +128,9 @@ body {
127128
<div class="row">
128129
<div class="offset-sm-1 col-sm-8">
129130
<h1>Git Project Settings</h1>
131+
<h3> Package version: #(version)# </h3>
130132
</div>
133+
131134
<div class="col-sm-2">
132135
<button class="btn btn-lg btn-outline-dark" id="goToWebUI">Go to WebUI
133136
</button>

git-webui/release/share/git-webui/webui/css/git-webui.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
#help-modal .img-fluid {
3535
max-width: 90%;
3636
}
37+
#packageVersion {
38+
color: white;
39+
font-size: 0.83em;
40+
align-self: center;
41+
}
3742
html,
3843
body {
3944
height: 100%;

git-webui/release/share/git-webui/webui/js/git-webui.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,13 @@ webui.SideBarView = function(mainView, noEventHandlers) {
483483
webui.git("fetch --prune",updateSideBar);
484484
}
485485

486+
self.getPackageVersion = function() {
487+
$.get("api/get-package-version", function(version) {
488+
var ver = JSON.parse(version)["version"];
489+
$("#packageVersion").text("package version " + ver)
490+
})
491+
}
492+
486493

487494
self.checkoutBranch = function(branchType, refName) {
488495
$("#confirm-branch-checkout").remove();
@@ -751,8 +758,10 @@ webui.SideBarView = function(mainView, noEventHandlers) {
751758
};
752759

753760
self.mainView = mainView;
761+
754762
self.element = $( '<div id="sidebar">' +
755763
'<a href="#" data-toggle="modal" data-target="#help-modal"><img id="sidebar-logo" src="img/git-logo.png"></a>' +
764+
'<h5 id="packageVersion"></h5>' +
756765
'<div id="sidebar-content">' +
757766
'<section id="sidebar-workspace">' +
758767
'<h4>Workspace</h4>' +
@@ -802,7 +811,7 @@ webui.SideBarView = function(mainView, noEventHandlers) {
802811
$('.btn-prune-remote-branches', self.element).click(self.pruneRemoteBranches);
803812
$("#sidebar-settings", self.element).click(self.goToSettingsPage);
804813
}
805-
814+
self.getPackageVersion();
806815
self.fetchSection($("#sidebar-local-branches", self.element)[0], "Local Branches", "local-branches", "branch --verbose --verbose");
807816
self.fetchSection($("#sidebar-remote-branches", self.element)[0], "Remote Branches", "remote-branches", "branch --remotes");
808817
self.fetchSection($("#sidebar-tags", self.element)[0], "Tags", "tags", "tag");

git-webui/src/share/git-webui/webui/css/git-webui.less

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@
7878
}
7979
}
8080

81+
#packageVersion {
82+
color: white;
83+
font-size: 0.83em;
84+
align-self: center;
85+
}
86+
8187
.display-flex() {
8288
display: flex;
8389
display: -webkit-flex;

git-webui/src/share/git-webui/webui/js/git-webui.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,13 @@ webui.SideBarView = function(mainView, noEventHandlers) {
483483
webui.git("fetch --prune",updateSideBar);
484484
}
485485

486+
self.getPackageVersion = function() {
487+
$.get("api/get-package-version", function(version) {
488+
var ver = JSON.parse(version)["version"];
489+
$("#packageVersion").text("package version " + ver)
490+
})
491+
}
492+
486493

487494
self.checkoutBranch = function(branchType, refName) {
488495
$("#confirm-branch-checkout").remove();
@@ -751,8 +758,10 @@ webui.SideBarView = function(mainView, noEventHandlers) {
751758
};
752759

753760
self.mainView = mainView;
761+
754762
self.element = $( '<div id="sidebar">' +
755763
'<a href="#" data-toggle="modal" data-target="#help-modal"><img id="sidebar-logo" src="img/git-logo.png"></a>' +
764+
'<h5 id="packageVersion"></h5>' +
756765
'<div id="sidebar-content">' +
757766
'<section id="sidebar-workspace">' +
758767
'<h4>Workspace</h4>' +
@@ -802,7 +811,7 @@ webui.SideBarView = function(mainView, noEventHandlers) {
802811
$('.btn-prune-remote-branches', self.element).click(self.pruneRemoteBranches);
803812
$("#sidebar-settings", self.element).click(self.goToSettingsPage);
804813
}
805-
814+
self.getPackageVersion();
806815
self.fetchSection($("#sidebar-local-branches", self.element)[0], "Local Branches", "local-branches", "branch --verbose --verbose");
807816
self.fetchSection($("#sidebar-remote-branches", self.element)[0], "Remote Branches", "remote-branches", "branch --remotes");
808817
self.fetchSection($("#sidebar-tags", self.element)[0], "Tags", "tags", "tag");
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
Class UnitTest.SourceControl.Git.BaselineExport Extends %UnitTest.TestCase
2+
{
3+
4+
Method TestBaselineExport()
5+
{
6+
// create a mac routine
7+
if '##class(%Routine).Exists("test.mac") {
8+
set r = ##class(%Routine).%New("test.mac")
9+
do r.WriteLine(" write 22,!")
10+
do r.Save()
11+
do r.Compile()
12+
}
13+
// create an inc routine
14+
if '##class(%Routine).Exists("test.inc") {
15+
set r = ##class(%Routine).%New("test.inc")
16+
do r.WriteLine(" ; test include routine")
17+
do r.Save()
18+
do r.Compile()
19+
}
20+
// create a class
21+
if '##class(%Dictionary.ClassDefinition).%OpenId("TestPkg.Class") {
22+
set class = ##class(%Dictionary.ClassDefinition).%New()
23+
set class.Name = "TestPkg.Class"
24+
$$$ThrowOnError(class.%Save())
25+
do $system.OBJ.Compile("TestPkg.Class")
26+
}
27+
do $$$AssertNotTrue(##class(SourceControl.Git.Utils).IsInSourceControl("test.mac"))
28+
do $$$AssertNotTrue(##class(SourceControl.Git.Utils).IsInSourceControl("test.inc"))
29+
do $$$AssertNotTrue(##class(SourceControl.Git.Utils).IsInSourceControl("TestPkg.Class.cls"))
30+
do $$$AssertStatusOK(##class(SourceControl.Git.API).BaselineExport())
31+
do $$$AssertTrue(##class(SourceControl.Git.Utils).IsInSourceControl("test.mac"))
32+
do $$$AssertTrue(##class(SourceControl.Git.Utils).IsInSourceControl("test.inc"))
33+
do $$$AssertTrue(##class(SourceControl.Git.Utils).IsInSourceControl("TestPkg.Class.cls"))
34+
}
35+
36+
Property InitialExtension As %String [ InitialExpression = {##class(%Studio.SourceControl.Interface).SourceControlClassGet()} ];
37+
38+
Property SourceControlGlobal [ MultiDimensional ];
39+
40+
Method %OnNew(initvalue) As %Status
41+
{
42+
Merge ..SourceControlGlobal = ^SYS("SourceControl")
43+
Kill ^SYS("SourceControl")
44+
Set settings = ##class(SourceControl.Git.Settings).%New()
45+
Set settings.namespaceTemp = ##class(%Library.File).TempFilename()_"dir"
46+
Set settings.Mappings("MAC","*")="rtn/"
47+
Set settings.Mappings("CLS","*")="cls/"
48+
Do settings.%Save()
49+
Do ##class(%Studio.SourceControl.Interface).SourceControlClassSet("SourceControl.Git.Extension")
50+
Quit ##super(initvalue)
51+
}
52+
53+
Method %OnClose() As %Status [ Private, ServerOnly = 1 ]
54+
{
55+
Do ##class(%Studio.SourceControl.Interface).SourceControlClassSet(..InitialExtension)
56+
Kill ^SYS("SourceControl")
57+
Merge ^SYS("SourceControl") = ..SourceControlGlobal
58+
Quit $$$OK
59+
}
60+
61+
}

0 commit comments

Comments
 (0)