Skip to content

Commit 3c9c3b3

Browse files
authored
Merge pull request #248 from covexo/add-package
Add, Remove, List package
2 parents dc4d1ac + 3435296 commit 3c9c3b3

28 files changed

Lines changed: 830 additions & 90 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@
1515
# History Plugin for VS Code
1616
.history/
1717

18-
devspace
18+
/devspace
1919
debug
20+
.DS_STORE

.vscode/launch.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
"remotePath": "",
1010
"port": 2345,
1111
"host": "127.0.0.1",
12-
"cwd": "${workspaceFolder}/examples/nodejs",
12+
"cwd": "${workspaceFolder}",
1313
"program": "${workspaceFolder}/main.go",
1414
"env": {},
15-
"args": [""],
15+
"args": ["list", "package"],
1616
"showLog": true
1717
}
1818
]

Gopkg.lock

Lines changed: 13 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161

6262
[[constraint]]
6363
name = "k8s.io/helm"
64-
version = "v2.9.1"
64+
version = "v2.10.0"
6565

6666
[[constraint]]
6767
name = "github.com/foomo/htpasswd"

cmd/add.go

Lines changed: 191 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,35 @@ package cmd
22

33
import (
44
"fmt"
5+
"io/ioutil"
56
"os"
7+
"path/filepath"
68
"strconv"
79
"strings"
810

11+
"k8s.io/helm/pkg/repo"
12+
13+
"github.com/covexo/devspace/pkg/util/stdinutil"
14+
"github.com/covexo/devspace/pkg/util/tar"
15+
"github.com/covexo/devspace/pkg/util/yamlutil"
16+
17+
helmClient "github.com/covexo/devspace/pkg/devspace/clients/helm"
18+
"github.com/covexo/devspace/pkg/devspace/clients/kubectl"
919
"github.com/covexo/devspace/pkg/devspace/config/configutil"
1020
"github.com/covexo/devspace/pkg/devspace/config/v1"
1121
"github.com/covexo/devspace/pkg/util/log"
22+
"github.com/russross/blackfriday"
23+
"github.com/skratchdot/open-golang/open"
1224
"github.com/spf13/cobra"
1325
)
1426

1527
// AddCmd holds the information needed for the add command
1628
type AddCmd struct {
17-
flags *AddCmdFlags
18-
syncFlags *addSyncCmdFlags
19-
portFlags *addPortCmdFlags
20-
dsConfig *v1.DevSpaceConfig
29+
flags *AddCmdFlags
30+
syncFlags *addSyncCmdFlags
31+
portFlags *addPortCmdFlags
32+
packageFlags *addPackageFlags
33+
dsConfig *v1.DevSpaceConfig
2134
}
2235

2336
// AddCmdFlags holds the possible flags for the add command
@@ -37,11 +50,18 @@ type addPortCmdFlags struct {
3750
Selector string
3851
}
3952

