cronbark 0.0.1__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.
cronbark-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CronBark
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: cronbark
3
+ Version: 0.0.1
4
+ Summary: CronBark Python SDK & CLI — 크론잡 모니터링을 위한 간편 연동 도구
5
+ Author: CronBark Team
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/wookja-0/cronbark-sdk
8
+ Project-URL: Repository, https://github.com/wookja-0/cronbark-sdk
9
+ Project-URL: Issues, https://github.com/wookja-0/cronbark-sdk/issues
10
+ Project-URL: Documentation, https://cronbark.com/docs
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: System Administrators
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: System :: Monitoring
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: httpx>=0.25.0
29
+ Requires-Dist: click>=8.0.0
30
+ Dynamic: license-file
31
+
32
+ # CronBark Python SDK
33
+
34
+ Python SDK and CLI for [CronBark](https://cronbark.com) — monitor any cron job
35
+ with a single decorator.
36
+
37
+ > **Preview / Alpha.** This SDK is in preview and the CronBark SaaS service is
38
+ > launching soon. The public API may change in backwards-incompatible ways
39
+ > before the 1.0 release.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install cronbark
45
+ ```
46
+
47
+ Requires **Python 3.9+**.
48
+
49
+ ## Quickstart
50
+
51
+ Get an API token from your CronBark dashboard, then pick whichever style fits
52
+ your job best.
53
+
54
+ ### 1. Context manager
55
+
56
+ Wrap any block of code — `start` is sent on entry, and `success` or `fail`
57
+ (with the traceback) is sent on exit.
58
+
59
+ ```python
60
+ import cronbark
61
+
62
+ cronbark.configure(token="YOUR_TOKEN")
63
+
64
+ with cronbark.monitor():
65
+ run_backup()
66
+ ```
67
+
68
+ ### 2. Decorator
69
+
70
+ Instrument an existing function in one line.
71
+
72
+ ```python
73
+ import cronbark
74
+
75
+ @cronbark.job("YOUR_TOKEN")
76
+ def generate_report():
77
+ ...
78
+ ```
79
+
80
+ ### 3. CLI — wrap any command
81
+
82
+ The easiest way to monitor an existing cron entry without touching its source:
83
+
84
+ ```bash
85
+ cronbark exec --token YOUR_TOKEN "python backup.py"
86
+ ```
87
+
88
+ Use it directly in `crontab`:
89
+
90
+ ```crontab
91
+ # Before
92
+ 0 * * * * /usr/bin/python3 /opt/scripts/backup.py
93
+
94
+ # After
95
+ 0 * * * * cronbark exec --token YOUR_TOKEN "/usr/bin/python3 /opt/scripts/backup.py"
96
+ ```
97
+
98
+ The CLI captures stdout/stderr, forwards them to CronBark, and exits with the
99
+ same status code as the wrapped command.
100
+
101
+ ## Configuration
102
+
103
+ The SDK reads configuration from environment variables by default:
104
+
105
+ | Variable | Purpose | Default |
106
+ |----------|---------|---------|
107
+ | `CRONBARK_TOKEN` | Your job's API token | _(none — required)_ |
108
+ | `CRONBARK_URL` | API base URL override (self-hosted, staging, etc.) | `https://api.cronbark.com` |
109
+
110
+ You can also configure the SDK programmatically:
111
+
112
+ ```python
113
+ import cronbark
114
+
115
+ cronbark.configure(
116
+ token="YOUR_TOKEN",
117
+ base_url="https://api.cronbark.com", # optional
118
+ timeout=10, # seconds, optional
119
+ )
120
+ ```
121
+
122
+ ## Public API
123
+
124
+ Top-level functions exported from the `cronbark` package:
125
+
126
+ | Symbol | Description |
127
+ |--------|-------------|
128
+ | `configure(token, base_url, timeout)` | Set global SDK configuration. |
129
+ | `monitor(token=None)` | Context manager — auto `start` / `success` / `fail`. |
130
+ | `job(token=None)` | Decorator wrapping a function with `monitor`. |
131
+ | `ping(token=None)` | One-shot `start + success`. |
132
+ | `start(token=None)` | Report execution start. |
133
+ | `success(token=None, output=None, metrics=None)` | Report success. |
134
+ | `fail(token=None, error_message=None, output=None)` | Report failure. |
135
+ | `tick(token=None)` | Heartbeat — report success without a prior `start`. |
136
+
137
+ CLI commands (`cronbark --help`):
138
+
139
+ ```
140
+ cronbark exec --token TOKEN "<command>" # wrap and run a command
141
+ cronbark ping TOKEN # one-shot start+success
142
+ cronbark start TOKEN
143
+ cronbark success TOKEN
144
+ cronbark fail TOKEN --msg "..."
145
+ cronbark tick TOKEN
146
+ cronbark discover # scan local crontab
147
+ ```
148
+
149
+ All HTTP calls are best-effort: network errors are swallowed and returned as
150
+ `{"status": "error", "message": "..."}` so an unreachable monitoring service
151
+ will never break your job.
152
+
153
+ ## Links
154
+
155
+ - Website: [cronbark.com](https://cronbark.com)
156
+ - Documentation: [cronbark.com/docs](https://cronbark.com/docs) _(coming soon)_
157
+ - Issues: [github.com/wookja-0/cronbark-sdk/issues](https://github.com/wookja-0/cronbark-sdk/issues)
158
+
159
+ ## License
160
+
161
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,130 @@
1
+ # CronBark Python SDK
2
+
3
+ Python SDK and CLI for [CronBark](https://cronbark.com) — monitor any cron job
4
+ with a single decorator.
5
+
6
+ > **Preview / Alpha.** This SDK is in preview and the CronBark SaaS service is
7
+ > launching soon. The public API may change in backwards-incompatible ways
8
+ > before the 1.0 release.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pip install cronbark
14
+ ```
15
+
16
+ Requires **Python 3.9+**.
17
+
18
+ ## Quickstart
19
+
20
+ Get an API token from your CronBark dashboard, then pick whichever style fits
21
+ your job best.
22
+
23
+ ### 1. Context manager
24
+
25
+ Wrap any block of code — `start` is sent on entry, and `success` or `fail`
26
+ (with the traceback) is sent on exit.
27
+
28
+ ```python
29
+ import cronbark
30
+
31
+ cronbark.configure(token="YOUR_TOKEN")
32
+
33
+ with cronbark.monitor():
34
+ run_backup()
35
+ ```
36
+
37
+ ### 2. Decorator
38
+
39
+ Instrument an existing function in one line.
40
+
41
+ ```python
42
+ import cronbark
43
+
44
+ @cronbark.job("YOUR_TOKEN")
45
+ def generate_report():
46
+ ...
47
+ ```
48
+
49
+ ### 3. CLI — wrap any command
50
+
51
+ The easiest way to monitor an existing cron entry without touching its source:
52
+
53
+ ```bash
54
+ cronbark exec --token YOUR_TOKEN "python backup.py"
55
+ ```
56
+
57
+ Use it directly in `crontab`:
58
+
59
+ ```crontab
60
+ # Before
61
+ 0 * * * * /usr/bin/python3 /opt/scripts/backup.py
62
+
63
+ # After
64
+ 0 * * * * cronbark exec --token YOUR_TOKEN "/usr/bin/python3 /opt/scripts/backup.py"
65
+ ```
66
+
67
+ The CLI captures stdout/stderr, forwards them to CronBark, and exits with the
68
+ same status code as the wrapped command.
69
+
70
+ ## Configuration
71
+
72
+ The SDK reads configuration from environment variables by default:
73
+
74
+ | Variable | Purpose | Default |
75
+ |----------|---------|---------|
76
+ | `CRONBARK_TOKEN` | Your job's API token | _(none — required)_ |
77
+ | `CRONBARK_URL` | API base URL override (self-hosted, staging, etc.) | `https://api.cronbark.com` |
78
+
79
+ You can also configure the SDK programmatically:
80
+
81
+ ```python
82
+ import cronbark
83
+
84
+ cronbark.configure(
85
+ token="YOUR_TOKEN",
86
+ base_url="https://api.cronbark.com", # optional
87
+ timeout=10, # seconds, optional
88
+ )
89
+ ```
90
+
91
+ ## Public API
92
+
93
+ Top-level functions exported from the `cronbark` package:
94
+
95
+ | Symbol | Description |
96
+ |--------|-------------|
97
+ | `configure(token, base_url, timeout)` | Set global SDK configuration. |
98
+ | `monitor(token=None)` | Context manager — auto `start` / `success` / `fail`. |
99
+ | `job(token=None)` | Decorator wrapping a function with `monitor`. |
100
+ | `ping(token=None)` | One-shot `start + success`. |
101
+ | `start(token=None)` | Report execution start. |
102
+ | `success(token=None, output=None, metrics=None)` | Report success. |
103
+ | `fail(token=None, error_message=None, output=None)` | Report failure. |
104
+ | `tick(token=None)` | Heartbeat — report success without a prior `start`. |
105
+
106
+ CLI commands (`cronbark --help`):
107
+
108
+ ```
109
+ cronbark exec --token TOKEN "<command>" # wrap and run a command
110
+ cronbark ping TOKEN # one-shot start+success
111
+ cronbark start TOKEN
112
+ cronbark success TOKEN
113
+ cronbark fail TOKEN --msg "..."
114
+ cronbark tick TOKEN
115
+ cronbark discover # scan local crontab
116
+ ```
117
+
118
+ All HTTP calls are best-effort: network errors are swallowed and returned as
119
+ `{"status": "error", "message": "..."}` so an unreachable monitoring service
120
+ will never break your job.
121
+
122
+ ## Links
123
+
124
+ - Website: [cronbark.com](https://cronbark.com)
125
+ - Documentation: [cronbark.com/docs](https://cronbark.com/docs) _(coming soon)_
126
+ - Issues: [github.com/wookja-0/cronbark-sdk/issues](https://github.com/wookja-0/cronbark-sdk/issues)
127
+
128
+ ## License
129
+
130
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,50 @@
1
+ """
2
+ CronBark Python SDK
3
+ 크론잡 모니터링을 위한 간편 연동 라이브러리.
4
+
5
+ 사용 예:
6
+ import cronbark
7
+
8
+ # 환경변수 또는 직접 설정
9
+ cronbark.configure(token="YOUR_TOKEN", base_url="https://api.cronbark.com")
10
+
11
+ # 컨텍스트 매니저 — 자동 start/success/fail
12
+ with cronbark.monitor("backup-daily"):
13
+ run_backup()
14
+
15
+ # 데코레이터
16
+ @cronbark.job("report-gen")
17
+ def generate_report():
18
+ ...
19
+
20
+ # 수동 호출
21
+ cronbark.ping("YOUR_TOKEN")
22
+ cronbark.start("YOUR_TOKEN")
23
+ cronbark.success("YOUR_TOKEN", output="Done: 100 rows")
24
+ cronbark.fail("YOUR_TOKEN", error_message="Connection refused")
25
+ cronbark.tick("YOUR_TOKEN")
26
+ """
27
+
28
+ from cronbark.client import (
29
+ configure,
30
+ fail,
31
+ job,
32
+ monitor,
33
+ ping,
34
+ start,
35
+ success,
36
+ tick,
37
+ )
38
+
39
+ __version__ = "0.0.1"
40
+
41
+ __all__ = [
42
+ "configure",
43
+ "monitor",
44
+ "job",
45
+ "ping",
46
+ "start",
47
+ "success",
48
+ "fail",
49
+ "tick",
50
+ ]
@@ -0,0 +1,185 @@
1
+ """
2
+ CronBark CLI — 터미널에서 크론잡을 모니터링하는 명령줄 도구.
3
+
4
+ 사용 예:
5
+ # 명령어 감싸기 (자동 start → 실행 → success/fail)
6
+ cronbark exec --token TOKEN "python backup.py"
7
+
8
+ # 수동 이벤트 전송
9
+ cronbark ping TOKEN
10
+ cronbark start TOKEN
11
+ cronbark success TOKEN
12
+ cronbark fail TOKEN --msg "Connection refused"
13
+ cronbark tick TOKEN
14
+
15
+ # crontab 자동 스캔
16
+ cronbark discover
17
+ """
18
+
19
+ import os
20
+ import subprocess
21
+ import sys
22
+
23
+ import click
24
+
25
+ from cronbark.client import configure, fail, ping, start, success, tick
26
+
27
+
28
+ @click.group()
29
+ @click.option(
30
+ "--url",
31
+ envvar="CRONBARK_URL",
32
+ default="https://api.cronbark.com",
33
+ help="CronBark API URL (기본: https://api.cronbark.com)",
34
+ )
35
+ def main(url: str):
36
+ """CronBark CLI - 크론잡 모니터링 도구"""
37
+ configure(base_url=url)
38
+
39
+
40
+ @main.command(name="ping")
41
+ @click.argument("token")
42
+ def do_ping(token: str):
43
+ """간단 ping (start + success 한 번에)"""
44
+ result = ping(token)
45
+ click.echo(f"[cronbark] {result.get('status', 'error')}: {result.get('message', '')}")
46
+
47
+
48
+ @main.command(name="start")
49
+ @click.argument("token")
50
+ def do_start(token: str):
51
+ """실행 시작 알림"""
52
+ result = start(token)
53
+ click.echo(f"[cronbark] {result.get('status', 'error')}: {result.get('message', '')}")
54
+
55
+
56
+ @main.command(name="success")
57
+ @click.argument("token")
58
+ def do_success(token: str):
59
+ """실행 성공 알림"""
60
+ result = success(token)
61
+ click.echo(f"[cronbark] {result.get('status', 'error')}: {result.get('message', '')}")
62
+
63
+
64
+ @main.command(name="fail")
65
+ @click.argument("token")
66
+ @click.option("--msg", default=None, help="에러 메시지")
67
+ def do_fail(token: str, msg: str):
68
+ """실행 실패 알림"""
69
+ result = fail(token, error_message=msg)
70
+ click.echo(f"[cronbark] {result.get('status', 'error')}: {result.get('message', '')}")
71
+
72
+
73
+ @main.command(name="tick")
74
+ @click.argument("token")
75
+ def do_tick(token: str):
76
+ """하트비트 전송"""
77
+ result = tick(token)
78
+ click.echo(f"[cronbark] {result.get('status', 'error')}: {result.get('message', '')}")
79
+
80
+
81
+ @main.command(name="exec")
82
+ @click.option("--token", envvar="CRONBARK_TOKEN", required=True, help="API 토큰")
83
+ @click.argument("command", nargs=-1, required=True)
84
+ def do_exec(token: str, command: tuple):
85
+ """
86
+ 명령어를 실행하고 결과를 자동 보고한다.
87
+
88
+ 사용: cronbark exec --token TOKEN "python backup.py"
89
+ """
90
+ cmd_str = " ".join(command)
91
+ click.echo(f"[cronbark] 실행: {cmd_str}")
92
+
93
+ # start 전송
94
+ start(token)
95
+
96
+ try:
97
+ # 명령어 실행
98
+ result = subprocess.run(
99
+ cmd_str,
100
+ shell=True,
101
+ capture_output=True,
102
+ text=True,
103
+ )
104
+
105
+ output = ""
106
+ if result.stdout:
107
+ output += result.stdout
108
+ if result.stderr:
109
+ output += "\n--- STDERR ---\n" + result.stderr
110
+
111
+ if result.returncode == 0:
112
+ # 성공
113
+ resp = success(token, output=output[:1_000_000] if output else None)
114
+ click.echo(f"[cronbark] 성공 (exit code 0)")
115
+ else:
116
+ # 실패
117
+ error_msg = f"Exit code {result.returncode}"
118
+ if result.stderr:
119
+ error_msg += f": {result.stderr[:500]}"
120
+ resp = fail(token, error_message=error_msg, output=output[:1_000_000] if output else None)
121
+ click.echo(f"[cronbark] 실패 (exit code {result.returncode})")
122
+
123
+ sys.exit(result.returncode)
124
+
125
+ except Exception as e:
126
+ fail(token, error_message=str(e))
127
+ click.echo(f"[cronbark] 에러: {e}")
128
+ sys.exit(1)
129
+
130
+
131
+ @main.command()
132
+ def discover():
133
+ """
134
+ 시스템의 crontab을 스캔하여 등록 가능한 크론잡 목록을 표시한다.
135
+ """
136
+ click.echo("[cronbark] crontab 스캔 중...")
137
+
138
+ try:
139
+ # 현재 사용자의 crontab 조회
140
+ result = subprocess.run(
141
+ ["crontab", "-l"],
142
+ capture_output=True,
143
+ text=True,
144
+ )
145
+
146
+ if result.returncode != 0:
147
+ click.echo("[cronbark] crontab이 비어있거나 접근할 수 없습니다.")
148
+ return
149
+
150
+ lines = result.stdout.strip().split("\n")
151
+ jobs = []
152
+ for line in lines:
153
+ line = line.strip()
154
+ # 주석과 빈 줄 건너뛰기
155
+ if not line or line.startswith("#"):
156
+ continue
157
+ # 환경변수 설정 건너뛰기
158
+ if "=" in line.split()[0]:
159
+ continue
160
+ jobs.append(line)
161
+
162
+ if not jobs:
163
+ click.echo("[cronbark] 등록된 crontab 작업이 없습니다.")
164
+ return
165
+
166
+ click.echo(f"\n발견된 크론잡 {len(jobs)}개:\n")
167
+ click.echo(f"{'#':<4} {'스케줄':<20} {'명령어'}")
168
+ click.echo("-" * 70)
169
+ for i, job_line in enumerate(jobs, 1):
170
+ parts = job_line.split(None, 5)
171
+ if len(parts) >= 6:
172
+ schedule = " ".join(parts[:5])
173
+ command = parts[5]
174
+ else:
175
+ schedule = "파싱 불가"
176
+ command = job_line
177
+ click.echo(f"{i:<4} {schedule:<20} {command}")
178
+
179
+ click.echo(f"\n[cronbark] 위 크론잡을 CronBark에 등록하려면 각 crontab 명령어를 다음처럼 감싸세요:")
180
+ click.echo(' cronbark exec --token YOUR_TOKEN "명령어"')
181
+
182
+ except FileNotFoundError:
183
+ click.echo("[cronbark] crontab 명령어를 찾을 수 없습니다. (Windows에서는 지원되지 않습니다)")
184
+ except Exception as e:
185
+ click.echo(f"[cronbark] 스캔 에러: {e}")
@@ -0,0 +1,161 @@
1
+ """
2
+ CronBark Python SDK 클라이언트.
3
+ HTTP API를 래핑하여 간편한 크론잡 모니터링을 제공한다.
4
+ """
5
+
6
+ import functools
7
+ import os
8
+ import sys
9
+ import traceback
10
+ from contextlib import contextmanager
11
+ from typing import Any, Callable, Optional
12
+
13
+ import httpx
14
+
15
+ # ── 글로벌 설정 ────────────────────────────────────────────────
16
+
17
+ _config = {
18
+ "token": os.environ.get("CRONBARK_TOKEN", ""),
19
+ "base_url": os.environ.get("CRONBARK_URL", "https://api.cronbark.com"),
20
+ "timeout": 10,
21
+ }
22
+
23
+
24
+ def configure(
25
+ token: Optional[str] = None,
26
+ base_url: Optional[str] = None,
27
+ timeout: int = 10,
28
+ ) -> None:
29
+ """SDK 글로벌 설정을 변경한다."""
30
+ if token is not None:
31
+ _config["token"] = token
32
+ if base_url is not None:
33
+ _config["base_url"] = base_url
34
+ _config["timeout"] = timeout
35
+
36
+
37
+ def _get_token(token: Optional[str] = None) -> str:
38
+ """토큰을 결정한다 (직접 전달 > 환경변수 > 글로벌 설정)."""
39
+ return token or _config["token"] or os.environ.get("CRONBARK_TOKEN", "")
40
+
41
+
42
+ def _api_url(token: str, endpoint: str) -> str:
43
+ """API URL을 구성한다."""
44
+ base = _config["base_url"].rstrip("/")
45
+ return f"{base}/api/v1/health/{token}/{endpoint}"
46
+
47
+
48
+ def _send(token: str, endpoint: str, body: Optional[dict] = None) -> dict:
49
+ """
50
+ 텔레메트리 이벤트를 전송한다.
51
+ 실패해도 예외를 발생시키지 않고 에러 dict를 반환한다.
52
+ """
53
+ url = _api_url(token, endpoint)
54
+ try:
55
+ with httpx.Client(timeout=_config["timeout"]) as client:
56
+ if body:
57
+ resp = client.post(url, json=body)
58
+ else:
59
+ resp = client.post(url)
60
+ return resp.json()
61
+ except Exception as e:
62
+ return {"status": "error", "message": str(e)}
63
+
64
+
65
+ # ── 공개 API ─────────────────────────────────────────────────
66
+
67
+
68
+ def ping(token: Optional[str] = None) -> dict:
69
+ """간단 ping — start+success를 한 번에."""
70
+ t = _get_token(token)
71
+ base = _config["base_url"].rstrip("/")
72
+ url = f"{base}/api/v1/ping/{t}"
73
+ try:
74
+ with httpx.Client(timeout=_config["timeout"]) as client:
75
+ resp = client.get(url)
76
+ return resp.json()
77
+ except Exception as e:
78
+ return {"status": "error", "message": str(e)}
79
+
80
+
81
+ def start(token: Optional[str] = None) -> dict:
82
+ """실행 시작을 알린다."""
83
+ return _send(_get_token(token), "start")
84
+
85
+
86
+ def success(
87
+ token: Optional[str] = None,
88
+ output: Optional[str] = None,
89
+ metrics: Optional[dict] = None,
90
+ ) -> dict:
91
+ """실행 성공을 알린다. output/metrics를 함께 전송할 수 있다."""
92
+ body = {}
93
+ if output:
94
+ body["output"] = output
95
+ if metrics:
96
+ body["metrics"] = metrics
97
+ return _send(_get_token(token), "success", body or None)
98
+
99
+
100
+ def fail(
101
+ token: Optional[str] = None,
102
+ error_message: Optional[str] = None,
103
+ output: Optional[str] = None,
104
+ ) -> dict:
105
+ """실행 실패를 알린다."""
106
+ body = {}
107
+ if error_message:
108
+ body["error_message"] = error_message
109
+ if output:
110
+ body["output"] = output
111
+ return _send(_get_token(token), "fail", body or None)
112
+
113
+
114
+ def tick(token: Optional[str] = None) -> dict:
115
+ """하트비트를 전송한다 (start 없이 즉시 성공)."""
116
+ return _send(_get_token(token), "tick")
117
+
118
+
119
+ # ── 컨텍스트 매니저 & 데코레이터 ───────────────────────────────
120
+
121
+
122
+ @contextmanager
123
+ def monitor(token: Optional[str] = None):
124
+ """
125
+ 컨텍스트 매니저 — with 블록 진입 시 start, 종료 시 success/fail 자동 전송.
126
+
127
+ 사용 예:
128
+ with cronbark.monitor("YOUR_TOKEN"):
129
+ run_backup()
130
+ """
131
+ t = _get_token(token)
132
+ start(t)
133
+ try:
134
+ yield
135
+ success(t)
136
+ except Exception as e:
137
+ # stdout/stderr 캡처
138
+ tb = traceback.format_exc()
139
+ fail(t, error_message=str(e), output=tb)
140
+ raise
141
+
142
+
143
+ def job(token: Optional[str] = None) -> Callable:
144
+ """
145
+ 데코레이터 — 함수 실행을 자동으로 모니터링한다.
146
+
147
+ 사용 예:
148
+ @cronbark.job("YOUR_TOKEN")
149
+ def generate_report():
150
+ ...
151
+ """
152
+
153
+ def decorator(func: Callable) -> Callable:
154
+ @functools.wraps(func)
155
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
156
+ with monitor(token):
157
+ return func(*args, **kwargs)
158
+
159
+ return wrapper
160
+
161
+ return decorator
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: cronbark
3
+ Version: 0.0.1
4
+ Summary: CronBark Python SDK & CLI — 크론잡 모니터링을 위한 간편 연동 도구
5
+ Author: CronBark Team
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/wookja-0/cronbark-sdk
8
+ Project-URL: Repository, https://github.com/wookja-0/cronbark-sdk
9
+ Project-URL: Issues, https://github.com/wookja-0/cronbark-sdk/issues
10
+ Project-URL: Documentation, https://cronbark.com/docs
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: System Administrators
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: System :: Monitoring
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: httpx>=0.25.0
29
+ Requires-Dist: click>=8.0.0
30
+ Dynamic: license-file
31
+
32
+ # CronBark Python SDK
33
+
34
+ Python SDK and CLI for [CronBark](https://cronbark.com) — monitor any cron job
35
+ with a single decorator.
36
+
37
+ > **Preview / Alpha.** This SDK is in preview and the CronBark SaaS service is
38
+ > launching soon. The public API may change in backwards-incompatible ways
39
+ > before the 1.0 release.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install cronbark
45
+ ```
46
+
47
+ Requires **Python 3.9+**.
48
+
49
+ ## Quickstart
50
+
51
+ Get an API token from your CronBark dashboard, then pick whichever style fits
52
+ your job best.
53
+
54
+ ### 1. Context manager
55
+
56
+ Wrap any block of code — `start` is sent on entry, and `success` or `fail`
57
+ (with the traceback) is sent on exit.
58
+
59
+ ```python
60
+ import cronbark
61
+
62
+ cronbark.configure(token="YOUR_TOKEN")
63
+
64
+ with cronbark.monitor():
65
+ run_backup()
66
+ ```
67
+
68
+ ### 2. Decorator
69
+
70
+ Instrument an existing function in one line.
71
+
72
+ ```python
73
+ import cronbark
74
+
75
+ @cronbark.job("YOUR_TOKEN")
76
+ def generate_report():
77
+ ...
78
+ ```
79
+
80
+ ### 3. CLI — wrap any command
81
+
82
+ The easiest way to monitor an existing cron entry without touching its source:
83
+
84
+ ```bash
85
+ cronbark exec --token YOUR_TOKEN "python backup.py"
86
+ ```
87
+
88
+ Use it directly in `crontab`:
89
+
90
+ ```crontab
91
+ # Before
92
+ 0 * * * * /usr/bin/python3 /opt/scripts/backup.py
93
+
94
+ # After
95
+ 0 * * * * cronbark exec --token YOUR_TOKEN "/usr/bin/python3 /opt/scripts/backup.py"
96
+ ```
97
+
98
+ The CLI captures stdout/stderr, forwards them to CronBark, and exits with the
99
+ same status code as the wrapped command.
100
+
101
+ ## Configuration
102
+
103
+ The SDK reads configuration from environment variables by default:
104
+
105
+ | Variable | Purpose | Default |
106
+ |----------|---------|---------|
107
+ | `CRONBARK_TOKEN` | Your job's API token | _(none — required)_ |
108
+ | `CRONBARK_URL` | API base URL override (self-hosted, staging, etc.) | `https://api.cronbark.com` |
109
+
110
+ You can also configure the SDK programmatically:
111
+
112
+ ```python
113
+ import cronbark
114
+
115
+ cronbark.configure(
116
+ token="YOUR_TOKEN",
117
+ base_url="https://api.cronbark.com", # optional
118
+ timeout=10, # seconds, optional
119
+ )
120
+ ```
121
+
122
+ ## Public API
123
+
124
+ Top-level functions exported from the `cronbark` package:
125
+
126
+ | Symbol | Description |
127
+ |--------|-------------|
128
+ | `configure(token, base_url, timeout)` | Set global SDK configuration. |
129
+ | `monitor(token=None)` | Context manager — auto `start` / `success` / `fail`. |
130
+ | `job(token=None)` | Decorator wrapping a function with `monitor`. |
131
+ | `ping(token=None)` | One-shot `start + success`. |
132
+ | `start(token=None)` | Report execution start. |
133
+ | `success(token=None, output=None, metrics=None)` | Report success. |
134
+ | `fail(token=None, error_message=None, output=None)` | Report failure. |
135
+ | `tick(token=None)` | Heartbeat — report success without a prior `start`. |
136
+
137
+ CLI commands (`cronbark --help`):
138
+
139
+ ```
140
+ cronbark exec --token TOKEN "<command>" # wrap and run a command
141
+ cronbark ping TOKEN # one-shot start+success
142
+ cronbark start TOKEN
143
+ cronbark success TOKEN
144
+ cronbark fail TOKEN --msg "..."
145
+ cronbark tick TOKEN
146
+ cronbark discover # scan local crontab
147
+ ```
148
+
149
+ All HTTP calls are best-effort: network errors are swallowed and returned as
150
+ `{"status": "error", "message": "..."}` so an unreachable monitoring service
151
+ will never break your job.
152
+
153
+ ## Links
154
+
155
+ - Website: [cronbark.com](https://cronbark.com)
156
+ - Documentation: [cronbark.com/docs](https://cronbark.com/docs) _(coming soon)_
157
+ - Issues: [github.com/wookja-0/cronbark-sdk/issues](https://github.com/wookja-0/cronbark-sdk/issues)
158
+
159
+ ## License
160
+
161
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ cronbark/__init__.py
5
+ cronbark/cli.py
6
+ cronbark/client.py
7
+ cronbark.egg-info/PKG-INFO
8
+ cronbark.egg-info/SOURCES.txt
9
+ cronbark.egg-info/dependency_links.txt
10
+ cronbark.egg-info/entry_points.txt
11
+ cronbark.egg-info/requires.txt
12
+ cronbark.egg-info/top_level.txt
13
+ tests/test_smoke.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ cronbark = cronbark.cli:main
@@ -0,0 +1,2 @@
1
+ httpx>=0.25.0
2
+ click>=8.0.0
@@ -0,0 +1 @@
1
+ cronbark
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cronbark"
7
+ version = "0.0.1"
8
+ description = "CronBark Python SDK & CLI — 크론잡 모니터링을 위한 간편 연동 도구"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = {text = "MIT"}
12
+ authors = [{name = "CronBark Team"}]
13
+ dependencies = [
14
+ "httpx>=0.25.0",
15
+ "click>=8.0.0",
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Developers",
20
+ "Intended Audience :: System Administrators",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.9",
26
+ "Programming Language :: Python :: 3.10",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Topic :: Software Development :: Libraries :: Python Modules",
31
+ "Topic :: System :: Monitoring",
32
+ ]
33
+
34
+ [project.scripts]
35
+ cronbark = "cronbark.cli:main"
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/wookja-0/cronbark-sdk"
39
+ Repository = "https://github.com/wookja-0/cronbark-sdk"
40
+ Issues = "https://github.com/wookja-0/cronbark-sdk/issues"
41
+ Documentation = "https://cronbark.com/docs"
42
+
43
+ [tool.setuptools.packages.find]
44
+ include = ["cronbark*"]
45
+
46
+ [tool.ruff]
47
+ # 초기 릴리스 — 느슨한 설정, 나중에 조일 수 있음
48
+ line-length = 100
49
+ target-version = "py39"
50
+
51
+ [tool.ruff.lint]
52
+ # pycodestyle/pyflakes 기본만, 노이즈 규칙 제외
53
+ select = ["E", "F", "W"]
54
+ ignore = [
55
+ "E501", # line too long (line-length 로 제어)
56
+ ]
57
+
58
+ [tool.ruff.lint.per-file-ignores]
59
+ "__init__.py" = ["F401"] # 재수출 허용
60
+ "tests/*" = ["F401", "F811"]
61
+
62
+ [tool.pytest.ini_options]
63
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,19 @@
1
+ """스모크 테스트 — 패키지 임포트 및 버전 확인."""
2
+
3
+ import cronbark
4
+
5
+
6
+ def test_import():
7
+ """패키지가 정상적으로 임포트되는지 확인."""
8
+ assert cronbark is not None
9
+
10
+
11
+ def test_version():
12
+ """버전이 예상 값과 일치하는지 확인."""
13
+ assert cronbark.__version__ == "0.0.1"
14
+
15
+
16
+ def test_public_api():
17
+ """공개 API가 모두 export 되어 있는지 확인."""
18
+ for name in ("configure", "monitor", "job", "ping", "start", "success", "fail", "tick"):
19
+ assert hasattr(cronbark, name), f"cronbark.{name} 누락"