mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-06 02:00:54 +03:00
feat(db-*): после загрузки расширения проверяется его применимость
Платформа отчитывается успехом и о расширении, которое не применит: отказ всплывает лениво, при первом вызове метода, записью в журнал регистрации. Теперь db-load-xml, db-load-git, db-load-cf и db-update после успешной операции с расширением спрашивают платформу явно и печатают предупреждение; код возврата операции не меняется — применение неприменимого расширения не разрушительно, платформа просто работает по оригиналу. Поднять код возврата может -StrictLog, он для регрессов и в инструкциях не значится. Проверка обязана быть ОТДЕЛЬНЫМ запуском платформы: в одной командной строке DESIGNER выполняет только последнюю пакетную команду, и дописанная проверка отменила бы саму загрузку (замер: /LoadConfigFromFiles + /CheckCanApply… → код 0, пустой лог, расширение в базе не изменилось). Об этом сказано в теле функции, чтобы «оптимизация» не вернула команды в одну строку. Выключатель: ключ -NoApplyCheck и настройка проекта extensionApplyCheck (ключ команды сильнее). В ветке ibcmd проверка идёт соседним 1cv8; если его рядом нет — одна строка [note], а не тишина. Общий блок (Invoke-ApplyCheck / Invoke-ApplyCheckReport / Get-ApplyCheckEnabled и их py-двойники) объявлен семьёй в check-inline-drift.mjs: разъехавшиеся копии означали бы, что один навык предупреждает, а соседний по той же операции молчит. db-load-cf получил недостающие копии Find-V8Project и ключ -StrictLog. Раннер: у фейковой платформы появился отдельный ответ на проверку (spec.check), выбираемый по составу аргументов, — иначе сценарий «загрузка прошла, проверка провалилась» невыразим. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QoAJmoNbgWKobA7JGgN5S3
This commit is contained in:
co-authored by
Claude Opus 5
parent
5943828216
commit
a3ea0b7be6
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Проверка прошла — предупреждения нет",
|
||||
"fakePlatform": {
|
||||
"log": "Загрузка конфигурации из файлов.\r\n",
|
||||
"check": {
|
||||
"log": "",
|
||||
"exit": 0
|
||||
}
|
||||
},
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{fakePlatform}",
|
||||
"-InfoBasePath",
|
||||
"{workDir}/ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}/src",
|
||||
"-Extension",
|
||||
"Проба"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": "Load completed successfully",
|
||||
"stdoutNotContains": "will not apply"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется постусловие",
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Загрузка провалилась — применимость не проверяем (проверять нечего)",
|
||||
"fakePlatform": {
|
||||
"log": "Ошибка загрузки конфигурации\r\n",
|
||||
"exit": 1,
|
||||
"check": {
|
||||
"log": "Проба: Список параметров метода \"Проба_Расчёт\" не соответствует методу \"Расчёт\".\r\n",
|
||||
"exit": 1
|
||||
}
|
||||
},
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{fakePlatform}",
|
||||
"-InfoBasePath",
|
||||
"{workDir}/ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}/src",
|
||||
"-Extension",
|
||||
"Проба"
|
||||
],
|
||||
"expectError": true,
|
||||
"expect": {
|
||||
"stdoutNotContains": "will not apply"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется условие запуска"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "Загрузка основной конфигурации: применимость не проверяется",
|
||||
"fakePlatform": {
|
||||
"log": "Загрузка конфигурации из файлов.\r\n",
|
||||
"check": {
|
||||
"log": "Проба: Список параметров метода \"Проба_Расчёт\" не соответствует методу \"Расчёт\".\r\n",
|
||||
"exit": 1
|
||||
}
|
||||
},
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{fakePlatform}",
|
||||
"-InfoBasePath",
|
||||
"{workDir}/ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}/src"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": "Load completed successfully",
|
||||
"stdoutNotContains": "will not apply"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется условие запуска",
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "extensionApplyCheck: false в .v8-project.json выключает проверку",
|
||||
"fakePlatform": {
|
||||
"log": "Загрузка конфигурации из файлов.\r\n",
|
||||
"check": {
|
||||
"log": "Проба: Список параметров метода \"Проба_Расчёт\" не соответствует методу \"Расчёт\".\r\n",
|
||||
"exit": 1
|
||||
}
|
||||
},
|
||||
"cwd": "workDir",
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": ".v8-project.json",
|
||||
"content": "{\n \"extensionApplyCheck\": false\n}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{fakePlatform}",
|
||||
"-InfoBasePath",
|
||||
"{workDir}/ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}/src",
|
||||
"-Extension",
|
||||
"Проба"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": "Load completed successfully",
|
||||
"stdoutNotContains": "will not apply"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется настройка проекта"
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "-NoApplyCheck: проверка не запускается вовсе",
|
||||
"fakePlatform": {
|
||||
"log": "Загрузка конфигурации из файлов.\r\n",
|
||||
"check": {
|
||||
"log": "Проба: Список параметров метода \"Проба_Расчёт\" не соответствует методу \"Расчёт\".\r\n",
|
||||
"exit": 1
|
||||
}
|
||||
},
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{fakePlatform}",
|
||||
"-InfoBasePath",
|
||||
"{workDir}/ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}/src",
|
||||
"-Extension",
|
||||
"Проба",
|
||||
"-NoApplyCheck"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": "Load completed successfully",
|
||||
"stdoutNotContains": "will not apply"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется постусловие",
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "То же с -StrictLog: предупреждение поднимает код возврата",
|
||||
"fakePlatform": {
|
||||
"log": "Загрузка конфигурации из файлов.\r\n",
|
||||
"check": {
|
||||
"log": "Проба: Список параметров метода \"Проба_Расчёт\" не соответствует методу \"Расчёт\".\r\n",
|
||||
"exit": 1
|
||||
}
|
||||
},
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{fakePlatform}",
|
||||
"-InfoBasePath",
|
||||
"{workDir}/ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}/src",
|
||||
"-Extension",
|
||||
"Проба",
|
||||
"-StrictLog"
|
||||
],
|
||||
"expectError": true,
|
||||
"expect": {
|
||||
"stdoutContains": "will not apply it"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется постусловие",
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "Расширение загрузилось, но платформа его не применит — предупреждение, код возврата не меняется",
|
||||
"fakePlatform": {
|
||||
"log": "Загрузка конфигурации из файлов.\r\n",
|
||||
"check": {
|
||||
"log": "Проба: Список параметров метода \"Проба_Расчёт\" не соответствует методу \"Расчёт\".\r\n",
|
||||
"exit": 1
|
||||
}
|
||||
},
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{fakePlatform}",
|
||||
"-InfoBasePath",
|
||||
"{workDir}/ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}/src",
|
||||
"-Extension",
|
||||
"Проба"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": [
|
||||
"Load completed successfully",
|
||||
"[warning] the extension is loaded, but the platform will not apply it:",
|
||||
"не соответствует методу"
|
||||
]
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется постусловие",
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "Обновление расширения прошло, но платформа его не применит — предупреждение",
|
||||
"fakePlatform": {
|
||||
"log": "Обновление конфигурации успешно завершено\r\n",
|
||||
"check": {
|
||||
"log": "Проба: Список параметров метода \"Проба_Расчёт\" не соответствует методу \"Расчёт\".\r\n",
|
||||
"exit": 1
|
||||
}
|
||||
},
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{fakePlatform}",
|
||||
"-InfoBasePath",
|
||||
"{workDir}/ib",
|
||||
"-Extension",
|
||||
"Проба"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": [
|
||||
"Database configuration updated successfully",
|
||||
"will not apply it"
|
||||
]
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется постусловие"
|
||||
}
|
||||
@@ -71,7 +71,7 @@ const FAMILIES = [
|
||||
// вверх. Группа db-* использует её же, чтобы найти запись базы и взять реквизиты
|
||||
// хранилища — задача одна, поэтому семья общая, а не вторая с тем же телом.
|
||||
{ id: 'full', authority: 'cf-edit',
|
||||
consumers: ['cfe-borrow', 'db-cfe-admin', 'db-dump-xml', 'db-load-git', 'db-load-xml', 'db-repo', 'db-update',
|
||||
consumers: ['cfe-borrow', 'db-cfe-admin', 'db-dump-xml', 'db-load-cf', 'db-load-git', 'db-load-xml', 'db-repo', 'db-update',
|
||||
'form-add', 'form-compile', 'form-edit', 'help-add', 'interface-edit', 'meta-compile',
|
||||
'meta-edit', 'meta-remove', 'mxl-compile', 'role-compile', 'skd-compile', 'skd-edit',
|
||||
'subsystem-compile', 'subsystem-edit', 'template-add', 'xdto-compile', 'xdto-edit'] },
|
||||
@@ -250,6 +250,50 @@ const FAMILIES = [
|
||||
{ id: 'base', authority: 'db-load-xml', consumers: ['db-load-git', 'db-update'] },
|
||||
],
|
||||
},
|
||||
// ─── Постусловие применимости расширения ────────────────────────────────
|
||||
// Проверку ОБЯЗАТЕЛЬНО запускать отдельным процессом: в одной командной строке DESIGNER
|
||||
// выполняет только последнюю пакетную команду, и дописанная проверка отменяет саму загрузку.
|
||||
// Разъехавшиеся копии означали бы, что один навык предупреждает о неприменимом расширении,
|
||||
// а соседний по той же операции — молчит.
|
||||
{
|
||||
name: 'apply check: run', py: 'run_apply_check', ps1: 'Invoke-ApplyCheck',
|
||||
variants: [
|
||||
{ id: 'base', authority: 'db-load-xml', consumers: ['db-load-cf', 'db-load-git', 'db-update'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'apply check: report', py: 'apply_check_report', ps1: 'Invoke-ApplyCheckReport',
|
||||
variants: [
|
||||
{ id: 'base', authority: 'db-load-xml', consumers: ['db-load-cf', 'db-load-git', 'db-update'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'apply check: enabled', py: 'apply_check_enabled', ps1: 'Get-ApplyCheckEnabled',
|
||||
variants: [
|
||||
{ id: 'base', authority: 'db-load-xml', consumers: ['db-load-cf', 'db-load-git', 'db-update'] },
|
||||
],
|
||||
},
|
||||
// Дополнительные аргументы: и владение ключами, и запрет пакетных команд. Разъехавшиеся копии
|
||||
// означали бы, что один навык отбивает команду, отменяющую его же операцию, а соседний — нет.
|
||||
{
|
||||
name: 'platform: assert_extra_args', py: 'assert_extra_args', ps1: 'Assert-ExtraArgs',
|
||||
variants: [
|
||||
{ id: 'base', authority: 'db-create',
|
||||
consumers: ['db-cfe-admin', 'db-dump-cf', 'db-dump-dt', 'db-dump-xml', 'db-load-cf', 'db-load-dt',
|
||||
'db-load-git', 'db-load-xml', 'db-repo', 'db-run', 'db-update', 'epf-build', 'epf-dump'] },
|
||||
// NB: stub-db-create.py внутри epf-build держит свою копию с выводом в stderr, но гарду она
|
||||
// не видна: индекс берёт первый файл навыка по алфавиту (epf-build.py). Правя эту семью,
|
||||
// не забывать про стаб — автоматически он не проверяется.
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'platform: arg_key_match', py: 'arg_key_match', ps1: 'Test-ArgKeyMatch',
|
||||
variants: [
|
||||
{ id: 'base', authority: 'db-create',
|
||||
consumers: ['db-cfe-admin', 'db-dump-cf', 'db-dump-dt', 'db-dump-xml', 'db-load-cf', 'db-load-dt',
|
||||
'db-load-git', 'db-load-xml', 'db-repo', 'db-run', 'db-update', 'epf-build', 'epf-dump'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'platform: resolve_extra_args', py: 'resolve_extra_args', ps1: 'Resolve-ExtraArgs',
|
||||
variants: [
|
||||
|
||||
+11
-5
@@ -373,15 +373,20 @@ function buildArgs(skillConfig, caseData, workDir, inputFilePath, runtime) {
|
||||
// под текущую ОС, поэтому один кейс проверяется на обеих. Раньше каждый такой сценарий
|
||||
// приходилось дублировать -posix двойником, и забытый двойник означал дыру: у db-repo на
|
||||
// маке выполнялся 1 кейс из 12, и заметили это случайно.
|
||||
const FAKE_PLATFORM_CMD = "@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";
|
||||
const FAKE_PLATFORM_SH = "#!/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 0\n";
|
||||
// Второй ответ — на проверку применимости расширения: навык запускает её ОТДЕЛЬНЫМ процессом
|
||||
// (в одной командной строке платформа выполнила бы только последнюю команду), поэтому фейк
|
||||
// отличает проверку по составу аргументов, а не по номеру вызова.
|
||||
const FAKE_PLATFORM_CMD = "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\nset KIND=main\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nif /i \"%~1\"==\"/CheckCanApplyConfigurationExtensions\" set KIND=check\r\nshift\r\ngoto loop\r\n:done\r\nif \"%KIND%\"==\"check\" if exist \"%SELF%log_check.txt\" (copy /y \"%SELF%log_check.txt\" \"%OUT%\" >nul & exit /b CHECKCODE)\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b EXITCODE\r\n";
|
||||
const FAKE_PLATFORM_SH = "#!/bin/sh\n# Фейк платформы для *nix: вычитывает путь из /Out и кладёт туда готовый лог.\n# Значение /Out несёт кавычки ВНУТРИ токена (соглашение 1С, см. run_v8) — в batch их\n# снимает %~2, в sh их надо снять руками, иначе cp целится в имя с кавычками.\nSELF=$(dirname \"$0\")\nOUT=\"\"\nKIND=main\nwhile [ $# -gt 0 ]; do\n if [ \"$1\" = \"/CheckCanApplyConfigurationExtensions\" ]; then\n KIND=check\n fi\n if [ \"$1\" = \"/Out\" ]; then\n OUT=\"$2\"\n OUT=\"${OUT#\\\"}\"\n OUT=\"${OUT%\\\"}\"\n fi\n shift\ndone\nif [ \"$KIND\" = check ] && [ -f \"$SELF/log_check.txt\" ]; then\n cp \"$SELF/log_check.txt\" \"$OUT\"\n exit CHECKCODE\nfi\ncp \"$SELF/log.txt\" \"$OUT\"\nexit EXITCODE\n";
|
||||
|
||||
function writeFakePlatform(workDir, spec) {
|
||||
const isWin = process.platform === 'win32';
|
||||
const code = Number.isInteger(spec.exit) ? spec.exit : 0;
|
||||
const body = isWin
|
||||
? FAKE_PLATFORM_CMD.replace('exit /b 0', `exit /b ${code}`)
|
||||
: FAKE_PLATFORM_SH.replace('exit 0', `exit ${code}`);
|
||||
// spec.check — ответ на проверку применимости расширения (отдельный запуск платформы)
|
||||
const checkCode = spec.check && Number.isInteger(spec.check.exit) ? spec.check.exit : 0;
|
||||
const body = (isWin ? FAKE_PLATFORM_CMD : FAKE_PLATFORM_SH)
|
||||
.replaceAll('EXITCODE', String(code))
|
||||
.replaceAll('CHECKCODE', String(checkCode));
|
||||
const exe = join(workDir, isWin ? 'fake.cmd' : 'fake.sh');
|
||||
writeFileSync(exe, body, 'utf8');
|
||||
// Бит исполнения: на *nix навык запускает платформу через exec, без +x фейк не стартует.
|
||||
@@ -389,6 +394,7 @@ function writeFakePlatform(workDir, spec) {
|
||||
// Лог пишется как есть — вместе с BOM и CRLF, если кейс их объявил: /Out платформы
|
||||
// выглядит именно так, и разбор должен проверяться на настоящей форме.
|
||||
writeFileSync(join(workDir, 'log.txt'), spec.log ?? '', 'utf8');
|
||||
if (spec.check) writeFileSync(join(workDir, 'log_check.txt'), spec.check.log ?? '', 'utf8');
|
||||
// Заглушка базы: навыки отказываются работать, не найдя 1Cv8.1CD, и это правильно.
|
||||
if (spec.baseStub !== false) {
|
||||
const ib = join(workDir, 'ib');
|
||||
|
||||
Reference in New Issue
Block a user