peak-sdk 1.4.0__py3-none-any.whl → 1.6.0__py3-none-any.whl

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.
Files changed (50) hide show
  1. peak/_metadata.py +58 -3
  2. peak/_version.py +1 -1
  3. peak/cli/cli.py +4 -2
  4. peak/cli/helpers.py +2 -0
  5. peak/cli/press/blocks/specs.py +2 -2
  6. peak/cli/press/specs.py +4 -2
  7. peak/cli/resources/alerts/__init__.py +35 -0
  8. peak/cli/resources/alerts/emails.py +360 -0
  9. peak/cli/resources/images.py +1 -1
  10. peak/cli/resources/services.py +23 -0
  11. peak/cli/resources/users.py +71 -0
  12. peak/cli/resources/workflows.py +77 -15
  13. peak/cli/ruff.toml +5 -3
  14. peak/compression.py +2 -2
  15. peak/exceptions.py +4 -6
  16. peak/handler.py +3 -5
  17. peak/helpers.py +35 -9
  18. peak/output.py +2 -2
  19. peak/press/apps.py +8 -16
  20. peak/press/blocks.py +8 -16
  21. peak/press/deployments.py +2 -4
  22. peak/press/specs.py +12 -14
  23. peak/resources/__init__.py +3 -2
  24. peak/resources/alerts.py +309 -0
  25. peak/resources/artifacts.py +2 -4
  26. peak/resources/images.py +8 -14
  27. peak/resources/services.py +7 -6
  28. peak/resources/users.py +93 -0
  29. peak/resources/webapps.py +3 -5
  30. peak/resources/workflows.py +106 -16
  31. peak/sample_yaml/resources/emails/send_email.yaml +15 -0
  32. peak/sample_yaml/resources/services/create_or_update_service.yaml +1 -0
  33. peak/sample_yaml/resources/services/create_service.yaml +1 -0
  34. peak/sample_yaml/resources/services/update_service.yaml +1 -0
  35. peak/sample_yaml/resources/workflows/create_or_update_workflow.yaml +28 -0
  36. peak/sample_yaml/resources/workflows/create_workflow.yaml +10 -0
  37. peak/sample_yaml/resources/workflows/patch_workflow.yaml +28 -0
  38. peak/sample_yaml/resources/workflows/update_workflow.yaml +28 -0
  39. peak/session.py +7 -4
  40. peak/telemetry.py +1 -1
  41. peak/template.py +6 -4
  42. peak/tools/logging/__init__.py +26 -268
  43. peak/tools/logging/log_level.py +35 -3
  44. peak/tools/logging/logger.py +389 -0
  45. peak/validators.py +34 -2
  46. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/METADATA +11 -12
  47. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/RECORD +50 -43
  48. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/WHEEL +1 -1
  49. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/LICENSE +0 -0
  50. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/entry_points.txt +0 -0
peak/_metadata.py CHANGED
@@ -24,13 +24,14 @@ The metadata represents the following:
24
24
  - table_params: Parameters required for the table output formatting.
25
25
  - request_body_yaml_path: File containing the yaml file examples for the command.
