From 19cd4152506d4c3884e904f8c2d146137a20ecb3 Mon Sep 17 00:00:00 2001 From: Nick Guenther Date: Fri, 24 Feb 2023 23:00:07 -0500 Subject: [PATCH 1/5] Use url.JoinPath() This shortens the code, but requires upgrading to go1.19, which Gitea itself upgraded to recently. --- bids-hook.go | 8 ++------ go.mod | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/bids-hook.go b/bids-hook.go index 26c1ce5..043b574 100644 --- a/bids-hook.go +++ b/bids-hook.go @@ -16,7 +16,6 @@ import ( "net/url" "os" "os/exec" - "path" "path/filepath" "regexp" "strconv" @@ -286,9 +285,7 @@ type job struct { // web link to the results page for this job // see also j.resultPath() func (j job) resultUrl() string { - url := *giteaPublicUrl - url.Path = path.Join(url.Path, fmt.Sprintf("%s.html", j.uuid)) - return url.String() + return giteaPublicUrl.JoinPath(fmt.Sprintf("%s.html", j.uuid)).String() } // file path to the results page for this job @@ -305,8 +302,7 @@ func (j job) logPath() string { // postStatus posts a commit status to Gitea // 'state' should be one of the constants defined at the top of this module func (j job) postStatus(ctx context.Context, state string) error { - url := *giteaApiUrl - url.Path = path.Join(url.Path, "repos", j.user, j.repo, "statuses", j.commit) + url := giteaApiUrl.JoinPath("repos", j.user, j.repo, "statuses", j.commit) var description, targetUrl string switch state { diff --git a/go.mod b/go.mod index 7b69f53..33f5627 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/neuropoly/bids-hook -go 1.18 +go 1.19 From be570b9b6122f1d83c63a49d7a2996252d31cab1 Mon Sep 17 00:00:00 2001 From: Nick Guenther Date: Fri, 24 Feb 2023 11:38:00 -0500 Subject: [PATCH 2/5] Combine GITEA_PUBLIC_URL + GITEA_API_URL -> GITEA_ROOT_URL This is easier to get right, since it mirrors Gitea's app.ini. Gitea also has a STATIC_URL_PREFIX which is similar to what GITEA_PUBLIC_URL was; but we have little motivation to use it, since we are designing that bids-hook runs _on the same server_ as gitea. Also, if we did keep it, I would want to more closely mirror app.ini's config behaviour. --- bids-hook.go | 34 ++++++++++------------------------ start | 3 +-- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/bids-hook.go b/bids-hook.go index 043b574..14558db 100644 --- a/bids-hook.go +++ b/bids-hook.go @@ -42,21 +42,16 @@ var ( // this should be entered as-in in Gitea to configure the webhook bidsHookSecret []byte - // the base URL to reach Gitea's API - // read from environment variable GITEA_API_URL - // should end with "/api/v1" - giteaApiUrl *url.URL + // the base URL to reach Gitea + // read from environment variable GITEA_ROOT_URL + // should match Gitea's app.ini's [server].ROOT_URL + giteaRootUrl *url.URL // secret used to authenticate api calls from bids-hook to Gitea // read from environment variable GITEA_API_SECRET // can be generated from a gitea admin account under "Settings" -> "Applications" giteaApiSecret []byte - // the base URL for writing links to Gitea's static assets - // read from environment variable GITEA_PUBLIC_URL - // should end with "/assets" - giteaPublicUrl *url.URL - // the path to Gitea's static assets directory // read from environment variable GITEA_PUBLIC_PATH // used to save job result pages @@ -285,7 +280,7 @@ type job struct { // web link to the results page for this job // see also j.resultPath() func (j job) resultUrl() string { - return giteaPublicUrl.JoinPath(fmt.Sprintf("%s.html", j.uuid)).String() + return giteaRootUrl.JoinPath("assets", fmt.Sprintf("%s.html", j.uuid)).String() } // file path to the results page for this job @@ -302,7 +297,7 @@ func (j job) logPath() string { // postStatus posts a commit status to Gitea // 'state' should be one of the constants defined at the top of this module func (j job) postStatus(ctx context.Context, state string) error { - url := giteaApiUrl.JoinPath("repos", j.user, j.repo, "statuses", j.commit) + url := giteaRootUrl.JoinPath("api", "v1", "repos", j.user, j.repo, "statuses", j.commit) var description, targetUrl string switch state { @@ -447,13 +442,13 @@ func readConfig() { } bidsHookSecret = []byte(val) - val, ok = os.LookupEnv("GITEA_API_URL") + val, ok = os.LookupEnv("GITEA_ROOT_URL") if !ok { - log.Fatal("missing environment variable GITEA_API_URL") + log.Fatal("missing environment variable GITEA_ROOT_URL") } - giteaApiUrl, err = url.Parse(val) + giteaRootUrl, err = url.Parse(val) if err != nil { - log.Fatalf("error parsing GITEA_API_URL: %v", err) + log.Fatalf("error parsing GITEA_ROOT_URL: %v", err) } val, ok = os.LookupEnv("GITEA_API_SECRET") @@ -462,15 +457,6 @@ func readConfig() { } giteaApiSecret = []byte(val) - val, ok = os.LookupEnv("GITEA_PUBLIC_URL") - if !ok { - log.Fatal("missing environment variable GITEA_PUBLIC_URL") - } - giteaPublicUrl, err = url.Parse(val) - if err != nil { - log.Fatalf("error parsing GITEA_PUBLIC_URL: %v", err) - } - val, ok = os.LookupEnv("GITEA_PUBLIC_PATH") if !ok { log.Fatal("missing environment variable GITEA_PUBLIC_PATH") diff --git a/start b/start index c22ffb1..f3d8be9 100755 --- a/start +++ b/start @@ -4,10 +4,9 @@ export BIDS_HOOK_URL='http://127.0.0.1:2845/bids-hook' export BIDS_HOOK_SECRET='blabla' -export GITEA_API_URL='http://127.0.0.1:3000/api/v1' +export GITEA_ROOT_URL='http://127.0.0.1:3000' export GITEA_API_SECRET='69e45fa9cfa75a7497633c6be8dd2347226e2f62' -export GITEA_PUBLIC_URL='http://127.0.0.1:3000/assets' export GITEA_PUBLIC_PATH='./custom/public' export WORKER_SCRIPT='./worker' From 7caa4a6522204a66ffd4f071eb07e87fc29c0156 Mon Sep 17 00:00:00 2001 From: Nick Guenther Date: Fri, 24 Feb 2023 22:55:34 -0500 Subject: [PATCH 3/5] Rename GITEA_API_SECRET -> GITEA_TOKEN to use Gitea's nomenclature. --- bids-hook.go | 12 ++++++------ start | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bids-hook.go b/bids-hook.go index 14558db..9d37a6f 100644 --- a/bids-hook.go +++ b/bids-hook.go @@ -48,9 +48,9 @@ var ( giteaRootUrl *url.URL // secret used to authenticate api calls from bids-hook to Gitea - // read from environment variable GITEA_API_SECRET + // read from environment variable GITEA_TOKEN // can be generated from a gitea admin account under "Settings" -> "Applications" - giteaApiSecret []byte + giteaToken []byte // the path to Gitea's static assets directory // read from environment variable GITEA_PUBLIC_PATH @@ -332,7 +332,7 @@ func (j job) postStatus(ctx context.Context, state string) error { if err != nil { return err } - req.Header.Add("Authorization", fmt.Sprintf("token %s", giteaApiSecret)) + req.Header.Add("Authorization", fmt.Sprintf("token %s", giteaToken)) req.Header.Add("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) @@ -451,11 +451,11 @@ func readConfig() { log.Fatalf("error parsing GITEA_ROOT_URL: %v", err) } - val, ok = os.LookupEnv("GITEA_API_SECRET") + val, ok = os.LookupEnv("GITEA_TOKEN") if !ok { - log.Fatal("missing environment variable GITEA_API_SECRET") + log.Fatal("missing environment variable GITEA_TOKEN") } - giteaApiSecret = []byte(val) + giteaToken = []byte(val) val, ok = os.LookupEnv("GITEA_PUBLIC_PATH") if !ok { diff --git a/start b/start index f3d8be9..ba9f448 100755 --- a/start +++ b/start @@ -5,7 +5,7 @@ export BIDS_HOOK_URL='http://127.0.0.1:2845/bids-hook' export BIDS_HOOK_SECRET='blabla' export GITEA_ROOT_URL='http://127.0.0.1:3000' -export GITEA_API_SECRET='69e45fa9cfa75a7497633c6be8dd2347226e2f62' +export GITEA_TOKEN='69e45fa9cfa75a7497633c6be8dd2347226e2f62' export GITEA_PUBLIC_PATH='./custom/public' From 2d9114c8ad80157cc9243e7d94b10b84e3bdfa1e Mon Sep 17 00:00:00 2001 From: Nick Guenther Date: Fri, 24 Feb 2023 21:56:36 -0500 Subject: [PATCH 4/5] GITEA_PUBLIC_PATH -> GITEA_CUSTOM This is an environment variable Gitea also can use. --- README.md | 12 ++++++++++++ bids-hook.go | 26 +++++++++++--------------- start | 13 +++++++++++-- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 94b60f6..257ea7a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ # bids-hook Tiny CI server to run bids-validator using Gitea webhooks + + +## Deployment + +Results are placed in `%(GITEA_CUSTOM)/public/bids-validator/`; +this folder needs to be writable (and ideally created first and owned) +by the user running this daemon. + +It assumes the URL `%(ROOT_URL)s/static/assets/` loads from +Gitea's `%(GITEA_CUSTOM)/public/`; it is **not** compatible +with configuring Gitea's `%(STATIC_URL_PREFIX)` so that +static files are hosted on a different server or CDN. diff --git a/bids-hook.go b/bids-hook.go index 9d37a6f..a792ec6 100644 --- a/bids-hook.go +++ b/bids-hook.go @@ -52,12 +52,11 @@ var ( // can be generated from a gitea admin account under "Settings" -> "Applications" giteaToken []byte - // the path to Gitea's static assets directory - // read from environment variable GITEA_PUBLIC_PATH + // the path to Gitea's custom/ directory + // read from environment variable GITEA_CUSTOM // used to save job result pages - // it should already exist - // should end with "/custom/public" - giteaPublicPath string + // see https://docs.gitea.io/en-us/config-cheat-sheet/#default-configuration-non-appini-configuration + giteaCustom string // executable run by the worker for each accepted job // read from environment variable WORKER_SCRIPT @@ -286,7 +285,7 @@ func (j job) resultUrl() string { // file path to the results page for this job // see also j.resultUrl() func (j job) resultPath() string { - return filepath.Join(giteaPublicPath, fmt.Sprintf("%s.html", j.uuid)) + return filepath.Join(giteaCustom, "public", fmt.Sprintf("%s.html", j.uuid)) } // file path to the log file for this job @@ -457,20 +456,17 @@ func readConfig() { } giteaToken = []byte(val) - val, ok = os.LookupEnv("GITEA_PUBLIC_PATH") + val, ok = os.LookupEnv("GITEA_CUSTOM") if !ok { - log.Fatal("missing environment variable GITEA_PUBLIC_PATH") + log.Fatal("missing environment variable GITEA_CUSTOM") } - giteaPublicPath, err = filepath.Abs(val) + giteaCustom, err = filepath.Abs(val) if err != nil { - log.Fatalf("invalid GITEA_PUBLIC_PATH: %v", err) + log.Fatalf("invalid GITEA_CUSTOM: %v", err) } - info, err = os.Stat(giteaPublicPath) + err = os.MkdirAll(filepath.Join(giteaCustom, "public"), 0750) if err != nil { - log.Fatalf("error opening GITEA_PUBLIC_PATH: %v", err) - } - if !info.IsDir() { - log.Fatal("GITEA_PUBLIC_PATH is not a directory") + log.Fatalf("error creating output folder: %v", err) } val, ok = os.LookupEnv("WORKER_SCRIPT") diff --git a/start b/start index ba9f448..39640e4 100755 --- a/start +++ b/start @@ -1,5 +1,16 @@ #!/bin/bash +set -e + +# this replicates the default location logic from https://docs.gitea.io/en-us/config-cheat-sheet/ +# any setting can be overridden just by setting its variable before calling this script +: ${GITEA_APP_PATH:=../gitea/gitea} +: ${GITEA_WORK_DIR:="$(dirname "$GITEA_APP_PATH")"} + +: ${GITEA_CUSTOM:="$GITEA_WORK_DIR/custom"} + +export GITEA_CUSTOM + # 127.0.0.1 is localhost, and 2845 is 0xB1D export BIDS_HOOK_URL='http://127.0.0.1:2845/bids-hook' export BIDS_HOOK_SECRET='blabla' @@ -7,8 +18,6 @@ export BIDS_HOOK_SECRET='blabla' export GITEA_ROOT_URL='http://127.0.0.1:3000' export GITEA_TOKEN='69e45fa9cfa75a7497633c6be8dd2347226e2f62' -export GITEA_PUBLIC_PATH='./custom/public' - export WORKER_SCRIPT='./worker' export WORKER_LOG_PATH='./log' export WORKER_QUEUE_CAPACITY=20 From 6d9aec7fd026c200574ba681940480059fd9e7f3 Mon Sep 17 00:00:00 2001 From: Nick Guenther Date: Fri, 24 Feb 2023 22:00:19 -0500 Subject: [PATCH 5/5] Define GITEA_REPOSITORY_ROOT. This isn't an environment variable Gitea uses, but it is close to a name in its config file: [repository].ROOT. The worker will need this to find its input. This mirrors the rules for that's default value. --- start | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/start b/start index 39640e4..89be690 100755 --- a/start +++ b/start @@ -9,6 +9,10 @@ set -e : ${GITEA_CUSTOM:="$GITEA_WORK_DIR/custom"} +: ${GITEA_APP_DATA_PATH:="$GITEA_WORK_DIR/data"} +: ${GITEA_REPOSITORY_ROOT:="$GITEA_APP_DATA_PATH/gitea-repositories"} + +export GITEA_REPOSITORY_ROOT export GITEA_CUSTOM # 127.0.0.1 is localhost, and 2845 is 0xB1D