Skip to content

Commit 2f9f660

Browse files
Laura Warrlaurawarr
authored andcommitted
feat: Add search params to variable and feature commands
1 parent dae66d8 commit 2f9f660

File tree

12 files changed

+254
-23
lines changed

12 files changed

+254
-23
lines changed

docs/variables.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,14 @@ DESCRIPTION
4646
```
4747
USAGE
4848
$ dvc variables get [--config-path <value>] [--auth-path <value>] [--repo-config-path <value>] [--client-id
49-
<value>] [--client-secret <value>] [--project <value>] [--no-api] [--headless] [--keys <value>] [--page <value>]
50-
[--per-page <value>]
49+
<value>] [--client-secret <value>] [--project <value>] [--no-api] [--headless] [--keys <value>] [--search <value>]
50+
[--page <value>] [--per-page <value>]
5151
5252
FLAGS
5353
--keys=<value> Comma-separated list of variable keys to fetch details for
5454
--page=<value> Page number to fetch
5555
--per-page=<value> Number of variables to fetch per page
56+
--search=<value> Filter variables by search query
5657
5758
GLOBAL FLAGS
5859
--auth-path=<value> Override the default location to look for an auth.yml file
@@ -71,11 +72,13 @@ GLOBAL FLAGS
7172
```
7273
USAGE
7374
$ dvc variables list [--config-path <value>] [--auth-path <value>] [--repo-config-path <value>] [--client-id
74-
<value>] [--client-secret <value>] [--project <value>] [--no-api] [--headless] [--page <value>] [--per-page <value>]
75+
<value>] [--client-secret <value>] [--project <value>] [--no-api] [--headless] [--search <value>] [--page <value>]
76+
[--per-page <value>]
7577
7678
FLAGS
7779
--page=<value> Page number to fetch
7880
--per-page=<value> Number of variables to fetch per page
81+
--search=<value> Filter variables by search query
7982
8083
GLOBAL FLAGS
8184
--auth-path=<value> Override the default location to look for an auth.yml file

