diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 2cb9e03..f5b8e3b 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -23,7 +23,8 @@ jobs: include: - exist-version: latest experimental: true - + - exist-version: 5.2.0 + experimental: true services: # Label used to access the service container exist: diff --git a/package.json b/package.json index 3876e61..3b48251 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,12 @@ { "name": "tuttle", - "version": "1.2.0", + "version": "2.0.0", "description": "tuttle - a Git-integration for eXist-db", "scripts": { "start": "gulp", "test": "gulp install && mocha --exit", "test:watch": "mocha --watch", - "test:build": "gulp test:install", - "build": "gulp build", - "build:all": "gulp build && gulp test:build", + "build": "gulp xar", "deploy": "gulp install", "copy": "gulp copyStatic" }, diff --git a/src/api.json b/src/api.json index fae0dd9..a3520e8 100644 --- a/src/api.json +++ b/src/api.json @@ -19,7 +19,7 @@ }, "cookieAuth": { "type": "apiKey", - "name": "eeditiones.org.login", + "name": "org.exist.login", "in": "cookie" } } @@ -29,7 +29,7 @@ "get": { "summary": "Fetch git repo to staging collection", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:git-pull", "parameters": [ @@ -71,7 +71,7 @@ "post": { "summary": "Deploy repo to final collection", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:git-deploy", "parameters": [ @@ -107,7 +107,7 @@ "get": { "summary": "Fetch git repo to staging collection", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:git-pull-default", "parameters": [ @@ -141,7 +141,7 @@ "post": { "summary": "Deploy repo to final collection", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:git-deploy", "responses": { @@ -167,7 +167,7 @@ "post": { "summary": "Trigger incremental update", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:incremental", "parameters": [ @@ -215,7 +215,7 @@ "post": { "summary": "Trigger incremental update", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:incremental", "parameters": [ @@ -255,7 +255,7 @@ "get": { "summary": "Get remote and local hash", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:get-hash", "parameters": [ @@ -299,7 +299,7 @@ "get": { "summary": "Get remote and local hash", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:get-hash", "responses": { @@ -333,7 +333,7 @@ "get": { "summary": "Get commits", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:get-commits", "parameters": [ @@ -373,7 +373,7 @@ "get": { "summary": "Get commits", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:get-commits-default", "parameters": [ @@ -461,7 +461,7 @@ "get": { "summary": "Generate API-Webhook-Keys", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:api-keygen", "parameters": [ @@ -497,7 +497,7 @@ "get": { "summary": "Generate API-Webhook-Keys", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:api-keygen", "responses": { @@ -523,7 +523,7 @@ "get": { "summary": "Get Tuttle configuration", "x-constraints": { - "user": "admin" + "groups": ["dba"] }, "operationId": "api:get-status", "responses": { diff --git a/src/expath-pkg.xml b/src/expath-pkg.xml index b1557a7..046b8d9 100644 --- a/src/expath-pkg.xml +++ b/src/expath-pkg.xml @@ -2,7 +2,7 @@ Tuttle - Git for eXist-db - + - + diff --git a/src/modules/api.xql b/src/modules/api.xql index 57ce29f..afb734a 100644 --- a/src/modules/api.xql +++ b/src/modules/api.xql @@ -25,19 +25,23 @@ declare variable $api:definitions := ("api.json"); :) declare function api:get-status($request as map(*)) { if (contains(request:get-header('Accept'), 'application/json')) - then map { - 'default': config:default-collection(), - 'repos': array { - config:list-collections() ! api:collection-info(.) + then + map { + 'default': config:default-collection(), + 'repos': array { + for $collection-info in config:list-collections() + return + api:collection-info($collection-info) + } } - } else {config:default-collection()} { - config:list-collections() - ! api:collection-info(.) - ! api:repo-xml(.) + for $collection-info in config:list-collections() + return + api:repo-xml( + api:collection-info($collection-info)) } }; @@ -53,7 +57,9 @@ declare function api:repo-xml ($info as map(*)) as element(repo) { declare function api:collection-info ($collection as xs:string) as map(*) { let $collection-config := api:get-collection-config($collection) (: hide passwords and tokens :) - let $masked := map:remove($collection-config, ("hookpasswd", "token")) + let $masked := + map:remove( + map:remove($collection-config, "hookpasswd"), "token") return try { @@ -103,7 +109,7 @@ declare function api:get-hash($request as map(*)) as map(*) { let $last-remote-commit := $actions?get-last-commit($collection-config) return map { - "remote-hash": $last-remote-commit?sha, + "remote-hash": app:shorten-sha($last-remote-commit?sha), "local-hash": $collection-config?deployed, "local-staging-hash": doc($collection-staging)/hash/value/text() } @@ -413,6 +419,8 @@ declare function api:hook($request as map(*)) as map(*) { let $config := api:get-collection-config($request?parameters?collection) let $apikey := doc(config:apikeys())//apikeys/collection[name = $config?collection]/key/string() let $lockfile := $config?path || "/" || config:lock() + let $actions := vcs:get-actions($config?type) + return if (empty($apikey)) then ( map { "message": "apikey does not exist" } @@ -430,7 +438,7 @@ declare function api:hook($request as map(*)) as map(*) { let $incremental := $actions?incremental($config) - let $remove-lock := app:lock-remove($collection-path) + let $remove-lock := app:lock-remove($config?path) return map { diff --git a/src/modules/app.xql b/src/modules/app.xql index 4905480..ae27d09 100644 --- a/src/modules/app.xql +++ b/src/modules/app.xql @@ -151,7 +151,10 @@ declare function app:set-permission($collection as xs:string) { }; declare function app:get-permissions ($collection as xs:string) { - if (doc-available($collection || "/repo.xml")) then ( + if ( + doc-available($collection || "/repo.xml") and + exists(doc($collection || "/repo.xml")//repo:permissions) + ) then ( let $repo := doc($collection || "/repo.xml")//repo:permissions return map { "user": $repo/@user/string(), diff --git a/src/modules/github.xql b/src/modules/github.xql index 3fac5fd..5feafe5 100644 --- a/src/modules/github.xql +++ b/src/modules/github.xql @@ -120,8 +120,21 @@ declare function github:get-changes ($collection-config as map(*)) as map(*) { return github:get-commit-files($collection-config, $sha)?* (: aggregate file changes :) - return fold-left($changes, map{}, github:aggregate-filechanges#2) - + let $aggregated := fold-left($changes, map{}, github:aggregate-filechanges#2) + let $filtered := fold-left($aggregated?new, map{}, function($res, $next) { + if ( + $next = ("build.xml", "repo.xml", "expath-pkg.xml") + or starts-with($next, ".git") + or ends-with($next, ".xconf") + ) + then map:put($res, 'ignored', ($res?ignored, $next)) + else map:put($res, 'new', ($res?new, $next)) + }) + return map { + "del": $aggregated?del, + "new": $filtered?new, + "ignored": $filtered?ignored + } }; (:~ @@ -137,14 +150,18 @@ declare function github:remove-or-ignore ($changes as map(*), $filename as xs:st else map:put($changes, "del", ($changes?del, $filename)) (: add document to be removed :) }; +(: unhandled cases: "copied", "changed", "unchanged" :) declare function github:aggregate-filechanges ($changes as map(*), $next as map(*)) as map(*) { switch ($next?status) case "added" (: fall-through :) case "modified" return - map:put($changes, "new", ($changes?new, $next?filename)) + if ($next?filename = $changes?new) (: file already in new list :) + then $changes + else map:put($changes, "new", ($changes?new, $next?filename)) case "renamed" return - github:remove-or-ignore($changes, $next?previous_filename) - => map:put("new", ($changes?new, $next?filename)) + github:remove-or-ignore( + map:put($changes, "new", ($changes?new, $next?filename)), + $next?previous_filename) case "removed" return github:remove-or-ignore($changes, $next?filename) default return @@ -158,7 +175,8 @@ declare function github:incremental-dry($config as map(*)) { let $changes := github:get-changes($config) return map { 'new': array{ $changes?new }, - 'del': array{ $changes?del } + 'del': array{ $changes?del }, + 'ignored': array{ $changes?ignored } } };