Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions internal/link/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package link
import (
"context"
"fmt"
"net/http"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -238,24 +239,31 @@ func updatePoolerConfig(config api.SupavisorConfigResponse) {
}
}

var errProjectPaused = errors.New("project is paused")

func checkRemoteProjectStatus(ctx context.Context, projectRef string) error {
resp, err := utils.GetSupabase().V1GetProjectWithResponse(ctx, projectRef)
if err != nil {
return errors.Errorf("failed to retrieve remote project status: %w", err)
}
if resp.JSON200 == nil {
switch resp.StatusCode() {
case http.StatusNotFound:
// Ignore not found error to support linking branch projects
return nil
case http.StatusOK:
// resp.JSON200 is not nil, proceed
default:
return errors.New("Unexpected error retrieving remote project status: " + string(resp.Body))
}

switch resp.JSON200.Status {
case api.V1ProjectResponseStatusINACTIVE:
utils.CmdSuggestion = fmt.Sprintf("An admin must unpause it from the Supabase dashboard at %s", utils.Aqua(fmt.Sprintf("%s/project/%s", utils.GetSupabaseDashboardURL(), projectRef)))
return errors.New("project is paused")
return errors.New(errProjectPaused)
case api.V1ProjectResponseStatusACTIVEHEALTHY:
// Project is in the desired state, do nothing
return nil
default:
fmt.Fprintf(os.Stderr, "%s: Project status is %s instead of Active Healthy. Some operations might fail.\n", utils.Yellow("Warning"), resp.JSON200.Status)
fmt.Fprintf(os.Stderr, "%s: Project status is %s instead of Active Healthy. Some operations might fail.\n", utils.Yellow("WARNING"), resp.JSON200.Status)
}

return nil
Expand Down
28 changes: 23 additions & 5 deletions internal/link/link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package link
import (
"context"
"errors"
"net/http"
"testing"

"github.com/h2non/gock"
Expand Down Expand Up @@ -209,20 +210,37 @@ func TestLinkCommand(t *testing.T) {
assert.NoError(t, err)
assert.False(t, exists)
})
}

func TestStatusCheck(t *testing.T) {
project := "test-project"

t.Run("ignores project not found", func(t *testing.T) {
// Flush pending mocks after test execution
defer gock.OffAll()
// Mock project status
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project).
Reply(http.StatusNotFound)
// Run test
err := checkRemoteProjectStatus(context.Background(), project)
// Check error
assert.NoError(t, err)
assert.Empty(t, apitest.ListUnmatchedRequests())
})

t.Run("throws error on project inactive", func(t *testing.T) {
// Setup in-memory fs
fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
// Flush pending mocks after test execution
defer gock.OffAll()
// Mock project status
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project).
Reply(200).
Reply(http.StatusOK).
JSON(api.V1ProjectResponse{Status: api.V1ProjectResponseStatusINACTIVE})
// Run test
err := Run(context.Background(), project, fsys)
err := checkRemoteProjectStatus(context.Background(), project)
// Check error
assert.ErrorContains(t, err, "project is paused")
assert.ErrorIs(t, err, errProjectPaused)
assert.Empty(t, apitest.ListUnmatchedRequests())
})
}
Expand Down