diff --git a/.claude/skills/db-repo/scripts/db-repo.ps1 b/.claude/skills/db-repo/scripts/db-repo.ps1 index 9c3f458fa..202de4b65 100644 --- a/.claude/skills/db-repo/scripts/db-repo.ps1 +++ b/.claude/skills/db-repo/scripts/db-repo.ps1 @@ -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 # NB: движок только 1cv8 — ibcmd работу с хранилищем не поддерживает (нет такого режима). <# @@ -718,7 +718,11 @@ function Write-ReceivedWarning { if (-not $Received -or $Received.Count -eq 0) { return } Write-Host "" 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 $hasRoot = @($Received | Where-Object { ($_ -split '\.').Count -eq 1 }).Count -gt 0 if ($owners.Count -gt 0) { @@ -804,11 +808,29 @@ function Get-ObjectKey { 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 { - 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 } 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 { @@ -816,7 +838,11 @@ function Write-RepoVerdict { if ($Log.Missing.Count -gt 0) { 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 " - опечатка в имени. Принимаются обе формы: Справочник.Номенклатура и Catalog.Номенклатура" -ForegroundColor Yellow Write-Host " - база отстала от хранилища, объект появился позже — выполните /db-repo update" -ForegroundColor Yellow @@ -829,10 +855,15 @@ function Write-RepoVerdict { 'lock' { # Порядок вывода: факты, затем вердикт, и только потом совет. Совет длинный, и # между фактами и вердиктом он прятал бы главную строку. - Write-RepoObjects "Захвачено" $Log.Locked + Write-RepoObjects "Захвачено" $Log.Locked 'Green' 'locked' if ($Log.LockedByOther.Count -gt 0) { 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) { # «Уже захвачено мной» платформа не печатает вовсе, поэтому отличить его от @@ -877,15 +908,19 @@ function Write-RepoVerdict { if ($PlatformExit -ne 0) { if ($Log.Modified.Count -gt 0) { 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 } else { Write-Host "Отмена захвата не выполнена (код $PlatformExit)$(Get-ExitAnnotation $PlatformExit)" -ForegroundColor Red } return 1 } - Write-RepoObjects "Захват отменён" $Log.Unlocked - Write-RepoObjects "Не были захвачены — снимать нечего" $Log.NotLocked 'Yellow' + Write-RepoObjects "Захват отменён" $Log.Unlocked 'Green' 'unlocked' + Write-RepoObjects "Не были захвачены — снимать нечего" $Log.NotLocked 'Yellow' 'not-locked' if ($Log.Unlocked.Count -eq 0) { Write-Host "Изменений не потребовалось." -ForegroundColor Green } Write-ReceivedWarning $Log.Received return 0 @@ -901,8 +936,8 @@ function Write-RepoVerdict { Write-Host " - есть ли у пользователя хранилища право на помещение" -ForegroundColor Yellow return 1 } - Write-RepoObjects "Помещено в хранилище" $Log.Committed - Write-RepoObjects "Без изменений — не помещались" $Log.Unchanged 'Yellow' + Write-RepoObjects "Помещено в хранилище" $Log.Committed 'Green' 'committed' + Write-RepoObjects "Без изменений — не помещались" $Log.Unchanged 'Yellow' 'unchanged' if ($Log.Committed.Count -eq 0) { Write-Host "Новая версия в хранилище НЕ создана: помещать было нечего." -ForegroundColor Yellow } @@ -922,7 +957,7 @@ function Write-RepoVerdict { Write-Host " всю конфигурацию базы содержимым хранилища. Проверьте состояние базы." -ForegroundColor Red return 1 } - Write-RepoObjects "Получено из хранилища" $Log.Received + Write-RepoObjects "Получено из хранилища" $Log.Received 'Green' 'received' if ($Log.Received.Count -eq 0) { Write-Host "Изменений в хранилище нет — конфигурация уже актуальна." -ForegroundColor Green return 0 @@ -1154,8 +1189,16 @@ try { $verdict = Write-RepoVerdict $cmd $log $exitCode $requested # Разбор мог не покрыть причину (у commit её вовсе нет в логе) — при отказе показываем сырой лог. if ($verdict -ne 0 -and $logText.Trim()) { + # Лог операции над всей конфигурацией — тысячи строк. Показываем хвост: итог и причина + # отказа платформа пишет в конце. + $logLines = @($logText.TrimEnd() -split "`r?`n") + $logLimit = 200 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-PlatformOutput $proc.Output diff --git a/.claude/skills/db-repo/scripts/db-repo.py b/.claude/skills/db-repo/scripts/db-repo.py index 47e289611..1945a2f88 100644 --- a/.claude/skills/db-repo/scripts/db-repo.py +++ b/.claude/skills/db-repo/scripts/db-repo.py @@ -1,5 +1,5 @@ #!/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 # NB: движок только 1cv8 — ibcmd работу с хранилищем не поддерживает (нет такого режима). """Работа с хранилищем конфигурации 1С. @@ -622,8 +622,10 @@ def print_received_warning(received): return print("") print("[warning] локальная конфигурация изменена, получено объектов из хранилища: %d" % len(received)) - for n in received: + for n in received[:LIST_LIMIT]: print(" %s" % n) + if len(received) > LIST_LIMIT: + print(" … и ещё %d" % (len(received) - LIST_LIMIT)) owners = owner_objects(received) has_root = any(len(n.split(".")) == 1 for n in received) if owners: @@ -705,19 +707,39 @@ def object_key(name): 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: return print("%s (%d):" % (title, len(names))) - for n in names: + for n in names[:LIST_LIMIT]: 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=""): if log["missing"]: print("Error: objects not found in the configuration:") - for n in log["missing"]: + for n in log["missing"][:LIST_LIMIT]: 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(" - опечатка в имени. Принимаются обе формы: Справочник.Номенклатура и Catalog.Номенклатура") print(" - база отстала от хранилища, объект появился позже — выполните /db-repo update") @@ -728,11 +750,16 @@ def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", out if cmd == "lock": # Порядок вывода: факты, затем вердикт, и только потом совет. Совет длинный, и # между фактами и вердиктом он прятал бы главную строку. - print_repo_objects("Захвачено", log["locked"]) + print_repo_objects("Захвачено", log["locked"], "locked") if 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"])) + 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"]: # «Уже захвачено мной» платформа не печатает вовсе, поэтому отличить его от # «не захвачено» по логу нельзя — сверяем с тем, что просили. Заняты ВСЕ @@ -770,15 +797,18 @@ def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", out if platform_exit != 0: if log["modified"]: print("Отмена захвата не выполнена: у объектов есть локальные изменения (%d):" % len(log["modified"])) - for n in log["modified"]: + for n in log["modified"][:LIST_LIMIT]: 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 перезапишет " "объекты версией из хранилища.") else: print("Отмена захвата не выполнена (код %s)%s" % (platform_exit, describe_exit(platform_exit))) return 1 - print_repo_objects("Захват отменён", log["unlocked"]) - print_repo_objects("Не были захвачены — снимать нечего", log["not_locked"]) + print_repo_objects("Захват отменён", log["unlocked"], "unlocked") + print_repo_objects("Не были захвачены — снимать нечего", log["not_locked"], "not-locked") if not log["unlocked"]: print("Изменений не потребовалось.") print_received_warning(log["received"]) @@ -794,8 +824,8 @@ def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", out print(" - не держит ли его другой пользователь") print(" - есть ли у пользователя хранилища право на помещение") return 1 - print_repo_objects("Помещено в хранилище", log["committed"]) - print_repo_objects("Без изменений — не помещались", log["unchanged"]) + print_repo_objects("Помещено в хранилище", log["committed"], "committed") + print_repo_objects("Без изменений — не помещались", log["unchanged"], "unchanged") if not log["committed"]: print("Новая версия в хранилище НЕ создана: помещать было нечего.") return 0 @@ -812,7 +842,7 @@ def write_repo_verdict(cmd, log, platform_exit, requested, report_format="", out print(" Похоже, база НЕ подключена к хранилищу — в этом случае команда заменяет") print(" всю конфигурацию базы содержимым хранилища. Проверьте состояние базы.") return 1 - print_repo_objects("Получено из хранилища", log["received"]) + print_repo_objects("Получено из хранилища", log["received"], "received") if not log["received"]: print("Изменений в хранилище нет — конфигурация уже актуальна.") return 0 @@ -1119,8 +1149,15 @@ def main(): args.ReportFormat, args.OutputFile) # Разбор мог не покрыть причину (у commit её вовсе нет в логе) — при отказе показываем сырой лог. if verdict != 0 and log_text.strip(): + # Лог операции над всей конфигурацией — тысячи строк. Показываем хвост: итог и причина + # отказа платформа пишет в конце. + log_lines = log_text.rstrip().splitlines() + log_limit = 200 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_platform_output(result) sys.exit(verdict) diff --git a/tests/skills/cases/db-repo/_skill.json b/tests/skills/cases/db-repo/_skill.json new file mode 100644 index 000000000..3f20d3bde --- /dev/null +++ b/tests/skills/cases/db-repo/_skill.json @@ -0,0 +1,5 @@ +{ + "script": "db-repo/scripts/db-repo", + "setup": "none", + "args": [] +} diff --git a/tests/skills/cases/db-repo/commit-nothing-to-place.json b/tests/skills/cases/db-repo/commit-nothing-to-place.json new file mode 100644 index 000000000..ab6915e8a --- /dev/null +++ b/tests/skills/cases/db-repo/commit-nothing-to-place.json @@ -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": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы" +} diff --git a/tests/skills/cases/db-repo/error-no-command.json b/tests/skills/cases/db-repo/error-no-command.json new file mode 100644 index 000000000..7b84447d9 --- /dev/null +++ b/tests/skills/cases/db-repo/error-no-command.json @@ -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": "разбор аргументов, платформа не запускается" +} diff --git a/tests/skills/cases/db-repo/error-no-repository.json b/tests/skills/cases/db-repo/error-no-repository.json new file mode 100644 index 000000000..38c9f44f5 --- /dev/null +++ b/tests/skills/cases/db-repo/error-no-repository.json @@ -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": "разбор аргументов, платформа не запускается" +} diff --git a/tests/skills/cases/db-repo/error-root-with-children.json b/tests/skills/cases/db-repo/error-root-with-children.json new file mode 100644 index 000000000..d712bbf79 --- /dev/null +++ b/tests/skills/cases/db-repo/error-root-with-children.json @@ -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": "разбор аргументов, платформа не запускается" +} diff --git a/tests/skills/cases/db-repo/error-unbind-ambiguous.json b/tests/skills/cases/db-repo/error-unbind-ambiguous.json new file mode 100644 index 000000000..f7e760f59 --- /dev/null +++ b/tests/skills/cases/db-repo/error-unbind-ambiguous.json @@ -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": "разбор аргументов, платформа не запускается" +} diff --git a/tests/skills/cases/db-repo/error-unknown-command.json b/tests/skills/cases/db-repo/error-unknown-command.json new file mode 100644 index 000000000..992dab0e9 --- /dev/null +++ b/tests/skills/cases/db-repo/error-unknown-command.json @@ -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": "разбор аргументов, платформа не запускается" +} diff --git a/tests/skills/cases/db-repo/error-whole-config-needs-all.json b/tests/skills/cases/db-repo/error-whole-config-needs-all.json new file mode 100644 index 000000000..79fc45d91 --- /dev/null +++ b/tests/skills/cases/db-repo/error-whole-config-needs-all.json @@ -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": "разбор аргументов, платформа не запускается" +} diff --git a/tests/skills/cases/db-repo/lock-attribute-resolves-to-owner.json b/tests/skills/cases/db-repo/lock-attribute-resolves-to-owner.json new file mode 100644 index 000000000..899652c8c --- /dev/null +++ b/tests/skills/cases/db-repo/lock-attribute-resolves-to-owner.json @@ -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": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы" +} diff --git a/tests/skills/cases/db-repo/lock-long-list-truncated.json b/tests/skills/cases/db-repo/lock-long-list-truncated.json new file mode 100644 index 000000000..ec99fa827 --- /dev/null +++ b/tests/skills/cases/db-repo/lock-long-list-truncated.json @@ -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": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы" +} diff --git a/tests/skills/cases/db-repo/lock-partial-is-success-posix.json b/tests/skills/cases/db-repo/lock-partial-is-success-posix.json new file mode 100644 index 000000000..b567e5b65 --- /dev/null +++ b/tests/skills/cases/db-repo/lock-partial-is-success-posix.json @@ -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": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы" +} diff --git a/tests/skills/cases/db-repo/lock-partial-is-success.json b/tests/skills/cases/db-repo/lock-partial-is-success.json new file mode 100644 index 000000000..6316c22fa --- /dev/null +++ b/tests/skills/cases/db-repo/lock-partial-is-success.json @@ -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": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы" +} diff --git a/tests/skills/cases/db-repo/update-unbound-base-detected.json b/tests/skills/cases/db-repo/update-unbound-base-detected.json new file mode 100644 index 000000000..52b2125c4 --- /dev/null +++ b/tests/skills/cases/db-repo/update-unbound-base-detected.json @@ -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 +}