53+
type addPackageFlags struct {
54+
AppVersion string
55+
ChartVersion string
56+
SkipQuestion bool
57+
}
58+
4059
func init() {
4160
cmd := &AddCmd{
42-
flags: &AddCmdFlags{},
43-
syncFlags: &addSyncCmdFlags{},
44-
portFlags: &addPortCmdFlags{},
61+
flags: &AddCmdFlags{},
62+
syncFlags: &addSyncCmdFlags{},
63+
portFlags: &addPortCmdFlags{},
64+
packageFlags: &addPackageFlags{},
4565
}
4666

4767
addCmd := &cobra.Command{
@@ -93,7 +113,7 @@ func init() {
93113

94114
addPortCmd := &cobra.Command{
95115
Use: "port",
96-
Short: "Lists port forwarding configuration",
116+
Short: "Add a new port forward configuration",
97117
Long: `
98118
#######################################################
99119
################ devspace add port ####################
@@ -111,6 +131,169 @@ func init() {
111131
addPortCmd.Flags().StringVar(&cmd.portFlags.Selector, "selector", "", "Comma separated key=value selector list (e.g. release=test)")
112132

113133
addCmd.AddCommand(addPortCmd)
134+
135+
addPackageCmd := &cobra.Command{
136+
Use: "package",
137+
Short: "Add a helm chart",
138+
Long: `
139+
#######################################################
140+
############### devspace add package ##################
141+
#######################################################
142+
Adds an existing helm chart to the devspace
143+
(run 'devspace add package' to display all available
144+
helm charts)
145+
146+
Examples:
147+
devspace add package
148+
devspace add package mysql
149+
devspace add package mysql --app-version=5.7.14
150+
devspace add package mysql --chart-version=0.10.3
151+
#######################################################
152+
`,
153+
Run: cmd.RunAddPackage,
154+
}
155+
156+
addPackageCmd.Flags().StringVar(&cmd.packageFlags.AppVersion, "app-version", "", "App version")
157+
addPackageCmd.Flags().StringVar(&cmd.packageFlags.ChartVersion, "chart-version", "", "Chart version")
158+
addPackageCmd.Flags().BoolVar(&cmd.packageFlags.SkipQuestion, "skip-question", false, "Skips the question to show the readme in a browser")
159+
160+
addCmd.AddCommand(addPackageCmd)
161+
}
162+
163+
// RunAddPackage executes the add package command logic
164+
func (cmd *AddCmd) RunAddPackage(cobraCmd *cobra.Command, args []string) {
165+
kubectl, err := kubectl.NewClient()
166+
if err != nil {
167+
log.Fatalf("Unable to create new kubectl client: %v", err)
168+
}
169+
170+
helm, err := helmClient.NewClient(kubectl, false)
171+
if err != nil {
172+
log.Fatalf("Error initializing helm client: %v", err)
173+
}
174+
175+
if len(args) != 1 {
176+
helm.PrintAllAvailableCharts()
177+
return
178+
}
179+
180+
log.StartWait("Search Chart")
181+
repo, version, err := helm.SearchChart(args[0], cmd.packageFlags.ChartVersion, cmd.packageFlags.AppVersion)
182+
log.StopWait()
183+
184+
if err != nil {
185+
log.Fatal(err)
186+
}
187+
188+
log.Done("Chart found")
189+
190+
cwd, err := os.Getwd()
191+
if err != nil {
192+
log.Fatal(err)
193+
}
194+
195+
requirementsFile := filepath.Join(cwd, "chart", "requirements.yaml")
196+
_, err = os.Stat(requirementsFile)
197+
if os.IsNotExist(err) {
198+
entry := "dependencies:\n" +
199+
"- name: \"" + version.GetName() + "\"\n" +
200+
" version: \"" + version.GetVersion() + "\"\n" +
201+
" repository: \"" + repo.URL + "\"\n"
202+
203+
err = ioutil.WriteFile(requirementsFile, []byte(entry), 0600)
204+
if err != nil {
205+
log.Fatal(err)
206+
}
207+
} else {
208+
yamlContents := map[interface{}]interface{}{}
209+
err = yamlutil.ReadYamlFromFile(requirementsFile, yamlContents)
210+
if err != nil {
211+
log.Fatalf("Error parsing %s: %v", requirementsFile, err)
212+
}
213+
214+
dependenciesArr := []interface{}{}
215+
if dependencies, ok := yamlContents["dependencies"]; ok {
216+
dependenciesArr, ok = dependencies.([]interface{})
217+
if ok == false {
218+
log.Fatalf("Error parsing %s: Key dependencies is not an array", requirementsFile)
219+
}
220+
}
221+
222+
dependenciesArr = append(dependenciesArr, map[interface{}]interface{}{
223+
"name": version.GetName(),
224+
"version": version.GetVersion(),
225+
"repository": repo.URL,
226+
})
227+
yamlContents["dependencies"] = dependenciesArr
228+
229+
err = yamlutil.WriteYamlToFile(yamlContents, requirementsFile)
230+
if err != nil {
231+
log.Fatal(err)
232+
}
233+
}
234+
235+
log.StartWait("Update chart dependencies")
236+
err = helm.UpdateDependencies(filepath.Join(cwd, "chart"))
237+
log.StopWait()
238+
239+
if err != nil {
240+
log.Fatal(err)
241+
}
242+
243+
f, err := os.OpenFile(filepath.Join(cwd, "chart", "values.yaml"), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
244+
if err != nil {
245+
log.Fatal(err)
246+
}
247+
248+
defer f.Close()
249+
if _, err = f.WriteString("\n" + version.GetName() + ": {}\n"); err != nil {
250+
log.Fatal(err)
251+
}
252+
253+
log.Donef("Successfully added %s as chart dependency, you can configure the package in 'chart/values.yaml'", version.GetName())
254+
cmd.showReadme(version)
255+
}
256+
257+
func (cmd *AddCmd) showReadme(chartVersion *repo.ChartVersion) {
258+
cwd, err := os.Getwd()
259+
if err != nil {
260+
log.Fatal(err)
261+
}
262+
263+
if cmd.packageFlags.SkipQuestion {
264+
return
265+
}
266+
267+
showReadme := *stdinutil.GetFromStdin(&stdinutil.GetFromStdinParams{
268+
Question: "Do you want to open the package README? (y|n)",
269+
DefaultValue: "y",
270+
ValidationRegexPattern: "^(y|n)",
271+
})
272+
273+
if showReadme == "n" {
274+
return
275+
}
276+
277+
content, err := tar.ExtractSingleFileToStringTarGz(filepath.Join(cwd, "chart", "charts", chartVersion.GetName()+"-"+chartVersion.GetVersion()+".tgz"), chartVersion.GetName()+"/README.md")
278+
if err != nil {
279+
log.Fatal(err)
280+
}
281+
282+
output := blackfriday.MarkdownCommon([]byte(content))
283+
f, err := os.OpenFile(filepath.Join(os.TempDir(), "Readme.html"), os.O_RDWR|os.O_CREATE, 0600)
284+
if err != nil {
285+
log.Fatal(err)
286+
}
287+
288+
defer f.Close()
289+
290+
_, err = f.Write(output)
291+
if err != nil {
292+
log.Fatal(err)
293+
}
294+
295+
f.Close()
296+
open.Start(f.Name())
114297
}
115298

116299
// RunAddSync executes the add sync command logic
@@ -161,7 +344,6 @@ func (cmd *AddCmd) RunAddSync(cobraCmd *cobra.Command, args []string) {
161344
config.DevSpace.Sync = &syncConfig
162345

163346
err = configutil.SaveConfig()
164-
165347
if err != nil {
166348
log.Fatalf("Couldn't save config file: %s", err.Error())
167349
}

0 commit comments

Comments
 (0)