Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add apps detect command #1227

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,4 +406,13 @@ const (

// ArgAlertPolicySlackURLs are the Slack URLs to send alerts to.
ArgAlertPolicySlackURLs = "slack-urls"

// ArgCommitHash are the Git commit hash.
ArgCommitHash = "sha"
// ArgProjectSource is either git, github or gitlab.
ArgProjectSource = "source"
// ArgDeployOnPush allow auto deploy on project update.
ArgDeployOnPush = "deployonpush"
ChiefMateStarbuck marked this conversation as resolved.
Show resolved Hide resolved
// ArgProjectBrach is git project branch.
ChiefMateStarbuck marked this conversation as resolved.
Show resolved Hide resolved
ArgProjectBrach = "branch"
ChiefMateStarbuck marked this conversation as resolved.
Show resolved Hide resolved
)
73 changes: 73 additions & 0 deletions commands/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -113,6 +114,15 @@ This permanently deletes the app and all its associated deployments.`,
)
AddBoolFlag(deleteApp, doctl.ArgForce, doctl.ArgShortForce, false, "Delete the App without a confirmation prompt")

// output is global flag
detect := CmdBuilder(cmd,
RunAppsDetect, "detect", "Detect functions", "Detect functions project and convert it into apps project by adding the AppSpec.", Writer, aliasOpt("dt"))
AddStringFlag(detect, doctl.ArgProjectSource, "", "", `Project source.`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check if we are currently in a git project directory and attempt to default to that source repo.

AddStringFlag(detect, doctl.ArgCommitHash, "", "", `Git commit hash`) // not sure if need to support commit hash?
AddStringFlag(detect, doctl.ArgProjectName, "", "", `App name to be used`)
AddStringFlag(detect, doctl.ArgProjectBrach, "", "", `Project branch to be used`)
AddBoolFlag(detect, doctl.ArgDeployOnPush, "", *boolPtr(true), `Auto deploy on project update.`)

deploymentCreate := CmdBuilder(
cmd,
RunAppsCreateDeployment,
Expand Down Expand Up @@ -393,6 +403,69 @@ func RunAppsDelete(c *CmdConfig) error {
return nil
}

// RunAppsDetect detects an function project and converts it into apps project.
func RunAppsDetect(c *CmdConfig) error {
source, err := c.Doit.GetString(c.NS, doctl.ArgProjectSource)
if err != nil {
return err
}
if len(source) == 0 {
return fmt.Errorf("source cannot be empty")
}

sha, err := c.Doit.GetString(c.NS, doctl.ArgCommitHash)
if err != nil {
return err
}

name, err := c.Doit.GetString(c.NS, doctl.ArgProjectName)
if err != nil {
return err
}
if len(name) == 0 {
return fmt.Errorf("name cannot be empty")
}

branch, err := c.Doit.GetString(c.NS, doctl.ArgProjectBrach)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
branch, err := c.Doit.GetString(c.NS, doctl.ArgProjectBrach)
branch, err := c.Doit.GetString(c.NS, doctl.ArgProjectBranch)

if err != nil {
return err
}
if len(branch) == 0 {
return fmt.Errorf("branch cannot be empty")
}

// Need to check, How user value will be overrided
autoDeploy, err := c.Doit.GetBool(c.NS, doctl.ArgDeployOnPush)
if err != nil {
return err
}
if len(c.Args) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need argument parsing here if we are including auto-deploy as a flag as well.

fmt.Println(c.Args[0])
x, err := strconv.ParseBool(c.Args[0])
if err == nil {
autoDeploy = x
} else {
return fmt.Errorf("expected true/false for deployonpush, received : %s", c.Args[0])
ChiefMateStarbuck marked this conversation as resolved.
Show resolved Hide resolved
}
}

spec, err := c.Apps().Detect(source, sha, name, branch, autoDeploy)
if err != nil {
return err
}

switch Output {
case "json":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should support YAML here as well

e := json.NewEncoder(c.Out)
e.SetIndent("", " ")
return e.Encode(spec)
case "text":
return nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(assuming this is just not implemented yet) just a reminder to either error out if not supported or implemented output support

default:
return fmt.Errorf("unknown output type")
}
}

// RunAppsCreateDeployment creates a deployment for an app.
func RunAppsCreateDeployment(c *CmdConfig) error {
if len(c.Args) < 1 {
Expand Down
1 change: 1 addition & 0 deletions commands/apps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestAppsCommand(t *testing.T) {
require.NotNil(t, cmd)
assertCommandNames(t, cmd,
"create",
"detect",
"get",
"list",
"update",
Expand Down
82 changes: 82 additions & 0 deletions do/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package do

import (
"context"
"strings"

"github.com/digitalocean/godo"
)
Expand All @@ -26,6 +27,7 @@ type AppsService interface {
List() ([]*godo.App, error)
Update(appID string, req *godo.AppUpdateRequest) (*godo.App, error)
Delete(appID string) error
Detect(source string, sha string, name string, branch string, autoDeploy bool) (*godo.AppSpec, error)
Propose(req *godo.AppProposeRequest) (*godo.AppProposeResponse, error)

CreateDeployment(appID string, forceRebuild bool) (*godo.Deployment, error)
Expand Down Expand Up @@ -119,6 +121,86 @@ func (s *appsService) Delete(appID string) error {
return err
}

func (s *appsService) Detect(source string, sha string, name string, branch string, autoDeploy bool) (*godo.AppSpec, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should consider changing this signature to only inline required parameters and put the rest in an options struct. e.g.:

type DetectOpts struct {
  Name string // random name generated by default
  Sha string // latest sha in branch by default
  AutoDeploy bool // False by default
}

func (s *appsService) Detect(source, branch string, opts DetectOpts) (*godo.AppSpec, error) {

var dr godo.DetectRequest
if strings.Contains(source, "github") {
dr.GitHub = &godo.GitHubSourceSpec{
Repo: verifyGitSource(source, "github"),
Branch: branch,
DeployOnPush: autoDeploy,
}
} else if strings.Contains(source, "gitlab") {
dr.GitLab = &godo.GitLabSourceSpec{
Repo: verifyGitSource(source, "gitlab"),
Branch: branch,
DeployOnPush: autoDeploy,
}
} else {
dr.Git = &godo.GitSourceSpec{
RepoCloneURL: source,
Branch: branch,
}
}
dr.SourceDir = "/"
dr.CommitSHA = sha

resp, _, err := s.client.Apps.Detect(context.Background(), &dr)
if err != nil {
return nil, err
}

var appSpec godo.AppSpec

appSpec.Name = name
var funcSpecArray []*godo.AppFunctionsSpec
for _, component := range resp.Components {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a warning message stating other component types are not yet supported if we encounter them in the spec.


if component.Strategy == "SERVERLESS" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should print out a warning if we detect non serverless component strategies for now until we support them.

for _, serverlessPackage := range component.ServerlessPackages {
var functionSpec godo.AppFunctionsSpec
functionSpec.Name = serverlessPackage.Name
if strings.Contains(source, "github") {
functionSpec.GitHub = &godo.GitHubSourceSpec{
Repo: verifyGitSource(source, "github"),
Branch: branch,
DeployOnPush: autoDeploy,
}
} else if strings.Contains(source, "gitlab") {
functionSpec.GitLab = &godo.GitLabSourceSpec{
Repo: verifyGitSource(source, "gitlab"),
Branch: branch,
DeployOnPush: autoDeploy,
}
} else {
functionSpec.Git = &godo.GitSourceSpec{
RepoCloneURL: source,
Branch: branch,
}
}
functionSpec.SourceDir = "/"
functionSpec.Routes = []*godo.AppRouteSpec{
{
Path: "/",
PreservePathPrefix: false,
},
}
funcSpecArray = append(funcSpecArray, &functionSpec)

}
}
appSpec.Functions = funcSpecArray
}
return &appSpec, nil
}

func verifyGitSource(s string, splitter string) string {
x := strings.Split(s, splitter+".com/")
if strings.Contains(x[1], ".git") {
x = strings.Split(x[1], ".")
}
return x[0]
}

func (s *appsService) Propose(req *godo.AppProposeRequest) (*godo.AppProposeResponse, error) {
res, _, err := s.client.Apps.Propose(s.ctx, req)
if err != nil {
Expand Down
15 changes: 15 additions & 0 deletions do/mocks/AppsService.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 15 additions & 14 deletions do/mocks/DatabasesService.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.