pingera-cli 0.1.9__tar.gz → 0.1.11__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.
- {pingera_cli-0.1.9/pingera_cli.egg-info → pingera_cli-0.1.11}/PKG-INFO +2 -2
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/docs/cli-commands.md +9 -6
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/__init__.py +1 -1
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/commands/checks.py +8 -36
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/commands/on_demand_checks.py +20 -45
- pingera_cli-0.1.11/pingera_cli/utils/file_utils.py +91 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11/pingera_cli.egg-info}/PKG-INFO +2 -2
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli.egg-info/SOURCES.txt +1 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli.egg-info/requires.txt +1 -1
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pyproject.toml +1 -1
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/tests/test_on_demand_checks.py +3 -6
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/.gitignore +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/.replit +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/LICENSE +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/README.md +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/assert +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/docs/example-check.yaml +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/docs/example-synthetic-screenshot.json +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/docs/example-web-check.json +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/__main__.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/commands/__init__.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/commands/auth.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/commands/base.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/commands/check_groups.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/commands/check_secrets.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/commands/secrets.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/formatters/__init__.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/formatters/base_formatter.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/formatters/generic_formatter.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/formatters/multistep_formatter.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/formatters/registry.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/formatters/ssl_formatter.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/formatters/synthetic_formatter.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/formatters/web_formatter.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/main.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/utils/__init__.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/utils/config.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli/utils/console.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli.egg-info/dependency_links.txt +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli.egg-info/entry_points.txt +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/pingera_cli.egg-info/top_level.txt +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/replit.md +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/run_tests.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/setup.cfg +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/setup.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/tests/__init__.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/tests/conftest.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/tests/requirements.txt +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/tests/test_auth.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/tests/test_checks.py +0 -0
- {pingera_cli-0.1.9 → pingera_cli-0.1.11}/tests/test_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pingera-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: A beautiful Python CLI tool built with typer and rich, distributed via pip and based on Pingera SDK
|
|
5
5
|
Home-page: https://github.com/pingera/pingera-cli
|
|
6
6
|
Author: PingeraCLI Team
|
|
@@ -31,7 +31,7 @@ Description-Content-Type: text/markdown
|
|
|
31
31
|
License-File: LICENSE
|
|
32
32
|
Requires-Dist: typer[all]>=0.9.0
|
|
33
33
|
Requires-Dist: rich>=13.0.0
|
|
34
|
-
Requires-Dist: pingera-sdk>=1.0.
|
|
34
|
+
Requires-Dist: pingera-sdk>=1.0.8
|
|
35
35
|
Requires-Dist: click>=8.0.0
|
|
36
36
|
Provides-Extra: dev
|
|
37
37
|
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
@@ -348,15 +348,18 @@ pngr checks create --from-file check-config.json --name "Override Name"
|
|
|
348
348
|
|
|
349
349
|
### Run on-demand checks
|
|
350
350
|
```bash
|
|
351
|
-
# From command line options
|
|
352
|
-
pngr checks run custom --url https://example.com --type web
|
|
351
|
+
# From command line options (waits for result by default)
|
|
352
|
+
pngr checks run custom --url https://example.com --type web
|
|
353
353
|
|
|
354
|
-
#
|
|
355
|
-
pngr checks run custom --
|
|
356
|
-
|
|
354
|
+
# Just queue without waiting for results
|
|
355
|
+
pngr checks run custom --url https://example.com --type web --no-wait
|
|
356
|
+
|
|
357
|
+
# From configuration file (waits for result by default)
|
|
358
|
+
pngr checks run custom --from-file check-config.json
|
|
359
|
+
pngr checks run custom --from-file check-config.yaml
|
|
357
360
|
|
|
358
361
|
# Combine file and command line (command line options override file values)
|
|
359
|
-
pngr checks run custom --from-file check-config.json --name "Override Name"
|
|
362
|
+
pngr checks run custom --from-file check-config.json --name "Override Name"
|
|
360
363
|
```
|
|
361
364
|
|
|
362
365
|
## 🔐 Secrets Management
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Pingera CLI - A beautiful CLI tool for Pingera Platform
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
__version__ = "0.1.
|
|
5
|
+
__version__ = "0.1.11"
|
|
6
6
|
__author__ = "Pingera Team"
|
|
7
7
|
__description__ = "A beautiful Python CLI tool built with typer and rich, distributed via pip and based on Pingera SDK"
|
|
8
8
|
|
|
@@ -390,45 +390,17 @@ class ChecksCommand(BaseCommand):
|
|
|
390
390
|
raise typer.Exit(1)
|
|
391
391
|
|
|
392
392
|
def _parse_check_file(self, file_path: str) -> dict:
|
|
393
|
-
"""Parse check configuration from JSON or YAML file"""
|
|
394
|
-
import
|
|
395
|
-
import os
|
|
396
|
-
|
|
397
|
-
if not os.path.exists(file_path):
|
|
398
|
-
self.display_error(f"Check file not found: {file_path}")
|
|
399
|
-
raise typer.Exit(1)
|
|
393
|
+
"""Parse check configuration from JSON or YAML file (local or URL)"""
|
|
394
|
+
from ..utils.file_utils import load_check_file, is_url
|
|
400
395
|
|
|
401
396
|
try:
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
if not content:
|
|
406
|
-
self.display_error(f"Check file is empty: {file_path}")
|
|
407
|
-
raise typer.Exit(1)
|
|
397
|
+
if is_url(file_path):
|
|
398
|
+
self.display_info(f"Downloading check configuration from: {file_path}")
|
|
408
399
|
|
|
409
|
-
|
|
410
|
-
file_ext = os.path.splitext(file_path)[1].lower()
|
|
400
|
+
return load_check_file(file_path)
|
|
411
401
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
import yaml
|
|
415
|
-
return yaml.safe_load(content)
|
|
416
|
-
except ImportError:
|
|
417
|
-
self.display_error("YAML support not available. Install with: pip install pyyaml")
|
|
418
|
-
raise typer.Exit(1)
|
|
419
|
-
except yaml.YAMLError as e:
|
|
420
|
-
self.display_error(f"Invalid YAML in file {file_path}: {str(e)}")
|
|
421
|
-
raise typer.Exit(1)
|
|
422
|
-
else:
|
|
423
|
-
# Default to JSON
|
|
424
|
-
try:
|
|
425
|
-
return json.loads(content)
|
|
426
|
-
except json.JSONDecodeError as e:
|
|
427
|
-
self.display_error(f"Invalid JSON in file {file_path}: {str(e)}")
|
|
428
|
-
raise typer.Exit(1)
|
|
429
|
-
|
|
430
|
-
except IOError as e:
|
|
431
|
-
self.display_error(f"Failed to read check file: {str(e)}")
|
|
402
|
+
except Exception as e:
|
|
403
|
+
self.display_error(str(e))
|
|
432
404
|
raise typer.Exit(1)
|
|
433
405
|
|
|
434
406
|
def create_check(self, name: str, check_type: str, url: Optional[str] = None, host: Optional[str] = None, port: Optional[int] = None, interval: int = 300, timeout: int = 30, parameters: Optional[str] = None, pw_script_file: Optional[str] = None, from_file: Optional[str] = None):
|
|
@@ -1195,7 +1167,7 @@ def create_check(
|
|
|
1195
1167
|
timeout: int = typer.Option(30, "--timeout", help="Timeout in seconds"),
|
|
1196
1168
|
parameters: Optional[str] = typer.Option(None, "--parameters", help="JSON string with check parameters (e.g., '{\"regions\": [\"US\", \"EU\"]}')"),
|
|
1197
1169
|
pw_script_file: Optional[str] = typer.Option(None, "--pw-script-file", help="Path to file containing Playwright script for synthetic/multistep checks"),
|
|
1198
|
-
from_file: Optional[str] = typer.Option(None, "--from-file", help="Path to JSON or YAML file containing check configuration")
|
|
1170
|
+
from_file: Optional[str] = typer.Option(None, "--from-file", "-f", help="Path to JSON or YAML file containing check configuration")
|
|
1199
1171
|
):
|
|
1200
1172
|
"""Create a new monitoring check. Can be created from command line options or from a JSON/YAML file.
|
|
1201
1173
|
|
|
@@ -23,45 +23,17 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
23
23
|
super().__init__(output_format)
|
|
24
24
|
|
|
25
25
|
def _parse_check_file(self, file_path: str) -> dict:
|
|
26
|
-
"""Parse check configuration from JSON or YAML file"""
|
|
27
|
-
import
|
|
28
|
-
import os
|
|
29
|
-
|
|
30
|
-
if not os.path.exists(file_path):
|
|
31
|
-
self.display_error(f"Check file not found: {file_path}")
|
|
32
|
-
raise typer.Exit(1)
|
|
26
|
+
"""Parse check configuration from JSON or YAML file (local or URL)"""
|
|
27
|
+
from ..utils.file_utils import load_check_file, is_url
|
|
33
28
|
|
|
34
29
|
try:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if not content:
|
|
39
|
-
self.display_error(f"Check file is empty: {file_path}")
|
|
40
|
-
raise typer.Exit(1)
|
|
30
|
+
if is_url(file_path):
|
|
31
|
+
self.display_info(f"Downloading check configuration from: {file_path}")
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
file_ext = os.path.splitext(file_path)[1].lower()
|
|
33
|
+
return load_check_file(file_path)
|
|
44
34
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
import yaml
|
|
48
|
-
return yaml.safe_load(content)
|
|
49
|
-
except ImportError:
|
|
50
|
-
self.display_error("YAML support not available. Install with: pip install pyyaml")
|
|
51
|
-
raise typer.Exit(1)
|
|
52
|
-
except yaml.YAMLError as e:
|
|
53
|
-
self.display_error(f"Invalid YAML in file {file_path}: {str(e)}")
|
|
54
|
-
raise typer.Exit(1)
|
|
55
|
-
else:
|
|
56
|
-
# Default to JSON
|
|
57
|
-
try:
|
|
58
|
-
return json.loads(content)
|
|
59
|
-
except json.JSONDecodeError as e:
|
|
60
|
-
self.display_error(f"Invalid JSON in file {file_path}: {str(e)}")
|
|
61
|
-
raise typer.Exit(1)
|
|
62
|
-
|
|
63
|
-
except IOError as e:
|
|
64
|
-
self.display_error(f"Failed to read check file: {str(e)}")
|
|
35
|
+
except Exception as e:
|
|
36
|
+
self.display_error(str(e))
|
|
65
37
|
raise typer.Exit(1)
|
|
66
38
|
|
|
67
39
|
def get_client(self):
|
|
@@ -90,7 +62,7 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
90
62
|
self.display_error(f"Failed to initialize client: {str(e)}")
|
|
91
63
|
raise typer.Exit(1)
|
|
92
64
|
|
|
93
|
-
def execute_custom_check(self, url: Optional[str] = None, check_type: str = "web", host: Optional[str] = None, port: Optional[int] = None, timeout: int = 30, name: str = "On-demand check", parameters: Optional[str] = None, pw_script_file: Optional[str] = None, from_file: Optional[str] = None, wait_for_result: bool =
|
|
65
|
+
def execute_custom_check(self, url: Optional[str] = None, check_type: str = "web", host: Optional[str] = None, port: Optional[int] = None, timeout: int = 30, name: str = "On-demand check", parameters: Optional[str] = None, pw_script_file: Optional[str] = None, from_file: Optional[str] = None, wait_for_result: bool = True):
|
|
94
66
|
"""Execute custom on-demand check"""
|
|
95
67
|
try:
|
|
96
68
|
import json
|
|
@@ -274,7 +246,7 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
274
246
|
})
|
|
275
247
|
else:
|
|
276
248
|
self.display_success(
|
|
277
|
-
f"On-demand check queued successfully!\n" + "\n".join(success_details) + f"\n\nUse 'pngr checks jobs result {job_id}' to check status.",
|
|
249
|
+
f"On-demand check queued successfully!\n" + "\n".join(success_details) + f"\n\nUse 'pngr checks jobs result {job_id}' to check status.\n\n💡 Tip: Remove --no-wait to see results immediately.",
|
|
278
250
|
"✅ Check Queued"
|
|
279
251
|
)
|
|
280
252
|
|
|
@@ -282,7 +254,7 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
282
254
|
self.display_error(f"Failed to execute custom check: {str(e)}")
|
|
283
255
|
raise typer.Exit(1)
|
|
284
256
|
|
|
285
|
-
def execute_existing_check(self, check_id: str, wait_for_result: bool =
|
|
257
|
+
def execute_existing_check(self, check_id: str, wait_for_result: bool = True):
|
|
286
258
|
"""Execute existing check on demand"""
|
|
287
259
|
try:
|
|
288
260
|
checks_api = self.get_client()
|
|
@@ -304,7 +276,7 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
304
276
|
})
|
|
305
277
|
else:
|
|
306
278
|
self.display_success(
|
|
307
|
-
f"Existing check executed successfully!\nJob ID: {job_id}\nCheck ID: {check_id}\n\nUse 'pngr checks jobs result {job_id}' to check status.",
|
|
279
|
+
f"Existing check executed successfully!\nJob ID: {job_id}\nCheck ID: {check_id}\n\nUse 'pngr checks jobs result {job_id}' to check status.\n\n💡 Tip: Remove --no-wait to see results immediately.",
|
|
308
280
|
"✅ Check Executed"
|
|
309
281
|
)
|
|
310
282
|
|
|
@@ -717,11 +689,14 @@ def run_custom_check(
|
|
|
717
689
|
name: str = typer.Option("On-demand check", "--name", "-n", help="Check name"),
|
|
718
690
|
parameters: Optional[str] = typer.Option(None, "--parameters", help="JSON string with check parameters (e.g., '{\"regions\": [\"US\", \"EU\"]}')"),
|
|
719
691
|
pw_script_file: Optional[str] = typer.Option(None, "--pw-script-file", help="Path to file containing Playwright script for synthetic/multistep checks"),
|
|
720
|
-
from_file: Optional[str] = typer.Option(None, "--from-file", help="Path to JSON or YAML file containing check configuration"),
|
|
721
|
-
|
|
692
|
+
from_file: Optional[str] = typer.Option(None, "--from-file", "-f", help="Path to JSON or YAML file containing check configuration"),
|
|
693
|
+
no_wait: bool = typer.Option(False, "--no-wait", help="Don't wait for job completion, just queue the check and return job ID"),
|
|
722
694
|
):
|
|
723
695
|
"""Execute custom on-demand check. Can be executed from command line options or from a JSON/YAML file.
|
|
724
696
|
|
|
697
|
+
By default, waits for job completion and shows result immediately (max 5 minutes).
|
|
698
|
+
Use --no-wait to just queue the check and return the job ID.
|
|
699
|
+
|
|
725
700
|
When using --from-file:
|
|
726
701
|
- Command line options override file values
|
|
727
702
|
- File should contain check configuration in JSON or YAML format
|
|
@@ -732,17 +707,17 @@ def run_custom_check(
|
|
|
732
707
|
- ssl: --url or --host required
|
|
733
708
|
- synthetic/multistep: --pw-script-file or --parameters with pw_script required"""
|
|
734
709
|
on_demand_cmd = OnDemandChecksCommand(get_output_format())
|
|
735
|
-
on_demand_cmd.execute_custom_check(url, check_type, host, port, timeout, name, parameters, pw_script_file, from_file,
|
|
710
|
+
on_demand_cmd.execute_custom_check(url, check_type, host, port, timeout, name, parameters, pw_script_file, from_file, not no_wait)
|
|
736
711
|
|
|
737
712
|
|
|
738
713
|
@run_app.command("existing")
|
|
739
714
|
def run_existing_check(
|
|
740
715
|
check_id: str = typer.Argument(..., help="Existing check ID to execute"),
|
|
741
|
-
|
|
716
|
+
no_wait: bool = typer.Option(False, "--no-wait", help="Don't wait for job completion, just queue the check and return job ID"),
|
|
742
717
|
):
|
|
743
|
-
"""Execute existing check on demand"""
|
|
718
|
+
"""Execute existing check on demand. By default, waits for job completion and shows result immediately (max 5 minutes). Use --no-wait to just queue the check."""
|
|
744
719
|
on_demand_cmd = OnDemandChecksCommand(get_output_format())
|
|
745
|
-
on_demand_cmd.execute_existing_check(check_id,
|
|
720
|
+
on_demand_cmd.execute_existing_check(check_id, not no_wait)
|
|
746
721
|
|
|
747
722
|
|
|
748
723
|
@jobs_app.command("list")
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
File utilities for PingeraCLI
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import json
|
|
8
|
+
from typing import Dict, Any
|
|
9
|
+
from urllib.parse import urlparse
|
|
10
|
+
from urllib.request import urlopen, Request
|
|
11
|
+
from urllib.error import URLError, HTTPError
|
|
12
|
+
import typer
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def is_url(file_path: str) -> bool:
|
|
16
|
+
"""Check if the file path is a URL"""
|
|
17
|
+
try:
|
|
18
|
+
result = urlparse(file_path)
|
|
19
|
+
return all([result.scheme, result.netloc])
|
|
20
|
+
except Exception:
|
|
21
|
+
return False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def download_file_content(url: str) -> str:
|
|
25
|
+
"""Download content from a URL"""
|
|
26
|
+
try:
|
|
27
|
+
# Add a user agent to avoid being blocked by some servers
|
|
28
|
+
req = Request(url, headers={'User-Agent': 'PingeraCLI/1.0'})
|
|
29
|
+
|
|
30
|
+
with urlopen(req, timeout=30) as response:
|
|
31
|
+
if response.status != 200:
|
|
32
|
+
raise Exception(f"HTTP {response.status}: {response.reason}")
|
|
33
|
+
|
|
34
|
+
content = response.read().decode('utf-8')
|
|
35
|
+
return content
|
|
36
|
+
|
|
37
|
+
except HTTPError as e:
|
|
38
|
+
raise Exception(f"HTTP error {e.code}: {e.reason}")
|
|
39
|
+
except URLError as e:
|
|
40
|
+
raise Exception(f"URL error: {e.reason}")
|
|
41
|
+
except Exception as e:
|
|
42
|
+
raise Exception(f"Failed to download file: {str(e)}")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def parse_file_content(content: str, file_path: str) -> Dict[Any, Any]:
|
|
46
|
+
"""Parse file content as JSON or YAML"""
|
|
47
|
+
if not content.strip():
|
|
48
|
+
raise Exception(f"File content is empty: {file_path}")
|
|
49
|
+
|
|
50
|
+
# Try to determine format from file extension or content
|
|
51
|
+
file_ext = os.path.splitext(file_path)[1].lower()
|
|
52
|
+
|
|
53
|
+
if file_ext in ['.yaml', '.yml']:
|
|
54
|
+
try:
|
|
55
|
+
import yaml
|
|
56
|
+
return yaml.safe_load(content)
|
|
57
|
+
except ImportError:
|
|
58
|
+
raise Exception("YAML support not available. Install with: pip install pyyaml")
|
|
59
|
+
except yaml.YAMLError as e:
|
|
60
|
+
raise Exception(f"Invalid YAML in file {file_path}: {str(e)}")
|
|
61
|
+
else:
|
|
62
|
+
# Default to JSON
|
|
63
|
+
try:
|
|
64
|
+
return json.loads(content)
|
|
65
|
+
except json.JSONDecodeError as e:
|
|
66
|
+
raise Exception(f"Invalid JSON in file {file_path}: {str(e)}")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def load_check_file(file_path: str) -> Dict[Any, Any]:
|
|
70
|
+
"""Load check configuration from local file or URL"""
|
|
71
|
+
try:
|
|
72
|
+
if is_url(file_path):
|
|
73
|
+
# Download from URL
|
|
74
|
+
content = download_file_content(file_path)
|
|
75
|
+
return parse_file_content(content, file_path)
|
|
76
|
+
else:
|
|
77
|
+
# Load from local file
|
|
78
|
+
if not os.path.exists(file_path):
|
|
79
|
+
raise Exception(f"Check file not found: {file_path}")
|
|
80
|
+
|
|
81
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
82
|
+
content = f.read()
|
|
83
|
+
|
|
84
|
+
return parse_file_content(content, file_path)
|
|
85
|
+
|
|
86
|
+
except Exception as e:
|
|
87
|
+
# Re-raise with a more specific error message
|
|
88
|
+
if "Check file not found" in str(e) or "File content is empty" in str(e) or "Invalid JSON" in str(e) or "Invalid YAML" in str(e):
|
|
89
|
+
raise typer.Exit(1) from e
|
|
90
|
+
else:
|
|
91
|
+
raise Exception(f"Failed to load check file: {str(e)}") from e
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pingera-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: A beautiful Python CLI tool built with typer and rich, distributed via pip and based on Pingera SDK
|
|
5
5
|
Home-page: https://github.com/pingera/pingera-cli
|
|
6
6
|
Author: PingeraCLI Team
|
|
@@ -31,7 +31,7 @@ Description-Content-Type: text/markdown
|
|
|
31
31
|
License-File: LICENSE
|
|
32
32
|
Requires-Dist: typer[all]>=0.9.0
|
|
33
33
|
Requires-Dist: rich>=13.0.0
|
|
34
|
-
Requires-Dist: pingera-sdk>=1.0.
|
|
34
|
+
Requires-Dist: pingera-sdk>=1.0.8
|
|
35
35
|
Requires-Dist: click>=8.0.0
|
|
36
36
|
Provides-Extra: dev
|
|
37
37
|
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
@@ -259,8 +259,7 @@ class TestOnDemandChecksCommand:
|
|
|
259
259
|
'checks', 'run', 'custom',
|
|
260
260
|
'--url', 'https://example.com',
|
|
261
261
|
'--type', 'web',
|
|
262
|
-
'--name', 'Test Wait Check'
|
|
263
|
-
'--wait-for-result'
|
|
262
|
+
'--name', 'Test Wait Check'
|
|
264
263
|
])
|
|
265
264
|
|
|
266
265
|
assert result.exit_code == 0
|
|
@@ -290,8 +289,7 @@ class TestOnDemandChecksCommand:
|
|
|
290
289
|
|
|
291
290
|
with patch('time.sleep'): # Speed up the test
|
|
292
291
|
result = cli_runner.invoke(app, [
|
|
293
|
-
'checks', 'run', 'existing', 'check_123'
|
|
294
|
-
'--wait-for-result'
|
|
292
|
+
'checks', 'run', 'existing', 'check_123'
|
|
295
293
|
])
|
|
296
294
|
|
|
297
295
|
assert result.exit_code == 0
|
|
@@ -321,8 +319,7 @@ class TestOnDemandChecksCommand:
|
|
|
321
319
|
result = cli_runner.invoke(app, [
|
|
322
320
|
'checks', 'run', 'custom',
|
|
323
321
|
'--url', 'https://example.com',
|
|
324
|
-
'--type', 'web'
|
|
325
|
-
'--wait-for-result'
|
|
322
|
+
'--type', 'web'
|
|
326
323
|
])
|
|
327
324
|
|
|
328
325
|
# The command should still succeed (exit code 0) even with timeout
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|