Skip to content

Commit 3fed88e

Browse files
committed
feat: add repo and app creation for cli prompt
Signed-off-by: Meng JiaFeng <[email protected]>
1 parent 37b6527 commit 3fed88e

File tree

8 files changed

+184
-35
lines changed

8 files changed

+184
-35
lines changed

go.mod

Lines changed: 2 additions & 1 deletion
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
@@ -36,7 +37,7 @@ require (
3637
github.com/xanzy/go-gitlab v0.74.0
3738
go.uber.org/multierr v1.6.0
3839
golang.org/x/crypto v0.1.0
39-
golang.org/x/exp v0.0.0-20221114191408-850992195362
40+
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201
4041
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
4142
gopkg.in/gookit/color.v1 v1.1.6
4243
gopkg.in/yaml.v3 v3.0.1

go.sum

Lines changed: 5 additions & 2 deletions
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=
@@ -955,6 +957,7 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef
955957
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
956958
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
957959
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=
958961
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
959962
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
960963
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -1482,8 +1485,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
14821485
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
14831486
golang.org/x/exp v0.0.0-20210220032938-85be41e4509f/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4=
14841487
golang.org/x/exp v0.0.0-20210901193431-a062eea981d2/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA=
1485-
golang.org/x/exp v0.0.0-20221114191408-850992195362 h1:NoHlPRbyl1VFI6FjwHtPQCN7wAMXI6cKcqrmXhOOfBQ=
1486-
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=
14871490
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
14881491
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
14891492
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=

internal/pkg/create/create.go

Lines changed: 107 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,131 @@ import (
44
"fmt"
55
"time"
66

7+
"github.com/devstream-io/devstream/internal/pkg/configmanager"
78
"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"
813
)
914

1015
func Create() error {
11-
helloMsg := func() {
12-
fmt.Println("I'll scaffold a new repository for you.")
13-
time.Sleep(time.Second)
14-
fmt.Println("Are you ready?")
15-
time.Sleep(time.Second)
16-
fmt.Println("Let's get started.")
17-
time.Sleep(time.Second)
18-
}
19-
helloMsg()
20-
2116
params, err := param.GetParams()
2217
if err != nil {
2318
return err
2419
}
25-
20+
fmt.Printf("Start create app %s's stream...\n", params.GitHubRepo)
2621
return create(params)
2722
}
2823

29-
// TODO: @jf
24+
// create will do folling three things:
25+
// 1. create repo by repoScaffolding
26+
// 2. config github actions for this repo
27+
// 3. create argocd application for this repo
3028
func create(params *param.Param) error {
31-
err := createRepo(params)
32-
if err != nil {
29+
if err := createRepo(params); err != nil {
3330
return err
3431
}
3532

36-
return createApp(params)
37-
}
33+
if err := createApp(params); err != nil {
34+
return err
35+
}
3836

39-
// TODO(daniel-hutao): support python/flask first
40-
func createRepo(params *param.Param) error {
41-
fmt.Printf("Lang: %s, Fram: %s\n", params.Language, params.Framework)
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 browser
43+
Thanks for using DevStream! 😊
44+
`
45+
fmt.Printf(finalMessage, params.GitHubRepo)
4246
return nil
4347
}
4448

49+
func createRepo(params *param.Param) error {
50+
repoOptions := configmanager.RawOptions{
51+
"owner": params.GithubUsername,
52+
"name": params.GitHubRepo,
53+
"scmType": "github",
54+
"token": params.GithubToken,
55+
}
56+
// 1.create repo
57+
status := cli.StatusForPlugin()
58+
repoScaffoldingOptions := configmanager.RawOptions{
59+
"destinationRepo": repoOptions,
60+
"sourceRepo": configmanager.RawOptions{
61+
"url": params.RepoScaffoldingURL,
62+
},
63+
}
64+
status.Start("Creating repo from scaffolding 🖼")
65+
_, err := reposcaffolding.Create(repoScaffoldingOptions)
66+
status.End(err)
67+
if err != nil {
68+
return err
69+
}
70+
// 2.config ci
71+
ciOptions := configmanager.RawOptions{
72+
"scm": repoOptions,
73+
"pipeline": configmanager.RawOptions{
74+
"language": configmanager.RawOptions{
75+
"name": params.Language,
76+
"framework": params.Framework,
77+
},
78+
"imageRepo": configmanager.RawOptions{
79+
"user": params.DockerhubUsername,
80+
"password": params.DockerhubToken,
81+
},
82+
},
83+
}
84+
status.Start("Writing github action configuration ✍️ ")
85+
_, err = general.Create(ciOptions)
86+
status.End(err)
87+
status.Start("Waiting for github action finished 🐎")
88+
// 3.wait repo ci finished
89+
waitCIFinished()
90+
status.End(err)
91+
return err
92+
93+
}
4594
func createApp(params *param.Param) error {
46-
return nil
95+
status := cli.StatusForPlugin()
96+
argocdAppOption := configmanager.RawOptions{
97+
"app": configmanager.RawOptions{
98+
"name": params.GitHubRepo,
99+
"namespace": "argocd",
100+
},
101+
"destination": configmanager.RawOptions{
102+
"server": "https://kubernetes.default.svc",
103+
"namespace": "default",
104+
},
105+
"source": configmanager.RawOptions{
106+
"valuefile": "values.yaml",
107+
"path": fmt.Sprintf("helm/%s", params.GitHubRepo),
108+
"repoURL": fmt.Sprintf("https://github.com/%s/%s", params.GithubUsername, params.GitHubRepo),
109+
"repoBranch": "main",
110+
"token": params.GithubToken,
111+
},
112+
"imageRepo": configmanager.RawOptions{
113+
"user": params.DockerhubUsername,
114+
},
115+
}
116+
status.Start("Creating argocd app 🕹️")
117+
_, err := argocdapp.Create(argocdAppOption)
118+
status.End(err)
119+
status.Start("Waiting for app to running 🚀")
120+
// wait argocd app status to running
121+
waitAppUp()
122+
status.End(nil)
123+
return err
124+
}
125+
126+
// TODO(steinliber): add logic to wait for ci finished
127+
func waitCIFinished() {
128+
time.Sleep(70 * time.Second) // current github actions takes 62 seconds for finished
129+
}
130+
131+
// TODO(steinliber): add logic to wait for pod start running
132+
func waitAppUp() {
133+
time.Sleep(30 * time.Second)
47134
}

internal/pkg/create/param/github.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ func getGitHubUsername() (string, error) {
2222
return result, nil
2323
}
2424

25-
func getGitHubRepo(language, framework string) (string, error) {
25+
func getGitHubRepo() (string, error) {
2626
prompt := promptui.Prompt{
2727
Label: "What GitHub Repo You Want to Create",
2828
Validate: validate,
29-
Default: fmt.Sprintf("%s-%s-%s", "first", language, framework),
29+
Default: "firstapp",
3030
}
3131

3232
result, err := prompt.Run()

internal/pkg/create/param/param.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package param
22

3-
import "github.com/devstream-io/devstream/pkg/util/log"
4-
53
type Param struct {
64
GithubUsername string
75
GitHubRepo string
@@ -24,7 +22,7 @@ func GetParams() (*Param, error) {
2422
return nil, err
2523
}
2624

27-
githubRepo, err := getGitHubRepo(lang, frame)
25+
githubRepo, err := getGitHubRepo()
2826
if err != nil {
2927
return nil, err
3028
}
@@ -54,7 +52,5 @@ func GetParams() (*Param, error) {
5452
DockerhubUsername: dockerhubUsername,
5553
DockerhubToken: dockerhubToken,
5654
}
57-
// TODO: change to debug level
58-
log.Infof("param: %+v", param)
5955
return param, nil
6056
}

internal/pkg/create/param/repoScaffolding.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package param
33
import (
44
"fmt"
55
"strings"
6-
"time"
76

87
"github.com/manifoldco/promptui"
98
)
@@ -27,9 +26,7 @@ func selectRepoScaffolding() (language, framework, url string, err error) {
2726
return
2827
}
2928

30-
time.Sleep(time.Second)
3129
fmt.Println("\nPlease choose a framework next.")
32-
time.Sleep(time.Second)
3330

3431
framework, url, err = selectFrameworks(languagesRepoMap[language])
3532
if err != nil {
@@ -39,6 +36,8 @@ func selectRepoScaffolding() (language, framework, url string, err error) {
3936
break
4037
}
4138
}
39+
language = strings.ToLower(language)
40+
framework = strings.ToLower(framework)
4241

4342
return language, framework, url, nil
4443

@@ -72,8 +71,8 @@ func selectLanguage(languagesRepoMap map[string][]RepoScaffolding) (language str
7271
Inactive: " {{ .Language | cyan }}",
7372
Selected: "🐰 Language: {{ .Language | blue | cyan }}",
7473
Details: `
75-
--------- Supported Frameworks ----------
76-
{{ .Language}}: {{ join .Frameworks ", " }}`,
74+
--------- Supported Frameworks For {{ .Language}} ----------
75+
{{ join .Frameworks ", " }}`,
7776
FuncMap: combinedFuncMap,
7877
}
7978

pkg/util/cli/status.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package cli
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"time"
7+
8+
"github.com/briandowns/spinner"
9+
10+
"github.com/devstream-io/devstream/pkg/util/log"
11+
)
12+
13+
type Status struct {
14+
spinner *spinner.Spinner
15+
logBuffer *bytes.Buffer
16+
statusMessage string
17+
successFormat string
18+
failureFormat string
19+
}
20+
21+
func StatusForPlugin() *Status {
22+
spinner := spinner.New(spinner.CharSets[7], 5000*time.Microsecond)
23+
_ = spinner.Color("yellow")
24+
return &Status{
25+
spinner: spinner,
26+
logBuffer: new(bytes.Buffer),
27+
successFormat: "\x1b[32m✓\x1b[0m %s\n",
28+
failureFormat: "\x1b[31m✗\x1b[0m %s\n",
29+
}
30+
}
31+
32+
func (s *Status) Start(status string) {
33+
s.statusMessage = status
34+
s.spinner.Suffix = fmt.Sprintf(" %s", status)
35+
log.RedirectOutput(s.logBuffer)
36+
s.spinner.Start()
37+
}
38+
39+
// End completes the current status, ending any previous spinning and
40+
// marking the status as success or failure
41+
func (s *Status) End(err error) {
42+
log.RecoverOutput()
43+
if err == nil {
44+
s.spinner.FinalMSG = fmt.Sprintf(s.successFormat, s.statusMessage)
45+
} else {
46+
s.spinner.FinalMSG = fmt.Sprintf(s.failureFormat, s.statusMessage)
47+
}
48+
// logBuffer contains log during status.Start to status.End
49+
// we should write this logBuffer to something for error trace
50+
s.logBuffer.Reset()
51+
s.spinner.Stop()
52+
}

pkg/util/log/log.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package log
22

33
import (
4+
"io"
5+
"os"
6+
47
"github.com/sirupsen/logrus"
58
)
69

@@ -14,6 +17,14 @@ var (
1417
separatorLog = &SeparatorFormatter{}
1518
)
1619

20+
func RedirectOutput(writer io.Writer) {
21+
logrus.SetOutput(writer)
22+
}
23+
24+
func RecoverOutput() {
25+
logrus.SetOutput(os.Stdout)
26+
}
27+
1728
// Debugf log info with color,symbol and format for a notice
1829
func Debugf(format string, args ...interface{}) {
1930
logrus.SetFormatter(debugLog)

0 commit comments

Comments
 (0)