26
26
  """
27
+
28
+ from __future__ import annotations
29
+
27
30
  from typing import Any, Dict, List
28
31
 
29
32
 
30
33
  def tag_parser(data: Any) -> str:
31
- tag_array = []
32
- for tag in data:
33
- tag_array.append(tag["name"])
34
+ tag_array = [tag["name"] for tag in data]
34
35
  return ", ".join(tag_array)
35
36
 
36
37
 
@@ -623,6 +624,57 @@ command_metadata: Dict[str, Any] = {
623
624
  "data_key": "data",
624
625
  },
625
626
  },
627
+ "list_emails": {
628
+ "table_params": {
629
+ "output_keys": {
630
+ "id": {
631
+ "label": "ID",
632
+ },
633
+ "subject": {
634
+ "label": "Subject",
635
+ },
636
+ "status": {
637
+ "label": "Status",
638
+ },
639
+ "templateName": {
640
+ "label": "Template Name",
641
+ },
642
+ "createdAt": {
643
+ "label": "Created At",
644
+ },
645
+ "createdBy": {
646
+ "label": "Created By",
647
+ },
648
+ },
649
+ "title": "Emails",
650
+ "data_key": "emails",
651
+ "subheader_key": "emailCount",
652
+ },
653
+ },
654
+ "list_templates": {
655
+ "table_params": {
656
+ "output_keys": {
657
+ "id": {
658
+ "label": "ID",
659
+ },
660
+ "name": {
661
+ "label": "Name",
662
+ },
663
+ "scope": {
664
+ "label": "Status",
665
+ },
666
+ "createdAt": {
667
+ "label": "Created At",
668
+ },
669
+ "createdBy": {
670
+ "label": "Created By",
671
+ },
672
+ },
673
+ "title": "Templates",
674
+ "data_key": "templates",
675
+ "subheader_key": "templateCount",
676
+ },
677
+ },
626
678
  "create_artifact": {
627
679
  "request_body_yaml_path": "sample_yaml/resources/artifacts/create_artifact.yaml",
628
680
  },
@@ -680,6 +732,9 @@ command_metadata: Dict[str, Any] = {
680
732
  "test_service": {
681
733
  "request_body_yaml_path": "sample_yaml/resources/services/test_service.yaml",
682
734
  },
735
+ "send_email": {
736
+ "request_body_yaml_path": "sample_yaml/resources/emails/send_email.yaml",
737
+ },
683
738
  "create_app_spec": {
684
739
  "request_body_yaml_path": "sample_yaml/press/apps/specs/create_app_spec.yaml",
685
740
  },
peak/_version.py CHANGED
@@ -18,4 +18,4 @@
18
18
  # # You should have received a copy of the APACHE LICENSE, VERSION 2.0
19
19
  # # along with this program. If not, see <https://apache.org/licenses/LICENSE-2.0>
20
20
  #
21
- __version__: str = "1.4.0"
21
+ __version__: str = "1.6.0"
peak/cli/cli.py CHANGED
@@ -25,15 +25,16 @@ import peak.config
25
25
  import typer
26
26
  from peak.cli import args, helpers
27
27
  from peak.cli.press import apps, blocks, deployments, specs
28
- from peak.cli.resources import artifacts, images, services, tenants, webapps, workflows
28
+ from peak.cli.resources import alerts, artifacts, images, services, tenants, users, webapps, workflows
29
29
  from peak.constants import Sources
30
30
  from peak.output import Writer
31
31
 
32
- # Hack to not gray out texts after first paragraph
32
+ # Workaround to not gray out texts after first paragraph
33
33
  typer.rich_utils.STYLE_HELPTEXT = ""
34
34
 
35
35
  typer_app = typer.Typer(rich_markup_mode="markdown", help="Create and Manage Peak Resources")
36
36
  typer_app.add_typer(images.app, name="images")
37
+ typer_app.add_typer(alerts.app, name="alerts")
37
38
  typer_app.add_typer(artifacts.app, name="artifacts")
38
39
  typer_app.add_typer(workflows.app, name="workflows")
39
40
  typer_app.add_typer(webapps.app, name="webapps")
@@ -43,6 +44,7 @@ typer_app.add_typer(apps.app, name="apps")
43
44
  typer_app.add_typer(blocks.app, name="blocks")
44
45
  typer_app.add_typer(specs.app, name="specs")
45
46
  typer_app.add_typer(deployments.app, name="deployments")
47
+ typer_app.add_typer(users.app, name="users")
46
48
 
47
49
 
48
50
  @typer_app.callback()
peak/cli/helpers.py CHANGED
@@ -251,5 +251,7 @@ def get_client(command: str) -> base_client.BaseClient:
251
251
  "services": resources.services,
252
252
  "webapps": resources.webapps,
253
253
  "tenants": resources.tenants,
254
+ "users": resources.users,
255
+ "alerts": resources.alerts,
254
256
  }
255
257
  return command_client_map[command].get_client() # type: ignore[no-any-return]
@@ -169,7 +169,7 @@ def create(
169
169
  - events (map):
170
170
  success (boolean | required: false): Whether to call event on success.
171
171
  fail (boolean | required: false): Whether to call event on failure.
172
- runtimeExceeded (int | required: false): The runtime after which event is called.
172
+ runtimeExceeded (int | required: false): The runtime in minutes after which event is called.
173
173
  user (string | required: false): User to be notified. To be added in case of user watcher.
174
174
  webhook (map | required: false): To be added in case of webhook watcher.
175
175
  name (string): Name of the webhook.
@@ -433,7 +433,7 @@ def create_release(
433
433
  - events (map):
434
434
  success (boolean | required: false): Whether to call event on success.
435
435
  fail (boolean | required: false): Whether to call event on failure.
436
- runtimeExceeded (int | required: false): The runtime after which event is called.
436
+ runtimeExceeded (int | required: false): The runtime in minutes after which event is called.
437
437
  user (string | required: false): User to be notified. To be added in case of user watcher.
438
438
  webhook (map | required: false): To be added in case of webhook watcher.
439
439
  name (string): Name of the webhook.
peak/cli/press/specs.py CHANGED
@@ -35,6 +35,8 @@ app = typer.Typer(
35
35
  )
36
36
  console = Console()
37
37
 
38
+ RELEASE_VERSION = typer.Option(None, help="The release version of the spec in valid semantic versioning format.")
39
+
38
40
 
39
41
  @app.command("list", short_help="List App and Block specs.", options_metavar="list_specs")
40
42
  def list_specs(
@@ -94,7 +96,7 @@ def list_specs(
94
96
  def list_release_deployments(
95
97
  ctx: typer.Context,
96
98
  spec_id: str = args.SPEC_ID,
97
- version: str = args.RELEASE_VERSION,
99
+ version: Optional[str] = RELEASE_VERSION,
98
100
  page_size: Optional[int] = args.PAGE_SIZE,
99
101
  page_number: Optional[int] = args.PAGE_NUMBER,
100
102
  status: Optional[List[str]] = args.STATUS_FILTER_SPEC_RELEASES,
@@ -104,7 +106,7 @@ def list_release_deployments(
104
106
  paging: Optional[bool] = PAGING, # noqa: ARG001
105
107
  output_type: Optional[OutputTypes] = OUTPUT_TYPES, # noqa: ARG001
106
108
  ) -> None:
107
- """***List*** all the deployments for a given spec release.
109
+ """***List*** all the deployments for a given spec. Version is optional and if not provided, all deployments for the spec will be returned.
108
110
 
109
111
  \b
110
112
  📝 ***Example usage:***<br/>
@@ -0,0 +1,35 @@
1
+ #
2
+ # # Copyright © 2024 Peak AI Limited. or its affiliates. All Rights Reserved.
3
+ # #
4
+ # # Licensed under the Apache License, Version 2.0 (the "License"). You
5
+ # # may not use this file except in compliance with the License. A copy of
6
+ # # the License is located at:
7
+ # #
8
+ # # https://github.com/PeakBI/peak-sdk/blob/main/LICENSE
9
+ # #
10
+ # # or in the "license" file accompanying this file. This file is
11
+ # # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
12
+ # # ANY KIND, either express or implied. See the License for the specific
13
+ # # language governing permissions and limitations under the License.
14
+ # #
15
+ # # This file is part of the peak-sdk.
16
+ # # see (https://github.com/PeakBI/peak-sdk)
17
+ # #
18
+ # # You should have received a copy of the APACHE LICENSE, VERSION 2.0
19
+ # # along with this program. If not, see <https://apache.org/licenses/LICENSE-2.0>
20
+ #
21
+ """Alerts Module."""
22
+
23
+ import typer
24
+ from peak.cli.resources.alerts import emails
25
+
26
+ app = typer.Typer(
27
+ help="Create and manage peak alerts.",
28
+ short_help="Create and manage peak alerts.",
29
+ )
30
+ app.add_typer(
31
+ emails.app,
32
+ name="emails",
33
+ help="Create and manage peak emails.",
34
+ short_help="Create and manage peak emails.",
35
+ )
@@ -0,0 +1,360 @@
1
+ #
2
+ # # Copyright © 2024 Peak AI Limited. or its affiliates. All Rights Reserved.
3
+ # #
4
+ # # Licensed under the Apache License, Version 2.0 (the "License"). You
5
+ # # may not use this file except in compliance with the License. A copy of
6
+ # # the License is located at:
7
+ # #
8
+ # # https://github.com/PeakBI/peak-sdk/blob/main/LICENSE
9
+ # #
10
+ # # or in the "license" file accompanying this file. This file is
11
+ # # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
12
+ # # ANY KIND, either express or implied. See the License for the specific
13
+ # # language governing permissions and limitations under the License.
14
+ # #
15
+ # # This file is part of the peak-sdk.
16
+ # # see (https://github.com/PeakBI/peak-sdk)
17
+ # #
18
+ # # You should have received a copy of the APACHE LICENSE, VERSION 2.0
19
+ # # along with this program. If not, see <https://apache.org/licenses/LICENSE-2.0>
20
+ #
21
+
22
+ """Peak Alerts commands."""
23
+
24
+ from typing import Any, Dict, List, Optional
25
+
26
+ import typer
27
+ from peak.cli import helpers
28
+ from peak.cli.args import OUTPUT_TYPES, PAGING, TEMPLATE_PARAMS, TEMPLATE_PARAMS_FILE
29
+ from peak.constants import OutputTypes, OutputTypesNoTable
30
+ from peak.helpers import combine_dictionaries, map_user_options, parse_list_of_strings, variables_to_dict
31
+ from peak.output import Writer
32
+ from peak.resources.alerts import Alert
33
+ from typing_extensions import Annotated
34
+
35
+ app = typer.Typer(
36
+ help="Alerts management commands.",
37
+ short_help="Manage alerts.",
38
+ )
39
+
40
+ _EMAIL_ID = typer.Argument(..., help="The ID of the email.")
41
+ _RECIPIENTS = typer.Option(None, help="The email addresses of the recipients.")
42
+ _SUBJECT = typer.Option(None, help="The subject of the email.")
43
+ _TEMPLATE_NAME = typer.Option(None, help="The name of the email template.")
44
+ _TEMPLATE_PARAMETERS = typer.Option(
45
+ None,
46
+ help="The parameters for the email template. To be passed in stringified JSON format.",
47
+ )
48
+ _COUNT = typer.Option(None, help="The number of emails to retrieve.")
49
+ _DATE_FROM = typer.Option(None, help="The date from which to retrieve emails (in ISO format).")
50
+ _DATE_TO = typer.Option(None, help="The date till which to retrieve emails (in ISO format).")
51
+ _PAGE_SIZE = typer.Option(None, help="The number of emails per page.")
52
+ _PAGE_NUMBER = typer.Option(None, help="The page number to retrieve.")
53
+ _CC = typer.Option(None, help="The email addresses of the recipients to be CC'd.")
54
+ _BCC = typer.Option(None, help="The email addresses of the recipients to be BCC'd.")
55
+ _LIST_TEMPLATE_NAME = typer.Option(None, help="Email Template Name to search for.")
56
+ _LIST_TEMPLATE_SCOPE = typer.Option(None, help="List of type of template to filter the templates by.")
57
+ _DESCRIBE_TEMPLATE_NAME = typer.Argument(None, help="The name of the email template.")
58
+
59
+
60
+ @app.command("list", short_help="List all emails.", options_metavar="list_emails")
61
+ def list_emails(
62
+ ctx: typer.Context,
63
+ page_size: Optional[int] = _PAGE_SIZE,
64
+ page_number: Optional[int] = _PAGE_NUMBER,
65
+ count: Optional[int] = _COUNT,
66
+ date_from: Optional[str] = _DATE_FROM,
67
+ date_to: Optional[str] = _DATE_TO,
68
+ paging: Optional[bool] = PAGING, # noqa: ARG001
69
+ output_type: Optional[OutputTypes] = OUTPUT_TYPES, # noqa: ARG001
70
+ ) -> None:
71
+ """Retrieve the history of emails sent.
72
+
73
+ \b
74
+ 📝 ***Example usage:***
75
+ ```bash
76
+ peak alerts emails list --page-size 10 --page-number 1
77
+ ```
78
+
79
+ \b
80
+ 🆗 ***Response:***
81
+ ```
82
+ {
83
+ "emailCount": 1,
84
+ "emails": [
85
+ {
86
+ "createdAt": "2024-01-01T00:00:00.200Z",
87
+ "createdBy": "platform@peak.ai",
88
+ "id": 1,
89
+ "status": "Delivered",
90
+ "subject": "email_subject",
91
+ "templateName": "template_name",
92
+ }
93
+ ],
94
+ "pageCount": 1,
95
+ "pageNumber": 1,
96
+ "pageSize": 25
97
+ }
98
+ ```
99
+
100
+ 🔗 [**API Documentation**](https://service.peak.ai/notifications/api-docs/index.htm#/Emails/get_api_v1_emails)
101
+ """
102
+ alert_client: Alert = ctx.obj["client"]
103
+ writer: Writer = ctx.obj["writer"]
104
+
105
+ with writer.pager():
106
+ response = alert_client.list_emails(
107
+ page_size=page_size,
108
+ page_number=page_number,
109
+ count=count,
110
+ date_from=date_from,
111
+ date_to=date_to,
112
+ return_iterator=False,
113
+ )
114
+ writer.write(response)
115
+
116
+
117
+ @app.command("send", short_help="Send an email.", options_metavar="send_email")
118
+ def send_email(
119
+ ctx: typer.Context,
120
+ file: Annotated[
121
+ Optional[str],
122
+ typer.Argument(
123
+ ...,
124
+ help="Path to the file that defines the body for this operation, supports both `yaml` file or a `jinja` template.",
125
+ ),
126
+ ] = None,
127
+ params_file: str = TEMPLATE_PARAMS_FILE,
128
+ params: List[str] = TEMPLATE_PARAMS,
129
+ recipients: Optional[List[str]] = _RECIPIENTS,
130
+ cc: Optional[List[str]] = _CC,
131
+ bcc: Optional[List[str]] = _BCC,
132
+ subject: Optional[str] = _SUBJECT,
133
+ template_name: Optional[str] = _TEMPLATE_NAME,
134
+ template_parameters: Optional[str] = _TEMPLATE_PARAMETERS,
135
+ paging: Optional[bool] = PAGING, # noqa: ARG001
136
+ output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
137
+ ) -> None:
138
+ """Send an email to the specified recipients using the specified template.
139
+
140
+ \b
141
+ 🧩 ***Input file schema(yaml):***<br/>
142
+ ```yaml
143
+ body (map):
144
+ recipients (list(str) | required: true): List of email addresses of the recipients.
145
+ cc (list(str) | required: false): List of email addresses of the recipients to be CC'd.
146
+ bcc (list(str) | required: false): List of email addresses of the recipients to be BCC'd.
147
+ subject (str | required: true): The subject of the email.
148
+ templateName (str | required: true): The name of the email template.
149
+ templateParameters (map | required: false): The parameters for the email template.
150
+ ```
151
+
152
+ \b
153
+ 📝 ***Example usage:***
154
+ ```bash
155
+ peak alerts emails send '/path/to/email.yaml' --params-file '/path/to/values.yaml'
156
+ ```
157
+
158
+ We can also provide the required parameters from the command line or combine the YAML template and command line arguments in which case the command line arguments will take precedence.
159
+
160
+ \b
161
+ 📝 ***Example usage without yaml:***
162
+ ```bash
163
+ peak alerts emails send --recipients <recipient_email_1> --recipients <recipient_email_2> --subject <email_subject> --template-name <template_name> --template-parameters '{"key": "value"}'
164
+ ```
165
+
166
+ \b
167
+ 🆗 ***Response:***
168
+ ```json
169
+ {
170
+ "id": 1
171
+ }
172
+ ```
173
+
174
+ 🔗 [**API Documentation**](https://service.peak.ai/notifications/api-docs/index.htm#/Emails/post_api_v1_emails)
175
+ """
176
+ alert_client: Alert = ctx.obj["client"]
177
+ writer: Writer = ctx.obj["writer"]
178
+
179
+ user_options: Dict[str, Any] = variables_to_dict(
180
+ recipients,
181
+ cc,
182
+ bcc,
183
+ subject,
184
+ template_name,
185
+ template_parameters,
186
+ )
187
+
188
+ body: Dict[str, Any] = {}
189
+ if file:
190
+ body = helpers.template_handler(file=file, params_file=params_file, params=params)
191
+ body = helpers.remove_unknown_args(body, alert_client.send_email)
192
+
193
+ updated_body = combine_dictionaries(body.get("body") or {}, user_options)
194
+
195
+ if recipients:
196
+ updated_body["recipients"] = parse_list_of_strings(recipients)
197
+
198
+ if cc:
199
+ updated_body["cc"] = parse_list_of_strings(cc)
200
+
201
+ if bcc:
202
+ updated_body["bcc"] = parse_list_of_strings(bcc)
203
+
204
+ if template_parameters:
205
+ updated_body["templateParameters"] = map_user_options(
206
+ user_options=user_options,
207
+ mapping={},
208
+ dict_type_keys=["templateParameters"],
209
+ )
210
+
211
+ with writer.pager():
212
+ response: Dict[str, Any] = alert_client.send_email(body=updated_body)
213
+ writer.write(response)
214
+
215
+
216
+ @app.command(short_help="Describe details of a specific email.", options_metavar="describe_email")
217
+ def describe(
218
+ ctx: typer.Context,
219
+ email_id: int = _EMAIL_ID,
220
+ paging: Optional[bool] = PAGING, # noqa: ARG001
221
+ output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
222
+ ) -> None:
223
+ """***Describe*** details of a specific email.
224
+
225
+ \b
226
+ 📝 ***Example usage:***
227
+ ```bash
228
+ peak alerts emails describe <email-id>
229
+ ```
230
+
231
+ \b
232
+ 🆗 ***Response:***
233
+ ```
234
+ {
235
+ "createdAt": "2024-01-01T00:00:00.000Z",
236
+ "createdBy": "platform@peak.ai",
237
+ "deliveredAt": "2024-01-01T00:00:00.000Z",
238
+ "id": 1,
239
+ "recipients": {
240
+ "cc": [],
241
+ "to": ["someone@peak.ai"],
242
+ "bcc": []
243
+ },
244
+ "status": "Delivered",
245
+ "statusDetails": [
246
+ {
247
+ "email": "someone@peak.ai",
248
+ "status": "Delivered",
249
+ "description": "The email was successfully delivered."
250
+ }
251
+ ],
252
+ "subject": "Hello, world!",
253
+ "templateName": "template_name",
254
+ }
255
+ ```
256
+
257
+ 🔗 [**API Documentation**](https://service.peak.ai/notifications/api-docs/index.htm#/Emails/get_api_v1_emails__id_)
258
+ """
259
+ alert_client: Alert = ctx.obj["client"]
260
+ writer: Writer = ctx.obj["writer"]
261
+
262
+ with writer.pager():
263
+ response = alert_client.describe_email(email_id=email_id)
264
+ writer.write(response)
265
+
266
+
267
+ @app.command(short_help="List all the templates.", options_metavar="list_templates")
268
+ def list_templates(
269
+ ctx: typer.Context,
270
+ page_size: Optional[int] = _PAGE_SIZE,
271
+ page_number: Optional[int] = _PAGE_NUMBER,
272
+ scope: Optional[List[str]] = _LIST_TEMPLATE_SCOPE,
273
+ name: Optional[str] = _LIST_TEMPLATE_NAME,
274
+ paging: Optional[bool] = PAGING, # noqa: ARG001
275
+ output_type: Optional[OutputTypes] = OUTPUT_TYPES, # noqa: ARG001
276
+ ) -> None:
277
+ """Retrieve the email templates list.
278
+
279
+ \b
280
+ 📝 ***Example usage:***
281
+ ```bash
282
+ peak alerts emails list-templates --page-size 10 --page-number 1
283
+ ```
284
+
285
+ \b
286
+ 🆗 ***Response:***
287
+ ```
288
+ {
289
+ "templateCount": 1,
290
+ "templates": [
291
+ {
292
+ "id": 1,
293
+ "createdAt": "2021-09-01T12:00:00Z",
294
+ "createdBy": "platform@peak.ai",
295
+ "name": "test_template",
296
+ "scope": "custom"
297
+ }
298
+ ],
299
+ "pageCount": 1,
300
+ "pageNumber": 1,
301
+ "pageSize": 25
302
+ }
303
+ ```
304
+
305
+ 🔗 [**API Documentation**](https://service.peak.ai/notifications/api-docs/index.htm#/Templates/get_api_v1_emails_templates)
306
+ """
307
+ alert_client: Alert = ctx.obj["client"]
308
+ writer: Writer = ctx.obj["writer"]
309
+
310
+ with writer.pager():
311
+ response = alert_client.list_templates(
312
+ page_size=page_size,
313
+ page_number=page_number,
314
+ scope=scope,
315
+ name=name,
316
+ return_iterator=False,
317
+ )
318
+ writer.write(response)
319
+
320
+
321
+ @app.command(
322
+ short_help="Describe details of a specific template.",
323
+ options_metavar="describe_template",
324
+ )
325
+ def describe_template(
326
+ ctx: typer.Context,
327
+ template_name: str = _DESCRIBE_TEMPLATE_NAME,
328
+ paging: Optional[bool] = PAGING, # noqa: ARG001
329
+ output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
330
+ ) -> None:
331
+ """***Describe*** details of a specific template.
332
+
333
+ \b
334
+ 📝 ***Example usage:***
335
+ ```bash
336
+ peak alerts emails describe-template <template-name>
337
+ ```
338
+
339
+ \b
340
+ 🆗 ***Response:***
341
+ ```
342
+ {
343
+ "id": 1,
344
+ "createdAt": "2021-09-01T12:00:00Z",
345
+ "createdBy": "platform@peak.ai",
346
+ "name": "test_template",
347
+ "subject": "Important Account Update Information",
348
+ "body": "<h1>Hello</h1><p>Your account has been updated.</p>",
349
+ "scope": "custom"
350
+ }
351
+ ```
352
+
353
+ 🔗 [**API Documentation**](https://service.peak.ai/notifications/api-docs/index.htm#/Templates/get_api_v1_emails_templates__name_)
354
+ """
355
+ alert_client: Alert = ctx.obj["client"]
356
+ writer: Writer = ctx.obj["writer"]
357
+
358
+ with writer.pager():
359
+ response = alert_client.describe_template(template_name=template_name)
360
+ writer.write(response)
@@ -1086,4 +1086,4 @@ def get_build_logs(
1086
1086
  writer.write(response)
1087
1087
  break
1088
1088
 
1089
- next_token = response["nextToken"] if "nextToken" in response else None
1089
+ next_token = response.get("nextToken", None)
@@ -87,6 +87,11 @@ _ENTRYPOINT = typer.Option(None, help="Entrypoint for the service.")
87
87
 
88
88
  _HEALTH_CHECK_URL = typer.Option(None, help="Endpoint to monitor service's operational status.")
89
89
 
90
+ _MIN_INSTANCES = typer.Option(
91
+ None,
92
+ help="Minimum number of instances that would run for a service. Default value is 1 and maximum value allowed is 2.",
93
+ )
94
+
90
95
  _HTTP_METHOD = typer.Option(None, help="HTTP method to be used to test the service.")
91
96
 
92
97
  _PATH = typer.Option(None, help="Path to be used to test the service.")
@@ -168,6 +173,7 @@ def create(
168
173
  secrets: Optional[List[str]] = _SECRETS,
169
174
  entrypoint: Optional[str] = _ENTRYPOINT,
170
175
  health_check_url: Optional[str] = _HEALTH_CHECK_URL,
176
+ min_instances: Optional[int] = _MIN_INSTANCES,
171
177
  dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
172
178
  paging: Optional[bool] = PAGING, # noqa: ARG001
173
179
  output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
@@ -194,6 +200,7 @@ def create(
194
200
  sessionStickiness (boolean | required: false): Enable session stickiness for the service. Default value is false. Enabling session stickiness will tie each user to a specific server for all their requests. Not required for API type services.
195
201
  entrypoint (string | required: false): Entrypoint for the service.
196
202
  healthCheckURL (string | required: false): Endpoint to monitor service's operational status.
203
+ minInstances (number | required: false): Minimum number of instances that would run for a service. Default value is 1 and maximum value allowed is 2.
197
204
  ```
198
205
 
199
206
  \b
@@ -252,6 +259,9 @@ def create(
252
259
  if health_check_url:
253
260
  updated_body["healthCheckURL"] = health_check_url
254
261
 
262
+ if min_instances:
263
+ updated_body["minInstances"] = min_instances
264
+
255
265
  with writer.pager():
256
266
  response = service_client.create_service(body=updated_body)
257
267
  writer.write(response)
@@ -274,6 +284,7 @@ def update(
274
284
  secrets: Optional[List[str]] = _SECRETS,
275
285
  entrypoint: Optional[str] = _ENTRYPOINT,
276
286
  health_check_url: Optional[str] = _HEALTH_CHECK_URL,
287
+ min_instances: Optional[int] = _MIN_INSTANCES,
277
288
  dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
278
289
  paging: Optional[bool] = PAGING, # noqa: ARG001
279
290
  output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
@@ -305,6 +316,7 @@ def update(
305
316
  sessionStickiness (boolean | required: false): Enable session stickiness for the service. Default value is false. Enabling session stickiness will tie each user to a specific server for all their requests. Not required for API type services.
306
317
  entrypoint (string | required: false): Entrypoint for the service.
307
318
  healthCheckURL (string | required: false): Endpoint to monitor service's operational status.
319
+ minInstances (number | required: false): Minimum number of instances that would run for a service. Default value is 1 and maximum value allowed is 2.
308
320
  ```
309
321
 
310
322
  \b
@@ -361,6 +373,9 @@ def update(
361
373
  if health_check_url:
362
374
  updated_body["healthCheckURL"] = health_check_url
363
375
 
376
+ if min_instances:
377
+ updated_body["minInstances"] = min_instances
378
+
364
379
  with writer.pager():
365
380
  response = service_client.update_service(service_id=service_id, body=updated_body)
366
381
  writer.write(response)
@@ -387,6 +402,7 @@ def create_or_update(
387
402
  secrets: Optional[List[str]] = _SECRETS,
388
403
  entrypoint: Optional[str] = _ENTRYPOINT,
389
404
  health_check_url: Optional[str] = _HEALTH_CHECK_URL,
405
+ min_instances: Optional[int] = _MIN_INSTANCES,
390
406
  dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
391
407
  paging: Optional[bool] = PAGING, # noqa: ARG001
392
408
  output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
@@ -418,6 +434,7 @@ def create_or_update(
418
434
  sessionStickiness (boolean | required: false): Enable session stickiness for the service. Default value is false. Enabling session stickiness will tie each user to a specific server for all their requests. Not required for API type services.
419
435
  entrypoint (string | required: false): Entrypoint for the service.
420
436
  healthCheckURL (string | required: false): Endpoint to monitor service's operational status.
437
+ minInstances (number | required: false): Minimum number of instances that would run for a service. Default value is 1 and maximum value allowed is 2.
421
438
  ```
422
439
 
423
440
  \b
@@ -478,6 +495,9 @@ def create_or_update(
478
495
  if health_check_url:
479
496
  updated_body["healthCheckURL"] = health_check_url
480
497
 
498
+ if min_instances:
499
+ updated_body["minInstances"] = min_instances
500
+
481
501
  response = service_client.create_or_update_service(body=updated_body)
482
502
  writer.write(response)
483
503
 
@@ -551,6 +571,9 @@ def describe(
551
571
  "createdBy": "someone@peak.ai",
552
572
  "updatedAt": "2020-01-01T18:00:00.000Z",
553
573
  "updatedBy": "someone@peak.ai",
574
+ "entrypoint": "/",
575
+ "healthCheckURL": "/health",
576
+ "minInstances": 1,
554
577
  "tags": [...]
555
578
  }
556
579
  ```