Repository: supabase/cli
Pull request #580 (2022-11-04 05:31:19)

fix: handle signals in organization list
## What kind of change does this PR introduce?

Bug fix

## What is the current behavior?

cancellation not propagated

## What is the new behavior?

- handle signals
- handle nil response

## Additional context

Add any other context or screenshots.


coveralls: ## Pull Request Test Coverage Report for [Build 3391472654](https://coveralls.io/builds/53903817)

* **5** of **10**   **(50.0%)**  changed or added relevant lines in **3** files are covered.
* **8** unchanged lines in **2** files lost coverage.
* Overall coverage decreased (**-0.3%**) to **49.113%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [cmd/orgs.go](https://coveralls.io/builds/53903817/source?filename=cmd%2Forgs.go#L24) | 0 | 2 | 0.0%
| [cmd/projects.go](https://coveralls.io/builds/53903817/source?filename=cmd%2Fprojects.go#L107) | 0 | 3 | 0.0%
<!-- | **Total:** | **5** | **10** | **50.0%** | -->

|  Files with Coverage Reduction | New Missed Lines | % |
| :-----|--------------|--: |
| [cmd/orgs.go](https://coveralls.io/builds/53903817/source?filename=cmd%2Forgs.go#L26) | 1 | 50.0% |
| [internal/utils/misc.go](https://coveralls.io/builds/53903817/source?filename=internal%2Futils%2Fmisc.go#L393) | 7 | 67.67% |
<!-- | **Total:** | **8** |  | -->

|  Totals | [![Coverage Status](https://coveralls.io/builds/53903817/badge)](https://coveralls.io/builds/53903817) |
| :-- | --: |
| Change from base [Build 3390502437](https://coveralls.io/builds/53900302): |  -0.3% |
| Covered Lines: | 2659 |
| Relevant Lines: | 5414 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/cmd/orgs.go b/cmd/orgs.go
index 0502add4..6b8ec627 100644
--- a/cmd/orgs.go
+++ b/cmd/orgs.go
@@ -1,6 +1,9 @@
 package cmd
 
 import (
+	"os"
+	"os/signal"
+
 	"github.com/spf13/afero"
 	"github.com/spf13/cobra"
 	"github.com/supabase/cli/internal/orgs/list"
@@ -18,7 +21,8 @@ var (
 		Short: "List all organizations",
 		Long:  "List all organizations the logged-in user belongs.",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return list.Run(afero.NewOsFs())
+			ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt)
+			return list.Run(ctx, afero.NewOsFs())
 		},
 	}
 )
diff --git a/cmd/projects.go b/cmd/projects.go
index baeee21c..dba2b7aa 100644
--- a/cmd/projects.go
+++ b/cmd/projects.go
@@ -1,6 +1,7 @@
 package cmd
 
 import (
+	"errors"
 	"fmt"
 	"os"
 	"os/signal"
@@ -103,6 +104,9 @@ func PromptCreateFlags(cmd *cobra.Command) error {
 		if err != nil {
 			return err
 		}
+		if resp.JSON200 == nil {
+			return errors.New("Unexpected error retrieving organizations: " + string(resp.Body))
+		}
 		items := make([]utils.PromptItem, len(*resp.JSON200))
 		for i, org := range *resp.JSON200 {
 			items[i] = utils.PromptItem{Summary: org.Name, Details: org.Id}
diff --git a/internal/orgs/list/list.go b/internal/orgs/list/list.go
index 8eda9d2a..b0054ac8 100644
--- a/internal/orgs/list/list.go
+++ b/internal/orgs/list/list.go
@@ -1,11 +1,9 @@
 package list
 
 import (
-	"encoding/json"
+	"context"
 	"errors"
 	"fmt"
-	"io"
-	"net/http"
 	"strings"
 
 	"github.com/charmbracelet/glamour"
@@ -18,46 +16,20 @@ type Organization struct {
 	Name string `json:"name"`
 }
 
-func Run(fsys afero.Fs) error {
-	accessToken, err := utils.LoadAccessTokenFS(fsys)
+func Run(ctx context.Context, fsys afero.Fs) error {
+	resp, err := utils.GetSupabase().GetOrganizationsWithResponse(ctx)
 	if err != nil {
 		return err
 	}
 
-	req, err := http.NewRequest("GET", utils.GetSupabaseAPIHost()+"/v1/organizations", nil)
-	if err != nil {
-		return err
-	}
-	req.Header.Add("Authorization", "Bearer "+string(accessToken))
-	resp, err := http.DefaultClient.Do(req)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		body, err := io.ReadAll(resp.Body)
-		if err != nil {
-			return fmt.Errorf("Unexpected error retrieving organizations: %w", err)
-		}
-
-		return errors.New("Unexpected error retrieving organizations: " + string(body))
-	}
-
-	body, err := io.ReadAll(resp.Body)
-	if err != nil {
-		return err
-	}
-
-	var orgs []Organization
-	if err := json.Unmarshal(body, &orgs); err != nil {
-		return err
+	if resp.JSON200 == nil {
+		return errors.New("Unexpected error retrieving organizations: " + string(resp.Body))
 	}
 
 	table := `|ID|NAME|
 |-|-|
 `
-	for _, org := range orgs {
+	for _, org := range *resp.JSON200 {
 		table += fmt.Sprintf("|`%s`|`%s`|\n", org.Id, strings.ReplaceAll(org.Name, "|", "\\|"))
 	}
 


Test patch:
diff --git a/internal/orgs/list/list_test.go b/internal/orgs/list/list_test.go
index 5c225f91..a06af2fa 100644
--- a/internal/orgs/list/list_test.go
+++ b/internal/orgs/list/list_test.go
@@ -1,6 +1,7 @@
 package list
 
 import (
+	"context"
 	"errors"
 	"testing"
 
@@ -29,13 +30,13 @@ func TestOrganizationListCommand(t *testing.T) {
 				},
 			})
 		// Run test
-		assert.NoError(t, Run(fsys))
+		assert.NoError(t, Run(context.Background(), fsys))
 		// Validate api
 		assert.Empty(t, apitest.ListUnmatchedRequests())
 	})
 
 	t.Run("throws error on failure to load token", func(t *testing.T) {
-		assert.Error(t, Run(afero.NewMemMapFs()))
+		assert.Error(t, Run(context.Background(), afero.NewMemMapFs()))
 	})
 
 	t.Run("throws error on network error", func(t *testing.T) {
@@ -50,7 +51,7 @@ func TestOrganizationListCommand(t *testing.T) {
 			Get("/v1/organizations").
 			ReplyError(errors.New("network error"))
 		// Run test
-		assert.Error(t, Run(fsys))
+		assert.Error(t, Run(context.Background(), fsys))
 		// Validate api
 		assert.Empty(t, apitest.ListUnmatchedRequests())
 	})
@@ -68,7 +69,7 @@ func TestOrganizationListCommand(t *testing.T) {
 			Reply(500).
 			JSON(map[string]string{"message": "unavailable"})
 		// Run test
-		assert.Error(t, Run(fsys))
+		assert.Error(t, Run(context.Background(), fsys))
 		// Validate api
 		assert.Empty(t, apitest.ListUnmatchedRequests())
 	})
@@ -86,7 +87,7 @@ func TestOrganizationListCommand(t *testing.T) {
 			Reply(200).
 			JSON(map[string]string{})
 		// Run test
-		assert.Error(t, Run(fsys))
+		assert.Error(t, Run(context.Background(), fsys))
 		// Validate api
 		assert.Empty(t, apitest.ListUnmatchedRequests())
 	})