Skip to content

Commit 3a7a938

Browse files
wannteclaude
andcommitted
Change prefix matching to substring (contains) matching in bundle open
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 15a2899 commit 3a7a938

File tree

4 files changed

+79
-21
lines changed

4 files changed

+79
-21
lines changed

bundle/resources/lookup.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,12 @@ func Lookup(b *bundle.Bundle, key string, filters ...Filter) (Reference, error)
100100
}
101101
}
102102

103-
// LookupByPrefix returns all resources whose key starts with the given prefix.
104-
func LookupByPrefix(b *bundle.Bundle, prefix string, filters ...Filter) []Reference {
103+
// LookupBySubstring returns all resources whose key contains the given substring.
104+
func LookupBySubstring(b *bundle.Bundle, substr string, filters ...Filter) []Reference {
105105
keyOnly, _ := References(b, filters...)
106106
var matches []Reference
107107
for k, refs := range keyOnly {
108-
if strings.HasPrefix(k, prefix) {
108+
if strings.Contains(k, substr) {
109109
matches = append(matches, refs...)
110110
}
111111
}

bundle/resources/lookup_test.go

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func TestLookup_NominalWithFilters(t *testing.T) {
130130
assert.ErrorContains(t, err, `resource with key "bar" not found`)
131131
}
132132

133-
func TestLookupByPrefix_NoMatches(t *testing.T) {
133+
func TestLookupBySubstring_NoMatches(t *testing.T) {
134134
b := &bundle.Bundle{
135135
Config: config.Root{
136136
Resources: config.Resources{
@@ -142,11 +142,11 @@ func TestLookupByPrefix_NoMatches(t *testing.T) {
142142
},
143143
}
144144

145-
matches := LookupByPrefix(b, "qux")
145+
matches := LookupBySubstring(b, "qux")
146146
assert.Empty(t, matches)
147147
}
148148

149-
func TestLookupByPrefix_SingleMatch(t *testing.T) {
149+
func TestLookupBySubstring_SingleMatch(t *testing.T) {
150150
b := &bundle.Bundle{
151151
Config: config.Root{
152152
Resources: config.Resources{
@@ -160,13 +160,13 @@ func TestLookupByPrefix_SingleMatch(t *testing.T) {
160160
},
161161
}
162162

163-
matches := LookupByPrefix(b, "foo")
163+
matches := LookupBySubstring(b, "foo")
164164
require.Len(t, matches, 1)
165165
assert.Equal(t, "foo_job", matches[0].Key)
166166
assert.Equal(t, "Foo job", matches[0].Resource.GetName())
167167
}
168168

169-
func TestLookupByPrefix_MultipleMatches(t *testing.T) {
169+
func TestLookupBySubstring_MultipleMatches(t *testing.T) {
170170
b := &bundle.Bundle{
171171
Config: config.Root{
172172
Resources: config.Resources{
@@ -179,15 +179,15 @@ func TestLookupByPrefix_MultipleMatches(t *testing.T) {
179179
},
180180
}
181181

182-
matches := LookupByPrefix(b, "my_")
182+
matches := LookupBySubstring(b, "my_")
183183
require.Len(t, matches, 2)
184184

185185
keys := []string{matches[0].Key, matches[1].Key}
186186
sort.Strings(keys)
187187
assert.Equal(t, []string{"my_job_1", "my_job_2"}, keys)
188188
}
189189

190-
func TestLookupByPrefix_WithFilters(t *testing.T) {
190+
func TestLookupBySubstring_WithFilters(t *testing.T) {
191191
b := &bundle.Bundle{
192192
Config: config.Root{
193193
Resources: config.Resources{
@@ -206,12 +206,52 @@ func TestLookupByPrefix_WithFilters(t *testing.T) {
206206
return ok
207207
}
208208

209-
matches := LookupByPrefix(b, "my_", includeJobs)
209+
matches := LookupBySubstring(b, "my_", includeJobs)
210210
require.Len(t, matches, 1)
211211
assert.Equal(t, "my_job", matches[0].Key)
212212
}
213213

214-
func TestLookupByPrefix_ExactPrefixMatchesAll(t *testing.T) {
214+
func TestLookupBySubstring_MiddleMatch(t *testing.T) {
215+
b := &bundle.Bundle{
216+
Config: config.Root{
217+
Resources: config.Resources{
218+
Jobs: map[string]*resources.Job{
219+
"my_foo_job": {
220+
JobSettings: jobs.JobSettings{Name: "My Foo Job"},
221+
},
222+
"bar_job": {},
223+
},
224+
},
225+
},
226+
}
227+
228+
matches := LookupBySubstring(b, "foo")
229+
require.Len(t, matches, 1)
230+
assert.Equal(t, "my_foo_job", matches[0].Key)
231+
}
232+
233+
func TestLookupBySubstring_SuffixMatch(t *testing.T) {
234+
b := &bundle.Bundle{
235+
Config: config.Root{
236+
Resources: config.Resources{
237+
Jobs: map[string]*resources.Job{
238+
"my_foo_job": {},
239+
"my_bar_job": {},
240+
"pipeline": {},
241+
},
242+
},
243+
},
244+
}
245+
246+
matches := LookupBySubstring(b, "_job")
247+
require.Len(t, matches, 2)
248+
249+
keys := []string{matches[0].Key, matches[1].Key}
250+
sort.Strings(keys)
251+
assert.Equal(t, []string{"my_bar_job", "my_foo_job"}, keys)
252+
}
253+
254+
func TestLookupBySubstring_ExactMatchAndContains(t *testing.T) {
215255
b := &bundle.Bundle{
216256
Config: config.Root{
217257
Resources: config.Resources{
@@ -225,7 +265,7 @@ func TestLookupByPrefix_ExactPrefixMatchesAll(t *testing.T) {
225265
},
226266
}
227267

228-
matches := LookupByPrefix(b, "foo")
268+
matches := LookupBySubstring(b, "foo")
229269
require.Len(t, matches, 3)
230270

231271
keys := make([]string, len(matches))

cmd/bundle/open.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ func resolveOpenArgument(ctx context.Context, b *bundle.Bundle, args []string) (
5353
return arg, nil
5454
}
5555

56-
// Check for prefix matches.
57-
matches := resources.LookupByPrefix(b, arg)
56+
// Check for substring matches.
57+
matches := resources.LookupBySubstring(b, arg)
5858
switch {
5959
case len(matches) == 1:
6060
return matches[0].Key, nil
@@ -74,7 +74,7 @@ func resolveOpenArgument(ctx context.Context, b *bundle.Bundle, args []string) (
7474
for _, ref := range matches {
7575
keys = append(keys, ref.Key)
7676
}
77-
return "", fmt.Errorf("multiple resources match prefix %q: %v", arg, keys)
77+
return "", fmt.Errorf("multiple resources match %q: %v", arg, keys)
7878
}
7979

8080
// No matches; return the arg as-is and let Lookup handle the "not found" error.

cmd/bundle/open_test.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestResolveOpenArgument_ExactMatch(t *testing.T) {
4040
assert.Equal(t, "my_job", key)
4141
}
4242

43-
func TestResolveOpenArgument_PrefixSingleMatch(t *testing.T) {
43+
func TestResolveOpenArgument_SubstringSingleMatch(t *testing.T) {
4444
ctx := cmdio.MockDiscard(context.Background())
4545
b := &bundle.Bundle{
4646
Config: config.Root{
@@ -58,7 +58,7 @@ func TestResolveOpenArgument_PrefixSingleMatch(t *testing.T) {
5858
assert.Equal(t, "foo_job", key)
5959
}
6060

61-
func TestResolveOpenArgument_PrefixMultipleMatches_NonInteractive(t *testing.T) {
61+
func TestResolveOpenArgument_SubstringMultipleMatches_NonInteractive(t *testing.T) {
6262
ctx := cmdio.MockDiscard(context.Background())
6363
b := &bundle.Bundle{
6464
Config: config.Root{
@@ -74,12 +74,30 @@ func TestResolveOpenArgument_PrefixMultipleMatches_NonInteractive(t *testing.T)
7474

7575
_, err := resolveOpenArgument(ctx, b, []string{"my_"})
7676
require.Error(t, err)
77-
assert.ErrorContains(t, err, "multiple resources match prefix")
77+
assert.ErrorContains(t, err, "multiple resources match")
7878
assert.ErrorContains(t, err, "my_job_1")
7979
assert.ErrorContains(t, err, "my_job_2")
8080
}
8181

82-
func TestResolveOpenArgument_PrefixNoMatch(t *testing.T) {
82+
func TestResolveOpenArgument_SubstringMiddleMatch(t *testing.T) {
83+
ctx := cmdio.MockDiscard(context.Background())
84+
b := &bundle.Bundle{
85+
Config: config.Root{
86+
Resources: config.Resources{
87+
Jobs: map[string]*resources.Job{
88+
"my_foo_job": {JobSettings: jobs.JobSettings{Name: "My Foo Job"}},
89+
"bar_job": {JobSettings: jobs.JobSettings{Name: "Bar Job"}},
90+
},
91+
},
92+
},
93+
}
94+
95+
key, err := resolveOpenArgument(ctx, b, []string{"foo"})
96+
require.NoError(t, err)
97+
assert.Equal(t, "my_foo_job", key)
98+
}
99+
100+
func TestResolveOpenArgument_SubstringNoMatch(t *testing.T) {
83101
ctx := cmdio.MockDiscard(context.Background())
84102
b := &bundle.Bundle{
85103
Config: config.Root{
@@ -91,7 +109,7 @@ func TestResolveOpenArgument_PrefixNoMatch(t *testing.T) {
91109
},
92110
}
93111

94-
// No prefix match; returns the arg as-is.
112+
// No substring match; returns the arg as-is.
95113
key, err := resolveOpenArgument(ctx, b, []string{"zzz"})
96114
require.NoError(t, err)
97115
assert.Equal(t, "zzz", key)

0 commit comments

Comments
 (0)