Skip to content

Commit af77b82

Browse files
committed
feat: implement command to create organization
1 parent 0fc9fd0 commit af77b82

File tree

5 files changed

+114
-44
lines changed

5 files changed

+114
-44
lines changed

cmd/orgs.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package cmd
22

33
import (
4-
"github.com/spf13/afero"
54
"github.com/spf13/cobra"
5+
"github.com/supabase/cli/internal/orgs/create"
66
"github.com/supabase/cli/internal/orgs/list"
77
)
88

@@ -18,12 +18,23 @@ var (
1818
Short: "List all organizations",
1919
Long: "List all organizations the logged-in user belongs.",
2020
RunE: func(cmd *cobra.Command, args []string) error {
21-
return list.Run(cmd.Context(), afero.NewOsFs())
21+
return list.Run(cmd.Context())
22+
},
23+
}
24+
25+
orgsCreateCmd = &cobra.Command{
26+
Use: "create",
27+
Short: "Create an organization",
28+
Long: "Create an organization for the logged-in user.",
29+
Args: cobra.ExactArgs(1),
30+
RunE: func(cmd *cobra.Command, args []string) error {
31+
return create.Run(cmd.Context(), args[0])
2232
},
2333
}
2434
)
2535

2636
func init() {
2737
orgsCmd.AddCommand(orgsListCmd)
38+
orgsCmd.AddCommand(orgsCreateCmd)
2839
rootCmd.AddCommand(orgsCmd)
2940
}

