current-cli 0.1.34__tar.gz → 0.1.36__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: current-cli
3
- Version: 0.1.34
3
+ Version: 0.1.36
4
4
  Summary: Command line interface for the Current API, generated from its OpenAPI schema at runtime
5
5
  Author-email: Orin <your-email@example.com>
6
6
  License-Expression: MIT
@@ -16,9 +16,14 @@ def _make_callback(op: Operation):
16
16
  for param in op.path_params:
17
17
  path = path.replace("{" + param.name + "}", str(kwargs.pop(param.name)))
18
18
 
19
- params: dict[str, str] = {}
19
+ params: dict[str, str | list[str]] = {}
20
20
  for param in op.query_params:
21
21
  value = kwargs.pop(param.name, None)
22
+ # click gives a repeatable option an empty tuple, not None, when
23
+ # it is absent; treat that as "not given" so it never becomes an
24
+ # empty query key.
25
+ if param.is_array:
26
+ value = list(value) if value else None
22
27
  if value is None and param.name == "workspace":
23
28
  value = config.get("default_workspace")
24
29
  if value is None:
@@ -48,6 +53,7 @@ def _make_command(op: Operation) -> click.Command:
48
53
  click.Option(
49
54
  [f"--{param.name.replace('_', '-')}"],
50
55
  required=False,
56
+ multiple=param.is_array,
51
57
  help=param.description or None,
52
58
  )
53
59
  )
@@ -21,6 +21,9 @@ class Parameter:
21
21
  location: str # "path" or "query"
22
22
  required: bool
23
23
  description: str
24
+ # An array query param is sent as the repeated key the API reads with
25
+ # getlist (?fields=a&fields=b), so its option has to be repeatable too.
26
+ is_array: bool = False
24
27
 
25
28
 
26
29
  @dataclass(frozen=True)
@@ -90,6 +93,7 @@ def extract_operations(spec: dict) -> list[Operation]:
90
93
  location=raw["in"],
91
94
  required=raw.get("required", False),
92
95
  description=raw.get("description", ""),
96
+ is_array=raw.get("schema", {}).get("type") == "array",
93
97
  )
94
98
  if param.location == "path":
95
99
  path_params.append(param)
@@ -811,6 +811,32 @@ paths:
811
811
  responses:
812
812
  '204':
813
813
  description: No response body
814
+ /api/integrations/connections/{id}/basecamp-accounts/:
815
+ get:
816
+ operationId: integrations_connections_basecamp_accounts_list
817
+ description: Basecamp accounts visible to the connected identity.
818
+ parameters:
819
+ - in: path
820
+ name: id
821
+ schema:
822
+ type: string
823
+ format: uuid
824
+ description: A UUID string identifying this integration connection.
825
+ required: true
826
+ tags:
827
+ - integrations
828
+ security:
829
+ - MessagingJobTokenAuth: []
830
+ - tokenAuth: []
831
+ responses:
832
+ '200':
833
+ content:
834
+ application/json:
835
+ schema:
836
+ type: array
837
+ items:
838
+ $ref: '#/components/schemas/BasecampAccount'
839
+ description: ''
814
840
  /api/integrations/connections/{id}/channels/:
815
841
  get:
816
842
  operationId: integrations_connections_channels_list
@@ -837,6 +863,42 @@ paths:
837
863
  items:
838
864
  $ref: '#/components/schemas/SlackChannel'
839
865
  description: ''
866
+ /api/integrations/connections/{id}/select-basecamp-account/:
867
+ post:
868
+ operationId: integrations_connections_select_basecamp_account_create
869
+ description: Choose the one Basecamp account synchronized into this workspace.
870
+ parameters:
871
+ - in: path
872
+ name: id
873
+ schema:
874
+ type: string
875
+ format: uuid
876
+ description: A UUID string identifying this integration connection.
877
+ required: true
878
+ tags:
879
+ - integrations
880
+ requestBody:
881
+ content:
882
+ application/json:
883
+ schema:
884
+ $ref: '#/components/schemas/BasecampAccountSelectionRequest'
885
+ application/x-www-form-urlencoded:
886
+ schema:
887
+ $ref: '#/components/schemas/BasecampAccountSelectionRequest'
888
+ multipart/form-data:
889
+ schema:
890
+ $ref: '#/components/schemas/BasecampAccountSelectionRequest'
891
+ required: true
892
+ security:
893
+ - MessagingJobTokenAuth: []
894
+ - tokenAuth: []
895
+ responses:
896
+ '200':
897
+ content:
898
+ application/json:
899
+ schema:
900
+ $ref: '#/components/schemas/IntegrationConnection'
901
+ description: ''
840
902
  /api/integrations/connections/{id}/teams-conversations/:
