Repository: digitalocean/doctl
Pull request #1289 (2022-10-20 16:57:07)

Main incorporation (deja vu all over again)
There was a priority bug fix on main that affected serverless and this crossed with my previous update of the feature branch.   So, I'm doing this one more conflict resolution merge from main to feature/serverless.



Patch:
diff --git a/commands/namespaces.go b/commands/namespaces.go
index 7b91fc3b..a496e779 100644
--- a/commands/namespaces.go
+++ b/commands/namespaces.go
@@ -95,7 +95,7 @@ func RunNamespacesCreate(c *CmdConfig) error {
 	if !uniq {
 		return fmt.Errorf("you are using  label '%s' for another namespace; labels should be unique", label)
 	}
-	if !skipConnect && ss.CheckServerlessStatus(hashAccessToken(c)) == do.ErrServerlessNotInstalled {
+	if !skipConnect && ss.CheckServerlessStatus() == do.ErrServerlessNotInstalled {
 		skipConnect = true
 		fmt.Fprintln(c.Out, "Warning: namespace will be created but not connected (serverless software is not installed)")
 	}
diff --git a/commands/serverless.go b/commands/serverless.go
index 44fb43a7..8c69e2de 100644
--- a/commands/serverless.go
+++ b/commands/serverless.go
@@ -148,7 +148,7 @@ func RunServerlessInstall(c *CmdConfig) error {
 		}
 		credsLeafDir = hashAccessToken(c)
 		serverless = c.Serverless()
-		status = serverless.CheckServerlessStatus(credsLeafDir)
+		status = serverless.CheckServerlessStatus()
 	}
 	switch status {
 	case nil:
@@ -170,7 +170,7 @@ func RunServerlessInstall(c *CmdConfig) error {
 func RunServerlessUpgrade(c *CmdConfig) error {
 	credsLeafDir := hashAccessToken(c)
 	serverless := c.Serverless()
-	status := serverless.CheckServerlessStatus(credsLeafDir)
+	status := serverless.CheckServerlessStatus()
 	switch status {
 	case nil:
 		fmt.Fprintln(c.Out, "Serverless support is already installed at an appropriate version.  No action needed.")
@@ -188,7 +188,7 @@ func RunServerlessUpgrade(c *CmdConfig) error {
 
 // RunServerlessUninstall removes the serverless support and any stored credentials
 func RunServerlessUninstall(c *CmdConfig) error {
-	err := c.Serverless().CheckServerlessStatus(hashAccessToken(c))
+	err := c.Serverless().CheckServerlessStatus()
 	if err == do.ErrServerlessNotInstalled {
 		return errors.New("Nothing to uninstall: no serverless support was found")
 	}
@@ -229,7 +229,7 @@ func RunServerlessConnect(c *CmdConfig) error {
 	}
 
 	// Non-standard check for the connect command (only): it's ok to not be connected.
-	err = sls.CheckServerlessStatus(hashAccessToken(c))
+	err = sls.CheckServerlessStatus()
 	if err != nil && err != do.ErrServerlessNotConnected {
 		return err
 	}
@@ -326,7 +326,7 @@ func finishConnecting(sls do.ServerlessService, creds do.ServerlessCredentials,
 // RunServerlessStatus gives a report on the status of the serverless (installed, up to date, connected)
 func RunServerlessStatus(c *CmdConfig) error {
 	sls := c.Serverless()
-	status := sls.CheckServerlessStatus(hashAccessToken(c))
+	status := sls.CheckServerlessStatus()
 	if status == do.ErrServerlessNotInstalled {
 		return status
 	}
diff --git a/commands/serverless_util.go b/commands/serverless_util.go
index b0869e5b..716df037 100644
--- a/commands/serverless_util.go
+++ b/commands/serverless_util.go
@@ -32,7 +32,7 @@ const (
 // ServerlessExec executes a serverless command
 func ServerlessExec(c *CmdConfig, command string, args ...string) (do.ServerlessOutput, error) {
 	serverless := c.Serverless()
-	err := serverless.CheckServerlessStatus(hashAccessToken(c))
+	err := serverless.CheckServerlessStatus()
 	if err != nil {
 		return do.ServerlessOutput{}, err
 	}
@@ -51,7 +51,7 @@ func serverlessExecNoCheck(serverless do.ServerlessService, command string, args
 // Sets up the arguments and (especially) the flags for the actual call
 func RunServerlessExec(command string, c *CmdConfig, booleanFlags []string, stringFlags []string) (do.ServerlessOutput, error) {
 	serverless := c.Serverless()
-	err := serverless.CheckServerlessStatus(hashAccessToken(c))
+	err := serverless.CheckServerlessStatus()
 	if err != nil {
 		return do.ServerlessOutput{}, err
 	}
@@ -68,7 +68,7 @@ func RunServerlessExec(command string, c *CmdConfig, booleanFlags []string, stri
 // RunServerlessExecStreaming is like RunServerlessExec but assumes that output will not be captured and can be streamed.
 func RunServerlessExecStreaming(command string, c *CmdConfig, booleanFlags []string, stringFlags []string) error {
 	serverless := c.Serverless()
-	err := serverless.CheckServerlessStatus(hashAccessToken(c))
+	err := serverless.CheckServerlessStatus()
 	if err != nil {
 		return err
 	}
diff --git a/do/mocks/ServerlessService.go b/do/mocks/ServerlessService.go
index ca8c9014..d56985fb 100644
--- a/do/mocks/ServerlessService.go
+++ b/do/mocks/ServerlessService.go
@@ -38,17 +38,17 @@ func (m *MockServerlessService) EXPECT() *MockServerlessServiceMockRecorder {
 }
 
 // CheckServerlessStatus mocks base method.
-func (m *MockServerlessService) CheckServerlessStatus(arg0 string) error {
+func (m *MockServerlessService) CheckServerlessStatus() error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CheckServerlessStatus", arg0)
+	ret := m.ctrl.Call(m, "CheckServerlessStatus")
 	ret0, _ := ret[0].(error)
 	return ret0
 }
 
 // CheckServerlessStatus indicates an expected call of CheckServerlessStatus.
-func (mr *MockServerlessServiceMockRecorder) CheckServerlessStatus(arg0 interface{}) *gomock.Call {
+func (mr *MockServerlessServiceMockRecorder) CheckServerlessStatus() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckServerlessStatus", reflect.TypeOf((*MockServerlessService)(nil).CheckServerlessStatus), arg0)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckServerlessStatus", reflect.TypeOf((*MockServerlessService)(nil).CheckServerlessStatus))
 }
 
 // Cmd mocks base method.
diff --git a/do/serverless.go b/do/serverless.go
index f49bd234..fde815f7 100644
--- a/do/serverless.go
+++ b/do/serverless.go
@@ -215,7 +215,7 @@ type ServerlessService interface {
 	WriteCredentials(ServerlessCredentials) error
 	ReadCredentials() (ServerlessCredentials, error)
 	GetHostInfo(string) (ServerlessHostInfo, error)
-	CheckServerlessStatus(string) error
+	CheckServerlessStatus() error
 	InstallServerless(string, bool) error
 	GetFunction(string, bool) (whisk.Action, []FunctionParameter, error)
 	ListFunctions(string, int, int) ([]whisk.Action, error)
@@ -350,7 +350,7 @@ func initWhisk(s *serverlessService) error {
 	if s.owClient != nil {
 		return nil
 	}
-	err := s.CheckServerlessStatus(HashAccessToken(s.accessToken))
+	err := s.CheckServerlessStatus()
 	if err != nil {
 		return err
 	}
@@ -368,7 +368,7 @@ func initWhisk(s *serverlessService) error {
 	return nil
 }
 
-func (s *serverlessService) CheckServerlessStatus(leafCredsDir string) error {
+func (s *serverlessService) CheckServerlessStatus() error {
 	_, err := os.Stat(s.serverlessDir)
 	if os.IsNotExist(err) {
 		return ErrServerlessNotInstalled
@@ -376,7 +376,7 @@ func (s *serverlessService) CheckServerlessStatus(leafCredsDir string) error {
 	if !serverlessUptodate(s.serverlessDir) {
 		return ErrServerlessNeedsUpgrade
 	}
-	if !isServerlessConnected(leafCredsDir, s.serverlessDir) {
+	if !isServerlessConnected(s.credsDir) {
 		return ErrServerlessNotConnected
 	}
 	return nil
@@ -892,7 +892,7 @@ func (s *serverlessService) WriteProject(project ServerlessProject) (string, err
 // of that function are listed.  If 'fcn' is empty all triggers are listed.
 func (s *serverlessService) ListTriggers(ctx context.Context, fcn string) ([]ServerlessTrigger, error) {
 	empty := []ServerlessTrigger{}
-	err := s.CheckServerlessStatus(HashAccessToken(s.accessToken))
+	err := s.CheckServerlessStatus()
 	if err != nil {
 		return empty, err
 	}
@@ -946,7 +946,7 @@ func fixBaseDate(trigger ServerlessTrigger) ServerlessTrigger {
 // GetTrigger gets the contents of a trigger for display
 func (s *serverlessService) GetTrigger(ctx context.Context, name string) (ServerlessTrigger, error) {
 	empty := ServerlessTrigger{}
-	err := s.CheckServerlessStatus(HashAccessToken(s.accessToken))
+	err := s.CheckServerlessStatus()
 	if err != nil {
 		return empty, err
 	}
@@ -1111,11 +1111,12 @@ func (s *serverlessService) ReadCredentials() (ServerlessCredentials, error) {
 // asking the plugin to validate credentials), so the test is not foolproof.
 // It merely tests whether a credentials directory has been created for the
 // current doctl access token and appears to have a credentials.json in it.
-func isServerlessConnected(leafCredsDir string, serverlessDir string) bool {
-	creds := GetCredentialDirectory(leafCredsDir, serverlessDir)
-	credsFile := filepath.Join(creds, CredentialsFile)
+func isServerlessConnected(credsDir string) bool {
+	credsFile := filepath.Join(credsDir, CredentialsFile)
 	_, err := os.Stat(credsFile)
-	return !os.IsNotExist(err)
+	// We used to test specifically for "not found" here but in fact any error is enough to
+	// prevent connections from working.
+	return err == nil
 }
 
 // serverlessUptodate answers whether the installed version of the serverless support is at least


Test patch:
diff --git a/commands/activations_test.go b/commands/activations_test.go
index 4301980c..bf570a9f 100644
--- a/commands/activations_test.go
+++ b/commands/activations_test.go
@@ -505,7 +505,7 @@ func TestActivationsLogs(t *testing.T) {
 					}
 				}
 
-				tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).MinTimes(1).Return(nil)
+				tm.serverless.EXPECT().CheckServerlessStatus().MinTimes(1).Return(nil)
 				if tt.expectStream {
 					expectedArgs := append([]string{"activation/logs"}, tt.expectedNimArgs...)
 					tm.serverless.EXPECT().Cmd("nocapture", expectedArgs).Return(fakeCmd, nil)
diff --git a/commands/namespaces_test.go b/commands/namespaces_test.go
index 08ef7427..46deccae 100644
--- a/commands/namespaces_test.go
+++ b/commands/namespaces_test.go
@@ -114,7 +114,7 @@ func TestNamespacesCreate(t *testing.T) {
 					tm.serverless.EXPECT().ListNamespaces(ctx).Return(initialList, nil)
 				}
 				if tt.willConnect {
-					tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).Return(nil)
+					tm.serverless.EXPECT().CheckServerlessStatus().Return(nil)
 					creds := do.ServerlessCredentials{Namespace: "hello", APIHost: "https://api.example.com"}
 					tm.serverless.EXPECT().WriteCredentials(creds).Return(nil)
 				}
diff --git a/commands/serverless_test.go b/commands/serverless_test.go
index bcdc39e7..baa352d4 100644
--- a/commands/serverless_test.go
+++ b/commands/serverless_test.go
@@ -100,7 +100,7 @@ func TestServerlessConnect(t *testing.T) {
 				nsResponse := do.NamespaceListResponse{Namespaces: tt.namespaceList}
 				creds := do.ServerlessCredentials{Namespace: "ns1", APIHost: "https://api.example.com"}
 
-				tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).Return(do.ErrServerlessNotConnected)
+				tm.serverless.EXPECT().CheckServerlessStatus().Return(do.ErrServerlessNotConnected)
 				ctx := context.TODO()
 				tm.serverless.EXPECT().ListNamespaces(ctx).Return(nsResponse, nil)
 				if tt.expectedError == nil {
@@ -128,7 +128,7 @@ func TestServerlessStatusWhenConnected(t *testing.T) {
 		buf := &bytes.Buffer{}
 		config.Out = buf
 
-		tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).MinTimes(1).Return(nil)
+		tm.serverless.EXPECT().CheckServerlessStatus().MinTimes(1).Return(nil)
 		tm.serverless.EXPECT().ReadCredentials().Return(do.ServerlessCredentials{
 			APIHost:   "https://api.example.com",
 			Namespace: "hello",
@@ -182,7 +182,7 @@ func TestServerlessStatusWithLanguages(t *testing.T) {
     go:1.22 (go:default)
 `
 
-		tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).MinTimes(1).Return(nil)
+		tm.serverless.EXPECT().CheckServerlessStatus().MinTimes(1).Return(nil)
 		tm.serverless.EXPECT().ReadCredentials().Return(do.ServerlessCredentials{
 			APIHost:   "https://api.example.com",
 			Namespace: "hello",
@@ -206,7 +206,7 @@ func TestServerlessStatusWithLanguages(t *testing.T) {
 func TestServerlessStatusWhenNotConnected(t *testing.T) {
 	withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
 
-		tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).MinTimes(1).Return(nil)
+		tm.serverless.EXPECT().CheckServerlessStatus().MinTimes(1).Return(nil)
 		tm.serverless.EXPECT().ReadCredentials().Return(do.ServerlessCredentials{
 			APIHost:   "https://api.example.com",
 			Namespace: "hello",
@@ -228,7 +228,7 @@ func TestServerlessStatusWhenNotConnected(t *testing.T) {
 
 func TestServerlessStatusWhenNotInstalled(t *testing.T) {
 	withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
-		tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).Return(do.ErrServerlessNotInstalled)
+		tm.serverless.EXPECT().CheckServerlessStatus().Return(do.ErrServerlessNotInstalled)
 
 		err := RunServerlessStatus(config)
 
@@ -239,7 +239,7 @@ func TestServerlessStatusWhenNotInstalled(t *testing.T) {
 
 func TestServerlessStatusWhenNotUpToDate(t *testing.T) {
 	withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
-		tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).Return(do.ErrServerlessNeedsUpgrade)
+		tm.serverless.EXPECT().CheckServerlessStatus().Return(do.ErrServerlessNeedsUpgrade)
 
 		err := RunServerlessStatus(config)
 
@@ -254,7 +254,7 @@ func TestServerlessInstallFromScratch(t *testing.T) {
 		config.Out = buf
 
 		credsToken := hashAccessToken(config)
-		tm.serverless.EXPECT().CheckServerlessStatus(credsToken).Return(do.ErrServerlessNotInstalled)
+		tm.serverless.EXPECT().CheckServerlessStatus().Return(do.ErrServerlessNotInstalled)
 		tm.serverless.EXPECT().InstallServerless(credsToken, false).Return(nil)
 
 		err := RunServerlessInstall(config)
@@ -267,8 +267,7 @@ func TestServerlessInstallWhenInstalledNotCurrent(t *testing.T) {
 		buf := &bytes.Buffer{}
 		config.Out = buf
 
-		credsToken := hashAccessToken(config)
-		tm.serverless.EXPECT().CheckServerlessStatus(credsToken).Return(do.ErrServerlessNeedsUpgrade)
+		tm.serverless.EXPECT().CheckServerlessStatus().Return(do.ErrServerlessNeedsUpgrade)
 
 		err := RunServerlessInstall(config)
 		require.NoError(t, err)
@@ -281,7 +280,7 @@ func TestServerlessInstallWhenInstalledAndCurrent(t *testing.T) {
 		buf := &bytes.Buffer{}
 		config.Out = buf
 
-		tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).Return(nil)
+		tm.serverless.EXPECT().CheckServerlessStatus().Return(nil)
 
 		err := RunServerlessInstall(config)
 		require.NoError(t, err)
@@ -294,8 +293,7 @@ func TestServerlessUpgradeWhenNotInstalled(t *testing.T) {
 		buf := &bytes.Buffer{}
 		config.Out = buf
 
-		credsToken := hashAccessToken(config)
-		tm.serverless.EXPECT().CheckServerlessStatus(credsToken).Return(do.ErrServerlessNotInstalled)
+		tm.serverless.EXPECT().CheckServerlessStatus().Return(do.ErrServerlessNotInstalled)
 
 		err := RunServerlessUpgrade(config)
 		require.NoError(t, err)
@@ -308,7 +306,7 @@ func TestServerlessUpgradeWhenInstalledAndCurrent(t *testing.T) {
 		buf := &bytes.Buffer{}
 		config.Out = buf
 
-		tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).Return(nil)
+		tm.serverless.EXPECT().CheckServerlessStatus().Return(nil)
 
 		err := RunServerlessUpgrade(config)
 		require.NoError(t, err)
@@ -322,7 +320,7 @@ func TestServerlessUpgradeWhenInstalledAndNotCurrent(t *testing.T) {
 		config.Out = buf
 
 		credsToken := hashAccessToken(config)
-		tm.serverless.EXPECT().CheckServerlessStatus(credsToken).Return(do.ErrServerlessNeedsUpgrade)
+		tm.serverless.EXPECT().CheckServerlessStatus().Return(do.ErrServerlessNeedsUpgrade)
 		tm.serverless.EXPECT().InstallServerless(credsToken, true).Return(nil)
 
 		err := RunServerlessUpgrade(config)
@@ -383,7 +381,7 @@ func TestServerlessInit(t *testing.T) {
 					}
 				}
 
-				tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).MinTimes(1).Return(nil)
+				tm.serverless.EXPECT().CheckServerlessStatus().MinTimes(1).Return(nil)
 				tm.serverless.EXPECT().Cmd("project/create", tt.expectedNimArgs).Return(fakeCmd, nil)
 				tm.serverless.EXPECT().Exec(fakeCmd).Return(do.ServerlessOutput{
 					Entity: tt.out,
@@ -447,7 +445,7 @@ func TestServerlessDeploy(t *testing.T) {
 					}
 				}
 
-				tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).MinTimes(1).Return(nil)
+				tm.serverless.EXPECT().CheckServerlessStatus().MinTimes(1).Return(nil)
 				tm.serverless.EXPECT().Cmd("project/deploy", tt.expectedNimArgs).Return(fakeCmd, nil)
 				tm.serverless.EXPECT().Exec(fakeCmd).Return(do.ServerlessOutput{}, nil)
 
@@ -583,7 +581,7 @@ func TestServerlessUndeploy(t *testing.T) {
 				}
 
 				if tt.expectedError == nil && len(tt.expectedNimCmds) > 0 {
-					tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).MinTimes(1).Return(nil)
+					tm.serverless.EXPECT().CheckServerlessStatus().MinTimes(1).Return(nil)
 				}
 				if tt.expectTriggerList {
 					tm.serverless.EXPECT().ListTriggers(context.TODO(), "").Return(cannedTriggerList, nil)
@@ -643,7 +641,7 @@ func TestServerlessWatch(t *testing.T) {
 					}
 				}
 
-				tm.serverless.EXPECT().CheckServerlessStatus(hashAccessToken(config)).MinTimes(1).Return(nil)
+				tm.serverless.EXPECT().CheckServerlessStatus().MinTimes(1).Return(nil)
 				tm.serverless.EXPECT().Cmd("nocapture", tt.expectedNimArgs).Return(fakeCmd, nil)
 				tm.serverless.EXPECT().Stream(fakeCmd).Return(nil)