Skip to content

Commit e847b6f

Browse files
committed
fix: several improvements and fixes
- check and warn if paged remote API endpoints have a next page - request maximum number of elements per page on remote endpoints to to mitigate risk of missing commits, files - read deployed hash when reading collection config as this info is needed almost all the time - expose all public data on /git/status - graceful handling of remote connection error in /git/status - test and fix gitlab: - drastically reduce requests to API on incremental updates - refactor incremental update functions to expect only one parameter
1 parent 001e3c1 commit e847b6f

File tree

12 files changed

+488
-292
lines changed

12 files changed

+488
-292
lines changed

.existdb.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"servers": {
33
"localhost": {
4-
"server": "https://localhost:8443/exist",
4+
"server": "https://127.0.0.1:8443/exist",
55
"user": "admin",
66
"password": "",
77
"root": "/db/apps/tuttle"

src/data/tuttle.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
<default>true</default>
55
<type>github</type>
66
<baseurl>https://api.github.com/</baseurl>
7-
<repo>tuttle-sample-data</repo>
87
<owner>eeditiones</owner>
8+
<repo>tuttle-sample-data</repo>
99
<token>XXX</token>
1010
<ref>next</ref>
1111
<hookuser>admin</hookuser>
@@ -15,9 +15,11 @@
1515
<collection name="tuttle-sample-gitlab">
1616
<type>gitlab</type>
1717
<baseurl>https://gitlab.com/api/v4/</baseurl>
18-
<project-id>tuttle-sample-data</project-id>
18+
<owner>line-o</owner>
19+
<repo>tuttle-sample-data</repo>
20+
<project-id>50872175</project-id>
1921
<token>XXX</token>
20-
<ref>master</ref>
22+
<ref>main</ref>
2123
<hookuser>admin</hookuser>
2224
<hookpasswd></hookpasswd>
2325
</collection>

src/modules/api.xql

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,34 +42,31 @@ declare function api:get-status($request as map(*)) {
4242
};
4343

4444
declare function api:repo-xml ($info as map(*)) as element(repo) {
45-
<repo type="{$info?type}" url="{$info?url}"
46-
ref="{$info?ref}" collection="{$info?collection}"
47-
message="{$info?message}" status="{$info?status}" />
45+
element repo {
46+
map:for-each($info, function ($name as xs:string, $value) as attribute() {
47+
attribute { $attribute } { $value }
48+
})
49+
}
4850
};
4951

5052
declare function api:collection-info ($collection as xs:string) as map(*) {
5153
let $collection-config := api:get-collection-config($collection)
52-
let $actions := vcs:get-actions($collection-config?vcs)
53-
let $deployed-commit-hash := doc($collection-config?path || "/gitsha.xml")/hash/value/string()
54-
let $info := map {
55-
'deployed': $deployed-commit-hash,
56-
'type': $collection-config?vcs,
57-
'ref': $collection-config?ref,
58-
'collection': $collection-config?collection
59-
}
54+
(: hide passwords and tokens :)
55+
let $masked := map:remove($collection-config, ("hookpasswd", "token"))
6056

6157
return
6258
try {
59+
let $actions := vcs:get-actions($collection-config?type)
6360
let $url := $actions?get-url($collection-config)
6461
let $last-remote-commit := $actions?get-last-commit($collection-config)
6562
let $remote-short-sha := app:shorten-sha($last-remote-commit?sha)
6663

6764
let $status :=
68-
if ($last-remote-commit?sha = "")
65+
if ($remote-short-sha = "")
6966
then "error"
70-
else if (empty($deployed-commit-hash))
67+
else if (empty($collection-config?deployed))
7168
then "new"
72-
else if ($deployed-commit-hash = $remote-short-sha)
69+
else if ($collection-config?deployed = $remote-short-sha)
7370
then "uptodate"
7471
else "behind"
7572

@@ -78,15 +75,15 @@ declare function api:collection-info ($collection as xs:string) as map(*) {
7875
then "no commit on remote"
7976
else "remote found"
8077

81-
return map:merge(( $info, map {
78+
return map:merge(( $masked, map {
8279
'url': $url,
8380
'remote': $remote-short-sha,
8481
'message': $message,
8582
'status': $status
8683
}))
8784
}
8885
catch * {
89-
map:merge(( $info, map {
86+
map:merge(( $masked, map {
9087
'message': $err:description,
9188
'status': 'error'
9289
}))
@@ -99,14 +96,14 @@ declare function api:collection-info ($collection as xs:string) as map(*) {
9996
declare function api:get-hash($request as map(*)) as map(*) {
10097
try {
10198
let $collection-config := api:get-collection-config($request?parameters?collection)
102-
let $actions := vcs:get-actions($collection-config?vcs)
99+
let $actions := vcs:get-actions($collection-config?type)
103100
let $collection-staging := $collection-config?path || config:suffix() || "/gitsha.xml"
104101

105102
let $last-remote-commit := $actions?get-last-commit($collection-config)
106103

107104
return map {
108105
"remote-hash": $last-remote-commit?sha,
109-
"local-hash": app:production-sha($collection-config?collection),
106+
"local-hash": $collection-config?deployed,
110107
"local-staging-hash": doc($collection-staging)/hash/value/text()
111108
}
112109
}
@@ -172,7 +169,7 @@ declare function api:git-pull($request as map(*)) {
172169
map { "message" : doc($lockfile)/task/value/text() || " in progress" }
173170
)
174171
else (
175-
let $actions := vcs:get-actions($config?vcs)
172+
let $actions := vcs:get-actions($config?type)
176173
let $write-lock := app:lock-write($collection-destination, "git-pull")
177174
let $commit :=
178175
if ($request?parameters?hash) then (
@@ -206,7 +203,7 @@ declare function api:git-pull-default($request as map(*)) {
206203
map { "message" : doc($lockfile)/task/value/text() || " in progress" }
207204
)
208205
else (
209-
let $actions := vcs:get-actions($config?vcs)
206+
let $actions := vcs:get-actions($config?type)
210207
let $write-lock := app:lock-write($collection-destination, "git-pull")
211208
let $commit :=
212209
if ($request?parameters?hash)
@@ -261,8 +258,8 @@ declare function api:git-deploy($request as map(*)) {
261258
let $set-permissions := app:set-permission($config?collection)
262259
return
263260
map {
264-
"sha" : app:production-sha($config?collection),
265-
"message" : "success"
261+
"sha": config:deployed-sha($config?path),
262+
"message": "success"
266263
}
267264
)
268265
else (
@@ -285,8 +282,8 @@ declare function api:git-deploy($request as map(*)) {
285282
let $install := repo:install-and-deploy-from-db(concat($collection-staging-uri, "/pkg.xar"))
286283
return
287284
map {
288-
"sha" : app:production-sha($config?collection),
289-
"message" : "success"
285+
"sha": config:deployed-sha($config?path),
286+
"message": "success"
290287
}
291288
)
292289
let $remove-staging := xmldb:remove($collection-staging-uri)
@@ -309,9 +306,11 @@ declare function api:git-deploy($request as map(*)) {
309306
declare function api:get-commits($request as map(*)) as map(*) {
310307
try {
311308
let $config := api:get-collection-config($request?parameters?collection)
312-
let $actions := vcs:get-actions($config?vcs)
309+
let $actions := vcs:get-actions($config?type)
313310

314-
return $actions?get-commits($config, $request?parameters?count)
311+
return map {
312+
'commits': $actions?get-commits($config, $request?parameters?count)
313+
}
315314
}
316315
catch * {
317316
map {
@@ -329,7 +328,7 @@ declare function api:get-commits($request as map(*)) as map(*) {
329328
declare function api:get-commits-default($request as map(*)) as map(*) {
330329
try {
331330
let $config := api:get-default-collection-config()
332-
let $actions := vcs:get-actions($config?vcs)
331+
let $actions := vcs:get-actions($config?type)
333332

334333
return map {
335334
'commits': $actions?get-commits($config, $request?parameters?count)
@@ -355,7 +354,7 @@ declare function api:incremental($request as map(*)) as map(*) {
355354
let $collection-path := $config?path
356355
let $lockfile := $collection-path || "/" || config:lock()
357356
let $collection-destination-sha := $collection-path || "/gitsha.xml"
358-
let $actions := vcs:get-actions($config?vcs)
357+
let $actions := vcs:get-actions($config?type)
359358

360359
return
361360
if (not(xmldb:collection-available($collection-path))) then (
@@ -366,21 +365,21 @@ declare function api:incremental($request as map(*)) as map(*) {
366365
)
367366
else if (exists($drymode) and $drymode) then
368367
map {
369-
"changes" : $actions?incremental-dry($config, $config?collection),
368+
"changes" : $actions?incremental-dry($config),
370369
"message" : "success"
371370
}
372371
else if (doc-available($lockfile)) then (
373372
map { "message" : doc($lockfile)/task/value/text() || " in progress" }
374373
)
375374
else (
376375
let $write-lock := app:lock-write($collection-path, "incremental")
377-
let $incremental := $actions?incremental($config, $config?collection)
376+
let $incremental := $actions?incremental($config)
378377
let $remove-lock := app:lock-remove($collection-path)
379378

380379
return
381380
map {
382-
"sha" : app:production-sha($config?collection),
383-
"message" : "success"
381+
"sha": config:deployed-sha($config?path),
382+
"message": "success"
384383
}
385384
)
386385
}
@@ -434,14 +433,14 @@ declare function api:hook($request as map(*)) {
434433
let $login := xmldb:login($config?path, $config?hookuser, $config?hookpasswd)
435434
let $write-lock := app:lock-write($config?path, "hook")
436435

437-
let $incremental := $actions?incremental($config, $config?collection)
436+
let $incremental := $actions?incremental($config)
438437

439438
let $remove-lock := app:lock-remove($collection-path)
440439

441-
return
440+
return
442441
map {
443-
"sha" : app:production-sha($config?collection),
444-
"message" : "success"
442+
"sha": config:deployed-sha($config?path),
443+
"message": "success"
445444
}
446445
)
447446
}

src/modules/app.xql

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -240,21 +240,6 @@ declare function app:set-permission($collection as xs:string, $path as xs:string
240240
)
241241
};
242242

243-
(:~
244-
: Get Sha of production collection
245-
:)
246-
declare function app:production-sha($collection as xs:string) {
247-
let $gitsha := config:prefix() || "/" || $collection || "/gitsha.xml"
248-
249-
return
250-
if (doc($gitsha)/hash/value/text()) then
251-
doc($gitsha)/hash/value/text()
252-
else
253-
map {
254-
"message" : concat($gitsha, " not exist")
255-
}
256-
};
257-
258243
(:~
259244
: Helper function of unzip:mkcol()
260245
:)
@@ -307,23 +292,24 @@ declare function app:shorten-sha($git-sha as xs:string?) as xs:string? {
307292

308293
declare function app:request-json($request as element(http:request)) {
309294
let $raw := app:request($request)
310-
let $decoded := util:base64-decode($raw)
295+
let $decoded := util:base64-decode($raw[2])
311296
let $json := parse-json($decoded)
312297

313-
return $json
298+
return ($raw[1], $json)
314299
};
315300

316301
(:~
317302
: Github request
318303
:)
319304
declare function app:request($request as element(http:request)) {
305+
(: let $_ := util:log("info", $request/@href) :)
320306
let $response := http:send-request($request)
321307
let $status-code := xs:integer($response[1]/@status)
322308

323309
return
324310
if ($status-code >= 400)
325311
then error(xs:QName("app:connection-error"), "server connection failed: " || $response[1]/@message || " (" || $status-code || ")", $response[1])
326-
else $response[2]
312+
else $response
327313
};
328314

329315
declare function app:extract-archive($zip, $collection as xs:string) {

src/modules/config.xql

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ declare variable $config:tuttle-config as element(tuttle) := doc("/db/apps/tuttl
1212
:)
1313
declare function config:collections($collection as xs:string) as map(*)? {
1414
let $collection-config := $config:tuttle-config/repos/collection[@name = $collection]
15+
let $path := config:prefix() || $collection
1516

1617
return
1718
if (empty($collection-config))
@@ -22,18 +23,30 @@ declare function config:collections($collection as xs:string) as map(*)? {
2223
"repo" : $collection-config/repo/string(),
2324
"owner" : $collection-config/owner/string(),
2425
"project-id" : $collection-config/project-id/string(),
25-
"vcs": $collection-config/type/string(),
26+
"type": $collection-config/type/string(),
2627
"baseurl": $collection-config/baseurl/string(),
2728
"ref": $collection-config/ref/string(),
2829
"collection": $collection-config/@name/string(),
29-
"path": config:prefix() || $collection,
3030
"hookuser": $collection-config/hookuser/string(),
31+
32+
"path": $path,
33+
"deployed": config:deployed-sha($path),
34+
3135
(: be careful never to expose these :)
3236
"hookpasswd": $collection-config/hookpasswd/string(),
3337
"token": config:token($collection-config)
3438
}
3539
};
3640

41+
(:~
42+
: Which commit is deployed?
43+
:)
44+
declare function config:deployed-sha($path as xs:string) as xs:string? {
45+
if (doc-available($path || "/gitsha.xml"))
46+
then doc($path || "/gitsha.xml")/hash/value/string()
47+
else ()
48+
};
49+
3750
declare %private function config:token($collection-config as element(collection)) as xs:string? {
3851
let $env-var := "tuttle_token_" || replace($collection-config/@name/string(), "-", "_")
3952
let $token-env := environment-variable($env-var)
@@ -54,57 +67,57 @@ declare function config:collection-config-available($collection as xs:string) as
5467
(:~
5568
: List collection names
5669
:)
57-
declare function config:list-collections() {
70+
declare function config:list-collections() as xs:string* {
5871
$config:tuttle-config/repos/collection/@name/string()
5972
};
6073

6174

6275
(:~
6376
: Defile default collection
6477
:)
65-
declare function config:default-collection(){
78+
declare function config:default-collection() as xs:string? {
6679
$config:tuttle-config/repos/collection[default="true"]/@name/string()
6780
};
6881

6982
(:~
7083
: Blacklist - these files are not checkout from git and are ignored
7184
:)
72-
declare function config:blacklist(){
85+
declare function config:blacklist() as xs:string* {
7386
$config:tuttle-config/blacklist/file/string()
7487
};
7588

7689
(:~
7790
: Suffix of the checked out git statging collection
7891
:)
79-
declare function config:suffix(){
92+
declare function config:suffix() as xs:string {
8093
$config:tuttle-config/config/@suffix/string()
8194
};
8295

8396
(:~
8497
: The running task is stored in the lockfile. It ensures that two tasks do not run at the same time.
8598
:)
86-
declare function config:lock(){
99+
declare function config:lock() as xs:string {
87100
$config:tuttle-config/config/@lock/string()
88101
};
89102

90103
(:~
91104
: Prefix for collections
92105
:)
93-
declare function config:prefix(){
106+
declare function config:prefix() as xs:string {
94107
$config:tuttle-config/config/@prefix/string()
95108
};
96109

97110
(:~
98111
: The destination where the key for the webhook is stored.
99112
:)
100-
declare function config:apikeys(){
113+
declare function config:apikeys() as xs:string* {
101114
$config:tuttle-config/config/@apikeys/string()
102115
};
103116

104117
(:~
105118
: DB User and Permissions as fallback if "permissions" not set in repo.xml
106119
:)
107-
declare function config:sm(){
120+
declare function config:sm() as map(*) {
108121
let $sm := $config:tuttle-config/config/sm
109122

110123
return map {

0 commit comments

Comments
 (0)