841
903
  get:
842
904
  operationId: integrations_connections_teams_conversations_list
@@ -1779,12 +1841,17 @@ paths:
1779
1841
  get:
1780
1842
  operationId: projects_projects_inventory_retrieve
1781
1843
  description: |-
1782
- Page current field values, optionally narrowed to named keys.
1844
+ Page current field values, optionally narrowed to named keys and
1845
+ to projects whose values match.
1783
1846
 
1784
1847
  The full project list serializes every field of every project —
1785
1848
  megabytes at production scale. This page is the compact census a
1786
1849
  chat agent can scan: identity plus the keys it asked for, no
1787
- timeline, no provenance. See state.list_projects.
1850
+ timeline, no provenance.
1851
+
1852
+ Filter here rather than page-and-sift: a caller that reads every
1853
+ page and picks the matches by eye miscounts, and "total" under a
1854
+ filter is the count it was really after. See state.list_projects.
1788
1855
  parameters:
1789
1856
  - in: query
1790
1857
  name: fields
@@ -1793,6 +1860,16 @@ paths:
1793
1860
  items:
1794
1861
  type: string
1795
1862
  description: Field keys to keep; omit to return every current value
1863
+ - in: query
1864
+ name: filter
1865
+ schema:
1866
+ type: array
1867
+ items:
1868
+ type: string
1869
+ description: Keep only projects whose current value matches, as 'key:value'
1870
+ (for example 'status:Active'). Repeat for more fields; repeating one key
1871
+ accepts any of its values. An option matches by label, value, or ID. 'total'
1872
+ counts the matching projects.
1796
1873
  - in: query
1797
1874
  name: limit
1798
1875
  schema:
@@ -1803,6 +1880,14 @@ paths:
1803
1880
  schema:
1804
1881
  type: integer
1805
1882
  description: Number of projects to skip (default 0)
1883
+ - in: query
1884
+ name: values
1885
+ schema:
1886
+ type: string
1887
+ enum:
1888
+ - ids
1889
+ - labels
1890
+ description: Read option values as labels (default) or as option IDs
1806
1891
  - in: query
1807
1892
  name: workspace
1808
1893
  schema:
@@ -3390,6 +3475,34 @@ components:
3390
3475
  format: uri
3391
3476
  required:
3392
3477
  - authorize_url
3478
+ BasecampAccount:
3479
+ type: object
3480
+ properties:
3481
+ account_id:
3482
+ type: string
3483
+ name:
3484
+ type: string
3485
+ href:
3486
+ type: string
3487
+ format: uri
3488
+ app_href:
3489
+ oneOf:
3490
+ - type: string
3491
+ format: uri
3492
+ - type: string
3493
+ maxLength: 0
3494
+ required:
3495
+ - account_id
3496
+ - href
3497
+ - name
3498
+ BasecampAccountSelectionRequest:
3499
+ type: object
3500
+ properties:
3501
+ account_id:
3502
+ type: string
3503
+ minLength: 1
3504
+ required:
3505
+ - account_id
3393
3506
  ClientCredentialsConnectRequestRequest:
3394
3507
  type: object
3395
3508
  description: |-
@@ -3980,16 +4093,19 @@ components:
3980
4093
  - workspace
3981
4094
  IntegrationConnectionStatusEnum:
3982
4095
  enum:
4096
+ - setup_required
3983
4097
  - active
3984
4098
  - error
3985
4099
  - revoked
3986
4100
  type: string
3987
4101
  description: |-
4102
+ * `setup_required` - Setup required
3988
4103
  * `active` - Active
3989
4104
  * `error` - Error
3990
4105
  * `revoked` - Revoked
3991
4106
  IntegrationProviderEnum:
3992
4107
  enum:
4108
+ - basecamp
3993
4109
  - slack
3994
4110
  - teams
3995
4111
  - sharepoint
@@ -3997,6 +4113,7 @@ components:
3997
4113
  - salesforce
3998
4114
  type: string
3999
4115
  description: |-
4116
+ * `basecamp` - Basecamp
4000
4117
  * `slack` - Slack
4001
4118
  * `teams` - Microsoft Teams
4002
4119
  * `sharepoint` - SharePoint
@@ -293,6 +293,12 @@ POST /api/integrations/connections/authorize/
293
293
  Options:
