feat(db-repo): порог на длину вывода и функциональные тесты

Операция над всей конфигурацией перечисляет тысячи объектов, и весь список
уезжал в вывод модели. Списки обрезаются на двадцати позициях, полный уходит
в файл, путь к которому назван. Сырой лог платформы при отказе показывается
хвостом в 200 строк: итог и причину платформа пишет в конце.

Тесты на фейковой платформе — 12 кейсов, разбор лога проверяется без 1С на
логах, снятых со стенда. Ключевой кейс закрывает главное правило навыка:
платформа вернула 1, часть объектов захвачена, навык возвращает 0 с поимённым
предупреждением. Обрезка списка проверена на логе из тридцати объектов —
кейс требует и строку «и ещё 10», и отсутствие двадцать первого объекта
в выводе.

Проверено негативным контролем: намеренно сломанное ожидание роняет кейс,
то есть тесты действительно сверяют вывод, а не проходят вхолостую.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-23 13:25:11 +03:00
co-authored by Claude Opus 5
parent 67b8ad5b47
commit 4a49eea422
15 changed files with 598 additions and 28 deletions
+57 -14
View File
@@ -1,4 +1,4 @@
# db-repo v1.4 — 1C configuration repository operations # db-repo v1.5 — 1C configuration repository operations
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# NB: движок только 1cv8 — ibcmd работу с хранилищем не поддерживает (нет такого режима). # NB: движок только 1cv8 — ibcmd работу с хранилищем не поддерживает (нет такого режима).
<# <#
@@ -718,7 +718,11 @@ function Write-ReceivedWarning {
if (-not $Received -or $Received.Count -eq 0) { return } if (-not $Received -or $Received.Count -eq 0) { return }
Write-Host "" Write-Host ""
Write-Host "[warning] локальная конфигурация изменена, получено объектов из хранилища: $($Received.Count)" -ForegroundColor Yellow Write-Host "[warning] локальная конфигурация изменена, получено объектов из хранилища: $($Received.Count)" -ForegroundColor Yellow
foreach ($n in $Received) { Write-Host " $n" -ForegroundColor Yellow } $recvLimit = [Math]::Min($Received.Count, $script:ListLimit)
foreach ($n in $Received[0..($recvLimit - 1)]) { Write-Host " $n" -ForegroundColor Yellow }
if ($Received.Count -gt $script:ListLimit) {
Write-Host " … и ещё $($Received.Count - $script:ListLimit)" -ForegroundColor Yellow
}
$owners = Get-OwnerObjects $Received $owners = Get-OwnerObjects $Received
$hasRoot = @($Received | Where-Object { ($_ -split '\.').Count -eq 1 }).Count -gt 0 $hasRoot = @($Received | Where-Object { ($_ -split '\.').Count -eq 1 }).Count -gt 0
if ($owners.Count -gt 0) { if ($owners.Count -gt 0) {
@@ -804,11 +808,29 @@ function Get-ObjectKey {
return ($own -join '.').ToLowerInvariant() return ($own -join '.').ToLowerInvariant()
} }
# Операция над всей конфигурацией перечисляет тысячи объектов. Печатаем начало списка,
# остальное кладём в файл: модели нужен факт и путь, а не простыня.
$script:ListLimit = 20
function Save-ObjectList {
param([string[]]$Names, [string]$Key)
if (-not $Key) { $Key = 'objects' }
$path = Join-Path $env:TEMP "db-repo-$Key.txt"
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllLines($path, $Names, $utf8Bom)
return $path
}
function Write-RepoObjects { function Write-RepoObjects {
param([string]$Title, [string[]]$Names, [string]$Color = 'Green') param([string]$Title, [string[]]$Names, [string]$Color = 'Green', [string]$FileKey = 'objects')
if (-not $Names -or $Names.Count -eq 0) { return } if (-not $Names -or $Names.Count -eq 0) { return }
Write-Host "$Title ($($Names.Count)):" -ForegroundColor $Color Write-Host "$Title ($($Names.Count)):" -ForegroundColor $Color
foreach ($n in $Names) { Write-Host " $n" } $limit = [Math]::Min($Names.Count, $script:ListLimit)
foreach ($n in $Names[0..($limit - 1)]) { Write-Host " $n" }
if ($Names.Count -gt $script:ListLimit) {
$path = Save-ObjectList $Names $FileKey
Write-Host " … и ещё $($Names.Count - $script:ListLimit); полный список: $path" -ForegroundColor Yellow
}
} }
function Write-RepoVerdict { function Write-RepoVerdict {
@@ -816,7 +838,11 @@ function Write-RepoVerdict {
if ($Log.Missing.Count -gt 0) { if ($Log.Missing.Count -gt 0) {
Write-Host "Error: objects not found in the configuration:" -ForegroundColor Red Write-Host "Error: objects not found in the configuration:" -ForegroundColor Red
foreach ($n in $Log.Missing) { Write-Host " $n" -ForegroundColor Red } $missLimit = [Math]::Min($Log.Missing.Count, $script:ListLimit)
foreach ($n in $Log.Missing[0..($missLimit - 1)]) { Write-Host " $n" -ForegroundColor Red }
if ($Log.Missing.Count -gt $script:ListLimit) {
Write-Host " … и ещё $($Log.Missing.Count - $script:ListLimit); полный список: $(Save-ObjectList $Log.Missing 'missing')" -ForegroundColor Red
}
Write-Host "Возможные причины:" -ForegroundColor Yellow Write-Host "Возможные причины:" -ForegroundColor Yellow
Write-Host " - опечатка в имени. Принимаются обе формы: Справочник.Номенклатура и Catalog.Номенклатура" -ForegroundColor Yellow Write-Host " - опечатка в имени. Принимаются обе формы: Справочник.Номенклатура и Catalog.Номенклатура" -ForegroundColor Yellow
Write-Host " - база отстала от хранилища, объект появился позже — выполните /db-repo update" -ForegroundColor Yellow Write-Host " - база отстала от хранилища, объект появился позже — выполните /db-repo update" -ForegroundColor Yellow
@@ -829,10 +855,15 @@ function Write-RepoVerdict {
'lock' { 'lock' {
# Порядок вывода: факты, затем вердикт, и только потом совет. Совет длинный, и # Порядок вывода: факты, затем вердикт, и только потом совет. Совет длинный, и
# между фактами и вердиктом он прятал бы главную строку. # между фактами и вердиктом он прятал бы главную строку.
Write-RepoObjects "Захвачено" $Log.Locked Write-RepoObjects "Захвачено" $Log.Locked 'Green' 'locked'
if ($Log.LockedByOther.Count -gt 0) { if ($Log.LockedByOther.Count -gt 0) {
Write-Host "Не удалось захватить ($($Log.LockedByOther.Count)):" -ForegroundColor Yellow Write-Host "Не удалось захватить ($($Log.LockedByOther.Count)):" -ForegroundColor Yellow
foreach ($o in $Log.LockedByOther) { Write-Host " $($o.Name) — держит $($o.Holder)" -ForegroundColor Yellow } $blockedLimit = [Math]::Min($Log.LockedByOther.Count, $script:ListLimit)
foreach ($o in $Log.LockedByOther[0..($blockedLimit - 1)]) { Write-Host " $($o.Name) — держит $($o.Holder)" -ForegroundColor Yellow }
if ($Log.LockedByOther.Count -gt $script:ListLimit) {
$blockedPath = Save-ObjectList @($Log.LockedByOther | ForEach-Object { "$($_.Name)$($_.Holder)" }) 'blocked'
Write-Host " … и ещё $($Log.LockedByOther.Count - $script:ListLimit); полный список: $blockedPath" -ForegroundColor Yellow
}
} }
if ($Log.Locked.Count -eq 0 -and $Log.LockedByOther.Count -gt 0) { if ($Log.Locked.Count -eq 0 -and $Log.LockedByOther.Count -gt 0) {
# «Уже захвачено мной» платформа не печатает вовсе, поэтому отличить его от # «Уже захвачено мной» платформа не печатает вовсе, поэтому отличить его от
@@ -877,15 +908,19 @@ function Write-RepoVerdict {
if ($PlatformExit -ne 0) { if ($PlatformExit -ne 0) {
if ($Log.Modified.Count -gt 0) { if ($Log.Modified.Count -gt 0) {
Write-Host "Отмена захвата не выполнена: у объектов есть локальные изменения ($($Log.Modified.Count)):" -ForegroundColor Red Write-Host "Отмена захвата не выполнена: у объектов есть локальные изменения ($($Log.Modified.Count)):" -ForegroundColor Red
foreach ($n in $Log.Modified) { Write-Host " $n" -ForegroundColor Red } $modLimit = [Math]::Min($Log.Modified.Count, $script:ListLimit)
foreach ($n in $Log.Modified[0..($modLimit - 1)]) { Write-Host " $n" -ForegroundColor Red }
if ($Log.Modified.Count -gt $script:ListLimit) {
Write-Host " … и ещё $($Log.Modified.Count - $script:ListLimit); полный список: $(Save-ObjectList $Log.Modified 'modified')" -ForegroundColor Red
}
Write-Host "Поместите их (/db-repo commit) либо откажитесь от них: -Force перезапишет объекты версией из хранилища." -ForegroundColor Yellow Write-Host "Поместите их (/db-repo commit) либо откажитесь от них: -Force перезапишет объекты версией из хранилища." -ForegroundColor Yellow
} else { } else {
Write-Host "Отмена захвата не выполнена (код $PlatformExit)$(Get-ExitAnnotation $PlatformExit)" -ForegroundColor Red Write-Host "Отмена захвата не выполнена (код $PlatformExit)$(Get-ExitAnnotation $PlatformExit)" -ForegroundColor Red
} }
return 1 return 1
} }
Write-RepoObjects "Захват отменён" $Log.Unlocked Write-RepoObjects "Захват отменён" $Log.Unlocked 'Green' 'unlocked'
Write-RepoObjects "Не были захвачены — снимать нечего" $Log.NotLocked 'Yellow' Write-RepoObjects "Не были захвачены — снимать нечего" $Log.NotLocked 'Yellow' 'not-locked'
if ($Log.Unlocked.Count -eq 0) { Write-Host "Изменений не потребовалось." -ForegroundColor Green } if ($Log.Unlocked.Count -eq 0) { Write-Host "Изменений не потребовалось." -ForegroundColor Green }
Write-ReceivedWarning $Log.Received Write-ReceivedWarning $Log.Received
return 0 return 0
@@ -901,8 +936,8 @@ function Write-RepoVerdict {
Write-Host " - есть ли у пользователя хранилища право на помещение" -ForegroundColor Yellow Write-Host " - есть ли у пользователя хранилища право на помещение" -ForegroundColor Yellow
return 1 return 1
} }
Write-RepoObjects "Помещено в хранилище" $Log.Committed Write-RepoObjects "Помещено в хранилище" $Log.Committed 'Green' 'committed'
Write-RepoObjects "Без изменений — не помещались" $Log.Unchanged 'Yellow' Write-RepoObjects "Без изменений — не помещались" $Log.Unchanged 'Yellow' 'unchanged'
if ($Log.Committed.Count -eq 0) { if ($Log.Committed.Count -eq 0) {
Write-Host "Новая версия в хранилище НЕ создана: помещать было нечего." -ForegroundColor Yellow Write-Host "Новая версия в хранилище НЕ создана: помещать было нечего." -ForegroundColor Yellow
} }
@@ -922,7 +957,7 @@ function Write-RepoVerdict {
Write-Host " всю конфигурацию базы содержимым хранилища. Проверьте состояние базы." -ForegroundColor Red Write-Host " всю конфигурацию базы содержимым хранилища. Проверьте состояние базы." -ForegroundColor Red
return 1 return 1
} }
Write-RepoObjects "Получено из хранилища" $Log.Received Write-RepoObjects "Получено из хранилища" $Log.Received 'Green' 'received'
if ($Log.Received.Count -eq 0) { if ($Log.Received.Count -eq 0) {
Write-Host "Изменений в хранилище нет — конфигурация уже актуальна." -ForegroundColor Green Write-Host "Изменений в хранилище нет — конфигурация уже актуальна." -ForegroundColor Green
return 0 return 0
@@ -1154,8 +1189,16 @@ try {
$verdict = Write-RepoVerdict $cmd $log $exitCode $requested $verdict = Write-RepoVerdict $cmd $log $exitCode $requested
# Разбор мог не покрыть причину (у commit её вовсе нет в логе) — при отказе показываем сырой лог. # Разбор мог не покрыть причину (у commit её вовсе нет в логе) — при отказе показываем сырой лог.
if ($verdict -ne 0 -and $logText.Trim()) { if ($verdict -ne 0 -and $logText.Trim()) {
# Лог операции над всей конфигурацией — тысячи строк. Показываем хвост: итог и причина
# отказа платформа пишет в конце.
$logLines = @($logText.TrimEnd() -split "`r?`n")
$logLimit = 200
Write-Host "--- Log ---" Write-Host "--- Log ---"
Write-Host $logText.TrimEnd() if ($logLines.Count -gt $logLimit) {
Write-Host "[... показаны последние $logLimit строк из $($logLines.Count) ...]"
$logLines = $logLines[($logLines.Count - $logLimit)..($logLines.Count - 1)]
}
Write-Host ($logLines -join [Environment]::NewLine)
Write-Host "--- End ---" Write-Host "--- End ---"
} }
Write-PlatformOutput $proc.Output Write-PlatformOutput $proc.Output
+51 -14
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# db-repo v1.4 — 1C configuration repository operations # db-repo v1.5 — 1C configuration repository operations
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# NB: движок только 1cv8 — ibcmd работу с хранилищем не поддерживает (нет такого режима). # NB: движок только 1cv8 — ibcmd работу с хранилищем не поддерживает (нет такого режима).
"""Работа с хранилищем конфигурации 1С. """Работа с хранилищем конфигурации 1С.
@@ -622,8 +622,10 @@ def print_received_warning(received):
return return
print("") print("")
print("[warning] локальная конфигурация изменена, получено объектов из хранилища: %d" % len(received)) print("[warning] локальная конфигурация изменена, получено объектов из хранилища: %d" % len(received))
for n in received: for n in received[:LIST_LIMIT]:
print(" %s" % n) print(" %s" % n)
if len(received) > LIST_LIMIT:
print(" … и ещё %d" % (len(received) - LIST_LIMIT))
owners = owner_objects(received) owners = owner_objects(received)
has_root = any(len(n.split(".")) == 1 for n in received) has_root = any(len(n.split(".")) == 1 for n in received)
if owners: if owners:
@@ -705,19 +707,39 @@ def object_key(name):
return ".".join(own).lower() return ".".join(own).lower()
def print_repo_objects(title, names): # Операция над всей конфигурацией перечисляет тысячи объектов. Печатаем начало списка,
# остальное кладём в файл: модели нужен факт и путь, а не простыня.
LIST_LIMIT = 20
def save_object_list(names, key):
if not key:
key = "objects"
path = os.path.join(tempfile.gettempdir(), "db-repo-%s.txt" % key)
with open(path, "w", encoding="utf-8-sig", newline="\n") as f:
f.write("\n".join(names) + "\n")
return path
def print_repo_objects(title, names, file_key="objects"):
if not names: if not names:
return return
print("%s (%d):" % (title, len(names))) print("%s (%d):" % (title, len(names)))
for n in names: for n in names[:LIST_LIMIT]:
print(" %s" % n) print(" %s" % n)
if len(names) > LIST_LIMIT:
path = save_object_list(names, file_key)
print(" … и ещё %d; полный список: %s" % (len(names) - LIST_LIMIT, path))
def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", output_file=""): def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", output_file=""):
if log["missing"]: if log["missing"]:
print("Error: objects not found in the configuration:") print("Error: objects not found in the configuration:")
for n in log["missing"]: for n in log["missing"][:LIST_LIMIT]:
print(" %s" % n) print(" %s" % n)
if len(log["missing"]) > LIST_LIMIT:
print(" … и ещё %d; полный список: %s"
% (len(log["missing"]) - LIST_LIMIT, save_object_list(log["missing"], "missing")))
print("Возможные причины:") print("Возможные причины:")
print(" - опечатка в имени. Принимаются обе формы: Справочник.Номенклатура и Catalog.Номенклатура") print(" - опечатка в имени. Принимаются обе формы: Справочник.Номенклатура и Catalog.Номенклатура")
print(" - база отстала от хранилища, объект появился позже — выполните /db-repo update") print(" - база отстала от хранилища, объект появился позже — выполните /db-repo update")
@@ -728,11 +750,16 @@ def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", out
if cmd == "lock": if cmd == "lock":
# Порядок вывода: факты, затем вердикт, и только потом совет. Совет длинный, и # Порядок вывода: факты, затем вердикт, и только потом совет. Совет длинный, и
# между фактами и вердиктом он прятал бы главную строку. # между фактами и вердиктом он прятал бы главную строку.
print_repo_objects("Захвачено", log["locked"]) print_repo_objects("Захвачено", log["locked"], "locked")
if log["locked_by_other"]: if log["locked_by_other"]:
print("Не удалось захватить (%d):" % len(log["locked_by_other"])) print("Не удалось захватить (%d):" % len(log["locked_by_other"]))
for o in log["locked_by_other"]: for o in log["locked_by_other"][:LIST_LIMIT]:
print(" %s — держит %s" % (o["name"], o["holder"])) print(" %s — держит %s" % (o["name"], o["holder"]))
if len(log["locked_by_other"]) > LIST_LIMIT:
path = save_object_list(
["%s%s" % (o["name"], o["holder"]) for o in log["locked_by_other"]], "blocked")
print(" … и ещё %d; полный список: %s"
% (len(log["locked_by_other"]) - LIST_LIMIT, path))
if not log["locked"] and log["locked_by_other"]: if not log["locked"] and log["locked_by_other"]:
# «Уже захвачено мной» платформа не печатает вовсе, поэтому отличить его от # «Уже захвачено мной» платформа не печатает вовсе, поэтому отличить его от
# «не захвачено» по логу нельзя — сверяем с тем, что просили. Заняты ВСЕ # «не захвачено» по логу нельзя — сверяем с тем, что просили. Заняты ВСЕ
@@ -770,15 +797,18 @@ def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", out
if platform_exit != 0: if platform_exit != 0:
if log["modified"]: if log["modified"]:
print("Отмена захвата не выполнена: у объектов есть локальные изменения (%d):" % len(log["modified"])) print("Отмена захвата не выполнена: у объектов есть локальные изменения (%d):" % len(log["modified"]))
for n in log["modified"]: for n in log["modified"][:LIST_LIMIT]:
print(" %s" % n) print(" %s" % n)
if len(log["modified"]) > LIST_LIMIT:
print(" … и ещё %d; полный список: %s"
% (len(log["modified"]) - LIST_LIMIT, save_object_list(log["modified"], "modified")))
print("Поместите их (/db-repo commit) либо откажитесь от них: -Force перезапишет " print("Поместите их (/db-repo commit) либо откажитесь от них: -Force перезапишет "
"объекты версией из хранилища.") "объекты версией из хранилища.")
else: else:
print("Отмена захвата не выполнена (код %s)%s" % (platform_exit, describe_exit(platform_exit))) print("Отмена захвата не выполнена (код %s)%s" % (platform_exit, describe_exit(platform_exit)))
return 1 return 1
print_repo_objects("Захват отменён", log["unlocked"]) print_repo_objects("Захват отменён", log["unlocked"], "unlocked")
print_repo_objects("Не были захвачены — снимать нечего", log["not_locked"]) print_repo_objects("Не были захвачены — снимать нечего", log["not_locked"], "not-locked")
if not log["unlocked"]: if not log["unlocked"]:
print("Изменений не потребовалось.") print("Изменений не потребовалось.")
print_received_warning(log["received"]) print_received_warning(log["received"])
@@ -794,8 +824,8 @@ def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", out
print(" - не держит ли его другой пользователь") print(" - не держит ли его другой пользователь")
print(" - есть ли у пользователя хранилища право на помещение") print(" - есть ли у пользователя хранилища право на помещение")
return 1 return 1
print_repo_objects("Помещено в хранилище", log["committed"]) print_repo_objects("Помещено в хранилище", log["committed"], "committed")
print_repo_objects("Без изменений — не помещались", log["unchanged"]) print_repo_objects("Без изменений — не помещались", log["unchanged"], "unchanged")
if not log["committed"]: if not log["committed"]:
print("Новая версия в хранилище НЕ создана: помещать было нечего.") print("Новая версия в хранилище НЕ создана: помещать было нечего.")
return 0 return 0
@@ -812,7 +842,7 @@ def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", out
print(" Похоже, база НЕ подключена к хранилищу — в этом случае команда заменяет") print(" Похоже, база НЕ подключена к хранилищу — в этом случае команда заменяет")
print(" всю конфигурацию базы содержимым хранилища. Проверьте состояние базы.") print(" всю конфигурацию базы содержимым хранилища. Проверьте состояние базы.")
return 1 return 1
print_repo_objects("Получено из хранилища", log["received"]) print_repo_objects("Получено из хранилища", log["received"], "received")
if not log["received"]: if not log["received"]:
print("Изменений в хранилище нет — конфигурация уже актуальна.") print("Изменений в хранилище нет — конфигурация уже актуальна.")
return 0 return 0
@@ -1119,8 +1149,15 @@ def main():
args.ReportFormat, args.OutputFile) args.ReportFormat, args.OutputFile)
# Разбор мог не покрыть причину (у commit её вовсе нет в логе) — при отказе показываем сырой лог. # Разбор мог не покрыть причину (у commit её вовсе нет в логе) — при отказе показываем сырой лог.
if verdict != 0 and log_text.strip(): if verdict != 0 and log_text.strip():
# Лог операции над всей конфигурацией — тысячи строк. Показываем хвост: итог и причина
# отказа платформа пишет в конце.
log_lines = log_text.rstrip().splitlines()
log_limit = 200
print("--- Log ---") print("--- Log ---")
print(log_text.rstrip()) if len(log_lines) > log_limit:
print("[... показаны последние %d строк из %d ...]" % (log_limit, len(log_lines)))
log_lines = log_lines[-log_limit:]
print("\n".join(log_lines))
print("--- End ---") print("--- End ---")
print_platform_output(result) print_platform_output(result)
sys.exit(verdict) sys.exit(verdict)
+5
View File
@@ -0,0 +1,5 @@
{
"script": "db-repo/scripts/db-repo",
"setup": "none",
"args": []
}
@@ -0,0 +1,47 @@
{
"name": "Помещение без изменений: код 0, но версия не создана — и это сказано",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "---- Начало операции с хранилищем конфигурации ----\r\nОбъект не был изменен: Справочник.Номенклатура\r\n---- Операция с хранилищем конфигурации завершена ----\r\nПомещение изменений объектов в хранилище успешно завершено\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-RepositoryPath",
"{workDir}\\repo",
"-RepositoryUser",
"Admin",
"-Command",
"commit",
"-Objects",
"Справочник.Номенклатура",
"-Comment",
"x"
],
"expect": {
"stdoutContains": [
"Без изменений — не помещались (1):",
"Новая версия в хранилище НЕ создана"
]
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,29 @@
{
"name": "Ошибка: подкоманда не указана",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib"
],
"expectError": true,
"expect": {
"stdoutContains": "-Command is required"
},
"noSnapshot": "разбор аргументов, платформа не запускается"
}
@@ -0,0 +1,33 @@
{
"name": "Ошибка: хранилище не объявлено в реестре и не задано явно",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-Command",
"lock",
"-Objects",
"Справочник.Номенклатура"
],
"expectError": true,
"expect": {
"stdoutContains": "repository path is unknown"
},
"noSnapshot": "разбор аргументов, платформа не запускается"
}
@@ -0,0 +1,38 @@
{
"name": "Ошибка: корень конфигурации с -WithChildren — это вся конфигурация",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-RepositoryPath",
"{workDir}\\repo",
"-RepositoryUser",
"Admin",
"-Command",
"lock",
"-Objects",
"Конфигурация",
"-WithChildren"
],
"expectError": true,
"expect": {
"stdoutContains": "means the WHOLE configuration"
},
"noSnapshot": "разбор аргументов, платформа не запускается"
}
@@ -0,0 +1,31 @@
{
"name": "Ошибка: unbind неоднозначен — unlock или disconnect",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-Command",
"unbind"
],
"expectError": true,
"expect": {
"stdoutContains": "'unbind' is ambiguous"
},
"noSnapshot": "разбор аргументов, платформа не запускается"
}
@@ -0,0 +1,31 @@
{
"name": "Ошибка: неизвестная подкоманда",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-Command",
"bogus"
],
"expectError": true,
"expect": {
"stdoutContains": "unknown command 'bogus'"
},
"noSnapshot": "разбор аргументов, платформа не запускается"
}
@@ -0,0 +1,38 @@
{
"name": "Ошибка: lock без -Objects затронул бы всю конфигурацию",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-RepositoryPath",
"{workDir}\\repo",
"-RepositoryUser",
"Admin",
"-Command",
"lock"
],
"expectError": true,
"expect": {
"stdoutContains": [
"would affect the WHOLE configuration",
"подтвердите явно: -All"
]
},
"noSnapshot": "разбор аргументов, платформа не запускается"
}
@@ -0,0 +1,46 @@
{
"name": "Реквизит не объект хранилища: подставляется владелец, подмена проговаривается",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "---- Начало операции с хранилищем конфигурации ----\r\nОбъект захвачен для редактирования: Справочник.Контрагенты\r\n---- Операция с хранилищем конфигурации завершена ----\r\nЗахват объектов в хранилище успешно завершен\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-RepositoryPath",
"{workDir}\\repo",
"-RepositoryUser",
"Admin",
"-Command",
"lock",
"-Objects",
"Справочник.Контрагенты.Реквизит.Телефон,Справочник.Контрагенты.ТабличнаяЧасть.Контакты"
],
"expect": {
"stdoutContains": [
"части объекта отдельно не захватываются",
"Справочник.Контрагенты.Реквизит.Телефон -> Справочник.Контрагенты",
"Захвачено (1):"
]
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,47 @@
{
"name": "Длинный список объектов обрезается, полный уходит в файл",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "---- Начало операции с хранилищем конфигурации ----\r\nОбъект захвачен для редактирования: Справочник.Объект01\r\nОбъект захвачен для редактирования: Справочник.Объект02\r\nОбъект захвачен для редактирования: Справочник.Объект03\r\nОбъект захвачен для редактирования: Справочник.Объект04\r\nОбъект захвачен для редактирования: Справочник.Объект05\r\nОбъект захвачен для редактирования: Справочник.Объект06\r\nОбъект захвачен для редактирования: Справочник.Объект07\r\nОбъект захвачен для редактирования: Справочник.Объект08\r\nОбъект захвачен для редактирования: Справочник.Объект09\r\nОбъект захвачен для редактирования: Справочник.Объект10\r\nОбъект захвачен для редактирования: Справочник.Объект11\r\nОбъект захвачен для редактирования: Справочник.Объект12\r\nОбъект захвачен для редактирования: Справочник.Объект13\r\nОбъект захвачен для редактирования: Справочник.Объект14\r\nОбъект захвачен для редактирования: Справочник.Объект15\r\nОбъект захвачен для редактирования: Справочник.Объект16\r\nОбъект захвачен для редактирования: Справочник.Объект17\r\nОбъект захвачен для редактирования: Справочник.Объект18\r\nОбъект захвачен для редактирования: Справочник.Объект19\r\nОбъект захвачен для редактирования: Справочник.Объект20\r\nОбъект захвачен для редактирования: Справочник.Объект21\r\nОбъект захвачен для редактирования: Справочник.Объект22\r\nОбъект захвачен для редактирования: Справочник.Объект23\r\nОбъект захвачен для редактирования: Справочник.Объект24\r\nОбъект захвачен для редактирования: Справочник.Объект25\r\nОбъект захвачен для редактирования: Справочник.Объект26\r\nОбъект захвачен для редактирования: Справочник.Объект27\r\nОбъект захвачен для редактирования: Справочник.Объект28\r\nОбъект захвачен для редактирования: Справочник.Объект29\r\nОбъект захвачен для редактирования: Справочник.Объект30\r\n---- Операция с хранилищем конфигурации завершена ----\r\nЗахват объектов в хранилище успешно завершен\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-RepositoryPath",
"{workDir}\\repo",
"-RepositoryUser",
"Admin",
"-Command",
"lock",
"-All"
],
"expect": {
"stdoutContains": [
"Захвачено (30):",
"Справочник.Объект20",
"… и ещё 10",
"db-repo-locked.txt"
],
"stdoutNotContains": "Справочник.Объект21"
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,52 @@
{
"name": "Частичный захват на *nix: py-порт даёт тот же вердикт",
"osOnly": [
"darwin",
"linux"
],
"runtimeOnly": "python",
"preRun": [
{
"writeFile": {
"path": "fake.sh",
"content": "#!/bin/sh\n# Фейк платформы для *nix: вычитывает путь из /Out и кладёт туда готовый лог.\n# Значение /Out несёт кавычки ВНУТРИ токена (соглашение 1С, см. run_v8) — в batch их\n# снимает %~2, в sh их надо снять руками, иначе cp целится в имя с кавычками.\nSELF=$(dirname \"$0\")\nOUT=\"\"\nwhile [ $# -gt 0 ]; do\n if [ \"$1\" = \"/Out\" ]; then\n OUT=\"$2\"\n OUT=\"${OUT#\\\"}\"\n OUT=\"${OUT%\\\"}\"\n fi\n shift\ndone\ncp \"$SELF/log.txt\" \"$OUT\"\nexit 1\n",
"executable": true
}
},
{
"writeFile": {
"path": "log.txt",
"content": "---- Начало операции с хранилищем конфигурации ----\r\nОбъект захвачен для редактирования: Справочник.Номенклатура\r\nОбъект захвачен для редактирования другим пользователем: Справочник.Номенклатура.Форма.ФормаЭлемента (Ivanov) \r\n---- Операция с хранилищем конфигурации завершена ----\r\nОшибка захвата объектов в хранилище\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}/fake.sh",
"-InfoBasePath",
"{workDir}/ib",
"-RepositoryPath",
"{workDir}/repo",
"-RepositoryUser",
"Admin",
"-Command",
"lock",
"-Objects",
"Справочник.Номенклатура",
"-WithChildren"
],
"expect": {
"stdoutContains": [
"Захвачено (1):",
"держит Ivanov",
"захват выполнен частично"
]
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,49 @@
{
"name": "Частичный захват: платформа вернула 1, навык — 0 с поимённым предупреждением",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 1\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "---- Начало операции с хранилищем конфигурации ----\r\nОбъект захвачен для редактирования: Справочник.Номенклатура\r\nОбъект захвачен для редактирования другим пользователем: Справочник.Номенклатура.Форма.ФормаЭлемента (Ivanov) \r\n---- Операция с хранилищем конфигурации завершена ----\r\nОшибка захвата объектов в хранилище\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-RepositoryPath",
"{workDir}\\repo",
"-RepositoryUser",
"Admin",
"-Command",
"lock",
"-Objects",
"Справочник.Номенклатура",
"-WithChildren"
],
"expect": {
"stdoutContains": [
"Захвачено (1):",
"Справочник.Номенклатура",
"Не удалось захватить (1):",
"держит Ivanov",
"захват выполнен частично"
]
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,44 @@
{
"name": "update: платформа отчиталась об успехе без блока операции — база не подключена",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "Обновление конфигурации из хранилища успешно завершено\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-RepositoryPath",
"{workDir}\\repo",
"-RepositoryUser",
"Admin",
"-Command",
"update"
],
"expect": {
"stdoutContains": [
"printed no repository operation block",
"НЕ подключена к хранилищу"
]
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы",
"expectError": true
}