Skip to content

Commit

Permalink
Merge pull request #1461 from devstream-io/mvp
Browse files Browse the repository at this point in the history
merge mvp branch to main
  • Loading branch information
daniel-hutao authored Feb 3, 2023
2 parents 6ddd1e0 + 402f78a commit f5d7629
Show file tree
Hide file tree
Showing 22 changed files with 883 additions and 7 deletions.
23 changes: 23 additions & 0 deletions cmd/devstream/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"fmt"

"github.com/spf13/cobra"

"github.com/devstream-io/devstream/internal/pkg/create"
)

var createCMD = &cobra.Command{
Use: "create",
Short: "create",
Long: `create.`,
Run: createCMDFunc,
}

func createCMDFunc(cmd *cobra.Command, args []string) {
err := create.Create()
if err != nil && err.Error() != "^C" {
fmt.Printf("Failed with error: %s", err)
}
}
3 changes: 3 additions & 0 deletions cmd/devstream/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ func init() {
rootCMD.AddCommand(listCMD)
rootCMD.AddCommand(showCMD)
rootCMD.AddCommand(upgradeCMD)

rootCMD.AddCommand(startCMD)
rootCMD.AddCommand(createCMD)
}

func initConfig() {
Expand Down
23 changes: 23 additions & 0 deletions cmd/devstream/start.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"fmt"

"github.com/spf13/cobra"

"github.com/devstream-io/devstream/internal/pkg/start"
)

var startCMD = &cobra.Command{
Use: "start",
Short: "start",
Long: `start.`,
Run: startCMDFunc,
}

