fix: ensure env vars are copied over when cloning or renaming an app

This commit is contained in:
Jose Diaz-Gonzalez
2024-03-14 00:25:25 -04:00
parent 883809f35e
commit e0409caf75
5 changed files with 80 additions and 31 deletions

View File

@@ -4,3 +4,4 @@
/triggers
/config-*
/config_sub
/post-*

View File

@@ -1,6 +1,6 @@
GOARCH ?= amd64
SUBCOMMANDS = subcommands/bundle subcommands/clear subcommands/export subcommands/get subcommands/keys subcommands/show subcommands/set subcommands/unset
TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global
TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global triggers/post-app-clone-setup triggers/post-app-rename-setup
BUILD = commands config_sub subcommands triggers
PLUGIN_NAME = config

View File

@@ -16,7 +16,7 @@ import (
"github.com/ryanuber/columnize"
)
//ExportFormat types of possible exports
// ExportFormat types of possible exports
type ExportFormat int
const (
@@ -40,14 +40,14 @@ const (
ExportFormatPackArgKeys
)
//Env is a representation for global or app environment
// Env is a representation for global or app environment
type Env struct {
name string
filename string
env map[string]string
}
//newEnvFromString creates an env from the given ENVFILE contents representation
// newEnvFromString creates an env from the given ENVFILE contents representation
func newEnvFromString(rep string) (env *Env, err error) {
envMap, err := godotenv.Unmarshal(rep)
env = &Env{
@@ -58,7 +58,7 @@ func newEnvFromString(rep string) (env *Env, err error) {
return
}
//LoadAppEnv loads an environment for the given app
// LoadAppEnv loads an environment for the given app
func LoadAppEnv(appName string) (env *Env, err error) {
appfile, err := getAppFile(appName)
if err != nil {
@@ -67,7 +67,7 @@ func LoadAppEnv(appName string) (env *Env, err error) {
return loadFromFile(appName, appfile)
}
//LoadMergedAppEnv loads an app environment merged with the global environment
// LoadMergedAppEnv loads an app environment merged with the global environment
func LoadMergedAppEnv(appName string) (env *Env, err error) {
env, err = LoadAppEnv(appName)
if err != nil {
@@ -83,7 +83,7 @@ func LoadMergedAppEnv(appName string) (env *Env, err error) {
return global, err
}
//LoadGlobalEnv loads the global environment
// LoadGlobalEnv loads the global environment
func LoadGlobalEnv() (*Env, error) {
return loadFromFile("<global>", getGlobalFile())
}
@@ -93,13 +93,13 @@ func (e *Env) Filename() string {
return e.filename
}
//Get an environment variable
// Get an environment variable
func (e *Env) Get(key string) (value string, ok bool) {
value, ok = e.env[key]
return
}
//GetDefault an environment variable or a default if it doesn't exist
// GetDefault an environment variable or a default if it doesn't exist
func (e *Env) GetDefault(key string, defaultValue string) string {
v, ok := e.env[key]
if !ok {
@@ -108,8 +108,8 @@ func (e *Env) GetDefault(key string, defaultValue string) string {
return v
}
//GetBoolDefault gets the bool value of the given key with the given default
//right now that is evaluated as `value != "0"`
// GetBoolDefault gets the bool value of the given key with the given default
// right now that is evaluated as `value != "0"`
func (e *Env) GetBoolDefault(key string, defaultValue bool) bool {
v, ok := e.Get(key)
if !ok {
@@ -118,17 +118,17 @@ func (e *Env) GetBoolDefault(key string, defaultValue bool) bool {
return v != "0"
}
//Set an environment variable
// Set an environment variable
func (e *Env) Set(key string, value string) {
e.env[key] = value
}
//Unset an environment variable
// Unset an environment variable
func (e *Env) Unset(key string) {
delete(e.env, key)
}
//Keys gets the keys in this environment
// Keys gets the keys in this environment
func (e *Env) Keys() (keys []string) {
keys = make([]string, 0, len(e.env))
for k := range e.env {
@@ -138,12 +138,12 @@ func (e *Env) Keys() (keys []string) {
return
}
//Len returns the number of items in this environment
// Len returns the number of items in this environment
func (e *Env) Len() int {
return len(e.env)
}
//Map returns the Env as a map
// Map returns the Env as a map
func (e *Env) Map() map[string]string {
return e.env
}
@@ -152,14 +152,14 @@ func (e *Env) String() string {
return e.EnvfileString()
}
//Merge merges the given environment on top of the receiver
// Merge merges the given environment on top of the receiver
func (e *Env) Merge(other *Env) {
for _, k := range other.Keys() {
e.Set(k, other.GetDefault(k, ""))
}
}
//Write an Env back to the file it was read from as an exportfile
// Write an Env back to the file it was read from as an exportfile
func (e *Env) Write() error {
if e.filename == "" {
return errors.New("this Env was created unbound to a file")
@@ -167,7 +167,7 @@ func (e *Env) Write() error {
return godotenv.Write(e.Map(), e.filename)
}
//Export the Env in the given format
// Export the Env in the given format
func (e *Env) Export(format ExportFormat) string {
switch format {
case ExportFormatExports:
@@ -194,23 +194,23 @@ func (e *Env) Export(format ExportFormat) string {
}
}
//EnvfileString returns the contents of this Env in dotenv format
// EnvfileString returns the contents of this Env in dotenv format
func (e *Env) EnvfileString() string {
rep, _ := godotenv.Marshal(e.Map())
return rep
}
//ExportfileString returns the contents of this Env as bash exports
// ExportfileString returns the contents of this Env as bash exports
func (e *Env) ExportfileString() string {
return e.stringWithPrefixAndSeparator("export ", "\n")
}
//DockerArgsString gets the contents of this Env in the form -env=KEY=VALUE --env...
// DockerArgsString gets the contents of this Env in the form -env=KEY=VALUE --env...
func (e *Env) DockerArgsString() string {
return e.stringWithPrefixAndSeparator("--env=", " ")
}
//DockerArgsKeysString gets the contents of this Env in the form -env=KEY --env...
// DockerArgsKeysString gets the contents of this Env in the form -env=KEY --env...
func (e *Env) DockerArgsKeysString() string {
keys := e.Keys()
entries := make([]string, len(keys))
@@ -220,7 +220,7 @@ func (e *Env) DockerArgsKeysString() string {
return strings.Join(entries, " ")
}
//JSONString returns the contents of this Env as a key/value json object
// JSONString returns the contents of this Env as a key/value json object
func (e *Env) JSONString() string {
data, err := json.Marshal(e.Map())
if err != nil {
@@ -230,7 +230,7 @@ func (e *Env) JSONString() string {
return string(data)
}
//JSONListString returns the contents of this Env as a json list of objects containing the name and the value of the env var
// JSONListString returns the contents of this Env as a json list of objects containing the name and the value of the env var
func (e *Env) JSONListString() string {
var list []map[string]string
for _, key := range e.Keys() {
@@ -249,7 +249,7 @@ func (e *Env) JSONListString() string {
return string(data)
}
//PackArgKeysAsString gets the contents of this Env in the form -env KEY --env...
// PackArgKeysAsString gets the contents of this Env in the form -env KEY --env...
func (e *Env) PackArgKeysAsString() string {
keys := e.Keys()
entries := make([]string, len(keys))
@@ -259,13 +259,13 @@ func (e *Env) PackArgKeysAsString() string {
return strings.Join(entries, " ")
}
//ShellString gets the contents of this Env in the form "KEY='value' KEY2='value'"
// ShellString gets the contents of this Env in the form "KEY='value' KEY2='value'"
// for passing the environment in the shell
func (e *Env) ShellString() string {
return e.stringWithPrefixAndSeparator("", " ")
}
//ExportBundle writes a tarfile of the environment to the given io.Writer.
// ExportBundle writes a tarfile of the environment to the given io.Writer.
// for every environment variable there is a file with the variable's key
// with its content set to the variable's value
func (e *Env) ExportBundle(dest io.Writer) error {
@@ -287,7 +287,7 @@ func (e *Env) ExportBundle(dest io.Writer) error {
return nil
}
//stringWithPrefixAndSeparator makes a string of the environment
// stringWithPrefixAndSeparator makes a string of the environment
// with the given prefix and separator for each entry
func (e *Env) stringWithPrefixAndSeparator(prefix string, separator string) string {
keys := e.Keys()
@@ -299,12 +299,12 @@ func (e *Env) stringWithPrefixAndSeparator(prefix string, separator string) stri
return strings.Join(entries, separator)
}
//singleQuoteEscape escapes the value as if it were shell-quoted in single quotes
// singleQuoteEscape escapes the value as if it were shell-quoted in single quotes
func singleQuoteEscape(value string) string { // so that 'esc'aped' -> 'esc'\''aped'
return strings.Replace(value, "'", "'\\''", -1)
}
//prettyPrintEnvEntries in columns
// prettyPrintEnvEntries in columns
func prettyPrintEnvEntries(prefix string, entries map[string]string) string {
colConfig := columnize.DefaultConfig()
colConfig.Prefix = prefix

View File

@@ -36,6 +36,14 @@ func main() {
case "config-get-global":
key := flag.Arg(0)
err = config.TriggerConfigGetGlobal(key)
case "post-app-clone-setup":
oldAppName := flag.Arg(0)
newAppName := flag.Arg(1)
err = config.TriggerPostAppCloneSetup(oldAppName, newAppName)
case "post-app-rename-setup":
oldAppName := flag.Arg(0)
newAppName := flag.Arg(1)
err = config.TriggerPostAppRenameSetup(oldAppName, newAppName)
default:
err = fmt.Errorf("Invalid plugin trigger call: %s", trigger)
}

View File

@@ -44,3 +44,43 @@ func TriggerConfigGetGlobal(key string) error {
return nil
}
// TriggerPostAppCloneSetup creates new buildpacks files
func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error {
oldEnv, err := LoadAppEnv(oldAppName)
if err != nil {
return fmt.Errorf("Unable to load old environment: %s", err.Error())
}
newEnv, err := LoadAppEnv(newAppName)
if err != nil {
return fmt.Errorf("Unable to load new environment: %s", err.Error())
}
newEnv.Merge(oldEnv)
if err := newEnv.Write(); err != nil {
return fmt.Errorf("Unable to write new environment: %s", err.Error())
}
return nil
}
// TriggerPostAppRenameSetup renames buildpacks files
func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error {
oldEnv, err := LoadAppEnv(oldAppName)
if err != nil {
return fmt.Errorf("Unable to load old environment: %s", err.Error())
}
newEnv, err := LoadAppEnv(newAppName)
if err != nil {
return fmt.Errorf("Unable to load new environment: %s", err.Error())
}
newEnv.Merge(oldEnv)
if err := newEnv.Write(); err != nil {
return fmt.Errorf("Unable to write new environment: %s", err.Error())
}
return nil
}