-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add
supabase unlink
command (#1849)
* feat: unlink * update to remove .temp and credentials based on project-ref * tests update * added mock for keyring * chore: update unit tests --------- Co-authored-by: Qiao Han <[email protected]> Co-authored-by: Han Qiao <[email protected]>
- Loading branch information
1 parent
c72e03a
commit f3f028c
Showing
3 changed files
with
130 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package cmd | ||
|
||
import ( | ||
"os" | ||
"os/signal" | ||
|
||
"github.com/spf13/afero" | ||
"github.com/spf13/cobra" | ||
"github.com/supabase/cli/internal/unlink" | ||
) | ||
|
||
var ( | ||
unlinkCmd = &cobra.Command{ | ||
GroupID: groupLocalDev, | ||
Use: "unlink", | ||
Short: "Unlink a Supabase project", | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) | ||
return unlink.Run(ctx, afero.NewOsFs()) | ||
}, | ||
} | ||
) | ||
|
||
func init() { | ||
rootCmd.AddCommand(unlinkCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package unlink | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/go-errors/errors" | ||
"github.com/spf13/afero" | ||
"github.com/supabase/cli/internal/utils" | ||
"github.com/supabase/cli/internal/utils/credentials" | ||
"github.com/supabase/cli/internal/utils/flags" | ||
"github.com/zalando/go-keyring" | ||
) | ||
|
||
func Run(ctx context.Context, fsys afero.Fs) error { | ||
projectRef, err := flags.LoadProjectRef(fsys) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Fprintln(os.Stderr, "Unlinking project:", projectRef) | ||
// Remove temp directory | ||
if err := fsys.RemoveAll(utils.TempDir); err != nil { | ||
return errors.Errorf("failed to remove temp directory: %w", err) | ||
} | ||
// Remove linked credentials | ||
if err := credentials.Delete(projectRef); err != nil && | ||
!errors.Is(err, credentials.ErrNotSupported) && | ||
!errors.Is(err, keyring.ErrNotFound) { | ||
return err | ||
} | ||
|
||
fmt.Fprintln(os.Stdout, "Finished "+utils.Aqua("supabase unlink")+".") | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package unlink | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"testing" | ||
|
||
"github.com/spf13/afero" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"github.com/supabase/cli/internal/testing/apitest" | ||
"github.com/supabase/cli/internal/utils" | ||
"github.com/supabase/cli/internal/utils/credentials" | ||
"github.com/zalando/go-keyring" | ||
) | ||
|
||
func TestUnlinkCommand(t *testing.T) { | ||
keyring.MockInit() | ||
project := apitest.RandomProjectRef() | ||
|
||
t.Run("unlinks project", func(t *testing.T) { | ||
// Setup in-memory fs | ||
fsys := afero.NewMemMapFs() | ||
require.NoError(t, afero.WriteFile(fsys, utils.ProjectRefPath, []byte(project), 0644)) | ||
// Save database password | ||
require.NoError(t, credentials.Set(project, "test")) | ||
// Run test | ||
err := Run(context.Background(), fsys) | ||
// Check error | ||
assert.NoError(t, err) | ||
// Validate file does not exist | ||
exists, err := afero.Exists(fsys, utils.ProjectRefPath) | ||
assert.NoError(t, err) | ||
assert.False(t, exists) | ||
// Check credentials does not exist | ||
_, err = credentials.Get(project) | ||
assert.ErrorIs(t, err, keyring.ErrNotFound) | ||
}) | ||
|
||
t.Run("unlinks project without credentials", func(t *testing.T) { | ||
// Setup in-memory fs | ||
fsys := afero.NewMemMapFs() | ||
require.NoError(t, afero.WriteFile(fsys, utils.ProjectRefPath, []byte(project), 0644)) | ||
// Run test | ||
err := Run(context.Background(), fsys) | ||
// Check error | ||
assert.NoError(t, err) | ||
}) | ||
|
||
t.Run("throws error if not linked", func(t *testing.T) { | ||
// Setup in-memory fs | ||
fsys := afero.NewMemMapFs() | ||
// Run test | ||
err := Run(context.Background(), fsys) | ||
// Check error | ||
assert.ErrorIs(t, err, utils.ErrNotLinked) | ||
}) | ||
|
||
t.Run("throws error on permission denied", func(t *testing.T) { | ||
// Setup in-memory fs | ||
fsys := afero.NewMemMapFs() | ||
require.NoError(t, afero.WriteFile(fsys, utils.ProjectRefPath, []byte(project), 0644)) | ||
// Run test | ||
err := Run(context.Background(), afero.NewReadOnlyFs(fsys)) | ||
// Check error | ||
assert.ErrorIs(t, err, os.ErrPermission) | ||
}) | ||
} |