internal/orgs/create/create.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package create
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
8+
"github.com/supabase/cli/internal/utils"
9+
"github.com/supabase/cli/pkg/api"
10+
)
11+
12+
func Run(ctx context.Context, name string) error {
13+
resp, err := utils.GetSupabase().CreateOrganizationWithResponse(ctx, api.CreateOrganizationJSONRequestBody{Name: name})
14+
if err != nil {
15+
return err
16+
}
17+
18+
if resp.JSON201 == nil {
19+
return errors.New("Unexpected error creating organization: " + string(resp.Body))
20+
}
21+
22+
fmt.Println("Created organization:", resp.JSON201.Id)
23+
return nil
24+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package create
2+
3+
import (
4+
"context"
5+
"errors"
6+
"net/http"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/supabase/cli/internal/testing/apitest"
11+
"github.com/supabase/cli/internal/utils"
12+
"github.com/supabase/cli/pkg/api"
13+
"gopkg.in/h2non/gock.v1"
14+
)
15+
16+
func TestOrganizationCreateCommand(t *testing.T) {
17+
orgName := "Test Organization"
18+
19+
t.Run("create an organization", func(t *testing.T) {
20+
// Setup valid access token
21+
token := apitest.RandomAccessToken(t)
22+
t.Setenv("SUPABASE_ACCESS_TOKEN", string(token))
23+
// Flush pending mocks after test execution
24+
defer gock.OffAll()
25+
gock.New(utils.DefaultApiHost).
26+
Post("/v1/organizations").
27+
Reply(http.StatusCreated).
28+
JSON(api.OrganizationResponse{
29+
Id: "combined-fuchsia-lion",
30+
Name: orgName,
31+
})
32+
// Run test
33+
assert.NoError(t, Run(context.Background(), orgName))
34+
// Validate api
35+
assert.Empty(t, apitest.ListUnmatchedRequests())
36+
})
37+
38+
t.Run("throws error on network error", func(t *testing.T) {
39+
// Setup valid access token
40+
token := apitest.RandomAccessToken(t)
41+
t.Setenv("SUPABASE_ACCESS_TOKEN", string(token))
42+
// Flush pending mocks after test execution
43+
defer gock.OffAll()
44+
gock.New(utils.DefaultApiHost).
45+
Post("/v1/organizations").
46+
ReplyError(errors.New("network error"))
47+
// Run test
48+
assert.Error(t, Run(context.Background(), orgName))
49+
// Validate api
50+
assert.Empty(t, apitest.ListUnmatchedRequests())
51+
})
52+
53+
t.Run("throws error on server unavailable", func(t *testing.T) {
54+
// Setup valid access token
55+
token := apitest.RandomAccessToken(t)
56+
t.Setenv("SUPABASE_ACCESS_TOKEN", string(token))
57+
// Flush pending mocks after test execution
58+
defer gock.OffAll()
59+
gock.New(utils.DefaultApiHost).
60+
Post("/v1/organizations").
61+
Reply(http.StatusServiceUnavailable).
62+
JSON(map[string]string{"message": "unavailable"})
63+
// Run test
64+
assert.Error(t, Run(context.Background(), orgName))
65+
// Validate api
66+
assert.Empty(t, apitest.ListUnmatchedRequests())
67+
})
68+
}

internal/orgs/list/list.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,11 @@ import (
66
"fmt"
77
"strings"
88

9-
"github.com/spf13/afero"
109
"github.com/supabase/cli/internal/migration/list"
1110
"github.com/supabase/cli/internal/utils"
1211
)
1312

14-
type Organization struct {
15-
Id string `json:"id"`
16-
Name string `json:"name"`
17-
}
18-
19-
func Run(ctx context.Context, fsys afero.Fs) error {
13+
func Run(ctx context.Context) error {
2014
resp, err := utils.GetSupabase().GetOrganizationsWithResponse(ctx)
2115
if err != nil {
2216
return err

internal/orgs/list/list_test.go

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,39 @@ package list
33
import (
44
"context"
55
"errors"
6+
"net/http"
67
"testing"
78

8-
"github.com/spf13/afero"
99
"github.com/stretchr/testify/assert"
1010
"github.com/supabase/cli/internal/testing/apitest"
1111
"github.com/supabase/cli/internal/utils"
12+
"github.com/supabase/cli/pkg/api"
1213
"gopkg.in/h2non/gock.v1"
1314
)
1415

1516
func TestOrganizationListCommand(t *testing.T) {
1617
t.Run("lists all organizations", func(t *testing.T) {
17-
// Setup in-memory fs
18-
fsys := afero.NewMemMapFs()
1918
// Setup valid access token
2019
token := apitest.RandomAccessToken(t)
2120
t.Setenv("SUPABASE_ACCESS_TOKEN", string(token))
2221
// Flush pending mocks after test execution
2322
defer gock.OffAll()
2423
gock.New(utils.DefaultApiHost).
2524
Get("/v1/organizations").
26-
Reply(200).
27-
JSON([]Organization{
25+
Reply(http.StatusOK).
26+
JSON([]api.OrganizationResponse{
2827
{
2928
Id: "combined-fuchsia-lion",
3029
Name: "Test Organization",
3130
},
3231
})
3332
// Run test
34-
assert.NoError(t, Run(context.Background(), fsys))
33+
assert.NoError(t, Run(context.Background()))
3534
// Validate api
3635
assert.Empty(t, apitest.ListUnmatchedRequests())
3736
})
3837

39-
t.Run("throws error on failure to load token", func(t *testing.T) {
40-
assert.Error(t, Run(context.Background(), afero.NewMemMapFs()))
41-
})
42-
4338
t.Run("throws error on network error", func(t *testing.T) {
44-
// Setup in-memory fs
45-
fsys := afero.NewMemMapFs()
4639
// Setup valid access token
4740
token := apitest.RandomAccessToken(t)
4841
t.Setenv("SUPABASE_ACCESS_TOKEN", string(token))
@@ -52,43 +45,23 @@ func TestOrganizationListCommand(t *testing.T) {
5245
Get("/v1/organizations").
5346
ReplyError(errors.New("network error"))
5447
// Run test
55-
assert.Error(t, Run(context.Background(), fsys))
48+
assert.Error(t, Run(context.Background()))
5649
// Validate api
5750
assert.Empty(t, apitest.ListUnmatchedRequests())
5851
})
5952

6053
t.Run("throws error on server unavailable", func(t *testing.T) {
61-
// Setup in-memory fs
62-
fsys := afero.NewMemMapFs()
6354
// Setup valid access token
6455
token := apitest.RandomAccessToken(t)
6556
t.Setenv("SUPABASE_ACCESS_TOKEN", string(token))
6657
// Flush pending mocks after test execution
6758
defer gock.OffAll()
6859
gock.New(utils.DefaultApiHost).
6960
Get("/v1/organizations").
70-
Reply(500).
61+
Reply(http.StatusServiceUnavailable).
7162
JSON(map[string]string{"message": "unavailable"})
7263
// Run test
73-
assert.Error(t, Run(context.Background(), fsys))
74-
// Validate api
75-
assert.Empty(t, apitest.ListUnmatchedRequests())
76-
})
77-
78-
t.Run("throws error on malformed json", func(t *testing.T) {
79-
// Setup in-memory fs
80-
fsys := afero.NewMemMapFs()
81-
// Setup valid access token
82-
token := apitest.RandomAccessToken(t)
83-
t.Setenv("SUPABASE_ACCESS_TOKEN", string(token))
84-
// Flush pending mocks after test execution
85-
defer gock.OffAll()
86-
gock.New(utils.DefaultApiHost).
87-
Get("/v1/organizations").
88-
Reply(200).
89-
JSON(map[string]string{})
90-
// Run test
91-
assert.Error(t, Run(context.Background(), fsys))
64+
assert.Error(t, Run(context.Background()))
9265
// Validate api
9366
assert.Empty(t, apitest.ListUnmatchedRequests())
9467
})

0 commit comments

Comments
 (0)