Skip to content

Commit

Permalink
feat: add supabase unlink command (#1849)
Browse files Browse the repository at this point in the history
* 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
3 people authored Jan 29, 2024
1 parent c72e03a commit f3f028c
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 0 deletions.
26 changes: 26 additions & 0 deletions cmd/unlink.go
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)
}
36 changes: 36 additions & 0 deletions internal/unlink/unlink.go
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
}
68 changes: 68 additions & 0 deletions internal/unlink/unlink_test.go
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)
})
}

0 comments on commit f3f028c

Please sign in to comment.