Skip to content

Commit 925e2cb

Browse files
committed
Merge branch 'main' of https://github.com/intersystems/git-source-control into claude-dev-container
2 parents b786b43 + 6438970 commit 925e2cb

11 files changed

Lines changed: 521 additions & 123 deletions

File tree

.github/pull_request_template.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## Description
2+
- Link the issue using the [magic closing words](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue).
3+
- Provide a summary of the change and how it addresses the issue (e.g. if it is a bug, explain the root cause of the bug and how this change fixes it).
4+
- Include any other necessary context, especially if any section warrants special reviewer attention.
5+
6+
## Testing
7+
How has this change been tested? Have you added unit or integration tests as appropriate?
8+
9+
## Checklist
10+
- [ ] This branch has the latest changes from the `main` branch rebased or merged.
11+
- [ ] Web UI has been built (any changes in `git-webui/src` have matching changes in `git-webui/release`)
12+
- [ ] CHANGELOG.md entry added if appropriate.
13+
- [ ] Documentation has been/will be updated

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111
- Import of decomposed production items now has a brief timeout in case another deploy is in progress (#949)
12+
- Option to view an individual file's history in the source control menu (#960)
13+
- Change context menu now lists IPM packages from all Git-enabled namespaces, prefixed with the namespace name (#952)
1214

1315
### Fixed
1416
- Changes to % routines mapped to the current namespace may now be added to source control and committed (#944)
1517
- Edits to a decomposed production in VS Code fixed after changes to the VS Code ObjectScript extension (#949)
18+
- Configure prompt no longer quits out with an unhelpful error if existing boolean settings are null (#962)
19+
- 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)
1620

1721
## [2.16.0] - 2026-03-06
1822

cls/SourceControl/Git/Extension.cls

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@ XData Menu
3636
<MenuItem Name="Import" />
3737
<MenuItem Name="ImportForce" />
3838
<MenuItem Name="TakeOwnership" />
39+
<MenuItem Name="FileHistory" Save="101" />
3940
</Menu>
4041
<Menu Name="%SourceContext" Type="1">
4142
<MenuItem Name="AddToSC" Save="100" />
4243
<MenuItem Name="RemoveFromSC"/>
4344
<MenuItem Name="Revert" Save="100" />
4445
<MenuItem Name="Commit" Save="100" />
4546
<MenuItem Name="TakeOwnership" />
47+
<MenuItem Name="FileHistory" Save="101" />
4648
</Menu>
4749
</MenuBase>
4850
}
@@ -153,6 +155,7 @@ Method LocalizeName(name As %String) As %String
153155
"Revert":$$$Text("@Revert@Discard changes to file"),
154156
"Commit":$$$Text("@Commit@Commit changes to file"),
155157
"TakeOwnership":$$$Text("@TakeOwnership@Take ownership of changes to file"),
158+
"FileHistory":$$$Text("@FileHistory@View file history"),
156159
"Sync":$$$Text("@Sync@Sync"),
157160
"Push":$$$Text("@Push@Push to remote branch"),
158161
"PushForce":$$$Text("@PushForce@Push to remote branch (Force)"),
@@ -175,7 +178,7 @@ Method OnSourceMenuItem(name As %String, ByRef Enabled As %String, ByRef Display
175178
}
176179
if ##class(SourceControl.Git.Utils).IsNamespaceInGit() {
177180

178-
if $listfind($listbuild("AddToSC", "RemoveFromSC", "Revert", "Commit", "ExportProduction", "TakeOwnership"), name) {
181+
if $listfind($listbuild("AddToSC", "RemoveFromSC", "Revert", "Commit", "ExportProduction", "TakeOwnership", "FileHistory"), name) {
179182
quit ..OnSourceMenuContextItem(InternalName,name,.Enabled,.DisplayName)
180183
}
181184

@@ -270,6 +273,8 @@ Method OnSourceMenuContextItem(itemName As %String, menuItemName As %String, ByR
270273
if isCheckedOut && (userCheckedOut '= $username) {
271274
set Enabled = 1
272275
}
276+
} elseif menuItemName = "FileHistory" {
277+
set Enabled = ##class(SourceControl.Git.Utils).IsInSourceControl(itemName)
273278
} elseif menuItemName = "ExportProduction" {
274279
set itemNameNoExt = $piece(itemName,".",1,*-1)
275280
set Enabled = (##class(SourceControl.Git.Production).IsProductionClass(itemNameNoExt,"FullExternalName"))

cls/SourceControl/Git/Settings.cls

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ ClassMethod CreateNamespaceTempFolder() As %Status [ Internal ]
280280
return $$$OK
281281
}
282282

283-
ClassMethod Configure() As %Boolean [ CodeMode = objectgenerator, Internal ]
283+
ClassMethod Configure(Output sc As %Status = {$$$OK}) As %Boolean [ CodeMode = objectgenerator, Internal ]
284284
{
285285
do %code.WriteLine(" set inst = ..%New()")
286286
do %code.WriteLine(" do inst.RetrieveDefaults()")
@@ -305,6 +305,7 @@ ClassMethod Configure() As %Boolean [ CodeMode = objectgenerator, Internal ]
305305
set promptQuoted = $replace(promptQuoted,"${username}","'""_$Username_""'")
306306
set propertyDef = ##class(%Dictionary.PropertyDefinition).%OpenId("SourceControl.Git.Settings||"_property_"")
307307
if ((propertyDef) && (propertyDef.Type = "%Boolean")) {
308+
do %code.WriteLine(" set value = ''value")
308309
do %code.WriteLine(" set response = ##class(%Library.Prompt).GetYesNo("_promptQuoted_",.value,,"_defaultPromptFlag_")")
309310
} elseif ((propertyDef) && (propertyDef.Name = "gitBinPath")) {
310311
do %code.WriteLine(" set valid = 0")
@@ -342,6 +343,7 @@ ClassMethod Configure() As %Boolean [ CodeMode = objectgenerator, Internal ]
342343
} else {
343344
do %code.WriteLine(" set response = ##class(%Library.Prompt).GetString("_promptQuoted_",.value,,,,"_defaultPromptFlag_")")
344345
}
346+
do %code.WriteLine(" if (response = $$$ErrorResponse) { set sc = $get(%objlasterror, 0) }")
345347
do %code.WriteLine(" if response '= $$$SuccessResponse { quit 0 }")
346348
do %code.WriteLine(" set value = $zstrip(value,""<>W"")")
347349
do %code.WriteLine(" set inst."_property_" = value")

cls/SourceControl/Git/Utils.cls

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ Parameter InstallNamespace = "%SYS";
1010
Parameter Slash = {$case($system.Version.GetOS(),"Windows":"\",:"/")};
1111

1212
/// Name of the file with version controlled items
13-
Parameter GitMenuItems = ",Settings,Commit,Sync,Pull,Fetch,Push,Revert,";
13+
Parameter GitMenuItems = ",Settings,Commit,Sync,Pull,Fetch,Push,Revert,FileHistory,";
1414

1515
Parameter ImportAfterGitMenuItems = ",Commit,Sync,Pull,Fetch,Push,";
1616

17-
Parameter GitContextMenuItems = ",%Diff,%Blame,";
17+
Parameter GitContextMenuItems = ",%Diff,%Blame,FileHistory,";
1818

1919
ClassMethod %SYSNamespaceStorage() As %String [ CodeMode = expression ]
2020
{
@@ -282,6 +282,12 @@ ClassMethod UserAction(InternalName As %String, MenuName As %String, ByRef Targe
282282
} elseif (menuItemName = "GitWebUI") {
283283
set Action = 2 + externalBrowser
284284
set Target = urlPrefix _ "/isc/studio/usertemplates/gitsourcecontrol/webuidriver.csp/"_$namespace_"/"_$zconvert(InternalName,"O","URL")_"?"_urlPostfix
285+
} elseif (menuItemName = "FileHistory") {
286+
set Action = 2 + externalBrowser
287+
set Target = urlPrefix _ "/isc/studio/usertemplates/gitsourcecontrol/webuidriver.csp/"_$namespace_"/"_$zconvert(InternalName,"O","URL")_"?view=file-history"
288+
if urlPostfix '= "" {
289+
set Target = Target_"&"_urlPostfix
290+
}
285291
} elseif (menuItemName = "Export") || (menuItemName = "ExportForce") {
286292
write !, "==export start==",!
287293
set ec = ..ExportAll($case(menuItemName="ExportForce",1:$$$Force,:0))
@@ -451,12 +457,22 @@ ClassMethod TakeOwnership(InternalName As %String) As %Status
451457
quit sc
452458
}
453459

460+
/// Validates that a branch name contains only supported characters.
461+
/// Supported: letters (a-z, A-Z), digits (0-9), hyphens (-), underscores (_), periods (.), and forward slashes (/).
462+
ClassMethod IsValidBranchName(branchName As %String) As %Boolean
463+
{
464+
quit $match(branchName, "[a-zA-Z0-9._/-]+")
465+
}
466+
454467
/// <p>This function performs <code>git checkout -b [newBranchName]</code> from the current commit.</p>
455468
/// <p>If the user is in "Basic Mode" AND there is a Default Merge Branch defined,
456469
/// then this method first checks out and pulls that default merge branch before creating the new branch. This is
457470
/// equivalent to <code>git checkout [defaultMergeBranch] && git pull</code>.</p>
458471
ClassMethod NewBranch(newBranchName As %String) As %Status
459472
{
473+
if '..IsValidBranchName(newBranchName) {
474+
quit $$$ERROR($$$GeneralError, "Invalid branch name. Branch names may only contain letters, numbers, hyphens, underscores, periods, and forward slashes.")
475+
}
460476
set settings = ##class(SourceControl.Git.Settings).%New()
461477
if (settings.basicMode) && (settings.defaultMergeBranch '= ""){
462478
set err = ..RunGitWithArgs(.errStream, .outStream, "checkout", settings.defaultMergeBranch)
@@ -2807,18 +2823,28 @@ ClassMethod GetContexts(onlyNamespaces As %Boolean) As %DynamicArray
28072823

28082824
set name = ""
28092825

2810-
// Using embedded for backwards compatability
2826+
// Using embedded instead of ExecDirectNoPriv() for backwards compatability
28112827
if '(onlyNamespaces) {
28122828
&sql(DECLARE C1 CURSOR FOR SELECT name into :name from %Library.RoutineMgr_StudioOpenDialog('*.ZPM'))
2813-
&sql(OPEN C1)
2814-
throw:SQLCODE<0 ##class(%Exception.SQL).CreateFromSQLCODE(SQLCODE, %msg)
2815-
&sql(FETCH C1)
2816-
while(SQLCODE = 0) {
2817-
set package = name
2818-
do contexts.%Push(package)
2819-
&sql(FETCH C1)
2829+
new $namespace
2830+
set ptr = 0
2831+
while $listnext(namespaces,ptr,ns) {
2832+
if '($FIND(ns,"^^")) {
2833+
try {
2834+
set $NAMESPACE = ns
2835+
&sql(OPEN C1)
2836+
throw:(SQLCODE<0) ##class(%Exception.SQL).CreateFromSQLCODE(SQLCODE, %msg)
2837+
&sql(FETCH C1)
2838+
while (SQLCODE = 0) {
2839+
do contexts.%Push(ns_":"_name)
2840+
&sql(FETCH C1)
2841+
}
2842+
&sql(CLOSE C1)
2843+
} catch e {
2844+
// skip inaccessible namespaces
2845+
}
2846+
}
28202847
}
2821-
&sql(CLOSE C1)
28222848
}
28232849

28242850
return contexts
@@ -3391,3 +3417,4 @@ ClassMethod IsSchemaStandard(pName As %String = "") As %Boolean [ Internal ]
33913417
}
33923418

33933419
}
3420+

cls/SourceControl/Git/WebUIDriver.cls

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ ClassMethod HandleRequest(pagePath As %String, InternalName As %String = "", Out
1616
set responseJSON = ..UserInfo()
1717
} elseif $extract(pagePath,6,*) = "uncommitted" {
1818
set responseJSON = ..Uncommitted()
19+
} elseif $extract(pagePath,6,*) = "page-info" {
20+
set responseJSON = ..PageInfo(InternalName, $get(%request.Data("view",1)))
1921
} elseif $extract(pagePath,6,*) = "settings" {
2022
set responseJSON = ..GetSettingsURL(%request)
2123
} elseif $extract(pagePath, 6, *) = "get-package-version"{
@@ -380,6 +382,21 @@ ClassMethod UserInfo() As %SystemBase
380382
}
381383
}
382384

385+
ClassMethod PageInfo(InternalName As %String = "", View As %String = "") As %SystemBase
386+
{
387+
set externalName = ""
388+
if InternalName '= "" {
389+
set externalName = ##class(SourceControl.Git.Utils).ExternalName(InternalName)
390+
set externalName = $translate(externalName, "\", "/")
391+
}
392+
quit {
393+
"internalName": (InternalName),
394+
"externalName": (externalName),
395+
"view": (View),
396+
"isFileHistory": (View = "file-history")
397+
}
398+
}
399+
383400
ClassMethod Uncommitted() As %SystemBase
384401
{
385402
// Stub

git-webui/package-lock.json

Lines changed: 49 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)