savetest-cli 0.3.0rc1__tar.gz → 0.3.0rc2__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: savetest-cli
3
- Version: 0.3.0rc1
3
+ Version: 0.3.0rc2
4
4
  Summary: CLI for SaveTest: upload Allure results as a ZIP, as raw files, or by watching a directory
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.8
@@ -220,7 +220,7 @@ savetest watch ./allure-results \
220
220
  - Если тесты и загрузка — разные джобы, отдайте каталог `allure-results` артефактом тоже с `when: always`.
221
221
  - `--wait` оставляйте включённым: джоба должна завершиться только когда импорт дошёл до конца.
222
222
  - Вложения включайте только если они реально нужны. По умолчанию CLI их не шлёт.
223
- - `0.3.0rc1` — предварительная версия для SaveTest 1.5.0: `pip install savetest-cli==0.3.0rc1`. Обычный `pip install savetest-cli` остаётся на последней стабильной версии.
223
+ - `0.3.0rc2` — предварительная версия для SaveTest 1.5.0: `pip install savetest-cli==0.3.0rc2`. Обычный `pip install savetest-cli` остаётся на последней стабильной версии.
224
224
 
225
225
  ### Результаты по мере прогона
226
226
 
@@ -210,7 +210,7 @@ savetest watch ./allure-results \
210
210
  - Если тесты и загрузка — разные джобы, отдайте каталог `allure-results` артефактом тоже с `when: always`.
211
211
  - `--wait` оставляйте включённым: джоба должна завершиться только когда импорт дошёл до конца.
212
212
  - Вложения включайте только если они реально нужны. По умолчанию CLI их не шлёт.
213
- - `0.3.0rc1` — предварительная версия для SaveTest 1.5.0: `pip install savetest-cli==0.3.0rc1`. Обычный `pip install savetest-cli` остаётся на последней стабильной версии.
213
+ - `0.3.0rc2` — предварительная версия для SaveTest 1.5.0: `pip install savetest-cli==0.3.0rc2`. Обычный `pip install savetest-cli` остаётся на последней стабильной версии.
214
214
 
215
215
  ### Результаты по мере прогона
216
216
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "savetest-cli"
7
- version = "0.3.0rc1"
7
+ version = "0.3.0rc2"
8
8
  description = "CLI for SaveTest: upload Allure results as a ZIP, as raw files, or by watching a directory"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -0,0 +1 @@
1
+ __version__ = "0.3.0rc2"
@@ -22,6 +22,7 @@ DEFAULT_POLL_INTERVAL_SEC = 1.5
22
22
  DEFAULT_WAIT_TIMEOUT_SEC = 3600
23
23
  DEFAULT_FILE_BATCH_COUNT = 20
24
24
  DEFAULT_FILE_BATCH_BYTES = 32 * 1024 * 1024
25
+ DEFAULT_WATCH_BATCH_COUNT = 200
25
26
  DEFAULT_WATCH_INTERVAL_SEC = 0.5
26
27
  DEFAULT_SETTLE_SEC = 1.0
27
28
  DEFAULT_ATTACHMENT_WAIT_SEC = 5.0
