diff --git a/internal/api/api.go b/internal/api/api.go index 0c3a95a..d6a0d50 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -55,6 +55,19 @@ func init() { log.Printf("TEMP_DIR=%s", tmpDir) } +// ReposResponse is the successful response to /api/repos +type ReposResponse struct { + Success bool `json:"success"` + Repos []Repo `json:"repos"` +} + +// Repo is one of the elements of /api/repos +type Repo struct { + ID string `json:"id"` + CloneURL string `json:"clone_url"` + Promotions []string `json:"_promotions"` +} + // Route will set up the API and such func Route(r chi.Router, runOpts *options.ServerConfig) { @@ -74,6 +87,7 @@ func Route(r chi.Router, runOpts *options.ServerConfig) { webhooks.RouteHandlers(r) r.Route("/api/admin", func(r chi.Router) { + r.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // r.Body is always .Close()ed by Go's http server @@ -126,6 +140,7 @@ func Route(r chi.Router, runOpts *options.ServerConfig) { w.Header().Set("Content-Type", "application/json") w.Write(append(b, '\n')) }) + r.Get("/jobs", func(w http.ResponseWriter, r *http.Request) { // again, possible race condition, but not one that much matters jjobs := []Job{} @@ -145,6 +160,7 @@ func Route(r chi.Router, runOpts *options.ServerConfig) { }) w.Write(append(b, '\n')) }) + r.Post("/jobs", func(w http.ResponseWriter, r *http.Request) { defer func() { _ = r.Body.Close() @@ -220,9 +236,16 @@ func Route(r chi.Router, runOpts *options.ServerConfig) { func runHook(hook webhooks.Ref, runOpts *options.ServerConfig) { fmt.Printf("%#v\n", hook) + jobID := base64.RawURLEncoding.EncodeToString([]byte( fmt.Sprintf("%s#%s", hook.HTTPSURL, hook.RefName), )) + repoID := getRepoID(hook.HTTPSURL) + jobName := fmt.Sprintf("%s#%s", strings.ReplaceAll(repoID, "/", "-"), hook.RefName) + + env := os.Environ() + envs := getEnvs(jobID, runOpts.RepoList, hook) + envs = append(envs, "GIT_DEPLOY_JOB_ID="+jobID) args := []string{ runOpts.ScriptsPath + "/deploy.sh", @@ -234,45 +257,6 @@ func runHook(hook webhooks.Ref, runOpts *options.ServerConfig) { hook.HTTPSURL, } cmd := exec.Command("bash", args...) - - // https://git.example.com/example/project.git - // => git.example.com/example/project - repoID := strings.TrimPrefix(hook.HTTPSURL, "https://") - repoID = strings.TrimPrefix(repoID, "https://") - repoID = strings.TrimSuffix(repoID, ".git") - jobName := fmt.Sprintf("%s#%s", strings.ReplaceAll(repoID, "/", "-"), hook.RefName) - - env := os.Environ() - envs := []string{ - "GIT_DEPLOY_JOB_ID=" + jobID, - "GIT_REF_NAME=" + hook.RefName, - "GIT_REF_TYPE=" + hook.RefType, - "GIT_REPO_ID=" + repoID, - "GIT_REPO_OWNER=" + hook.Owner, - "GIT_REPO_NAME=" + hook.Repo, - "GIT_CLONE_URL=" + hook.HTTPSURL, // deprecated - "GIT_HTTPS_URL=" + hook.HTTPSURL, - "GIT_SSH_URL=" + hook.SSHURL, - } - for _, repo := range strings.Fields(runOpts.RepoList) { - last := len(repo) - 1 - if len(repo) < 0 { - continue - } - repoID = strings.ToLower(repoID) - if '*' == repo[last] { - // Wildcard match a prefix, for example: - // github.com/whatever/* MATCHES github.com/whatever/foo - // github.com/whatever/ProjectX-* MATCHES github.com/whatever/ProjectX-Foo - if strings.HasPrefix(repoID, repo[:last]) { - envs = append(envs, "GIT_REPO_TRUSTED=true") - break - } - } else if repo == repoID { - envs = append(envs, "GIT_REPO_TRUSTED=true") - break - } - } cmd.Env = append(env, envs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -346,15 +330,8 @@ func runPromote(hook webhooks.Ref, promoteTo string, runOpts *options.ServerConf cmd := exec.Command("bash", args...) env := os.Environ() - envs := []string{ - "GIT_DEPLOY_JOB_ID=" + jobID1, - "GIT_DEPLOY_PROMOTE_TO=" + promoteTo, - "GIT_REF_NAME=" + hook.RefName, - "GIT_REF_TYPE=" + hook.RefType, - "GIT_REPO_OWNER=" + hook.Owner, - "GIT_REPO_NAME=" + hook.Repo, - "GIT_CLONE_URL=" + hook.HTTPSURL, - } + envs := getEnvs(jobID1, runOpts.RepoList, hook) + envs = append(envs, "GIT_DEPLOY_PROMOTE_TO="+promoteTo) cmd.Env = append(env, envs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -443,15 +420,52 @@ func restoreBacklog(jobName, jobID string) { webhooks.Hook(ref) } -// ReposResponse is the successful response to /api/repos -type ReposResponse struct { - Success bool `json:"success"` - Repos []Repo `json:"repos"` +// https://git.example.com/example/project.git +// => git.example.com/example/project +func getRepoID(httpsURL string) string { + repoID := strings.TrimPrefix(httpsURL, "https://") + repoID = strings.TrimPrefix(repoID, "https://") + repoID = strings.TrimSuffix(repoID, ".git") + return repoID } -// Repo is one of the elements of /api/repos -type Repo struct { - ID string `json:"id"` - CloneURL string `json:"clone_url"` - Promotions []string `json:"_promotions"` +func getEnvs(jobID string, repoList string, hook webhooks.Ref) []string { + repoID := getRepoID(hook.HTTPSURL) + + envs := []string{ + "GIT_DEPLOY_JOB_ID=" + jobID, + "GIT_REF_NAME=" + hook.RefName, + "GIT_REF_TYPE=" + hook.RefType, + "GIT_REPO_ID=" + repoID, + "GIT_REPO_OWNER=" + hook.Owner, + "GIT_REPO_NAME=" + hook.Repo, + "GIT_CLONE_URL=" + hook.HTTPSURL, // deprecated + "GIT_HTTPS_URL=" + hook.HTTPSURL, + "GIT_SSH_URL=" + hook.SSHURL, + } + + // GIT_REPO_TRUSTED + // Set GIT_REPO_TRUSTED=TRUE if the repo matches exactly, or by pattern + repoID = strings.ToLower(repoID) + for _, repo := range strings.Fields(repoList) { + last := len(repo) - 1 + if len(repo) < 0 { + continue + } + repo = strings.ToLower(repo) + if '*' == repo[last] { + // Wildcard match a prefix, for example: + // github.com/whatever/* MATCHES github.com/whatever/foo + // github.com/whatever/ProjectX-* MATCHES github.com/whatever/ProjectX-Foo + if strings.HasPrefix(repoID, repo[:last]) { + envs = append(envs, "GIT_REPO_TRUSTED=true") + break + } + } else if repo == repoID { + envs = append(envs, "GIT_REPO_TRUSTED=true") + break + } + } + + return envs }