• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / cli / 16030849241

02 Jul 2025 04:40PM UTC coverage: 56.237% (+0.6%) from 55.63%
16030849241

Pull #3781

github

web-flow
Merge 9f11335df into 036b16128
Pull Request #3781: Add unit tests for internal/service module

8 of 8 new or added lines in 1 file covered. (100.0%)

7 existing lines in 2 files now uncovered.

6158 of 10950 relevant lines covered (56.24%)

6.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.53
/internal/storage/rm/rm.go
1
package rm
2

3
import (
4
        "context"
5
        "fmt"
6
        "os"
7
        "strings"
8

9
        "github.com/go-errors/errors"
10
        "github.com/spf13/afero"
11
        "github.com/supabase/cli/internal/storage/client"
12
        "github.com/supabase/cli/internal/storage/cp"
13
        "github.com/supabase/cli/internal/storage/ls"
14
        "github.com/supabase/cli/internal/utils"
15
        "github.com/supabase/cli/internal/utils/flags"
16
        "github.com/supabase/cli/pkg/storage"
17
)
18

19
var (
20
        errMissingObject = errors.New("Object not found")
21
        errMissingBucket = errors.New("You must specify a bucket to delete.")
22
        errMissingFlag   = errors.New("You must specify -r flag to delete directories.")
23
)
24

25
type PrefixGroup struct {
26
        Bucket   string
27
        Prefixes []string
28
}
29

30
func Run(ctx context.Context, paths []string, recursive bool, fsys afero.Fs) error {
6✔
31
        // Group paths by buckets
6✔
32
        groups := map[string][]string{}
6✔
33
        for _, objectPath := range paths {
14✔
34
                remotePath, err := client.ParseStorageURL(objectPath)
8✔
35
                if err != nil {
9✔
36
                        return err
1✔
37
                }
1✔
38
                bucket, prefix := client.SplitBucketPrefix(remotePath)
7✔
39
                // Ignore attempts to delete all buckets
7✔
40
                if len(bucket) == 0 {
8✔
41
                        return errors.New(errMissingBucket)
1✔
42
                }
1✔
43
                if cp.IsDir(prefix) && !recursive {
7✔
44
                        return errors.New(errMissingFlag)
1✔
45
                }
1✔
46
                groups[bucket] = append(groups[bucket], prefix)
5✔
47
        }
48
        api, err := client.NewStorageAPI(ctx, flags.ProjectRef)
3✔
49
        if err != nil {
3✔
50
                return err
×
51
        }
×
52
        for bucket, prefixes := range groups {
7✔
53
                confirm := fmt.Sprintf("Confirm deleting files in bucket %v?", utils.Bold(bucket))
4✔
54
                if shouldDelete, err := utils.NewConsole().PromptYesNo(ctx, confirm, false); err != nil {
4✔
55
                        return err
×
56
                } else if !shouldDelete {
5✔
57
                        continue
1✔
58
                }
59
                // Always try deleting first in case the paths resolve to extensionless files
60
                fmt.Fprintln(os.Stderr, "Deleting objects:", prefixes)
3✔
61
                removed, err := api.DeleteObjects(ctx, bucket, prefixes)
3✔
62
                if err != nil {
4✔
63
                        return err
1✔
64
                }
1✔
65
                set := map[string]struct{}{}
2✔
66
                for _, object := range removed {
3✔
67
                        set[object.Name] = struct{}{}
1✔
68
                }
1✔
69
                for _, prefix := range prefixes {
5✔
70
                        if _, ok := set[prefix]; ok {
4✔
71
                                continue
1✔
72
                        }
73
                        if !recursive {
3✔
74
                                fmt.Fprintln(os.Stderr, "Object not found:", prefix)
1✔
75
                                continue
1✔
76
                        }
77
                        if len(prefix) > 0 {
1✔
UNCOV
78
                                prefix += "/"
×
UNCOV
79
                        }
×
80
                        if err := RemoveStoragePathAll(ctx, api, bucket, prefix); err != nil {
1✔
81
                                return err
×
82
                        }
×
83
                }
84
        }
85
        return nil
2✔
86
}
87

88
// Expects prefix to be terminated by "/" or ""
89
func RemoveStoragePathAll(ctx context.Context, api storage.StorageAPI, bucket, prefix string) error {
6✔
90
        // We must remove one directory at a time to avoid breaking pagination result
6✔
91
        queue := make([]string, 0)
6✔
92
        queue = append(queue, prefix)
6✔
93
        for len(queue) > 0 {
13✔
94
                dirPrefix := queue[len(queue)-1]
7✔
95
                queue = queue[:len(queue)-1]
7✔
96
                paths, err := ls.ListStoragePaths(ctx, api, fmt.Sprintf("/%s/%s", bucket, dirPrefix))
7✔
97
                if err != nil {
8✔
98
                        return err
1✔
99
                }
1✔
100
                if len(paths) == 0 && len(prefix) > 0 {
7✔
101
                        return errors.Errorf("%w: %s/%s", errMissingObject, bucket, prefix)
1✔
102
                }
1✔
103
                var files []string
5✔
104
                for _, objectName := range paths {
9✔
105
                        objectPrefix := dirPrefix + objectName
4✔
106
                        if strings.HasSuffix(objectName, "/") {
5✔
107
                                queue = append(queue, objectPrefix)
1✔
108
                        } else {
4✔
109
                                files = append(files, objectPrefix)
3✔
110
                        }
3✔
111
                }
112
                if len(files) > 0 {
7✔
113
                        fmt.Fprintln(os.Stderr, "Deleting objects:", files)
2✔
114
                        if _, err := api.DeleteObjects(ctx, bucket, files); err != nil {
3✔
115
                                return err
1✔
116
                        }
1✔
117
                }
118
        }
119
        if len(prefix) == 0 {
5✔
120
                fmt.Fprintln(os.Stderr, "Deleting bucket:", bucket)
2✔
121
                if data, err := api.DeleteBucket(ctx, bucket); err == nil {
3✔
122
                        fmt.Fprintln(os.Stderr, data.Message)
1✔
123
                } else if strings.Contains(err.Error(), `"error":"Bucket not found"`) {
3✔
124
                        fmt.Fprintln(os.Stderr, "Bucket not found:", bucket)
1✔
125
                } else {
1✔
126
                        return err
×
127
                }
×
128
        }
129
        return nil
3✔
130
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc