gitstack

grindlemire/gothem-stack code browser

2.9 KB Go 129 lines 2025-01-11 · 04d4ded raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/grindlemire/gothem-stack/magefiles/cmd"
	"github.com/grindlemire/gothem-stack/pkg/version"
	"github.com/pkg/errors"
	"go.uber.org/zap"
)

func release(ctx context.Context) error {
	config, err := GetConfig(ctx)
	if err != nil {
		return errors.Wrap(err, "failed to get config")
	}

	// Default to releasing both if no service specified
	if len(config.Args) < 1 {
		config.Args = []string{"all"}
	}

	// Only get version for backend releases
	var ver version.Version
	if config.Args[0] == "backend" || config.Args[0] == "all" {
		ver, err = version.Read()
		if err != nil {
			return errors.Wrap(err, "failed to read version")
		}
	}

	switch config.Args[0] {
	case "backend":
		err = releaseBackend(ctx, ver)
	case "frontend":
		err = releaseFrontend(ctx)
	case "all":
		// Release backend first
		if err = releaseBackend(ctx, ver); err != nil {
			return err
		}
		// Then release frontend
		err = releaseFrontend(ctx)
	default:
		return fmt.Errorf("invalid service: %s. Must be 'backend', 'frontend', or 'all'", config.Args[0])
	}

	if err != nil {
		return err
	}

	if config.Args[0] == "all" {
		zap.S().Info("Successfully released both services")
	} else if config.Args[0] == "backend" {
		zap.S().Infof("Successfully released backend version %s", ver)
	} else {
		zap.S().Infof("Successfully released frontend")
	}
	return nil
}

func releaseBackend(ctx context.Context, ver version.Version) error {
	projectID := os.Getenv("GOOGLE_CLOUD_PROJECT")
	if projectID == "" {
		return errors.New("GOOGLE_CLOUD_PROJECT environment variable not set")
	}

	region := os.Getenv("GOOGLE_CLOUD_REGION")
	if region == "" {
		region = "us-central1"
	}

	serviceName := os.Getenv("CLOUD_RUN_SERVICE_NAME")
	if serviceName == "" {
		return errors.New("CLOUD_RUN_SERVICE_NAME environment variable not set")
	}

	// Construct the image tag
	tagname, err := getImageTag(
		projectID,
		serviceName,
		"backend",
		fmt.Sprintf("v%s", ver),
	)
	if err != nil {
		return errors.Wrap(err, "failed to get image tag")
	}

	// Deploy to Cloud Run
	err = cmd.Run(ctx, cmd.WithCMD(
		"gcloud", "run", "deploy", serviceName,
		"--image", tagname,
		"--platform", "managed",
		"--region", region,
		"--project", projectID,
		"--allow-unauthenticated",
	))
	if err != nil {
		return errors.Wrap(err, "failed to deploy to cloud run")
	}

	return nil
}

func releaseFrontend(ctx context.Context) error {
	// if firebase is not installed, error out
	err := cmd.Run(ctx, cmd.WithCMD("firebase", "--version"), cmd.WithSilent())
	if err != nil {
		return errors.Wrap(err, "firebase is not installed. Run `mage install frontend` to install it")
	}

	zap.S().Info("Deploying frontend to Firebase hosting...")

	err = cmd.Run(ctx,
		cmd.WithDir("web"),
		cmd.WithCMD(
			"firebase",
			"deploy",
			"--only", "hosting",
		),
	)
	if err != nil {
		return errors.Wrap(err, "failed to deploy to firebase")
	}

	return nil
}