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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: doploy-cli
3
- Version: 0.2.5
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 running container's log
133
- instead and runs until Ctrl-C.
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 running container's log
111
- instead and runs until Ctrl-C.
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 running container (staging/prod)
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
- body, result['error'] = 'State mismatch. Close this tab and retry.', 'state mismatch'
199
+ status, result['error'] = 'error', 'state mismatch'
196
200
  elif q.get('error'):
197
- body, result['error'] = 'Login cancelled. You can close this tab.', q['error'][0]
201
+ status, result['error'] = 'cancelled', q['error'][0]
198
202
  else:
199
- body, result['code'] = 'Logged in to doploy. You can close this tab.', q.get('code', [''])[0]
200
- self.send_response(200)
201
- self.send_header('Content-Type', 'text/html')
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
- loader_rows = 0
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
- if loader_rows:
355
- print(f"\n(+{loader_rows} module-loading message(s); use --details to see them)")
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 a running container's stdout, so
423
- # it follows until Ctrl-C (like `docker logs -f`). Each odoo poll runs a
424
- # small playbook on the host, so it is polled no faster than every 15s.
425
- interval = max(args.interval, 15.0) if args.source == 'odoo' else 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 container logs every {interval:.0f}s; Ctrl-C to stop', file=sys.stderr)
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 15)')
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.5
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 running container's log
133
- instead and runs until Ctrl-C.
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
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "doploy-cli"
7
- version = "0.2.5"
7
+ version = "0.2.7"
8
8
  description = "doploy CLI: watch builds, read logs, and drive Odoo deployments from a terminal"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
File without changes
File without changes