-
Notifications
You must be signed in to change notification settings - Fork 6
/
dinghy.go
203 lines (175 loc) · 6.32 KB
/
dinghy.go
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package cmd
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/armory-io/arm/pkg"
"github.com/armory/dinghy/pkg/cache"
"github.com/armory/dinghy/pkg/dinghyfile"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"io/ioutil"
"os"
"path/filepath"
)
// dinghyCmd represents the dinghy command
var dinghyCmd = &cobra.Command{
Use: "dinghy",
Short: "Run dinghy subcommands",
}
var renderCmd = &cobra.Command{
Use: "render [dinghyfile]",
Short: "render a dinghyfile",
Run: func(cmd *cobra.Command, args []string) {
_, err := dinghyRender(args)
if err != nil {
os.Exit(1)
}
},
}
func processRawData(rawDataPath string) map[string]interface{} {
if rawDataPath != "" {
log.Info("Reading rawdata file")
rawData, err := ioutil.ReadFile(rawDataPath)
if err != nil {
log.Error("Invalid rawdata json file path")
} else {
log.Info("Parsing rawdata json")
rawPushData := make(map[string]interface{})
err = json.Unmarshal([]byte(rawData), &rawPushData)
if err != nil {
log.Error("Invalid rawData json file")
}
return rawPushData
}
}
return nil
}
func init() {
renderCmd.Flags().String("local_modules", "", "local path to the dinghy local_module repository, if not specified local_module will be base path from dinghyfile")
renderCmd.Flags().String("modules", "", "local path to the dinghy modules repository")
renderCmd.Flags().String("rawdata", "", "optional rawdata json in case is needed")
renderCmd.Flags().String("output", "", "output json rendered as it will be rendered by dinghy")
dinghyCmd.AddCommand(renderCmd)
rootCmd.AddCommand(dinghyCmd)
viper.BindPFlags(renderCmd.Flags())
}
func dinghyRender(args []string) (string, error) {
//Init log
log := initLog()
log.Info("Checking dinghyfile")
//Check that dinghyfile is entered
var file string
if len(args) > 0 {
file = args[0]
} else {
log.Error("No dinghy file was entered, please refer to documentation or execute this command with --help")
os.Exit(1)
}
//Get absolute path for dinghyfile
absFile, err := filepath.Abs(file)
if err != nil {
log.Errorf("Invalid path for dinghyfile: %v", err)
return "", fmt.Errorf("Invalid path for dinghyfile: %v", err)
}
//Separate directory path and filename
repoFolder := fmt.Sprint(filepath.Dir(absFile))
fileName := fmt.Sprint(filepath.Base(absFile))
//Downloader will have the original dinghyfile directory and the dinghyfile name so we can read the dinghyfile
//from the original location and then change it to the local_modules if some input parameter is there
downloader := pkg.LocalDownloader{
LocalModule: absFile,
RepoFolder: repoFolder,
DinghyfileName: fileName,
}
builder := &dinghyfile.PipelineBuilder{
Downloader: downloader,
Depman: cache.NewMemoryCache(),
TemplateRepo: viper.GetString("modules"),
TemplateOrg: "templateOrg",
Logger: log.WithField("arm-cli-test", ""),
Client: PlankMock{},
EventClient: &dinghyfile.EventsTestClient{},
Parser: &dinghyfile.DinghyfileParser{},
DinghyfileName: fileName,
Ums: []dinghyfile.Unmarshaller{&dinghyfile.DinghyJsonUnmarshaller{}},
}
//Process rawData and add it to the builder
builder.PushRaw = processRawData(viper.GetString("rawdata"))
log.Info("Parsing dinghyfile")
builder.Parser.SetBuilder(builder)
//If local_modules is entered we will change the repoFolder so all the files are read from that location
//The dinghyfile is the only file that will not be read from there, downloader already has the information from
//where to read
var localModulesPath = viper.GetString("local_modules")
if localModulesPath != "" {
absFile = filepath.Dir(localModulesPath) + string(filepath.Separator) + filepath.Base(file)
}
repoFolder = fmt.Sprint(filepath.Dir(absFile))
fileName = fmt.Sprint(filepath.Base(absFile))
//Parse dinghyfile
out, err := builder.Parser.Parse( "templateOrg", repoFolder, fileName, "", nil)
if err != nil {
log.Errorf("Parsing dinghyfile failed: %s", err )
return "", fmt.Errorf("Parsing dinghyfile failed: %s", err )
} else {
log.Info("Parsed dinghyfile")
if !json.Valid(out.Bytes()){
log.Info("Output:\n")
fmt.Println(out.String())
log.Error("The result is not a valid JSON Object, please fix your dinghyfile")
return "", errors.New(("The result is not a valid JSON Object, please fix your dinghyfile"))
} else {
log.Info("Parsing final dinghyfile to struct for validation")
d, err := dinghyfileStruct(builder, out)
if err != nil {
log.Errorf("Parsing to struct failed: %v", err)
return "", fmt.Errorf("Parsing to struct failed: %v", err)
}
errValidation := builder.ValidatePipelines(d, out.Bytes())
if errValidation != nil {
log.Errorf("Final Dinghyfile failed validations, please correct them and retry. %v", errValidation)
return "", fmt.Errorf("Final Dinghyfile failed validations, please correct them and retry. %v", errValidation)
}
errValidation = builder.ValidateAppNotifications(d, out.Bytes())
if errValidation != nil {
log.Errorf("Final Dinghyfile failed application notification validations, please correct them and retry. %v", errValidation)
return "", fmt.Errorf("Final Dinghyfile failed application notification validations, please correct them and retry. %v", errValidation)
}
//Save file if output exists
//Log output
var outIndent bytes.Buffer
json.Indent(&outIndent, out.Bytes(), "", " ")
saveOutputFile(viper.GetString("output"), outIndent)
log.Info("Output:\n")
fmt.Println(outIndent.String())
log.Info("Final dinghyfile is a valid JSON Object.")
return outIndent.String(), nil
}
}
}
func dinghyfileStruct(builder *dinghyfile.PipelineBuilder, out *bytes.Buffer) (dinghyfile.Dinghyfile, error) {
d := dinghyfile.NewDinghyfile()
parseErrs := 0
var err error
for _, ums := range builder.Ums {
log.Info("Parsing Dinghyfile to struct for validation")
if errmarshal := ums.Unmarshal(out.Bytes(), &d); errmarshal != nil {
err = errmarshal
log.Warnf("Cannot create Dinghyfile struct because of malformed syntax: %s", err.Error())
parseErrs++
continue
}
}
return d, err
}
func saveOutputFile(outputPath string, content bytes.Buffer) {
if outputPath != "" {
log.Info("Saving output file")
err := ioutil.WriteFile(outputPath, content.Bytes(), 0644)
if err != nil {
log.Error("Failed to save output file")
}
}
}