Skip to content

Commit

Permalink
Merge branch 'develop' into avallete/feat-stop-all-projects
Browse files Browse the repository at this point in the history
  • Loading branch information
avallete authored Sep 12, 2024
2 parents 1a91c58 + 3599b8e commit 881d231
Show file tree
Hide file tree
Showing 21 changed files with 235 additions and 42 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
go-version-file: go.mod
cache: true

# Required by: internal/utils/credentials/keyring_test.go
- uses: t1m0thyj/unlock-keyring@v1
- run: |
go run gotest.tools/gotestsum -- ./... -race -v -count=1 \
-coverpkg ./cmd/...,./internal/... -coverprofile=coverage.out
Expand Down
6 changes: 6 additions & 0 deletions cmd/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,15 @@ var (
},
}

noSeed bool

dbResetCmd = &cobra.Command{
Use: "reset",
Short: "Resets the local database to current migrations",
RunE: func(cmd *cobra.Command, args []string) error {
if noSeed {
utils.Config.Db.Seed.Enabled = false
}
return reset.Run(cmd.Context(), migrationVersion, flags.DbConfig, afero.NewOsFs())
},
}
Expand Down Expand Up @@ -304,6 +309,7 @@ func init() {
resetFlags.String("db-url", "", "Resets the database specified by the connection string (must be percent-encoded).")
resetFlags.Bool("linked", false, "Resets the linked project with local migrations.")
resetFlags.Bool("local", true, "Resets the local database with local migrations.")
resetFlags.BoolVar(&noSeed, "no-seed", false, "Skip running the seed script after reset.")
dbResetCmd.MarkFlagsMutuallyExclusive("db-url", "linked", "local")
resetFlags.StringVar(&migrationVersion, "version", "", "Reset up to the specified version.")
dbCmd.AddCommand(dbResetCmd)
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ require (
github.com/charmbracelet/glamour v0.7.0
github.com/charmbracelet/lipgloss v0.12.1
github.com/containers/common v0.59.2
github.com/danieljoos/wincred v1.2.1
github.com/deepmap/oapi-codegen/v2 v2.2.0
github.com/docker/cli v26.1.5+incompatible
github.com/docker/docker v26.1.5+incompatible
github.com/docker/cli v27.2.1+incompatible
github.com/docker/docker v27.2.1+incompatible
github.com/docker/go-connections v0.5.0
github.com/docker/go-units v0.5.0
github.com/getsentry/sentry-go v0.28.1
Expand Down Expand Up @@ -114,7 +115,6 @@ require (
github.com/curioswitch/go-reassign v0.2.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
github.com/daixiang0/gci v0.13.4 // indirect
github.com/danieljoos/wincred v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,13 @@ github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk=
github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE=
github.com/docker/cli v26.1.5+incompatible h1:NxXGSdz2N+Ibdaw330TDO3d/6/f7MvHuiMbuFaIQDTk=
github.com/docker/cli v26.1.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v27.2.1+incompatible h1:U5BPtiD0viUzjGAjV1p0MGB8eVA3L3cbIrnyWmSJI70=
github.com/docker/cli v27.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g=
github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI=
github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
Expand Down
6 changes: 3 additions & 3 deletions internal/db/branch/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"os"
"path/filepath"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stdcopy"
"github.com/go-errors/errors"
"github.com/spf13/afero"
Expand Down Expand Up @@ -70,7 +70,7 @@ func assertNewBranchIsValid(branchPath string, fsys afero.Fs) error {
}

func createBranch(ctx context.Context, branch string) error {
exec, err := utils.Docker.ContainerExecCreate(ctx, utils.DbId, types.ExecConfig{
exec, err := utils.Docker.ContainerExecCreate(ctx, utils.DbId, container.ExecOptions{
Cmd: []string{"/bin/bash", "-c", cloneScript},
Env: []string{"DB_NAME=" + branch},
AttachStderr: true,
Expand All @@ -80,7 +80,7 @@ func createBranch(ctx context.Context, branch string) error {
return err
}
// Read exec output
resp, err := utils.Docker.ContainerExecAttach(ctx, exec.ID, types.ExecStartCheck{})
resp, err := utils.Docker.ContainerExecAttach(ctx, exec.ID, container.ExecStartOptions{})
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions internal/db/branch/delete/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"io"
"path/filepath"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stdcopy"
"github.com/go-errors/errors"
"github.com/spf13/afero"
Expand Down Expand Up @@ -58,7 +58,7 @@ func deleteBranchDir(branch string, fsys afero.Fs) error {
}

func deleteBranchPG(ctx context.Context, branch string) error {
exec, err := utils.Docker.ContainerExecCreate(ctx, utils.DbId, types.ExecConfig{
exec, err := utils.Docker.ContainerExecCreate(ctx, utils.DbId, container.ExecOptions{
Cmd: []string{"dropdb", "--username", "postgres", "--host", "127.0.0.1", branch},
AttachStderr: true,
AttachStdout: true,
Expand All @@ -67,7 +67,7 @@ func deleteBranchPG(ctx context.Context, branch string) error {
return err
}
// Read exec output
resp, err := utils.Docker.ContainerExecAttach(ctx, exec.ID, types.ExecStartCheck{})
resp, err := utils.Docker.ContainerExecAttach(ctx, exec.ID, container.ExecStartOptions{})
if err != nil {
return err
}
Expand Down
27 changes: 27 additions & 0 deletions internal/db/reset/reset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,33 @@ func TestResetRemote(t *testing.T) {
assert.NoError(t, err)
})

t.Run("resets remote database with seed config disabled", func(t *testing.T) {
// Setup in-memory fs
fsys := afero.NewMemMapFs()
path := filepath.Join(utils.MigrationsDir, "0_schema.sql")
require.NoError(t, afero.WriteFile(fsys, path, nil, 0644))
seedPath := filepath.Join(utils.SeedDataPath)
// Will raise an error when seeding
require.NoError(t, afero.WriteFile(fsys, seedPath, []byte("INSERT INTO test_table;"), 0644))
// Setup mock postgres
conn := pgtest.NewConn()
defer conn.Close(t)
conn.Query(migration.ListSchemas, escapedSchemas).
Reply("SELECT 1", []interface{}{"private"}).
Query("DROP SCHEMA IF EXISTS private CASCADE").
Reply("DROP SCHEMA").
Query(migration.DropObjects).
Reply("INSERT 0")
helper.MockMigrationHistory(conn).
Query(migration.INSERT_MIGRATION_VERSION, "0", "schema", nil).
Reply("INSERT 0 1")
utils.Config.Db.Seed.Enabled = false
// Run test
err := resetRemote(context.Background(), "", dbConfig, fsys, conn.Intercept)
// No error should be raised since we're skipping the seed
assert.NoError(t, err)
})

t.Run("throws error on connect failure", func(t *testing.T) {
// Setup in-memory fs
fsys := afero.NewMemMapFs()
Expand Down
3 changes: 3 additions & 0 deletions internal/migration/apply/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ func MigrateAndSeed(ctx context.Context, version string, conn *pgx.Conn, fsys af
if err := migration.ApplyMigrations(ctx, migrations, conn, afero.NewIOFS(fsys)); err != nil {
return err
}
if !utils.Config.Db.Seed.Enabled {
return nil
}
return SeedDatabase(ctx, conn, fsys)
}

Expand Down
24 changes: 24 additions & 0 deletions internal/migration/apply/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,30 @@ func TestMigrateDatabase(t *testing.T) {
assert.NoError(t, err)
})

t.Run("skip seeding when seed config is disabled", func(t *testing.T) {
// Setup in-memory fs
fsys := afero.NewMemMapFs()
path := filepath.Join(utils.MigrationsDir, "0_test.sql")
sql := "create schema public"
require.NoError(t, afero.WriteFile(fsys, path, []byte(sql), 0644))
seedPath := filepath.Join(utils.SeedDataPath)
// This will raise an error when seeding
require.NoError(t, afero.WriteFile(fsys, seedPath, []byte("INSERT INTO test_table;"), 0644))
// Setup mock postgres
conn := pgtest.NewConn()
defer conn.Close(t)
helper.MockMigrationHistory(conn).
Query(sql).
Reply("CREATE SCHEMA").
Query(migration.INSERT_MIGRATION_VERSION, "0", "test", []string{sql}).
Reply("INSERT 0 1")
utils.Config.Db.Seed.Enabled = false
// Run test
err := MigrateAndSeed(context.Background(), "", conn.MockClient(t), fsys)
// No error should be returned since seeding is skipped
assert.NoError(t, err)
})

t.Run("ignores empty local directory", func(t *testing.T) {
assert.NoError(t, MigrateAndSeed(context.Background(), "", nil, afero.NewMemMapFs()))
})
Expand Down
5 changes: 3 additions & 2 deletions internal/start/start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/volume"
"github.com/h2non/gock"
"github.com/jackc/pgconn"
Expand Down Expand Up @@ -85,7 +86,7 @@ func TestDatabaseStart(t *testing.T) {
gock.New(utils.Docker.DaemonHost()).
Post("/v" + utils.Docker.ClientVersion() + "/networks/create").
Reply(http.StatusCreated).
JSON(types.NetworkCreateResponse{})
JSON(network.CreateResponse{})
// Caches all dependencies
imageUrl := utils.GetRegistryImageUrl(utils.Config.Db.Image)
gock.New(utils.Docker.DaemonHost()).
Expand Down Expand Up @@ -201,7 +202,7 @@ func TestDatabaseStart(t *testing.T) {
gock.New(utils.Docker.DaemonHost()).
Post("/v" + utils.Docker.ClientVersion() + "/networks/create").
Reply(http.StatusCreated).
JSON(types.NetworkCreateResponse{})
JSON(network.CreateResponse{})
// Caches all dependencies
imageUrl := utils.GetRegistryImageUrl(utils.Config.Db.Image)
gock.New(utils.Docker.DaemonHost()).
Expand Down
9 changes: 5 additions & 4 deletions internal/testing/apitest/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
Expand Down Expand Up @@ -38,7 +39,7 @@ func MockDockerStart(docker *client.Client, image, containerID string) {
gock.New(docker.DaemonHost()).
Post("/v" + docker.ClientVersion() + "/networks/create").
Reply(http.StatusCreated).
JSON(types.NetworkCreateResponse{})
JSON(network.CreateResponse{})
gock.New(docker.DaemonHost()).
Post("/v" + docker.ClientVersion() + "/volumes/create").
Persist().
Expand All @@ -62,15 +63,15 @@ func MockDockerStop(docker *client.Client) {
gock.New(docker.DaemonHost()).
Post("/v" + docker.ClientVersion() + "/containers/prune").
Reply(http.StatusOK).
JSON(types.ContainersPruneReport{})
JSON(container.PruneReport{})
gock.New(docker.DaemonHost()).
Post("/v" + docker.ClientVersion() + "/volumes/prune").
Reply(http.StatusOK).
JSON(types.VolumesPruneReport{})
JSON(volume.PruneReport{})
gock.New(docker.DaemonHost()).
Post("/v" + docker.ClientVersion() + "/networks/prune").
Reply(http.StatusOK).
JSON(types.NetworksPruneReport{})
JSON(network.PruneReport{})
}

// Ref: internal/utils/docker.go::DockerRunOnce
Expand Down
34 changes: 34 additions & 0 deletions internal/utils/credentials/keyring_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//go:build darwin

package credentials

import (
"os/exec"

"github.com/go-errors/errors"
)

const execPathKeychain = "/usr/bin/security"

func deleteAll(service string) error {
if len(service) == 0 {
return errors.New("missing service name")
}
// Delete each secret in a while loop until there is no more left
for {
if err := exec.Command(
execPathKeychain,
"delete-generic-password",
"-s", service,
).Run(); err == nil {
continue
} else if errors.Is(err, exec.ErrNotFound) {
return errors.New(ErrNotSupported)
} else if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == 44 {
// Exit 44 means no item exists for this service name
return nil
} else {
return errors.Errorf("failed to delete all credentials: %w", err)
}
}
}
33 changes: 33 additions & 0 deletions internal/utils/credentials/keyring_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//go:build linux

package credentials

import (
"github.com/go-errors/errors"
ss "github.com/zalando/go-keyring/secret_service"
)

func deleteAll(service string) error {
svc, err := ss.NewSecretService()
if err != nil {
return errors.Errorf("failed to create secret service: %w", err)
}

collection := svc.GetLoginCollection()
if err := svc.Unlock(collection.Path()); err != nil {
return errors.Errorf("failed to unlock collection: %w", err)
}

search := map[string]string{"service": service}
results, err := svc.SearchItems(collection, search)
if err != nil {
return errors.Errorf("failed to search items: %w", err)
}

for _, item := range results {
if err := svc.Delete(item); err != nil {
return errors.Errorf("failed to delete all credentials: %w", err)
}
}
return nil
}
28 changes: 28 additions & 0 deletions internal/utils/credentials/keyring_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package credentials

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/zalando/go-keyring"
)

func TestDeleteAll(t *testing.T) {
service := "test-cli"
// Nothing to delete
err := deleteAll(service)
assert.NoError(t, err)
// Setup 2 items
err = keyring.Set(service, "key1", "value")
assert.NoError(t, err)
err = keyring.Set(service, "key2", "value")
assert.NoError(t, err)
// Delete all items
err = deleteAll(service)
assert.NoError(t, err)
// Check items are gone
_, err = keyring.Get(service, "key1")
assert.ErrorIs(t, err, keyring.ErrNotFound)
_, err = keyring.Get(service, "key2")
assert.ErrorIs(t, err, keyring.ErrNotFound)
}
25 changes: 25 additions & 0 deletions internal/utils/credentials/keyring_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//go:build windows

package credentials

import (
"github.com/danieljoos/wincred"
"github.com/go-errors/errors"
)

func deleteAll(service string) error {
if err := assertKeyringSupported(); err != nil {
return err
}
creds, err := wincred.FilteredList(service + ":")
if err != nil {
return errors.Errorf("failed to list credentials: %w", err)
}
for _, c := range creds {
gc := wincred.GenericCredential{Credential: *c}
if err := gc.Delete(); err != nil {
return errors.Errorf("failed to delete all credentials: %w", err)
}
}
return nil
}
5 changes: 5 additions & 0 deletions internal/utils/credentials/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func Delete(project string) error {
return nil
}

// Deletes all stored credentials for the namespace
func DeleteAll() error {
return deleteAll(namespace)
}

func assertKeyringSupported() error {
// Suggested check: https://github.com/microsoft/WSL/issues/423
if f, err := os.ReadFile("/proc/sys/kernel/osrelease"); err == nil {
Expand Down
Loading

0 comments on commit 881d231

Please sign in to comment.