Skip to content
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"
// ArgProjectBrach is git project branch.
ArgProjectBrach = "branch"
)
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])
}
}

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.