func startCMDFunc(_ *cobra.Command, _ []string) {
err := start.Start()
if err != nil && err.Error() != "^C" {
fmt.Printf("Failed with error: %s", err)
}
}
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.15.5
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.9
github.com/bndr/gojenkins v1.1.0
github.com/briandowns/spinner v1.20.0
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cheggaaa/pb v1.0.29
github.com/deckarep/golang-set/v2 v2.1.0
Expand All @@ -21,6 +22,7 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-getter v1.6.2
github.com/imdario/mergo v0.3.12
github.com/manifoldco/promptui v0.9.0
github.com/mitchellh/mapstructure v1.5.0
github.com/mittwald/go-helm-client v0.8.4
github.com/onsi/ginkgo/v2 v2.1.4
Expand All @@ -35,7 +37,7 @@ require (
github.com/xanzy/go-gitlab v0.74.0
go.uber.org/multierr v1.6.0
golang.org/x/crypto v0.1.0
golang.org/x/exp v0.0.0-20221114191408-850992195362
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
gopkg.in/gookit/color.v1 v1.1.6
gopkg.in/yaml.v3 v3.0.1
Expand Down Expand Up @@ -83,6 +85,7 @@ require (
github.com/bradleyfalzon/ghinstallation/v2 v2.0.3 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/containerd/containerd v1.5.7 // indirect
github.com/cyphar/filepath-securejoin v0.2.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
Expand Down Expand Up @@ -171,7 +174,6 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
Expand Down Expand Up @@ -223,7 +225,6 @@ require (
gopkg.in/gorp.v1 v1.7.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/apiextensions-apiserver v0.22.4 // indirect
Expand Down
12 changes: 10 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ github.com/bombsimon/logrusr v1.0.0/go.mod h1:Jq0nHtvxabKE5EMwAAdgTaz7dfWE8C4i11
github.com/bradleyfalzon/ghinstallation/v2 v2.0.2/go.mod h1:GhRUp70E+QFvNemlFd4unyHZ8ryBiMQkJm6KgdilpUo=
github.com/bradleyfalzon/ghinstallation/v2 v2.0.3 h1:ywF/8q+GVpvlsEuvRb1SGSDQDUxntW1d4kFu/9q/YAE=
github.com/bradleyfalzon/ghinstallation/v2 v2.0.3/go.mod h1:tlgi+JWCXnKFx/Y4WtnDbZEINo31N5bcvnCoqieefmk=
github.com/briandowns/spinner v1.20.0 h1:GQq1Yf1KyzYT8CY19GzWrDKP6hYOFB6J72Ks7d8aO1U=
github.com/briandowns/spinner v1.20.0/go.mod h1:TcwZHb7Wb6vn/+bcVv1UXEzaA4pLS7yznHlkY/HzH44=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
Expand Down Expand Up @@ -258,8 +260,11 @@ github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d8
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo=
github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
Expand Down Expand Up @@ -940,6 +945,8 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8/go.mod h1:UtpLyb/EupVKXF/N0b4NRe1DNg+QYJsnsHQ038romhM=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
Expand All @@ -950,6 +957,7 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
Expand Down Expand Up @@ -1477,8 +1485,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20210220032938-85be41e4509f/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4=
golang.org/x/exp v0.0.0-20210901193431-a062eea981d2/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA=
golang.org/x/exp v0.0.0-20221114191408-850992195362 h1:NoHlPRbyl1VFI6FjwHtPQCN7wAMXI6cKcqrmXhOOfBQ=
golang.org/x/exp v0.0.0-20221114191408-850992195362/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE=
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
Expand Down
138 changes: 138 additions & 0 deletions internal/pkg/create/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package create

import (
"fmt"
"time"

"github.com/devstream-io/devstream/internal/pkg/configmanager"
"github.com/devstream-io/devstream/internal/pkg/create/param"
"github.com/devstream-io/devstream/internal/pkg/plugin/argocdapp"
general "github.com/devstream-io/devstream/internal/pkg/plugin/githubactions"
"github.com/devstream-io/devstream/internal/pkg/plugin/reposcaffolding"
"github.com/devstream-io/devstream/pkg/util/cli"
)

func Create() error {
params, err := param.GetParams()
if err != nil {
return err
}
fmt.Printf("Start create app %s's stream...\n", params.GitHubRepo)
return create(params)
}

// create will do following three things:
// 1. create repo by repoScaffolding
// 2. config GitHub actions for this repo
// 3. create Argo CD application for this repo
func create(params *param.Param) error {
if err := createRepo(params); err != nil {
return err
}

if err := createApp(params); err != nil {
return err
}

// finalMessage is used to help user to vist this app
finalMessage := `You can now connect to you app with:
kubectl port-forward service/%s 8080:8080 -n default
Then you can visit this app by http://127.0.0.1:8080 in your browser.
Happy Hacking! 😊
`
fmt.Printf(finalMessage, params.GitHubRepo)
return nil
}

func createRepo(params *param.Param) error {
repoOptions := configmanager.RawOptions{
"owner": params.GithubUsername,
"name": params.GitHubRepo,
"scmType": "github",
"token": params.GithubToken,
}

// 1.create repo
status := cli.StatusForPlugin()
repoScaffoldingOptions := configmanager.RawOptions{
"destinationRepo": repoOptions,
"sourceRepo": configmanager.RawOptions{
"url": params.RepoScaffoldingURL,
},
}
status.Start("Creating repo from scaffolding 🖼")
_, err := reposcaffolding.Create(repoScaffoldingOptions)
status.End(err)
if err != nil {
return err
}

// 2.config ci
ciOptions := configmanager.RawOptions{
"scm": repoOptions,
"pipeline": configmanager.RawOptions{
"language": configmanager.RawOptions{
"name": params.Language,
"framework": params.Framework,
},
"imageRepo": configmanager.RawOptions{
"user": params.DockerhubUsername,
"password": params.DockerhubToken,
},
},
}
status.Start("Writing github action configuration ✍️ ")
_, err = general.Create(ciOptions)
status.End(err)
status.Start("Waiting for github action finished 🐎")

// 3.wait repo ci finished
waitCIFinished()
status.End(err)
return err
}

func createApp(params *param.Param) error {
status := cli.StatusForPlugin()
argocdAppOption := configmanager.RawOptions{
"app": configmanager.RawOptions{
"name": params.GitHubRepo,
"namespace": "argocd",
},
"destination": configmanager.RawOptions{
"server": "https://kubernetes.default.svc",
"namespace": "default",
},
"source": configmanager.RawOptions{
"valuefile": "values.yaml",
"path": fmt.Sprintf("helm/%s", params.GitHubRepo),
"repoURL": fmt.Sprintf("https://github.com/%s/%s", params.GithubUsername, params.GitHubRepo),
"repoBranch": "main",
"token": params.GithubToken,
},
"imageRepo": configmanager.RawOptions{
"user": params.DockerhubUsername,
},
}
status.Start("Creating argocd app 🕹️")
_, err := argocdapp.Create(argocdAppOption)
status.End(err)
status.Start("Waiting for app to running 🚀")
// wait argocd app status to running
waitAppUp()
status.End(nil)
return err
}

// TODO(steinliber): add logic to wait for ci finished
func waitCIFinished() {
time.Sleep(70 * time.Second) // current github actions takes 62 seconds for finished
}

// TODO(steinliber): add logic to wait for pod start running
func waitAppUp() {
time.Sleep(30 * time.Second)
}
40 changes: 40 additions & 0 deletions internal/pkg/create/param/dockerhub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package param

import (
"fmt"

"github.com/manifoldco/promptui"
)

func getDockerHubUsername() (string, error) {
prompt := promptui.Prompt{
Label: "What is your DockerHub username",
Validate: validate,
}

result, err := prompt.Run()

if err != nil {
fmt.Printf("Failed to get DockerHub username %v\n", err)
return "", err
}

return result, nil
}

func getDockerHubToken() (string, error) {
prompt := promptui.Prompt{
Label: "Please input your DockerHub Personal Access Token",
Mask: '*',
Validate: validate,
}

result, err := prompt.Run()

if err != nil {
fmt.Printf("Failed to get DockerHub token %v\n", err)
return "", err
}

return result, nil
}
57 changes: 57 additions & 0 deletions internal/pkg/create/param/github.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package param

import (
"fmt"

"github.com/manifoldco/promptui"
)

func getGitHubUsername() (string, error) {
prompt := promptui.Prompt{
Label: "What is your GitHub username",
Validate: validate,
}

result, err := prompt.Run()

if err != nil {
fmt.Printf("Failed to get GitHub username %v\n", err)
return "", err
}

return result, nil
}

func getGitHubRepo() (string, error) {
prompt := promptui.Prompt{
Label: "What GitHub Repo You Want to Create",
Validate: validate,
Default: "firstapp",
}

result, err := prompt.Run()

if err != nil {
fmt.Printf("Failed to get GitHub repo %v\n", err)
return "", err
}

return result, nil
}

func getGitHubToken() (string, error) {
prompt := promptui.Prompt{
Label: "Please input your GitHub Personal Access Token",
Mask: '*',
Validate: validate,
}

result, err := prompt.Run()

if err != nil {
fmt.Printf("Failed to get GitHub token %v\n", err)
return "", err
}

return result, nil
}
Loading

0 comments on commit f5d7629

Please sign in to comment.