supabase-cli/tools/selfhost/main.go

117 lines
3.1 KiB
Go

package main
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"log"
"os"
"os/signal"
"strings"
"github.com/google/go-github/v62/github"
"github.com/supabase/cli/internal/utils"
"github.com/supabase/cli/pkg/config"
"github.com/supabase/cli/tools/shared"
"gopkg.in/yaml.v3"
)
const (
SUPABASE_REPO = "supabase"
SUPABASE_OWNER = "supabase"
)
func main() {
branch := "cli/latest"
if len(os.Args) > 1 {
branch = os.Args[1]
}
ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
if err := updateSelfHosted(ctx, branch); err != nil {
log.Fatalln(err)
}
}
type ComposeService struct {
Image string `yaml:"image,omitempty"`
}
type ComposeFile struct {
Services map[string]ComposeService `yaml:"services,omitempty"`
}
func updateSelfHosted(ctx context.Context, branch string) error {
client := utils.GetGitHubClient(ctx)
master := "master"
if err := shared.CreateGitBranch(ctx, client, SUPABASE_OWNER, SUPABASE_REPO, branch, master); err != nil {
return err
}
stable := getStableVersions()
if err := updateComposeVersion(ctx, client, "docker/docker-compose.yml", branch, stable); err != nil {
return err
}
pr := github.NewPullRequest{
Title: github.String("chore: update self-hosted image versions"),
Head: &branch,
Base: &master,
}
return shared.CreatePullRequest(ctx, client, SUPABASE_OWNER, SUPABASE_REPO, pr)
}
func getStableVersions() map[string]string {
images := append(config.Images.Services(), config.Images.Pg15)
result := make(map[string]string, len(images))
for _, img := range images {
parts := strings.Split(img, ":")
key := strings.TrimPrefix(parts[0], "library/")
result[key] = parts[1]
}
return result
}
func updateComposeVersion(ctx context.Context, client *github.Client, path, ref string, stable map[string]string) error {
fmt.Fprintln(os.Stderr, "Parsing file:", path)
opts := github.RepositoryContentGetOptions{Ref: "heads/" + ref}
file, _, _, err := client.Repositories.GetContents(ctx, SUPABASE_OWNER, SUPABASE_REPO, path, &opts)
if err != nil {
return err
}
content, err := base64.StdEncoding.DecodeString(*file.Content)
if err != nil {
return err
}
var data ComposeFile
if err := yaml.Unmarshal(content, &data); err != nil {
return err
}
updated := false
for _, v := range data.Services {
parts := strings.Split(v.Image, ":")
if version, ok := stable[parts[0]]; ok && parts[1] != version {
fmt.Fprintf(os.Stderr, "Updating %s: %s => %s\n", parts[0], parts[1], version)
image := strings.Join([]string{parts[0], version}, ":")
content = bytes.ReplaceAll(content, []byte(v.Image), []byte(image))
updated = true
}
}
if !updated {
fmt.Fprintln(os.Stderr, "All images are up to date.")
return nil
}
message := "chore: update image versions for " + path
commit := github.RepositoryContentFileOptions{
Message: &message,
Content: content,
SHA: file.SHA,
Branch: &ref,
}
resp, _, err := client.Repositories.UpdateFile(ctx, SUPABASE_OWNER, SUPABASE_REPO, path, &commit)
if err != nil {
return err
}
fmt.Fprintln(os.Stderr, "Committed changes to", *resp.Commit.SHA)
return nil
}