294
294
  - `--data` (required) - Request body as JSON: inline, @file.json, or - for stdin.
295
295
 
296
+ ### current integrations connections basecamp-accounts list <id>
297
+
298
+ Basecamp accounts visible to the connected identity.
299
+
300
+ GET /api/integrations/connections/{id}/basecamp-accounts/
301
+
296
302
  ### current integrations connections channels list <id>
297
303
 
298
304
  List public Slack channels — verifies a Slack connection works.
@@ -350,6 +356,15 @@ All known providers and whether OAuth credentials are configured.
350
356
 
351
357
  GET /api/integrations/connections/providers/
352
358
 
359
+ ### current integrations connections select-basecamp-account create <id>
360
+
361
+ Choose the one Basecamp account synchronized into this workspace.
362
+
363
+ POST /api/integrations/connections/{id}/select-basecamp-account/
364
+
365
+ Options:
366
+ - `--data` (required) - Request body as JSON: inline, @file.json, or - for stdin.
367
+
353
368
  ### current integrations connections teams-conversations list <id>
354
369
 
355
370
  Teams conversations the bot has seen, derived from the
@@ -602,19 +617,26 @@ Options:
602
617
 
603
618
  ### current projects inventory retrieve
604
619
 
605
- Page current field values, optionally narrowed to named keys.
620
+ Page current field values, optionally narrowed to named keys and
621
+ to projects whose values match.
606
622
 
607
623
  The full project list serializes every field of every project —
608
624
  megabytes at production scale. This page is the compact census a
609
625
  chat agent can scan: identity plus the keys it asked for, no
610
- timeline, no provenance. See state.list_projects.
626
+ timeline, no provenance.
627
+
628
+ Filter here rather than page-and-sift: a caller that reads every
629
+ page and picks the matches by eye miscounts, and "total" under a
630
+ filter is the count it was really after. See state.list_projects.
611
631
 
612
632
  GET /api/projects/projects/inventory/
613
633
 
614
634
  Options:
615
635
  - `--fields` - Field keys to keep; omit to return every current value
636
+ - `--filter` - Keep only projects whose current value matches, as 'key:value' (for example 'status:Active'). Repeat for more fields; repeating one key accepts any of its values. An option matches by label, value, or ID. 'total' counts the matching projects.
616
637
  - `--limit` - Max projects per page (default 100, max 200)
617
638
  - `--offset` - Number of projects to skip (default 0)
639
+ - `--values` - Read option values as labels (default) or as option IDs
618
640
  - `--workspace` - Workspace UUID
619
641
 
620
642
  ### current projects list
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "current-cli"
3
- version = "0.1.34"
3
+ version = "0.1.36"
4
4
  description = "Command line interface for the Current API, generated from its OpenAPI schema at runtime"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -60,6 +60,40 @@ def test_create_sends_json_body(cli, runner, transport_factory):
60
60
  assert json.loads(request.content) == {"name": "Order beams", "workspace": "w1"}
61
61
 
62
62
 
63
+ def test_array_query_param_repeats(cli, runner, transport_factory):
64
+ """An array param must repeat its key, the shape the API reads with
65
+ getlist — one AND-ed filter per --filter."""
66
+ transport = transport_factory(ok({}))
67
+
68
+ result = runner.invoke(
69
+ cli,
70
+ [
71
+ "projects",
72
+ "inventory",
73
+ "retrieve",
74
+ "--workspace",
75
+ "ws-uuid",
76
+ "--filter",
77
+ "status:Active",
78
+ "--filter",
79
+ "site_type:Garden Style",
80
+ ],
81
+ )
82
+
83
+ assert result.exit_code == 0, result.output
84
+ params = transport.requests[0].url.params
85
+ assert params.get_list("filter") == ["status:Active", "site_type:Garden Style"]
86
+
87
+
88
+ def test_array_query_param_is_absent_when_not_given(cli, runner, transport_factory):
89
+ transport = transport_factory(ok({}))
90
+
91
+ result = runner.invoke(cli, ["projects", "inventory", "retrieve", "--workspace", "ws-uuid"])
92
+
93
+ assert result.exit_code == 0, result.output
94
+ assert "filter" not in transport.requests[0].url.params
95
+
96
+
63
97
  def test_default_workspace_fallback(cli, runner, transport_factory):
64
98
  config.set_value("default_workspace", "default-ws")
65
99
  transport = transport_factory(ok({}))
File without changes
File without changes