oclif.manifest.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3729,6 +3729,12 @@
37293729
"description": "Comma-separated list of variable keys to fetch details for",
37303730
"multiple": false
37313731
},
3732+
"search": {
3733+
"name": "search",
3734+
"type": "option",
3735+
"description": "Filter variables by search query",
3736+
"multiple": false
3737+
},
37323738
"page": {
37333739
"name": "page",
37343740
"type": "option",
@@ -3825,6 +3831,12 @@
38253831
"vscode_extension"
38263832
]
38273833
},
3834+
"search": {
3835+
"name": "search",
3836+
"type": "option",
3837+
"description": "Filter variables by search query",
3838+
"multiple": false
3839+
},
38283840
"page": {
38293841
"name": "page",
38303842
"type": "option",

src/api/features.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,22 @@ import { buildHeaders } from './common'
66

77
const FEATURE_URL = '/v1/projects/:project/features'
88

9-
export const fetchFeatures = async (token: string, project_id: string): Promise<Feature[]> => {
9+
export const fetchFeatures = async (
10+
token: string,
11+
project_id: string,
12+
queries: {
13+
feature?: string
14+
page?: number
15+
perPage?: number
16+
search?: string
17+
} = {}
18+
): Promise<Feature[]> => {
1019
const response = await apiClient.get(FEATURE_URL, {
1120
headers: buildHeaders(token),
1221
params: {
1322
project: project_id
14-
}
23+
},
24+
queries
1525
})
1626

1727
return response

src/api/variables.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const fetchVariables = async (
5858
feature?: string
5959
page?: number
6060
perPage?: number
61+
search?: string
6162
} = {}
6263
) => {
6364
return await apiClient.get('/v1/projects/:project/variables', {

src/commands/features/get.test.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { expect } from '@oclif/test'
2+
import { dvcTest } from '../../../test-utils'
3+
import { BASE_URL } from '../../api/common'
4+
5+
describe('features get', () => {
6+
const projectKey = 'test-project'
7+
const authFlags = ['--client-id', 'test-client-id', '--client-secret', 'test-client-secret']
8+
9+
const mockFeatures = [
10+
{
11+
key: 'feature-1',
12+
name: 'Feature 1',
13+
_id: '61450f3daec96f5cf4a49946'
14+
},
15+
{
16+
key: 'feature-2',
17+
name: 'Feature 2',
18+
_id: '61450f3daec96f5cf4a49947',
19+
}
20+
]
21+
22+
dvcTest()
23+
.nock(BASE_URL, (api) => api
24+
.get(`/v1/projects/${projectKey}/features`)
25+
.reply(200, mockFeatures)
26+
)
27+
.stdout()
28+
.command(['features get', '--project', projectKey, ...authFlags])
29+
.it('returns a list of feature objects', (ctx) => {
30+
expect(ctx.stdout).to.contain(JSON.stringify(mockFeatures, null, 2))
31+
})
32+
33+
dvcTest()
34+
.nock(BASE_URL, (api) => api
35+
.get(`/v1/projects/${projectKey}/features`)
36+
.query({ page: 2, perPage: 10 })
37+
.reply(200, mockFeatures)
38+
)
39+
.stdout()
40+
.command([
41+
'features get',
42+
'--project', projectKey,
43+
'--page', '2',
44+
'--per-page', '10',
45+
...authFlags
46+
])
47+
.it('passes pagination params to api', (ctx) => {
48+
expect(ctx.stdout).to.contain(JSON.stringify(mockFeatures, null, 2))
49+
})
50+
51+
dvcTest()
52+
.nock(BASE_URL, (api) => api
53+
.get(`/v1/projects/${projectKey}/features`)
54+
.query({ search: 'hello world' })
55+
.reply(200, mockFeatures)
56+
)
57+
.stdout()
58+
.command([
59+
'features get',
60+
'--project', projectKey,
61+
'--search', 'hello world',
62+
...authFlags
63+
])
64+
.it('passes search param to api', (ctx) => {
65+
expect(ctx.stdout).to.contain(JSON.stringify(mockFeatures, null, 2))
66+
})
67+
})

src/commands/features/get.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ export default class DetailedFeatures extends Base {
1515
'keys': Flags.string({
1616
description: 'Comma-separated list of feature keys to fetch details for',
1717
}),
18+
'search': Flags.string({
19+
description: 'Filter features by search query'
20+
}),
21+
'page': Flags.integer({
22+
description: 'Page number to fetch'
23+
}),
24+
'per-page': Flags.integer({
25+
description: 'Number of features to fetch per page'
26+
})
1827
}
1928
authRequired = true
2029

@@ -30,7 +39,12 @@ export default class DetailedFeatures extends Base {
3039
(key) => fetchFeatureByKey(this.authToken, this.projectKey, key)
3140
)
3241
} else {
33-
features = await fetchFeatures(this.authToken, this.projectKey)
42+
const query = {
43+
page: flags['page'],
44+
perPage: flags['per-page'],
45+
search: flags['search'],
46+
}
47+
features = await fetchFeatures(this.authToken, this.projectKey, query)
3448
}
3549

3650
this.writer.showResults(features)

src/commands/features/list.test.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { expect } from '@oclif/test'
2+
import { dvcTest } from '../../../test-utils'
3+
import { BASE_URL } from '../../api/common'
4+
5+
describe('features list', () => {
6+
const projectKey = 'test-project'
7+
const authFlags = ['--client-id', 'test-client-id', '--client-secret', 'test-client-secret']
8+
9+
const mockFeatures = [
10+
{
11+
key: 'feature-1',
12+
name: 'Feature 1',
13+
_id: '61450f3daec96f5cf4a49946'
14+
},
15+
{
16+
key: 'feature-2',
17+
name: 'Feature 2',
18+
_id: '61450f3daec96f5cf4a49947',
19+
}
20+
]
21+
22+
dvcTest()
23+
.nock(BASE_URL, (api) => api
24+
.get(`/v1/projects/${projectKey}/features`)
25+
.reply(200, mockFeatures)
26+
)
27+
.stdout()
28+
.command(['features list', '--project', projectKey, ...authFlags])
29+
.it('returns a list of feature keys', (ctx) => {
30+
expect(ctx.stdout).to.contain(JSON.stringify(['feature-1', 'feature-2'], null, 2))
31+
})
32+
33+
dvcTest()
34+
.nock(BASE_URL, (api) => api
35+
.get(`/v1/projects/${projectKey}/features`)
36+
.query({ page: 2, perPage: 10 })
37+
.reply(200, mockFeatures)
38+
)
39+
.stdout()
40+
.command([
41+
'features list',
42+
'--project', projectKey,
43+
'--page', '2',
44+
'--per-page', '10',
45+
...authFlags
46+
])
47+
.it('passes pagination params to api', (ctx) => {
48+
expect(ctx.stdout).to.contain(JSON.stringify(['feature-1', 'feature-2'], null, 2))
49+
})
50+
51+
dvcTest()
52+
.nock(BASE_URL, (api) => api
53+
.get(`/v1/projects/${projectKey}/features`)
54+
.query({ search: 'hello world' })
55+
.reply(200, mockFeatures)
56+
)
57+
.stdout()
58+
.command([
59+
'features list',
60+
'--project', projectKey,
61+
'--search', 'hello world',
62+
...authFlags
63+
])
64+
.it('passes search param to api', (ctx) => {
65+
expect(ctx.stdout).to.contain(JSON.stringify(['feature-1', 'feature-2'], null, 2))
66+
})
67+
})

src/commands/features/list.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,35 @@
1+
import { Flags } from '@oclif/core'
12
import { fetchFeatures } from '../../api/features'
23
import Base from '../base'
34

45
export default class ListFeatures extends Base {
56
static hidden = false
67
static description = 'View all features in a project'
8+
static flags = {
9+
...Base.flags,
10+
'search': Flags.string({
11+
description: 'Filter features by search query'
12+
}),
13+
'page': Flags.integer({
14+
description: 'Page number to fetch'
15+
}),
16+
'per-page': Flags.integer({
17+
description: 'Number of features to fetch per page'
18+
})
19+
}
720
authRequired = true
821

922
public async run(): Promise<void> {
1023
const { flags } = await this.parse(ListFeatures)
1124
const { project, headless } = flags
1225
await this.requireProject(project, headless)
13-
const features = await fetchFeatures(this.authToken, this.projectKey)
26+
27+
const query = {
28+
page: flags['page'],
29+
perPage: flags['per-page'],
30+
search: flags['search'],
31+
}
32+
const features = await fetchFeatures(this.authToken, this.projectKey, query)
1433
const featureKeys = features.map((feature) => feature.key)
1534
this.writer.showResults(featureKeys)
1635
}

src/commands/variables/get.test.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ describe('variables get', () => {
2626
)
2727
.stdout()
2828
.command(['variables get', '--project', projectKey, ...authFlags])
29-
.it('returns a list of variable objects',
30-
(ctx) => {
31-
expect(ctx.stdout).to.contain(JSON.stringify(mockVariables, null, 2))
32-
})
29+
.it('returns a list of variable objects', (ctx) => {
30+
expect(ctx.stdout).to.contain(JSON.stringify(mockVariables, null, 2))
31+
})
3332

3433
dvcTest()
3534
.nock(BASE_URL, (api) => api
@@ -45,8 +44,24 @@ describe('variables get', () => {
4544
'--per-page', '10',
4645
...authFlags
4746
])
48-
.it('passes pagination params to api',
49-
(ctx) => {
50-
expect(ctx.stdout).to.contain(JSON.stringify(mockVariables, null, 2))
51-
})
47+
.it('passes pagination params to api', (ctx) => {
48+
expect(ctx.stdout).to.contain(JSON.stringify(mockVariables, null, 2))
49+
})
50+
51+
dvcTest()
52+
.nock(BASE_URL, (api) => api
53+
.get(`/v1/projects/${projectKey}/variables`)
54+
.query({ search: 'hello world' })
55+
.reply(200, mockVariables)
56+
)
57+
.stdout()
58+
.command([
59+
'variables get',
60+
'--project', projectKey,
61+
'--search', 'hello world',
62+
...authFlags
63+
])
64+
.it('passes search param to api', (ctx) => {
65+
expect(ctx.stdout).to.contain(JSON.stringify(mockVariables, null, 2))
66+
})
5267
})

src/commands/variables/get.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export default class DetailedVariables extends Base {
1010
'keys': Flags.string({
1111
description: 'Comma-separated list of variable keys to fetch details for',
1212
}),
13+
'search': Flags.string({
14+
description: 'Filter variables by search query'
15+
}),
1316
'page': Flags.integer({
1417
description: 'Page number to fetch'
1518
}),
@@ -36,6 +39,7 @@ export default class DetailedVariables extends Base {
3639
const query = {
3740
page: flags['page'],
3841
perPage: flags['per-page'],
42+
search: flags['search'],
3943
}
4044
variables = await fetchVariables(this.authToken, this.projectKey, query)
4145
}

0 commit comments

Comments
 (0)