github.com/supabase/cli@v1.168.1/tools/selfhost/main.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/base64" 7 "fmt" 8 "log" 9 "os" 10 "os/signal" 11 "strings" 12 13 "github.com/google/go-github/v62/github" 14 "github.com/supabase/cli/internal/utils" 15 "github.com/supabase/cli/tools/shared" 16 "gopkg.in/yaml.v3" 17 ) 18 19 const ( 20 SUPABASE_REPO = "supabase" 21 SUPABASE_OWNER = "supabase" 22 ) 23 24 func main() { 25 branch := "cli/latest" 26 if len(os.Args) > 1 { 27 branch = os.Args[1] 28 } 29 30 ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt) 31 if err := updateSelfHosted(ctx, branch); err != nil { 32 log.Fatalln(err) 33 } 34 } 35 36 type ComposeService struct { 37 Image string `yaml:"image,omitempty"` 38 } 39 40 type ComposeFile struct { 41 Services map[string]ComposeService `yaml:"services,omitempty"` 42 } 43 44 func updateSelfHosted(ctx context.Context, branch string) error { 45 client := utils.GetGtihubClient(ctx) 46 master := "master" 47 if err := shared.CreateGitBranch(ctx, client, SUPABASE_OWNER, SUPABASE_REPO, branch, master); err != nil { 48 return err 49 } 50 stable := getStableVersions() 51 if err := updateComposeVersion(ctx, client, "docker/docker-compose.yml", branch, stable); err != nil { 52 return err 53 } 54 pr := github.NewPullRequest{ 55 Title: github.String("chore: update self-hosted image versions"), 56 Head: &branch, 57 Base: &master, 58 } 59 return shared.CreatePullRequest(ctx, client, SUPABASE_OWNER, SUPABASE_REPO, pr) 60 } 61 62 func getStableVersions() map[string]string { 63 images := append([]string{utils.Pg15Image}, utils.ServiceImages...) 64 result := make(map[string]string, len(images)) 65 for _, img := range images { 66 parts := strings.Split(img, ":") 67 key := strings.TrimPrefix(parts[0], "library/") 68 result[key] = parts[1] 69 } 70 return result 71 } 72 73 func updateComposeVersion(ctx context.Context, client *github.Client, path, ref string, stable map[string]string) error { 74 fmt.Fprintln(os.Stderr, "Parsing file:", path) 75 opts := github.RepositoryContentGetOptions{Ref: "heads/" + ref} 76 file, _, _, err := client.Repositories.GetContents(ctx, SUPABASE_OWNER, SUPABASE_REPO, path, &opts) 77 if err != nil { 78 return err 79 } 80 content, err := base64.StdEncoding.DecodeString(*file.Content) 81 if err != nil { 82 return err 83 } 84 var data ComposeFile 85 if err := yaml.Unmarshal(content, &data); err != nil { 86 return err 87 } 88 updated := false 89 for _, v := range data.Services { 90 parts := strings.Split(v.Image, ":") 91 if version, ok := stable[parts[0]]; ok && parts[1] != version { 92 fmt.Fprintf(os.Stderr, "Updating %s: %s => %s\n", parts[0], parts[1], version) 93 image := strings.Join([]string{parts[0], version}, ":") 94 content = bytes.ReplaceAll(content, []byte(v.Image), []byte(image)) 95 updated = true 96 } 97 } 98 if !updated { 99 fmt.Fprintln(os.Stderr, "All images are up to date.") 100 return nil 101 } 102 message := "chore: update image versions for " + path 103 commit := github.RepositoryContentFileOptions{ 104 Message: &message, 105 Content: content, 106 SHA: file.SHA, 107 Branch: &ref, 108 } 109 resp, _, err := client.Repositories.UpdateFile(ctx, SUPABASE_OWNER, SUPABASE_REPO, path, &commit) 110 if err != nil { 111 return err 112 } 113 fmt.Fprintln(os.Stderr, "Committed changes to", *resp.Commit.SHA) 114 return nil 115 }