Skip to content

Commit f5d7629

Browse files
authored
Merge pull request #1461 from devstream-io/mvp
merge mvp branch to main
2 parents 6ddd1e0 + 402f78a commit f5d7629

File tree

22 files changed

+883
-7
lines changed

22 files changed

+883
-7
lines changed

cmd/devstream/create.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
8+
"github.com/devstream-io/devstream/internal/pkg/create"
9+
)
10+
11+
var createCMD = &cobra.Command{
12+
Use: "create",
13+
Short: "create",
14+
Long: `create.`,
15+
Run: createCMDFunc,
16+
}
17+
18+
func createCMDFunc(cmd *cobra.Command, args []string) {
19+
err := create.Create()
20+
if err != nil && err.Error() != "^C" {
21+
fmt.Printf("Failed with error: %s", err)
22+
}
23+
}

cmd/devstream/main.go

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ func init() {
4545
rootCMD.AddCommand(listCMD)
4646
rootCMD.AddCommand(showCMD)
4747
rootCMD.AddCommand(upgradeCMD)
48+
49+
rootCMD.AddCommand(startCMD)
50+
rootCMD.AddCommand(createCMD)
4851
}
4952

5053
func initConfig() {

cmd/devstream/start.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
8+
"github.com/devstream-io/devstream/internal/pkg/start"
9+
)
10+
11+
var startCMD = &cobra.Command{
12+
Use: "start",
13+
Short: "start",
14+
Long: `start.`,
15+
Run: startCMDFunc,
16+
}
17+
18+
func startCMDFunc(_ *cobra.Command, _ []string) {
19+
err := start.Start()
20+
if err != nil && err.Error() != "^C" {
21+
fmt.Printf("Failed with error: %s", err)
22+
}
23+
}

go.mod

