Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Starts comprehension #4

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,18 @@ Once this is done, we copy all the files from the scaffold directory into the ta

If there is a `.lagoon/post-message.txt` file, this is shown to the user.

Finally, the temporary directory with the scaffolding is removed.
Finally, the temporary directory with the scaffolding is removed.

## Values from exiting files

When doing something like importing from an existing project, we might sometimes need to read values from existing files.

This is achieved using the `valueFiles` section in the flow file.
We support `.env`, `.json`, and `.yml` files for the moment.

If you list a particular file name in the `valueFiles` section, we will attempt to read the file and parse it as the appropriate type.
These values will then be available to the template files when they're hydrated.

### example

```
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ require (
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
Expand Down
5 changes: 5 additions & 0 deletions internal/assets/comprehension_tests/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
10 changes: 10 additions & 0 deletions internal/assets/comprehension_tests/comprehension_test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "laravel/laravel",
"type": "project",
"keywords": ["framework", "testing"],
"require": {
"php": "^8.1"
},
"minimum-stability": "stable",
"prefer-stable": true
}
10 changes: 10 additions & 0 deletions internal/assets/comprehension_tests/comprehension_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
docker-compose-yaml: docker-compose.yml
project: "lagoon-sync"
lagoon-sync:
ssh:
host: "example.ssh"
port: "22"
verbose: true
mariadb:
config:
hostname: "${MARIADB_HOST:-mariadb}"
71 changes: 70 additions & 1 deletion internal/valgen.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package internal

import (
"encoding/json"
"errors"
"fmt"
"github.com/AlecAivazis/survey/v2"
"github.com/joho/godotenv"
"gopkg.in/yaml.v2"
"log"
"os"
"path/filepath"
)

type surveyQuestion struct {
Expand All @@ -18,8 +23,20 @@ type surveyQuestion struct {
Questions []surveyQuestion `yaml:"questions,omitempty"`
}

type valueFileValue struct {
Name string `yaml:"name"`
Path string `yaml:"path"` //this is going to depend on the type - but let's assume it's grandparent.parent.child
Default string `yaml:"default"` // The default if the value can't be found
}

type valueFile struct {
Name string `yaml:"name"`
Values []valueFileValue `yaml:"values"`
}

type surveyQuestionsFile struct {
Questions []surveyQuestion `yaml:"questions"`
Questions []surveyQuestion `yaml:"questions"`
ValueFiles []valueFile `yaml:"valueFiles"` // This is a list of files we can potentially source values from
}

func UnmarshallSurveyQuestions(incoming []byte) ([]surveyQuestion, error) {
Expand All @@ -32,6 +49,58 @@ func UnmarshallSurveyQuestions(incoming []byte) ([]surveyQuestion, error) {
return incomingMap.Questions, nil
}

func loadValuesFromValuesFiles(files []string) (map[string]interface{}, error) {
vals := make(map[string]interface{})
for _, file := range files {
f, err := os.Stat(file)
if err != nil {
//this might be okay, just log it
log.Default().Printf("Unable to find file `%v`", file)
}
extension := filepath.Ext(f.Name())
switch extension {
case ".env":
myEnv, err := godotenv.Read(file)
if err != nil {
log.Default().Printf("Unable to read env file `%v`", file)
continue
}
vals[f.Name()] = myEnv
case ".json":
fileData, err := os.ReadFile(file)
if err != nil {
log.Default().Printf("Unable to read json file `%v`", file)
continue
}
var v interface{}
err = json.Unmarshal(fileData, &v)
if err != nil {
log.Default().Printf("Unable to unmarshal json file `%v`", file)
continue
}
vals[f.Name()] = v
case ".yml":
fallthrough
case ".yaml":
fileData, err := os.ReadFile(file)
if err != nil {
log.Default().Printf("Unable to read yaml file `%v`", file)
continue
}
var v interface{}
err = yaml.Unmarshal(fileData, &v)
if err != nil {
log.Default().Printf("Unable to unmarshal json file `%v`", file)
continue
}
vals[f.Name()] = v
default:
return nil, errors.New(fmt.Sprintf("Unsupported file comprehension for `%v`", file))
}
}
return vals, nil
}

func RunFromSurveyQuestions(questions []surveyQuestion, interactive bool) (interface{}, error) {
vals := make(map[string]interface{})
for _, question := range questions {
Expand Down
85 changes: 85 additions & 0 deletions internal/valgen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,88 @@ func Test_runFromSurveyQuestions(t *testing.T) {
})
}
}

func Test_loadValuesFromValuesFiles(t *testing.T) {
type args struct {
files []string
}
tests := []struct {
name string
args args
want map[string]interface{}
wantErr bool
}{
{
name: "Test env file",
args: args{
files: []string{"assets/comprehension_tests/.env"},
},
want: map[string]interface{}{
".env": map[string]string{
"APP_NAME": "Laravel",
"APP_ENV": "local",
"APP_KEY": "",
"APP_DEBUG": "true",
"APP_URL": "http://localhost",
},
},
wantErr: false,
},
{
name: "Test json file",
args: args{
files: []string{"assets/comprehension_tests/comprehension_test.json"},
},
want: map[string]interface{}{
"comprehension_test.json": map[string]interface{}{
"name": "laravel/laravel",
"type": "project",
"keywords": []interface{}{"framework", "testing"},
"require": map[string]interface{}{
"php": "^8.1",
},
"minimum-stability": "stable",
"prefer-stable": true,
},
},
wantErr: false,
},
{
name: "Test yaml file",
args: args{
files: []string{"assets/comprehension_tests/comprehension_test.yml"},
},
want: map[string]interface{}{
"comprehension_test.yml": map[interface{}]interface{}{
"docker-compose-yaml": "docker-compose.yml",
"project": "lagoon-sync",
"lagoon-sync": map[interface{}]interface{}{
"ssh": map[interface{}]interface{}{
"host": "example.ssh",
"port": "22",
"verbose": true,
},
"mariadb": map[interface{}]interface{}{
"config": map[interface{}]interface{}{
"hostname": "${MARIADB_HOST:-mariadb}",
},
},
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := loadValuesFromValuesFiles(tt.args.files)
if (err != nil) != tt.wantErr {
t.Errorf("loadValuesFromValuesFiles() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("loadValuesFromValuesFiles() got = %v, want %v", got, tt.want)
}
})
}
}