feat: CLI interface created with clir
This commit is contained in:
parent
dd473a9808
commit
ed6afb94a1
11 changed files with 478 additions and 135 deletions
139
cmd/helix/main.go
Normal file
139
cmd/helix/main.go
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"gitlab.com/dananglin/forge-platform/internal/config"
|
||||||
|
"gitlab.com/dananglin/forge-platform/internal/stacks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := run(); err != nil {
|
||||||
|
fmt.Printf("ERROR: %v.\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() error {
|
||||||
|
helix := clir.NewCli("helix", "A CLI tool for managing your forge platform.", "v0.0.1")
|
||||||
|
helix.LongDescription(`Helix is a command line tool used to help manage your forge platform.
|
||||||
|
This uses the Pulumi Automation API library to create and manage different components
|
||||||
|
that builds your forge platform on a Linode instance.`)
|
||||||
|
|
||||||
|
versionCmd := helix.NewSubCommand("version", "Print the version of this application.")
|
||||||
|
versionCmd.Action(versionFunc(helix.Version()))
|
||||||
|
|
||||||
|
var file string
|
||||||
|
var stack string
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
updateCmd := helix.NewSubCommand("update", "Update a stack.")
|
||||||
|
updateCmd.Action(updateFunc(ctx, &file, &stack))
|
||||||
|
updateCmd.StringFlag("file", "the path to the configuration file", &file)
|
||||||
|
updateCmd.StringFlag("stack", "the name of the stack", &stack)
|
||||||
|
|
||||||
|
previewCmd := helix.NewSubCommand("preview", "Preview upcoming changes to a stack.")
|
||||||
|
previewCmd.Action(previewFunc(ctx, &file, &stack))
|
||||||
|
previewCmd.StringFlag("file", "the path to the configuration file", &file)
|
||||||
|
previewCmd.StringFlag("stack", "the name of the stack", &stack)
|
||||||
|
|
||||||
|
destroyCmd := helix.NewSubCommand("destroy", "Destroy a stack.")
|
||||||
|
destroyCmd.Action(destroyFunc(ctx, &file, &stack))
|
||||||
|
destroyCmd.StringFlag("file", "the path to the configuration file", &file)
|
||||||
|
destroyCmd.StringFlag("stack", "the name of the stack", &stack)
|
||||||
|
|
||||||
|
helix.DefaultCommand(versionCmd)
|
||||||
|
|
||||||
|
return helix.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func versionFunc(version string) clir.Action {
|
||||||
|
return func() error {
|
||||||
|
fmt.Printf("helix version %s\n", version)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func previewFunc(ctx context.Context, file, stack *string) clir.Action {
|
||||||
|
flagMap := map[string]*string{
|
||||||
|
"file": file,
|
||||||
|
"stack": stack,
|
||||||
|
}
|
||||||
|
|
||||||
|
return func() error {
|
||||||
|
if err := checkFlags(flagMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := config.NewConfig(*flagMap["file"])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to get configuration...\n%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
previewer, err := stacks.NewPreviewer(ctx, c.ProjectName, *stack, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := previewer.Preview(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateFunc(ctx context.Context, file, stack *string) clir.Action {
|
||||||
|
flagMap := map[string]*string{
|
||||||
|
"file": file,
|
||||||
|
"stack": stack,
|
||||||
|
}
|
||||||
|
|
||||||
|
return func() error {
|
||||||
|
if err := checkFlags(flagMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse json configuration (config package)
|
||||||
|
// create the updater (interface in stacks) (all logic in stacks)
|
||||||
|
// run the previewer
|
||||||
|
// return
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func destroyFunc(ctx context.Context, file, stack *string) clir.Action {
|
||||||
|
flagMap := map[string]*string{
|
||||||
|
"file": file,
|
||||||
|
"stack": stack,
|
||||||
|
}
|
||||||
|
|
||||||
|
return func() error {
|
||||||
|
if err := checkFlags(flagMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse json configuration (config package)
|
||||||
|
// create the destroyer (interface in stacks) (all logic in stacks)
|
||||||
|
// run the previewer
|
||||||
|
// return
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFlags(f map[string]*string) error {
|
||||||
|
for k, v := range f {
|
||||||
|
if len(*v) == 0 {
|
||||||
|
return fmt.Errorf("the value for the '%s' flag is not set", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module gitlab.com/dananglin/forge-platform
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/leaanthony/clir v1.0.4
|
||||||
github.com/pulumi/pulumi-docker/sdk/v3 v3.0.0
|
github.com/pulumi/pulumi-docker/sdk/v3 v3.0.0
|
||||||
github.com/pulumi/pulumi/sdk/v3 v3.4.0
|
github.com/pulumi/pulumi/sdk/v3 v3.4.0
|
||||||
)
|
)
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -123,6 +123,8 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
|
||||||
|
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||||
|
|
40
internal/config/config.go
Normal file
40
internal/config/config.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
ProjectName string `json:"project"`
|
||||||
|
Docker DockerConfig `json:"docker"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DockerConfig struct {
|
||||||
|
Network DockerNetworkConfig `json:"network"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DockerNetworkStackArgs contains arguments for
|
||||||
|
// creating the DockerNetworkStack
|
||||||
|
type DockerNetworkConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Subnet string `json:"subnet"`
|
||||||
|
Driver string `json:"driver"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfig(file string) (Config, error) {
|
||||||
|
var c Config
|
||||||
|
var err error
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return c, fmt.Errorf("unable to read data from %s...\n%v", file, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(data, &c); err != nil {
|
||||||
|
return c, fmt.Errorf("unable to decode the JSON configuration from %s...\n%v", file, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
86
internal/stacks/docker_network.go
Normal file
86
internal/stacks/docker_network.go
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package stacks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/auto"
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/auto/optdestroy"
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/auto/optpreview"
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/auto/optup"
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
||||||
|
"gitlab.com/dananglin/forge-platform/internal/config"
|
||||||
|
"gitlab.com/dananglin/forge-platform/internal/docker"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DockerNetworkStack is a stack for
|
||||||
|
// managing the Docker network.
|
||||||
|
type DockerNetworkStack struct {
|
||||||
|
Name string
|
||||||
|
Stack auto.Stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// newDockerNetworkStack creates a new DockerNetworkStack value.
|
||||||
|
func newDockerNetworkStack(ctx context.Context, project, stack string, args config.DockerNetworkConfig) (*DockerNetworkStack, error) {
|
||||||
|
|
||||||
|
deployFunc := deployDockerNetworkStack(args.Name, args.Subnet, args.Driver)
|
||||||
|
|
||||||
|
s, err := createOrSelectStack(ctx, project, stack, deployFunc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to initialise the '%s' stack...\n%w", stack, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
n := DockerNetworkStack{
|
||||||
|
Name: stack,
|
||||||
|
Stack: s,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DockerNetworkStack) Preview(ctx context.Context) error {
|
||||||
|
stdoutStreamer := optpreview.ProgressStreams(os.Stdout)
|
||||||
|
_, err := d.Stack.Preview(ctx, stdoutStreamer)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to preview the '%s' stack...\n%w", d.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DockerNetworkStack) Update(ctx context.Context) error {
|
||||||
|
stdoutStreamer := optup.ProgressStreams(os.Stdout)
|
||||||
|
_, err := d.Stack.Up(ctx, stdoutStreamer)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to update the '%s' stack...\n%w", d.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DockerNetworkStack) Destroy(ctx context.Context) error {
|
||||||
|
stdoutStreamer := optdestroy.ProgressStreams(os.Stdout)
|
||||||
|
_, err := d.Stack.Destroy(ctx, stdoutStreamer)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to destroy the '%s' stack...\n%w", d.Name, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeployDockerNetworkStack returns a Pulumi run function
|
||||||
|
// that deploys the Docker network stack.
|
||||||
|
func deployDockerNetworkStack(name, subnet, driver string) pulumi.RunFunc {
|
||||||
|
return func(ctx *pulumi.Context) error {
|
||||||
|
config := docker.DockerNetworkConfig{
|
||||||
|
Name: pulumi.String(name),
|
||||||
|
Subnet: pulumi.String(subnet),
|
||||||
|
Driver: pulumi.String(driver),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := docker.CreateNetwork(ctx, config); err != nil {
|
||||||
|
return fmt.Errorf("unable to complete the deployment...\n%w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
103
internal/stacks/manage.go
Normal file
103
internal/stacks/manage.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package stacks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/auto"
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
||||||
|
|
||||||
|
"gitlab.com/dananglin/forge-platform/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
dockerNetworkStackName string = "docker_network"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Previewer interface {
|
||||||
|
Preview(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Updater interface {
|
||||||
|
Update(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Destroyer interface {
|
||||||
|
Destroy(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func createOrSelectStack(ctx context.Context, projectName, stackName string, deployFunc pulumi.RunFunc) (auto.Stack, error) {
|
||||||
|
var s auto.Stack
|
||||||
|
|
||||||
|
opts, err := workspaceOptions(projectName, stackName)
|
||||||
|
if err != nil {
|
||||||
|
return s, fmt.Errorf("unable to create the workspace options...\n%w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Creating/selecting stack (%s)...\n", stackName)
|
||||||
|
s, err = auto.UpsertStackInlineSource(ctx, stackName, projectName, deployFunc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return s, fmt.Errorf("unable to create/select the stack...\n%w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Refreshing stack (%s)...\n", stackName)
|
||||||
|
_, err = s.Refresh(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return s, fmt.Errorf("unable to refresh the stack...\n%w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func workspaceOptions(projectName, stackName string) ([]auto.LocalWorkspaceOption, error) {
|
||||||
|
pulumiHome := auto.PulumiHome(filepath.Join(os.Getenv("HOME"), ".pulumi"))
|
||||||
|
|
||||||
|
wd := filepath.Join(os.Getenv("HOME"), "Pulumi", "projects", projectName, "workspaces", stackName)
|
||||||
|
|
||||||
|
fmt.Printf("Ensuring that %s exists...\n", wd)
|
||||||
|
if err := os.MkdirAll(wd, 0750); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to ensure that the directory exists...\n%w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
workDir := auto.WorkDir(wd)
|
||||||
|
|
||||||
|
secretsProvider := auto.SecretsProvider("passphrase")
|
||||||
|
|
||||||
|
backend := filepath.Join(os.Getenv("HOME"), "Pulumi", "projects", projectName, "stacks")
|
||||||
|
if err := os.MkdirAll(backend, 0750); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create the backend directory...\n%w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
project := auto.Project(workspace.Project{
|
||||||
|
Name: tokens.PackageName(projectName),
|
||||||
|
Runtime: workspace.NewProjectRuntimeInfo("go", nil),
|
||||||
|
Backend: &workspace.ProjectBackend{
|
||||||
|
URL: fmt.Sprintf("file://%s", backend),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
opts := []auto.LocalWorkspaceOption{pulumiHome, secretsProvider, project, workDir}
|
||||||
|
|
||||||
|
return opts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPreviewer(ctx context.Context, project, stack string, c config.Config) (Previewer, error) {
|
||||||
|
var p Previewer
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch stack {
|
||||||
|
case dockerNetworkStackName:
|
||||||
|
p, err = newDockerNetworkStack(ctx, project, stack, c.Docker.Network)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to initialise '%s' stack...\n%v", stack, err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown stack name '%s'", stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
package network
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
|
||||||
"gitlab.com/dananglin/forge-platform/internal/docker"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DeployDockerNetworkStack returns a Pulumi run function
|
|
||||||
// that deploys the Docker network stack.
|
|
||||||
func DeployDockerNetworkStack(name, subnet, driver string) pulumi.RunFunc {
|
|
||||||
return func(ctx *pulumi.Context) error {
|
|
||||||
config := docker.DockerNetworkConfig{
|
|
||||||
Name: pulumi.String(name),
|
|
||||||
Subnet: pulumi.String(subnet),
|
|
||||||
Driver: pulumi.String(driver),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := docker.CreateNetwork(ctx, config); err != nil {
|
|
||||||
return fmt.Errorf("unable to deploy the Docker Network Stack...\n%w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
package network
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/pulumi/pulumi/sdk/v3/go/auto"
|
|
||||||
"github.com/pulumi/pulumi/sdk/v3/go/auto/optdestroy"
|
|
||||||
"github.com/pulumi/pulumi/sdk/v3/go/auto/optpreview"
|
|
||||||
"github.com/pulumi/pulumi/sdk/v3/go/auto/optup"
|
|
||||||
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
actionPreview string = "preview"
|
|
||||||
actionUpdate string = "update"
|
|
||||||
actionDestroy string = "destroy"
|
|
||||||
|
|
||||||
stack string = "dockerNetwork"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DockerNetworkStackArgs contains arguments for
|
|
||||||
// creating the DockerNetworkStack
|
|
||||||
type DockerNetworkStackArgs struct {
|
|
||||||
NetworkName string
|
|
||||||
Subnet string
|
|
||||||
NetworkDriver string
|
|
||||||
}
|
|
||||||
|
|
||||||
// DockerNetworkStack is a stack for
|
|
||||||
// managing the Docker network.
|
|
||||||
type DockerNetworkStack struct {
|
|
||||||
Name string
|
|
||||||
Stack auto.Stack
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDockerNetworkStack creates a new DockerNetworkStack value.
|
|
||||||
func NewDockerNetworkStack(ctx context.Context, project string, args DockerNetworkStackArgs, opts ...auto.LocalWorkspaceOption) (*DockerNetworkStack, error) {
|
|
||||||
|
|
||||||
deployFunc := DeployDockerNetworkStack(args.NetworkName, args.Subnet, args.NetworkDriver)
|
|
||||||
|
|
||||||
s, err := createOrSelectStack(ctx, project, stack, deployFunc, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to initialise stack (%s)...\n%w", stack, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n := DockerNetworkStack{
|
|
||||||
Name: stack,
|
|
||||||
Stack: s,
|
|
||||||
}
|
|
||||||
|
|
||||||
return &n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process performs an action on the DockerNetworkStack.
|
|
||||||
func (n *DockerNetworkStack) Process(ctx context.Context, action string) error {
|
|
||||||
switch action {
|
|
||||||
case actionPreview:
|
|
||||||
stdoutStreamer := optpreview.ProgressStreams(os.Stdout)
|
|
||||||
_, err := n.Stack.Preview(ctx, stdoutStreamer)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to preview the stack...\n%w", err)
|
|
||||||
}
|
|
||||||
case actionUpdate:
|
|
||||||
stdoutStreamer := optup.ProgressStreams(os.Stdout)
|
|
||||||
_, err := n.Stack.Up(ctx, stdoutStreamer)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to update the stack...\n%w", err)
|
|
||||||
}
|
|
||||||
case actionDestroy:
|
|
||||||
stdoutStreamer := optdestroy.ProgressStreams(os.Stdout)
|
|
||||||
_, err := n.Stack.Destroy(ctx, stdoutStreamer)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to destroy the stack...\n%w", err)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown action '%s'", action)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createOrSelectStack(ctx context.Context, project, stack string, deployFunc pulumi.RunFunc, opts ...auto.LocalWorkspaceOption) (auto.Stack, error) {
|
|
||||||
wd := filepath.Join(os.Getenv("HOME"), "Pulumi", "projects", project, "workspaces", stack)
|
|
||||||
|
|
||||||
fmt.Printf("INFO: Ensuring that %s exists...\n", wd)
|
|
||||||
if err := os.MkdirAll(wd, 0750); err != nil {
|
|
||||||
return auto.Stack{}, fmt.Errorf("unable to ensure that the directory exists...\n%w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
workDir := auto.WorkDir(wd)
|
|
||||||
|
|
||||||
opts = append(opts, workDir)
|
|
||||||
|
|
||||||
fmt.Printf("INFO: Creating/selecting stack (%s)...\n", stack)
|
|
||||||
s, err := auto.UpsertStackInlineSource(ctx, stack, project, deployFunc, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return auto.Stack{}, fmt.Errorf("unable to create/select the stack...\n%w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("INFO: Refreshing stack (%s)...\n", stack)
|
|
||||||
_, err = s.Refresh(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return auto.Stack{}, fmt.Errorf("unable to refresh the stack...\n%w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
15
internal/stacks/templates/gitea/Dockerfile.tmpl
Normal file
15
internal/stacks/templates/gitea/Dockerfile.tmpl
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{{/* vim: set ft=dockerfile : */}}
|
||||||
|
|
||||||
|
ARG GITEA_VERSION={{ .Version }}
|
||||||
|
|
||||||
|
FROM gitea/gitea:${GITEA_VERSION}
|
||||||
|
|
||||||
|
ENV USER_UID=1000 \
|
||||||
|
USER_GID=1000 \
|
||||||
|
GITEA_CUSTOM=/helix/gitea/custom
|
||||||
|
|
||||||
|
ADD files app.ini /helix/gitea/custom/app.ini
|
||||||
|
|
||||||
|
RUN chown -R ${USER_ID}:${USER_GID} /helix
|
||||||
|
|
||||||
|
EXPOSE {{ .App.HttpPort }} {{ .App.SshPort }}
|
92
internal/stacks/templates/gitea/app.ini.tmpl
Normal file
92
internal/stacks/templates/gitea/app.ini.tmpl
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
{{/* vim: set ft=dosini : */}}
|
||||||
|
APP_NAME = {{ .App.Name }}
|
||||||
|
RUN_MODE = {{ .App.RunMode }}
|
||||||
|
|
||||||
|
[repository]
|
||||||
|
ROOT = /data/gitea/repositories
|
||||||
|
DEFAULT_BRANCH = main
|
||||||
|
|
||||||
|
[repository.local]
|
||||||
|
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
|
||||||
|
|
||||||
|
[repository.upload]
|
||||||
|
TEMP_PATH = /data/gitea/uploads
|
||||||
|
|
||||||
|
[repository.signing]
|
||||||
|
; Gitea will sign initial commits only if the user has a public key.
|
||||||
|
INITIAL_COMMIT = pubkey
|
||||||
|
|
||||||
|
[ui]
|
||||||
|
DEFAULT_THEME = arc-green
|
||||||
|
|
||||||
|
[server]
|
||||||
|
APP_DATA_PATH = /data/gitea
|
||||||
|
DOMAIN = {{ .App.Domain }}
|
||||||
|
HTTP_ADDR = {{ .Container.Ip }}
|
||||||
|
HTTP_PORT = {{ .App.HttpPort }}
|
||||||
|
ROOT_URL = {{ .App.RootUrl }}
|
||||||
|
DISABLE_SSH = false
|
||||||
|
SSH_DOMAIN = {{ .App.SshDomain }}
|
||||||
|
SSH_PORT = {{ .App.SshPort }}
|
||||||
|
SSH_LISTEN_PORT = {{ .App.SshPort }}
|
||||||
|
LFS_START_SERVER = false
|
||||||
|
LFS_CONTENT_PATH = /data/gitea/lfs
|
||||||
|
|
||||||
|
[ssh.minimum_key_sizes]
|
||||||
|
ED25519 = 256
|
||||||
|
ECDSA = 256
|
||||||
|
RSA = 4096
|
||||||
|
DSA = -1
|
||||||
|
|
||||||
|
[database]
|
||||||
|
DB_TYPE = sqlite3
|
||||||
|
PATH = /data/gitea/database/gitea.db
|
||||||
|
|
||||||
|
[indexer]
|
||||||
|
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
|
||||||
|
|
||||||
|
[session]
|
||||||
|
PROVIDER_CONFIG = /data/gitea/sessions
|
||||||
|
|
||||||
|
[queue]
|
||||||
|
DATADIR = /data/gitea/queues
|
||||||
|
|
||||||
|
[admin]
|
||||||
|
DISABLE_REGULAR_ORG_CREATION = true
|
||||||
|
DEFAULT_EMAIL_NOTIFICATION = disabled
|
||||||
|
|
||||||
|
[security]
|
||||||
|
INSTALL_LOCK = true
|
||||||
|
SECRET_KEY = {{ .App.SecretKey }}
|
||||||
|
LOGIN_REMEMBER_DAYS = 1
|
||||||
|
MIN_PASSWORD_LENGTH = 12
|
||||||
|
PASSWORD_COMPLEXITY = lower,upper,digit
|
||||||
|
|
||||||
|
[service]
|
||||||
|
DISABLED_REGISTRATION = true
|
||||||
|
REQUIRE_SIGNIN_VIEW = false
|
||||||
|
|
||||||
|
[picture]
|
||||||
|
AVATAR_UPLOAD_PATH = /data/gitea/avatars
|
||||||
|
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
|
||||||
|
|
||||||
|
[attachment]
|
||||||
|
ENABLED = true
|
||||||
|
PATH = /data/gitea/attachments
|
||||||
|
|
||||||
|
[log]
|
||||||
|
ROOT_PATH = /data/gitea/log
|
||||||
|
MODE = console
|
||||||
|
LEVEL = {{ .App.LogLevel }}
|
||||||
|
|
||||||
|
[log.console]
|
||||||
|
STDERR = false
|
||||||
|
|
||||||
|
[i18n]
|
||||||
|
LANGS = en-US
|
||||||
|
NAMES = English
|
||||||
|
|
||||||
|
[other]
|
||||||
|
SHOW_FOOTER_BRANDING = true
|
||||||
|
SHOW_FOOTER_VERSION = false
|
||||||
|
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false
|
Reference in a new issue