+4-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/aws/aws-sdk-go-v2/config v1.15.5
1212
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.9
1313
github.com/bndr/gojenkins v1.1.0
14+
github.com/briandowns/spinner v1.20.0
1415
github.com/cenkalti/backoff v2.2.1+incompatible
1516
github.com/cheggaaa/pb v1.0.29
1617
github.com/deckarep/golang-set/v2 v2.1.0
@@ -21,6 +22,7 @@ require (
2122
github.com/hashicorp/go-cleanhttp v0.5.2
2223
github.com/hashicorp/go-getter v1.6.2
2324
github.com/imdario/mergo v0.3.12
25+
github.com/manifoldco/promptui v0.9.0
2426
github.com/mitchellh/mapstructure v1.5.0
2527
github.com/mittwald/go-helm-client v0.8.4
2628
github.com/onsi/ginkgo/v2 v2.1.4
@@ -35,7 +37,7 @@ require (
3537
github.com/xanzy/go-gitlab v0.74.0
3638
go.uber.org/multierr v1.6.0
3739
golang.org/x/crypto v0.1.0
38-
golang.org/x/exp v0.0.0-20221114191408-850992195362
40+
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201
3941
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
4042
gopkg.in/gookit/color.v1 v1.1.6
4143
gopkg.in/yaml.v3 v3.0.1
@@ -83,6 +85,7 @@ require (
8385
github.com/bradleyfalzon/ghinstallation/v2 v2.0.3 // indirect
8486
github.com/cespare/xxhash/v2 v2.1.2 // indirect
8587
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
88+
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
8689
github.com/containerd/containerd v1.5.7 // indirect
8790
github.com/cyphar/filepath-securejoin v0.2.2 // indirect
8891
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -171,7 +174,6 @@ require (
171174
github.com/modern-go/reflect2 v1.0.2 // indirect
172175
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
173176
github.com/morikuni/aec v1.0.0 // indirect
174-
github.com/nxadm/tail v1.4.8 // indirect
175177
github.com/opencontainers/go-digest v1.0.0 // indirect
176178
github.com/opencontainers/image-spec v1.0.1 // indirect
177179
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
@@ -223,7 +225,6 @@ require (
223225
gopkg.in/gorp.v1 v1.7.2 // indirect
224226
gopkg.in/inf.v0 v0.9.1 // indirect
225227
gopkg.in/ini.v1 v1.62.0 // indirect
226-
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
227228
gopkg.in/warnings.v0 v0.1.2 // indirect
228229
gopkg.in/yaml.v2 v2.4.0 // indirect
229230
k8s.io/apiextensions-apiserver v0.22.4 // indirect

go.sum

+10-2
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ github.com/bombsimon/logrusr v1.0.0/go.mod h1:Jq0nHtvxabKE5EMwAAdgTaz7dfWE8C4i11
229229
github.com/bradleyfalzon/ghinstallation/v2 v2.0.2/go.mod h1:GhRUp70E+QFvNemlFd4unyHZ8ryBiMQkJm6KgdilpUo=
230230
github.com/bradleyfalzon/ghinstallation/v2 v2.0.3 h1:ywF/8q+GVpvlsEuvRb1SGSDQDUxntW1d4kFu/9q/YAE=
231231
github.com/bradleyfalzon/ghinstallation/v2 v2.0.3/go.mod h1:tlgi+JWCXnKFx/Y4WtnDbZEINo31N5bcvnCoqieefmk=
232+
github.com/briandowns/spinner v1.20.0 h1:GQq1Yf1KyzYT8CY19GzWrDKP6hYOFB6J72Ks7d8aO1U=
233+
github.com/briandowns/spinner v1.20.0/go.mod h1:TcwZHb7Wb6vn/+bcVv1UXEzaA4pLS7yznHlkY/HzH44=
232234
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
233235
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
234236
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
@@ -258,8 +260,11 @@ github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d8
258260
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
259261
github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo=
260262
github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30=
263+
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
261264
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
265+
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
262266
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
267+
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
263268
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
264269
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
265270
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
@@ -940,6 +945,8 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
940945
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
941946
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
942947
github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8/go.mod h1:UtpLyb/EupVKXF/N0b4NRe1DNg+QYJsnsHQ038romhM=
948+
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
949+
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
943950
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
944951
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
945952
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
@@ -950,6 +957,7 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef
950957
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
951958
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
952959
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
960+
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
953961
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
954962
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
955963
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -1477,8 +1485,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
14771485
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
14781486
golang.org/x/exp v0.0.0-20210220032938-85be41e4509f/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4=
14791487
golang.org/x/exp v0.0.0-20210901193431-a062eea981d2/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA=
1480-
golang.org/x/exp v0.0.0-20221114191408-850992195362 h1:NoHlPRbyl1VFI6FjwHtPQCN7wAMXI6cKcqrmXhOOfBQ=
1481-
golang.org/x/exp v0.0.0-20221114191408-850992195362/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
1488+
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE=
1489+
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
14821490
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
14831491
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
14841492
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=

internal/pkg/create/create.go

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package create
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
"github.com/devstream-io/devstream/internal/pkg/configmanager"
8+
"github.com/devstream-io/devstream/internal/pkg/create/param"
9+
"github.com/devstream-io/devstream/internal/pkg/plugin/argocdapp"
10+
general "github.com/devstream-io/devstream/internal/pkg/plugin/githubactions"
11+
"github.com/devstream-io/devstream/internal/pkg/plugin/reposcaffolding"
12+
"github.com/devstream-io/devstream/pkg/util/cli"
13+
)
14+
15+
func Create() error {
16+
params, err := param.GetParams()
17+
if err != nil {
18+
return err
19+
}
20+
fmt.Printf("Start create app %s's stream...\n", params.GitHubRepo)
21+
return create(params)
22+
}
23+
24+
// create will do following three things:
25+
// 1. create repo by repoScaffolding
26+
// 2. config GitHub actions for this repo
27+
// 3. create Argo CD application for this repo
28+
func create(params *param.Param) error {
29+
if err := createRepo(params); err != nil {
30+
return err
31+
}
32+
33+
if err := createApp(params); err != nil {
34+
return err
35+
}
36+
37+
// finalMessage is used to help user to vist this app
38+
finalMessage := `You can now connect to you app with:
39+
40+
kubectl port-forward service/%s 8080:8080 -n default
41+
42+
Then you can visit this app by http://127.0.0.1:8080 in your browser.
43+
44+
Happy Hacking! 😊
45+
`
46+
fmt.Printf(finalMessage, params.GitHubRepo)
47+
return nil
48+
}
49+
50+
func createRepo(params *param.Param) error {
51+
repoOptions := configmanager.RawOptions{
52+
"owner": params.GithubUsername,
53+
"name": params.GitHubRepo,
54+
"scmType": "github",
55+
"token": params.GithubToken,
56+
}
57+
58+
// 1.create repo
59+
status := cli.StatusForPlugin()
60+
repoScaffoldingOptions := configmanager.RawOptions{
61+
"destinationRepo": repoOptions,
62+
"sourceRepo": configmanager.RawOptions{
63+
"url": params.RepoScaffoldingURL,
64+
},
65+
}
66+
status.Start("Creating repo from scaffolding 🖼")
67+
_, err := reposcaffolding.Create(repoScaffoldingOptions)
68+
status.End(err)
69+
if err != nil {
70+
return err
71+
}
72+
73+
// 2.config ci
74+
ciOptions := configmanager.RawOptions{
75+
"scm": repoOptions,
76+
"pipeline": configmanager.RawOptions{
77+
"language": configmanager.RawOptions{
78+
"name": params.Language,
79+
"framework": params.Framework,
80+
},
81+
"imageRepo": configmanager.RawOptions{
82+
"user": params.DockerhubUsername,
83+
"password": params.DockerhubToken,
84+
},
85+
},
86+
}
87+
status.Start("Writing github action configuration ✍️ ")
88+
_, err = general.Create(ciOptions)
89+
status.End(err)
90+
status.Start("Waiting for github action finished 🐎")
91+
92+
// 3.wait repo ci finished
93+
waitCIFinished()
94+
status.End(err)
95+
return err
96+
}
97+
98+
func createApp(params *param.Param) error {
99+
status := cli.StatusForPlugin()
100+
argocdAppOption := configmanager.RawOptions{
101+
"app": configmanager.RawOptions{
102+
"name": params.GitHubRepo,
103+
"namespace": "argocd",
104+
},
105+
"destination": configmanager.RawOptions{
106+
"server": "https://kubernetes.default.svc",
107+
"namespace": "default",
108+
},
109+
"source": configmanager.RawOptions{
110+
"valuefile": "values.yaml",
111+
"path": fmt.Sprintf("helm/%s", params.GitHubRepo),
112+
"repoURL": fmt.Sprintf("https://github.com/%s/%s", params.GithubUsername, params.GitHubRepo),
113+
"repoBranch": "main",
114+
"token": params.GithubToken,
115+
},
116+
"imageRepo": configmanager.RawOptions{
117+
"user": params.DockerhubUsername,
118+
},
119+
}
120+
status.Start("Creating argocd app 🕹️")
121+
_, err := argocdapp.Create(argocdAppOption)
122+
status.End(err)
123+
status.Start("Waiting for app to running 🚀")
124+
// wait argocd app status to running
125+
waitAppUp()
126+
status.End(nil)
127+
return err
128+
}
129+
130+
// TODO(steinliber): add logic to wait for ci finished
131+
func waitCIFinished() {
132+
time.Sleep(70 * time.Second) // current github actions takes 62 seconds for finished
133+
}
134+
135+
// TODO(steinliber): add logic to wait for pod start running
136+
func waitAppUp() {
137+
time.Sleep(30 * time.Second)
138+
}
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package param
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/manifoldco/promptui"
7+
)
8+
9+
func getDockerHubUsername() (string, error) {
10+
prompt := promptui.Prompt{
11+
Label: "What is your DockerHub username",
12+
Validate: validate,
13+
}
14+
15+
result, err := prompt.Run()
16+
17+
if err != nil {
18+
fmt.Printf("Failed to get DockerHub username %v\n", err)
19+
return "", err
20+
}
21+
22+
return result, nil
23+
}
24+
25+
func getDockerHubToken() (string, error) {
26+
prompt := promptui.Prompt{
27+
Label: "Please input your DockerHub Personal Access Token",
28+
Mask: '*',
29+
Validate: validate,
30+
}
31+
32+
result, err := prompt.Run()
33+
34+
if err != nil {
35+
fmt.Printf("Failed to get DockerHub token %v\n", err)
36+
return "", err
37+
}
38+
39+
return result, nil
40+
}

internal/pkg/create/param/github.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package param
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/manifoldco/promptui"
7+
)
8+
9+
func getGitHubUsername() (string, error) {
10+
prompt := promptui.Prompt{
11+
Label: "What is your GitHub username",
12+
Validate: validate,
13+
}
14+
15+
result, err := prompt.Run()
16+
17+
if err != nil {
18+
fmt.Printf("Failed to get GitHub username %v\n", err)
19+
return "", err
20+
}
21+
22+
return result, nil
23+
}
24+
25+
func getGitHubRepo() (string, error) {
26+
prompt := promptui.Prompt{
27+
Label: "What GitHub Repo You Want to Create",
28+
Validate: validate,
29+
Default: "firstapp",
30+
}
31+
32+
result, err := prompt.Run()
33+
34+
if err != nil {
35+
fmt.Printf("Failed to get GitHub repo %v\n", err)
36+
return "", err
37+
}
38+
39+
return result, nil
40+
}
41+
42+
func getGitHubToken() (string, error) {
43+
prompt := promptui.Prompt{
44+
Label: "Please input your GitHub Personal Access Token",
45+
Mask: '*',
46+
Validate: validate,
47+
}
48+
49+
result, err := prompt.Run()
50+
51+
if err != nil {
52+
fmt.Printf("Failed to get GitHub token %v\n", err)
53+
return "", err
54+
}
55+
56+
return result, nil
57+
}

0 commit comments

Comments
 (0)