From 367baac3b48d9a9a1b7fb433dd496e0c6af93b90 Mon Sep 17 00:00:00 2001 From: programmersstudio Date: Thu, 8 Sep 2022 11:36:35 +0530 Subject: [PATCH] add apps detect command --- args.go | 9 ++++++ commands/apps.go | 73 ++++++++++++++++++++++++++++++++++++++++++ do/apps.go | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) diff --git a/args.go b/args.go index f11b60bda2..2f838508d7 100644 --- a/args.go +++ b/args.go @@ -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" ) diff --git a/commands/apps.go b/commands/apps.go index f6f70035c7..40e656b65a 100644 --- a/commands/apps.go +++ b/commands/apps.go @@ -22,6 +22,7 @@ import ( "net/http" "net/url" "os" + "strconv" "strings" "time" @@ -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.`) + 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, @@ -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) + 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 { + 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": + e := json.NewEncoder(c.Out) + e.SetIndent("", " ") + return e.Encode(spec) + case "text": + return nil + default: + return fmt.Errorf("unknown output type") + } +} + // RunAppsCreateDeployment creates a deployment for an app. func RunAppsCreateDeployment(c *CmdConfig) error { if len(c.Args) < 1 { diff --git a/do/apps.go b/do/apps.go index 0e7cfa159b..5bc36669f7 100644 --- a/do/apps.go +++ b/do/apps.go @@ -15,6 +15,7 @@ package do import ( "context" + "strings" "github.com/digitalocean/godo" ) @@ -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) @@ -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) { + 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 { + + if component.Strategy == "SERVERLESS" { + 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 {