@@ -868,14 +869,28 @@ def _snapshot_raw_files(root: Path, include_attachments: bool) -> Dict[str, Tupl
868
869
  return found
869
870
 
870
871
 
872
+ def _index_snapshot_names(
873
+ snapshot: Dict[str, Tuple[Path, int, int]],
874
+ ) -> Dict[str, List[str]]:
875
+ """Имя файла → пути. Сопоставление вложений не должно перебирать весь каталог."""
876
+ index: Dict[str, List[str]] = {}
877
+ for rel in snapshot:
878
+ index.setdefault(Path(rel).name, []).append(rel)
879
+ return index
880
+
881
+
871
882
  def _resolve_named_file(
872
883
  snapshot: Dict[str, Tuple[Path, int, int]],
873
884
  result_rel: str,
874
885
  source_name: str,
886
+ name_index: Optional[Dict[str, List[str]]] = None,
875
887
  ) -> Optional[str]:
876
888
  name = Path(source_name).name
877
889
  result_dir = str(Path(result_rel).parent)
878
- matches = [rel for rel in snapshot if Path(rel).name == name]
890
+ if name_index is None:
891
+ matches = [rel for rel in snapshot if Path(rel).name == name]
892
+ else:
893
+ matches = name_index.get(name) or []
879
894
  if not matches:
880
895
  return None
881
896
  for rel in matches:
@@ -921,6 +936,7 @@ def _pick_watch_batch(
921
936
  continue
922
937
  ready[rel] = path
923
938
 
939
+ name_index = _index_snapshot_names(snapshot)
924
940
  held = set()
925
941
  if include_attachments:
926
942
  for rel, path in list(ready.items()):
@@ -929,7 +945,7 @@ def _pick_watch_batch(
929
945
  document = _load_json_if_complete(path) or {}
930
946
  missing = False
931
947
  for source in _attachment_sources(document):
932
- attachment_rel = _resolve_named_file(snapshot, rel, source)
948
+ attachment_rel = _resolve_named_file(snapshot, rel, source, name_index)
933
949
  if attachment_rel is None or attachment_rel not in ready:
934
950
  missing = True
935
951
  break
@@ -952,7 +968,7 @@ def _pick_watch_batch(
952
968
  for rel, path in send_results:
953
969
  document = _load_json_if_complete(path) or {}
954
970
  for source in _attachment_sources(document):
955
- attachment_rel = _resolve_named_file(snapshot, rel, source)
971
+ attachment_rel = _resolve_named_file(snapshot, rel, source, name_index)
956
972
  if attachment_rel and attachment_rel in ready:
957
973
  needed.add(attachment_rel)
958
974
 
@@ -1005,6 +1021,9 @@ def _chunk_watch_selection(
1005
1021
  """Режет готовые файлы на пачки. Результат не отрывается от своих вложений."""
1006
1022
  results = [(rel, path) for rel, path in selected if _is_result_file(path)]
1007
1023
  extras = {rel: (rel, path) for rel, path in selected if not _is_result_file(path)}
1024
+ extras_by_name: Dict[str, List[str]] = {}
1025
+ for extra_rel in extras:
1026
+ extras_by_name.setdefault(Path(extra_rel).name, []).append(extra_rel)
1008
1027
  used = set()
1009
1028
  groups: List[List[Tuple[str, Path]]] = []
1010
1029
  for rel, path in results:
@@ -1012,10 +1031,10 @@ def _chunk_watch_selection(
1012
1031
  document = _load_json_if_complete(path) or {}
1013
1032
  for source in _attachment_sources(document):
1014
1033
  name = Path(source).name
1015
- for extra_rel, extra in extras.items():
1016
- if extra_rel in used or Path(extra_rel).name != name:
1034
+ for extra_rel in extras_by_name.get(name) or []:
1035
+ if extra_rel in used:
1017
1036
  continue
1018
- group.append(extra)
1037
+ group.append(extras[extra_rel])
1019
1038
  used.add(extra_rel)
1020
1039
  break
1021
1040
  groups.append(group)
@@ -1193,8 +1212,8 @@ def watch(
1193
1212
 
1194
1213
  Готовые файлы не уходят по одному. Если они появляются подряд, watch держит их
1195
1214
  --batch-window секунд после последнего нового и отправляет вместе. Дольше
1196
- --batch-max-wait секунд пачка не копится. Предел одной отправки — 20 файлов
1197
- или 32 МБ, как у upload_results.
1215
+ --batch-max-wait секунд пачка не копится. Предел одной отправки — 200 файлов
1216
+ или 32 МБ.
1198
1217
  """
1199
1218
  command = [arg for arg in ctx.args if arg != "--"]
1200
1219
  host = host.rstrip("/")
@@ -1209,6 +1228,7 @@ def watch(
1209
1228
  run_create_failed = False
1210
1229
  sent_batches = 0
1211
1230
  drain_until = 0.0
1231
+ announced_flush = False
1212
1232
  hold_opened = 0.0
1213
1233
  hold_quiet = 0.0
1214
1234
  hold_key: Optional[Tuple[str, ...]] = None
@@ -1267,6 +1287,10 @@ def watch(
1267
1287
  flushing = stop["requested"] or timed_out
1268
1288
 
1269
1289
  snapshot = _snapshot_raw_files(root, include_attachments) if root.is_dir() else {}
1290
+ if flushing and not announced_flush:
1291
+ pending = sum(1 for rel in snapshot if rel not in uploaded)
1292
+ click.echo(f"После остановки осталось файлов: {pending}.")
1293
+ announced_flush = True
1270
1294
  if any(rel not in uploaded for rel in snapshot):
1271
1295
  last_activity = now
1272
1296
 
@@ -1300,7 +1324,7 @@ def watch(
1300
1324
  hold_key = ready_key
1301
1325
 
1302
1326
  batch_full = bool(batch) and (
1303
- len(batch) >= DEFAULT_FILE_BATCH_COUNT
1327
+ len(batch) >= DEFAULT_WATCH_BATCH_COUNT
1304
1328
  or _selection_bytes(batch) >= DEFAULT_FILE_BATCH_BYTES
1305
1329
  )
1306
1330
  send_now = bool(batch) and _watch_batch_due(
@@ -1313,7 +1337,10 @@ def watch(
1313
1337
  flushing=flushing,
1314
1338
  )
1315
1339
  if send_now and not run_create_failed and (known_run_id or not inflight):
1316
- chunks = _chunk_watch_selection(batch)
1340
+ chunks = _chunk_watch_selection(
1341
+ batch,
1342
+ max_count=DEFAULT_WATCH_BATCH_COUNT,
1343
+ )
1317
1344
  if not known_run_id:
1318
1345
  chunks = chunks[:1]
1319
1346
  for chunk in chunks:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: savetest-cli
3
- Version: 0.3.0rc1
3
+ Version: 0.3.0rc2
4
4
  Summary: CLI for SaveTest: upload Allure results as a ZIP, as raw files, or by watching a directory
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.8
@@ -220,7 +220,7 @@ savetest watch ./allure-results \
220
220
  - Если тесты и загрузка — разные джобы, отдайте каталог `allure-results` артефактом тоже с `when: always`.
221
221
  - `--wait` оставляйте включённым: джоба должна завершиться только когда импорт дошёл до конца.
222
222
  - Вложения включайте только если они реально нужны. По умолчанию CLI их не шлёт.
223
- - `0.3.0rc1` — предварительная версия для SaveTest 1.5.0: `pip install savetest-cli==0.3.0rc1`. Обычный `pip install savetest-cli` остаётся на последней стабильной версии.
223
+ - `0.3.0rc2` — предварительная версия для SaveTest 1.5.0: `pip install savetest-cli==0.3.0rc2`. Обычный `pip install savetest-cli` остаётся на последней стабильной версии.
224
224
 
225
225
  ### Результаты по мере прогона
226
226
 
@@ -1 +0,0 @@
1
- __version__ = "0.3.0rc1"