Skip to content

Commit b13adef

Browse files
authored
Merge branch 'main' into fix-item-cache-case
2 parents 09afb83 + 82994ee commit b13adef

File tree

4 files changed

+142
-91
lines changed

4 files changed

+142
-91
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111
- Expanded Baseline Export to include custom HL7, X12, ASTM schemas and Lookup Tables (#693)
12+
- Settings page includes a test of the connection to the remote (#746)
1213

1314
### Fixed
1415
- Deletes are now properly owned by the user who did the delete (#729)
1516
- Pull page output now displays better when pull preview shows a lot of changes (#740)
16-
- extensions in item cache are consistently upper-case, so "export all" doesn't duplicate work (#727)
17+
- Extensions in item cache are consistently upper-case, so "export all" doesn't duplicate work (#727)
18+
- Fixed loop of loading classes with compilation errors in Studio (#766)
19+
- Fixed error popup when creating new record map or other interop items (#753)
20+
- Changing remotes in the git project settings pages now works if remote is not already defined (#746)
1721

1822
## [2.11.0] - 2025-04-23
1923

cls/SourceControl/Git/Production.cls

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,10 +380,24 @@ ClassMethod IsProductionClass(className As %String, nameMethod As %String) As %B
380380
if ##class(%File).Exists(settingsPTDFilename) {
381381
return 1
382382
}
383-
// check if there is a class export for this Production, load it for class definition
383+
// uses temporary flag to load item without loading into database (since the item may not be
384+
// compilable or not have been intended for import yet). Then check for Production Definition
385+
// XData. Approach taken from CvtXmlToClientDoc method in %Api.Atelier.v1
384386
set filename = $classmethod(##class(%Studio.SourceControl.Interface).SourceControlClassGet(), nameMethod, className_".CLS")
385-
if ##class(%File).Exists(filename) && (##class(%File).GetFileSize(filename) '= 0) {
386-
$$$ThrowOnError($System.OBJ.Load(filename))
387+
if ##class(%File).Exists(filename) && '##class(%File).DirectoryExists(filename) && (##class(%File).GetFileSize(filename) '= 0) {
388+
try {
389+
set ^||%oddDEF=1
390+
$$$ThrowOnError($system.OBJ.Load(filename, "-d"))
391+
// class XDatas are stored in ^||%oddDEF("<class name>","x","<XData name>") after temp load
392+
set hasProdDef = $data(^||%oddDEF(className,$$$cCLASSxdata,"ProductionDefinition"))
393+
kill ^||%oddDEF
394+
if hasProdDef {
395+
return 1
396+
}
397+
} catch err {
398+
kill ^||%oddDEF
399+
throw err
400+
}
387401
}
388402
// if Production exists as a class definition on the server, check if extending Ens.Production
389403
set classDef = ##class(%Dictionary.ClassDefinition).%OpenId(className)

cls/SourceControl/Git/Utils.cls

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,9 +1251,12 @@ ClassMethod IsInSourceControl(InternalName As %String, ByRef sourceControlItem A
12511251
quit isInSourceControl
12521252
}
12531253

1254-
ClassMethod FullExternalName(ByRef InternalName As %String, ByRef MappingExists As %Boolean) As %String [ CodeMode = expression ]
1254+
ClassMethod FullExternalName(ByRef InternalName As %String, ByRef MappingExists As %Boolean) As %String
12551255
{
1256-
..TempFolder()_..ExternalName(.InternalName, .MappingExists)
1256+
set externalName = ..ExternalName(.InternalName, .MappingExists)
1257+
return $select(
1258+
externalName="":"",
1259+
1: ..TempFolder()_externalName)
12571260
}
12581261

12591262
ClassMethod NormalizeInternalName(ByRef name As %String, Output fromWebApp As %Boolean = 0, Output cspFilename) As %String
@@ -3012,15 +3015,23 @@ ClassMethod BaselineExport(pCommitMessage = "", pPushToRemote = "") As %Status
30123015
return sc
30133016
}
30143017

3015-
/// Returns the url for the remote repository (censoring the username)
3016-
ClassMethod GetConfiguredRemote() As %String
3018+
/// Returns the url for the "origin" remote repository
3019+
ClassMethod GetConfiguredRemote(Output remoteExists As %Boolean = 0) As %String
30173020
{
3018-
d ..RunGitCommand("remote",.err,.out,"-v")
3019-
set line = out.ReadLine()
3020-
set url = $piece($piece(line,$char(9),2)," ",1)
3021+
set exitCode = ..RunGitCommand("remote",.err,.out,"get-url","origin")
3022+
if (exitCode = 0) {
3023+
set remoteExists = 1
3024+
set url = out.ReadLine()
3025+
} elseif (exitCode = 2) {
3026+
set remoteExists = 0
3027+
set url = ""
3028+
} else {
3029+
$$$ThrowStatus($$$ERROR($$$GeneralError,"git reported failure"))
3030+
}
30213031
return url
30223032
}
30233033

3034+
/// Returns the url for the "origin" remote repository, redacting the username
30243035
ClassMethod GetRedactedRemote() As %String
30253036
{
30263037
set url = ..GetConfiguredRemote()
@@ -3031,7 +3042,15 @@ ClassMethod GetRedactedRemote() As %String
30313042

30323043
ClassMethod SetConfiguredRemote(url) As %String
30333044
{
3034-
do ##class(SourceControl.Git.Utils).RunGitCommandWithInput("remote",,.errStream,.outStream,"set-url","origin",url)
3045+
do ..GetConfiguredRemote(.remoteExists)
3046+
set returnCode = $select(
3047+
remoteExists&&(url=""): ##class(SourceControl.Git.Utils).RunGitCommandWithInput("remote",,.errStream,.outStream,"remove","origin"),
3048+
remoteExists&&(url'=""): ##class(SourceControl.Git.Utils).RunGitCommandWithInput("remote",,.errStream,.outStream,"set-url","origin",url),
3049+
'remoteExists&&(url'=""): ##class(SourceControl.Git.Utils).RunGitCommandWithInput("remote",,.errStream,.outStream,"add","origin",url),
3050+
1: 0)
3051+
if (returnCode '= 0) {
3052+
$$$ThrowStatus($$$ERROR($$$GeneralError,"git reported failure"))
3053+
}
30353054
set output = outStream.ReadLine(outStream.Size)
30363055
quit output
30373056
}
@@ -3191,4 +3210,3 @@ ClassMethod IsSchemaStandard(pName As %String = "") As %Boolean [ Internal ]
31913210
}
31923211

31933212
}
3194-

csp/gitprojectsettings.csp

Lines changed: 93 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<style type='text/css'>
1212
.error {
1313
color: red;
14+
padding: 20px;
1415
}
1516

1617
body {
@@ -101,97 +102,105 @@ body {
101102
set homeURL = ##class(SourceControl.Git.WebUIDriver).GetHomeURL()
102103

103104
set settings = ##class(SourceControl.Git.Settings).%New()
104-
set remote = ##class(SourceControl.Git.Utils).GetRedactedRemote()
105-
/// After Save
106-
if (%request.Method="POST") && $Data(%request.Data("gitsettings",1)) {
107-
for param="gitUserName","gitUserEmail" {
108-
set $Property(settings,param) = $Get(%request.Data(param,1))
109-
}
110-
if ('settings.settingsUIReadOnly) {
111-
for param="gitBinPath","namespaceTemp","privateKeyFile","pullEventClass","percentClassReplace", "defaultMergeBranch","environmentName" {
105+
try {
106+
/// After Save
107+
if (%request.Method="POST") && $Data(%request.Data("gitsettings",1)) {
108+
for param="gitUserName","gitUserEmail" {
112109
set $Property(settings,param) = $Get(%request.Data(param,1))
113110
}
111+
if ('settings.settingsUIReadOnly) {
112+
for param="gitBinPath","namespaceTemp","privateKeyFile","pullEventClass","percentClassReplace", "defaultMergeBranch","environmentName" {
113+
set $Property(settings,param) = $Get(%request.Data(param,1))
114+
}
114115

115-
if ($Get(%request.Data("mappedItemsReadOnly", 1)) = 1) {
116-
set settings.mappedItemsReadOnly = 1
117-
} else {
118-
set settings.mappedItemsReadOnly = 0
119-
}
116+
if ($Get(%request.Data("mappedItemsReadOnly", 1)) = 1) {
117+
set settings.mappedItemsReadOnly = 1
118+
} else {
119+
set settings.mappedItemsReadOnly = 0
120+
}
120121

121-
set newRemote = $Get(%request.Data("remoteRepo",1))
122-
// If entry was modified, set new remote repo
123-
if (newRemote '= ##class(SourceControl.Git.Utils).GetRedactedRemote()) {
124-
do ##class(SourceControl.Git.Utils).SetConfiguredRemote(newRemote)
125-
}
122+
set newRemote = $Get(%request.Data("remoteRepo",1))
123+
// If entry was modified, set new remote repo
124+
if (newRemote '= ##class(SourceControl.Git.Utils).GetRedactedRemote()) {
125+
do ##class(SourceControl.Git.Utils).SetConfiguredRemote(newRemote)
126+
}
126127

127-
set settings.compileOnImport = ($Get(%request.Data("compileOnImport", 1)) = 1)
128-
set settings.decomposeProductions = ($Get(%request.Data("decomposeProductions", 1)) = 1)
129-
set settings.decomposeProdAllowIDE = ($Get(%request.Data("decomposeProdAllowIDE", 1)) = 1)
130-
set settings.lockBranch = ($Get(%request.Data("lockBranch", 1)) = 1)
131-
132-
if ($Get(%request.Data("basicMode", 1)) = 1) {
133-
set settings.basicMode = 1
134-
} elseif ($Get(%request.Data("basicMode", 1)) = "system"){
135-
set settings.basicMode = "system"
136-
} else {
137-
set settings.basicMode = 0
138-
}
128+
set settings.compileOnImport = ($Get(%request.Data("compileOnImport", 1)) = 1)
129+
set settings.decomposeProductions = ($Get(%request.Data("decomposeProductions", 1)) = 1)
130+
set settings.decomposeProdAllowIDE = ($Get(%request.Data("decomposeProdAllowIDE", 1)) = 1)
131+
set settings.lockBranch = ($Get(%request.Data("lockBranch", 1)) = 1)
132+
133+
if ($Get(%request.Data("basicMode", 1)) = 1) {
134+
set settings.basicMode = 1
135+
} elseif ($Get(%request.Data("basicMode", 1)) = "system"){
136+
set settings.basicMode = "system"
137+
} else {
138+
set settings.basicMode = 0
139+
}
139140

140-
if ($Get(%request.Data("systemBasicMode", 1)) = 1) {
141-
set settings.systemBasicMode = 1
142-
} else {
143-
set settings.systemBasicMode = 0
144-
}
145-
set i = 1
146-
set param = "NoFolders"
147-
kill settings.Mappings
148-
149-
while ( $Data(%request.Data("MappingsExt",i)) ){
150-
if ($get(%request.Data("MappingsExt",i)) '= "") {
151-
if ($Get(%request.Data(param,i)) = "NoFolders"){
152-
set settings.Mappings($Get(%request.Data("MappingsExt",i)), $Get(%request.Data("MappingsCov",i)), $Get(%request.Data(param,i))) = 1
153-
}
154-
set settings.Mappings($Get(%request.Data("MappingsExt",i)), $Get(%request.Data("MappingsCov",i))) = $Get(%request.Data("MappingsPath",i))
155-
}
156-
set i = i+1
157-
}
141+
if ($Get(%request.Data("systemBasicMode", 1)) = 1) {
142+
set settings.systemBasicMode = 1
143+
} else {
144+
set settings.systemBasicMode = 0
145+
}
146+
set i = 1
147+
set param = "NoFolders"
148+
kill settings.Mappings
149+
150+
while ( $Data(%request.Data("MappingsExt",i)) ){
151+
if ($get(%request.Data("MappingsExt",i)) '= "") {
152+
if ($Get(%request.Data(param,i)) = "NoFolders"){
153+
set settings.Mappings($Get(%request.Data("MappingsExt",i)), $Get(%request.Data("MappingsCov",i)), $Get(%request.Data(param,i))) = 1
154+
}
155+
set settings.Mappings($Get(%request.Data("MappingsExt",i)), $Get(%request.Data("MappingsCov",i))) = $Get(%request.Data("MappingsPath",i))
156+
}
157+
set i = i+1
158+
}
158159

159-
set i = 1
160-
set contexts = []
160+
set i = 1
161+
set contexts = []
161162

162-
while ( $Data(%request.Data("favNamespace",i)) ){
163-
if ($Get(%request.Data("favNamespace",i)) '= "") {
164-
do contexts.%Push($Get(%request.Data("favNamespace",i)))
165-
}
166-
set i = i+1
167-
}
163+
while ( $Data(%request.Data("favNamespace",i)) ){
164+
if ($Get(%request.Data("favNamespace",i)) '= "") {
165+
do contexts.%Push($Get(%request.Data("favNamespace",i)))
166+
}
167+
set i = i+1
168+
}
168169

169-
set settings.favoriteNamespaces = contexts
170+
set settings.favoriteNamespaces = contexts
170171

171-
if ($get(%request.Data("proxySubmitButton",1)) = "saveDefaults") {
172-
do settings.SaveDefaults()
172+
if ($get(%request.Data("proxySubmitButton",1)) = "saveDefaults") {
173+
do settings.SaveDefaults()
174+
}
173175
}
174-
}
175-
set err = ""
176-
try {
177-
set buffer = ##class(SourceControl.Git.Util.Buffer).%New()
178-
do buffer.BeginCaptureOutput()
179-
$$$ThrowOnError(settings.SaveWithSourceControl())
180-
do buffer.EndCaptureOutput(.out)
181-
if (out '= "") {
182-
&html<<div class="alert alert-primary">
183-
<div>#(..EscapeHTML(out))#</div>
184-
</div>>
176+
set err = ""
177+
try {
178+
set buffer = ##class(SourceControl.Git.Util.Buffer).%New()
179+
do buffer.BeginCaptureOutput()
180+
$$$ThrowOnError(settings.SaveWithSourceControl())
181+
do buffer.EndCaptureOutput(.out)
182+
if (out '= "") {
183+
&html<<div class="alert alert-primary">
184+
<div>#(..EscapeHTML(out))#</div>
185+
</div>>
186+
}
187+
} catch err {
188+
kill buffer
189+
throw err
185190
}
186-
} catch err {
187-
kill buffer
188-
do err.Log()
189-
&html<<div class="alert alert-danger">An error occurred and has been logged to the application error log.</div>>
191+
set successfullySavedSettings = 1
190192
}
193+
set remote = ##class(SourceControl.Git.Utils).GetRedactedRemote()
194+
if (remote'="") && (##class(SourceControl.Git.Utils).RunGitCommandWithInput("ls-remote",,.errStream,,"origin")'=0) {
195+
set remoteConnectionError = errStream.Read()
196+
}
197+
} catch err {
198+
do err.Log()
199+
&html<<div class="error alert-danger">An error occurred and has been logged to the application error log.</div>>
191200
}
192201
</server>
193202
<div class = 'container'>
194-
<csp:if condition='$D(%request.Data("gitsettings",1)) && (##class(SourceControl.Git.Utils).NeedSettings() = 0)'>
203+
<csp:if condition='$get(successfullySavedSettings) && (##class(SourceControl.Git.Utils).NeedSettings() = 0)'>
195204
<div class = "alert">
196205
<span class="closebtn" onclick="this.parentElement.style.display='none';">&times;</span>
197206
<strong>Success!</strong> Your changes have been saved.
@@ -318,7 +327,7 @@ body {
318327
set placeholder = $Select($system.Version.GetOS()="Windows":"(e.g. C:\Users\ExampleUser\.ssh\id_rsa)",
319328
1:"(e.g., /home/user/.ssh/id_rsa)")
320329
</server>
321-
<input type="text" class="#(class)#" id="privateKeyFile" name="privateKeyFile" value='#(..EscapeHTML(settings.privateKeyFile))#' placeholder=#(placeholder)#/>
330+
<input type="text" class="#(class)#" id="privateKeyFile" name="privateKeyFile" value='#(..EscapeHTML(settings.privateKeyFile))#' placeholder="#(..EscapeHTML(placeholder))#"/>
322331
<div class = "#(divClass)#">
323332
#(feedbackText)#
324333
<pre id="sshOutput"></pre>
@@ -416,12 +425,18 @@ body {
416425
</div>
417426

418427
<div class="form-group row mb-3">
419-
<label for="remoteRepo" class="offset-sm-1 col-sm-3 col-form-label" data-toggle="tooltip" data-placement="top" title="Url to Remote repository"><b>Remote Repository</b></label>
428+
<label for="remoteRepo" class="offset-sm-1 col-sm-3 col-form-label" data-toggle="tooltip" data-placement="top" title="Url to Remote repository (origin)"><b>Remote Repository</b></label>
420429
<div class="col-sm-7">
421-
<input type="text" class="form-control" id="remoteRepo" name="remoteRepo" value='#(..EscapeHTML(remote))#' placeholder="ex. [email protected]:User/UserRepo.git"/>
430+
<input type="text" class='form-control #($select($get(remote)="":"",$get(remoteConnectionError)="":"is-valid",1:"is-invalid"))#' id="remoteRepo" name="remoteRepo" value='#(..EscapeHTML($get(remote)))#' placeholder="e.g. [email protected]:User/UserRepo.git"/>
422431
<div class = "neutral-feedback">
423432
(Username is redacted)
424433
</div>
434+
<div class="invalid-feedback">
435+
Unable to contact remote: #(..EscapeHTML($get(remoteConnectionError)))#
436+
</div>
437+
<div class="valid-feedback">
438+
Connection successful
439+
</div>
425440
</div>
426441
</div>
427442

0 commit comments

Comments
 (0)