Skip to content

Commit

Permalink
Added support getting logs for an app by name. (#1627)
Browse files Browse the repository at this point in the history
Co-authored-by: Anna Lushnikova <[email protected]>
Co-authored-by: Andrew Starr-Bochicchio <[email protected]>
  • Loading branch information
3 people authored Dec 9, 2024
1 parent 5f5ce31 commit 45cd88d
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 9 deletions.
26 changes: 17 additions & 9 deletions commands/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/digitalocean/doctl/internal/apps"
"github.com/digitalocean/doctl/pkg/terminal"
"github.com/digitalocean/godo"
"github.com/google/uuid"
multierror "github.com/hashicorp/go-multierror"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -189,7 +190,7 @@ Only basic information is included with the text output format. For complete app
logs := CmdBuilder(
cmd,
RunAppsGetLogs,
"logs <app id> <component name (defaults to all components)>",
"logs <app name or id> <component name (defaults to all components)>",
"Retrieves logs",
`Retrieves component logs for a deployment of an app.
Expand Down Expand Up @@ -659,17 +660,24 @@ func RunAppsGetLogs(c *CmdConfig) error {
if err != nil {
return err
}
if deploymentID == "" {
app, err := c.Apps().Get(appID)

_, err = uuid.Parse(appID)
if err != nil || deploymentID == "" {
app, err := c.Apps().Find(appID)
if err != nil {
return err
}
if app.ActiveDeployment != nil {
deploymentID = app.ActiveDeployment.ID
} else if app.InProgressDeployment != nil {
deploymentID = app.InProgressDeployment.ID
} else {
return fmt.Errorf("unable to retrieve logs; no deployment found for app %s", appID)

appID = app.ID

if deploymentID == "" {
if app.ActiveDeployment != nil {
deploymentID = app.ActiveDeployment.ID
} else if app.InProgressDeployment != nil {
deploymentID = app.InProgressDeployment.ID
} else {
return fmt.Errorf("unable to retrieve logs; no deployment found for app %s", appID)
}
}
}

Expand Down
88 changes: 88 additions & 0 deletions commands/apps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,94 @@ func TestRunAppsGetLogs(t *testing.T) {
}
}

func TestRunAppsGetLogsWithAppName(t *testing.T) {
appName := "test-app"
component := "service"

testApp := &godo.App{
ID: uuid.New().String(),
Spec: &testAppSpec,
ActiveDeployment: &godo.Deployment{
ID: uuid.New().String(),
Spec: &testAppSpec,
},
}

types := map[string]godo.AppLogType{
"build": godo.AppLogTypeBuild,
"deploy": godo.AppLogTypeDeploy,
"run": godo.AppLogTypeRun,
}

for typeStr, logType := range types {
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
tm.apps.EXPECT().Find(appName).Times(1).Return(testApp, nil)
tm.apps.EXPECT().GetLogs(testApp.ID, testApp.ActiveDeployment.ID, component, logType, true, 1).Times(1).Return(&godo.AppLogs{LiveURL: "https://proxy-apps-prod-ams3-001.ondigitalocean.app/?token=aa-bb-11-cc-33"}, nil)
tm.listen.EXPECT().Listen(gomock.Any()).Times(1).Return(nil)

tc := config.Doit.(*doctl.TestConfig)
tc.ListenFn = func(url *url.URL, token string, schemaFunc listen.SchemaFunc, out io.Writer, in <-chan []byte) listen.ListenerService {
assert.Equal(t, "aa-bb-11-cc-33", token)
assert.Equal(t, "wss://proxy-apps-prod-ams3-001.ondigitalocean.app/?token=aa-bb-11-cc-33", url.String())
return tm.listen
}

config.Args = append(config.Args, appName, component)
config.Doit.Set(config.NS, doctl.ArgAppDeployment, "")
config.Doit.Set(config.NS, doctl.ArgAppLogType, typeStr)
config.Doit.Set(config.NS, doctl.ArgAppLogFollow, true)
config.Doit.Set(config.NS, doctl.ArgAppLogTail, 1)

err := RunAppsGetLogs(config)
require.NoError(t, err)
})
}
}

func TestRunAppsGetLogsWithAppNameAndDeploymentID(t *testing.T) {
appName := "test-app"
component := "service"

testApp := &godo.App{
ID: uuid.New().String(),
Spec: &testAppSpec,
ActiveDeployment: &godo.Deployment{
ID: uuid.New().String(),
Spec: &testAppSpec,
},
}

types := map[string]godo.AppLogType{
"build": godo.AppLogTypeBuild,
"deploy": godo.AppLogTypeDeploy,
"run": godo.AppLogTypeRun,
}

for typeStr, logType := range types {
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
tm.apps.EXPECT().Find(appName).Times(1).Return(testApp, nil)
tm.apps.EXPECT().GetLogs(testApp.ID, testApp.ActiveDeployment.ID, component, logType, true, 1).Times(1).Return(&godo.AppLogs{LiveURL: "https://proxy-apps-prod-ams3-001.ondigitalocean.app/?token=aa-bb-11-cc-33"}, nil)
tm.listen.EXPECT().Listen(gomock.Any()).Times(1).Return(nil)

tc := config.Doit.(*doctl.TestConfig)
tc.ListenFn = func(url *url.URL, token string, schemaFunc listen.SchemaFunc, out io.Writer, in <-chan []byte) listen.ListenerService {
assert.Equal(t, "aa-bb-11-cc-33", token)
assert.Equal(t, "wss://proxy-apps-prod-ams3-001.ondigitalocean.app/?token=aa-bb-11-cc-33", url.String())
return tm.listen
}

config.Args = append(config.Args, appName, component)
config.Doit.Set(config.NS, doctl.ArgAppDeployment, testApp.ActiveDeployment.ID)
config.Doit.Set(config.NS, doctl.ArgAppLogType, typeStr)
config.Doit.Set(config.NS, doctl.ArgAppLogFollow, true)
config.Doit.Set(config.NS, doctl.ArgAppLogTail, 1)

err := RunAppsGetLogs(config)
require.NoError(t, err)
})
}
}

func TestRunAppsConsole(t *testing.T) {
appID := uuid.New().String()
deploymentID := uuid.New().String()
Expand Down
24 changes: 24 additions & 0 deletions do/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ package do

import (
"context"
"fmt"

"github.com/digitalocean/godo"
"github.com/google/uuid"
)

// AppsService is the interface that wraps godo AppsService.
type AppsService interface {
Create(req *godo.AppCreateRequest) (*godo.App, error)
Find(appRef string) (*godo.App, error)
Get(appID string) (*godo.App, error)
List(withProjects bool) ([]*godo.App, error)
Update(appID string, req *godo.AppUpdateRequest) (*godo.App, error)
Expand Down Expand Up @@ -74,11 +77,32 @@ func (s *appsService) Create(req *godo.AppCreateRequest) (*godo.App, error) {
return app, nil
}

func (s *appsService) Find(appRef string) (*godo.App, error) {
_, err := uuid.Parse(appRef)
if err == nil {
return s.Get(appRef)
}

apps, err := s.List(false)
if err != nil {
return nil, err
}

for _, app := range apps {
if app.Spec.Name == appRef {
return app, nil
}
}

return nil, fmt.Errorf("Cannot find app %s", appRef)
}

func (s *appsService) Get(appID string) (*godo.App, error) {
app, _, err := s.client.Apps.Get(s.ctx, appID)
if err != nil {
return nil, err
}

return app, 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.

0 comments on commit 45cd88d

Please sign in to comment.