doploy-cli 0.2.5__tar.gz → 0.2.7__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.
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/PKG-INFO +4 -3
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/README.md +3 -2
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/doploy_cli/SKILL.md +1 -1
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/doploy_cli/main.py +49 -21
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/doploy_cli.egg-info/PKG-INFO +4 -3
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/pyproject.toml +1 -1
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/LICENSE +0 -0
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/doploy_cli/__init__.py +0 -0
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/doploy_cli.egg-info/SOURCES.txt +0 -0
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/doploy_cli.egg-info/dependency_links.txt +0 -0
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/doploy_cli.egg-info/entry_points.txt +0 -0
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/doploy_cli.egg-info/requires.txt +0 -0
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/doploy_cli.egg-info/top_level.txt +0 -0
- {doploy_cli-0.2.5 → doploy_cli-0.2.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: doploy-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: doploy CLI: watch builds, read logs, and drive Odoo deployments from a terminal
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://doploy.io
|
|
@@ -129,8 +129,9 @@ doploy logs 418 --source test --filter ERROR
|
|
|
129
129
|
doploy logs 419 --source test -f
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
Exits on its own when the build settles. `--source odoo` follows the
|
|
133
|
-
|
|
132
|
+
Exits on its own when the build settles. `--source odoo` follows the Odoo server log (the same
|
|
133
|
+
odoo.log the dashboard's Logs tab shows, with tracebacks) and runs until Ctrl-C. It returns a 409
|
|
134
|
+
until Odoo has started for that build. `doploy --version` prints the installed CLI version.
|
|
134
135
|
|
|
135
136
|
**Ship a change to staging**
|
|
136
137
|
|
|
@@ -107,8 +107,9 @@ doploy logs 418 --source test --filter ERROR
|
|
|
107
107
|
doploy logs 419 --source test -f
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
Exits on its own when the build settles. `--source odoo` follows the
|
|
111
|
-
|
|
110
|
+
Exits on its own when the build settles. `--source odoo` follows the Odoo server log (the same
|
|
111
|
+
odoo.log the dashboard's Logs tab shows, with tracebacks) and runs until Ctrl-C. It returns a 409
|
|
112
|
+
until Odoo has started for that build. `doploy --version` prints the installed CLI version.
|
|
112
113
|
|
|
113
114
|
**Ship a change to staging**
|
|
114
115
|
|
|
@@ -39,7 +39,7 @@ Do not create a new build by hand for a branch you already pushed; the push did
|
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
doploy logs <build> --source test -f # follow the test run until the build settles
|
|
42
|
-
doploy logs <build> --source odoo --filter Traceback # the
|
|
42
|
+
doploy logs <build> --source odoo --filter Traceback # the Odoo server log (odoo.log), same as the Logs tab
|
|
43
43
|
doploy logs <build> --source build # doploy's own deploy log
|
|
44
44
|
```
|
|
45
45
|
|
|
@@ -183,8 +183,12 @@ def _free_port() -> int:
|
|
|
183
183
|
return s.getsockname()[1]
|
|
184
184
|
|
|
185
185
|
|
|
186
|
-
def _wait_for_callback(port: int, state: str, timeout: float = 300.0) -> str:
|
|
187
|
-
"""Serve one loopback request and return the OAuth `code` it carried.
|
|
186
|
+
def _wait_for_callback(port: int, state: str, done_url: str, timeout: float = 300.0) -> str:
|
|
187
|
+
"""Serve one loopback request and return the OAuth `code` it carried.
|
|
188
|
+
|
|
189
|
+
The browser is sent on to ``done_url?status=...`` (a branded page hosted by
|
|
190
|
+
the doploy server) rather than shown bare text from this loopback server.
|
|
191
|
+
"""
|
|
188
192
|
from urllib.parse import parse_qs, urlparse
|
|
189
193
|
result: dict = {}
|
|
190
194
|
|
|
@@ -192,15 +196,15 @@ def _wait_for_callback(port: int, state: str, timeout: float = 300.0) -> str:
|
|
|
192
196
|
def do_GET(self): # noqa: N802
|
|
193
197
|
q = parse_qs(urlparse(self.path).query)
|
|
194
198
|
if q.get('state', [''])[0] != state:
|
|
195
|
-
|
|
199
|
+
status, result['error'] = 'error', 'state mismatch'
|
|
196
200
|
elif q.get('error'):
|
|
197
|
-
|
|
201
|
+
status, result['error'] = 'cancelled', q['error'][0]
|
|
198
202
|
else:
|
|
199
|
-
|
|
200
|
-
self.send_response(
|
|
201
|
-
self.send_header('
|
|
203
|
+
status, result['code'] = 'ok', q.get('code', [''])[0]
|
|
204
|
+
self.send_response(302)
|
|
205
|
+
self.send_header('Location', f'{done_url}?status={status}')
|
|
206
|
+
self.send_header('Content-Length', '0')
|
|
202
207
|
self.end_headers()
|
|
203
|
-
self.wfile.write(f'<html><body style="font-family:sans-serif"><p>{body}</p></body></html>'.encode())
|
|
204
208
|
|
|
205
209
|
def log_message(self, *a): # silence
|
|
206
210
|
pass
|
|
@@ -241,7 +245,7 @@ def _browser_login(base: str) -> None:
|
|
|
241
245
|
print('Opening your browser to sign in to doploy. If it does not open, visit:')
|
|
242
246
|
print(f' {url}')
|
|
243
247
|
webbrowser.open(url)
|
|
244
|
-
code = _wait_for_callback(port, state)
|
|
248
|
+
code = _wait_for_callback(port, state, f'{issuer}/cli/complete')
|
|
245
249
|
|
|
246
250
|
tok = _oauth_token_request(base, {
|
|
247
251
|
'grant_type': 'authorization_code', 'code': code, 'redirect_uri': redirect_uri,
|
|
@@ -339,20 +343,29 @@ def cmd_tests(args):
|
|
|
339
343
|
c = data['counts']
|
|
340
344
|
print(f"build {data['build_id']} [{data['build_status']}] — "
|
|
341
345
|
f"{c['error']} errors, {c['fail']} failures, {c['warning']} warnings")
|
|
342
|
-
|
|
346
|
+
summarized = 0
|
|
343
347
|
for r in data['results']:
|
|
344
348
|
if r['error_type'] not in ('ERROR', 'FAIL') and not args.warnings:
|
|
345
349
|
continue
|
|
346
350
|
is_test = bool(r.get('test')) and r['test'] != 'Unknown'
|
|
347
|
-
if not is_test and not args.details:
|
|
348
|
-
loader_rows += 1 # module-loading summaries: only interesting with --details
|
|
349
|
-
continue
|
|
350
351
|
where = f"{r['module']}.{r['test']}" if is_test else '(module loading)'
|
|
351
352
|
print(f"\n[{r['error_type']}] {where}")
|
|
352
353
|
if args.details:
|
|
353
354
|
print(r['details'])
|
|
354
|
-
|
|
355
|
-
|
|
355
|
+
else:
|
|
356
|
+
# Without --details, the last line of the traceback is the one
|
|
357
|
+
# that names the problem (AssertionError: ..., ParseError: ...).
|
|
358
|
+
summary = _last_line(r.get('details'))
|
|
359
|
+
if summary:
|
|
360
|
+
print(f" {summary}")
|
|
361
|
+
summarized += 1
|
|
362
|
+
if summarized:
|
|
363
|
+
print("\n(use --details for full tracebacks)")
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def _last_line(text):
|
|
367
|
+
lines = [ln.strip() for ln in (text or '').splitlines() if ln.strip()]
|
|
368
|
+
return lines[-1] if lines else ''
|
|
356
369
|
|
|
357
370
|
|
|
358
371
|
def cmd_rebuild(args):
|
|
@@ -389,8 +402,14 @@ def _new_lines(previous: list[str], current: list[str]) -> list[str]:
|
|
|
389
402
|
_TERMINAL_BUILD_STATUSES = {'success', 'error', 'warning', 'active error', 'cancelled', 'deleted'}
|
|
390
403
|
|
|
391
404
|
|
|
405
|
+
_LOG_LINES_MAX = 2000
|
|
406
|
+
|
|
407
|
+
|
|
392
408
|
def cmd_logs(args):
|
|
393
409
|
client = _client(args)
|
|
410
|
+
if args.lines > _LOG_LINES_MAX:
|
|
411
|
+
print(f"note: the API returns at most {_LOG_LINES_MAX} lines; showing the last {_LOG_LINES_MAX}. "
|
|
412
|
+
f"Use --filter to search further back.", file=sys.stderr)
|
|
394
413
|
params = {'source': args.source, 'lines': str(args.lines)}
|
|
395
414
|
if args.filter:
|
|
396
415
|
params['filter'] = args.filter
|
|
@@ -419,12 +438,12 @@ def cmd_logs(args):
|
|
|
419
438
|
print(f"... (showing last {len(shown)} lines; use --lines to see more)", file=sys.stderr)
|
|
420
439
|
return
|
|
421
440
|
# Follow: poll and print only what is new. Build and test logs end when
|
|
422
|
-
# the build settles; the odoo source is
|
|
423
|
-
#
|
|
424
|
-
#
|
|
425
|
-
interval = max(args.interval,
|
|
441
|
+
# the build settles; the odoo source is the live Odoo server log, so it
|
|
442
|
+
# follows until Ctrl-C (like `tail -f`). Each odoo poll is an SSH tail on
|
|
443
|
+
# the host, so it is polled no faster than every 5s.
|
|
444
|
+
interval = max(args.interval, 5.0) if args.source == 'odoo' else args.interval
|
|
426
445
|
if args.source == 'odoo':
|
|
427
|
-
print(f'following
|
|
446
|
+
print(f'following the Odoo server log every {interval:.0f}s; Ctrl-C to stop', file=sys.stderr)
|
|
428
447
|
previous = shown
|
|
429
448
|
try:
|
|
430
449
|
while True:
|
|
@@ -549,8 +568,17 @@ def cmd_skill(args):
|
|
|
549
568
|
print('Other agents: `doploy skill print >> AGENTS.md`')
|
|
550
569
|
|
|
551
570
|
|
|
571
|
+
def _cli_version():
|
|
572
|
+
try:
|
|
573
|
+
from importlib.metadata import version
|
|
574
|
+
return version('doploy-cli')
|
|
575
|
+
except Exception: # not installed as a distribution (source checkout)
|
|
576
|
+
return 'unknown'
|
|
577
|
+
|
|
578
|
+
|
|
552
579
|
def main(argv=None):
|
|
553
580
|
p = argparse.ArgumentParser(prog='doploy', description=__doc__.splitlines()[0])
|
|
581
|
+
p.add_argument('--version', action='version', version=f'doploy {_cli_version()}')
|
|
554
582
|
p.add_argument('--token', help=argparse.SUPPRESS)
|
|
555
583
|
p.add_argument('--base', help=f'API base URL (default {DEFAULT_BASE})')
|
|
556
584
|
sub = p.add_subparsers(dest='command', required=True)
|
|
@@ -622,7 +650,7 @@ def main(argv=None):
|
|
|
622
650
|
help='keep printing new lines: build/test until the build settles, '
|
|
623
651
|
'odoo until Ctrl-C')
|
|
624
652
|
sp.add_argument('--interval', type=float, default=5.0,
|
|
625
|
-
help='poll seconds for --follow (odoo source: minimum
|
|
653
|
+
help='poll seconds for --follow (odoo source: minimum 5)')
|
|
626
654
|
sp.add_argument('--json', action='store_true')
|
|
627
655
|
sp.set_defaults(func=cmd_logs)
|
|
628
656
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: doploy-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: doploy CLI: watch builds, read logs, and drive Odoo deployments from a terminal
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://doploy.io
|
|
@@ -129,8 +129,9 @@ doploy logs 418 --source test --filter ERROR
|
|
|
129
129
|
doploy logs 419 --source test -f
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
Exits on its own when the build settles. `--source odoo` follows the
|
|
133
|
-
|
|
132
|
+
Exits on its own when the build settles. `--source odoo` follows the Odoo server log (the same
|
|
133
|
+
odoo.log the dashboard's Logs tab shows, with tracebacks) and runs until Ctrl-C. It returns a 409
|
|
134
|
+
until Odoo has started for that build. `doploy --version` prints the installed CLI version.
|
|
134
135
|
|
|
135
136
|
**Ship a change to staging**
|
|
136
137
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|