mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-20 09:15:52 +03:00
feat(db-*,epf-*,erf-*,web-publish): v8path на уровне записи базы
В одном проекте базы могут жить на разных версиях платформы, а версию формата
XML-выгрузки задаёт та платформа, которая выгружает: без выбора платформы по базе
срабатывает автопоиск и берёт самую старшую установленную — то есть самый новый
формат, который коллега на младшей платформе уже не загрузит.
Теперь порядок такой: явный -V8Path -> v8path записи базы -> корневой v8path ->
автопоиск. Запись базы ищет сам скрипт тем же матчем, которым добывал реквизиты
хранилища (Find-ProjectDatabase): файловую по path, серверную по server + ref.
- в 9 навыков, где матча не было, скопирован блок из авторитета db-repo;
- списки потребителей трёх семей в check-inline-drift расширены; заведена семья
platform: resolve_v8path — обёртка меняла сигнатуру, а под гардом не была;
- раннер подставляет {workDir}/{fakePlatform} и в содержимое preRun.writeFile,
иначе кейс про выбор платформы нельзя написать кроссплатформенно;
- в SKILL.md платформа теперь берётся ПОСЛЕ разрешения базы, строка про
автоопределение через Program Files убрана как деталь реализации.
Живой прогон: две базы в одном проекте при корневом v8path = 8.5 дали формат
2.17 (8.3.24) и 2.20 (8.3.27), оба порта.
Closes #93
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
303db4e9f9
commit
874ae650ca
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "Платформа берётся из v8path записи базы, а не из корневого",
|
||||
"fakePlatform": { "log": "" },
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": ".v8-project.json",
|
||||
"content": {
|
||||
"v8path": "{workDir}/nowhere/1cv8.exe",
|
||||
"databases": [
|
||||
{ "id": "dev", "name": "Dev", "type": "file", "path": "{workDir}/ib", "v8path": "{fakePlatform}" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": ["-InfoBasePath", "{workDir}/ib"],
|
||||
"cwd": "workDir",
|
||||
"expect": {
|
||||
"stdoutContains": "Information base created successfully",
|
||||
"stdoutNotContains": "nowhere"
|
||||
},
|
||||
"noSnapshot": "проверяется выбор платформы по stdout, файлов на выходе нет"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "Соединение не совпало ни с одной записью — берётся корневой v8path",
|
||||
"fakePlatform": { "log": "" },
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": ".v8-project.json",
|
||||
"content": {
|
||||
"v8path": "{workDir}/nowhere/1cv8.exe",
|
||||
"databases": [
|
||||
{ "id": "other", "name": "Other", "type": "file", "path": "{workDir}/other", "v8path": "{fakePlatform}" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": ["-InfoBasePath", "{workDir}/ib"],
|
||||
"cwd": "workDir",
|
||||
"expectError": true,
|
||||
"expect": { "stdoutContains": "1C executable not found at" },
|
||||
"noSnapshot": "проверяется выбор платформы по stdout, файлов на выходе нет"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "У записи базы нет v8path — берётся корневой",
|
||||
"fakePlatform": { "log": "" },
|
||||
"preRun": [
|
||||
{
|
||||
"writeFile": {
|
||||
"path": ".v8-project.json",
|
||||
"content": {
|
||||
"v8path": "{fakePlatform}",
|
||||
"databases": [
|
||||
{ "id": "dev", "name": "Dev", "type": "file", "path": "{workDir}/ib" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": ["-InfoBasePath", "{workDir}/ib"],
|
||||
"cwd": "workDir",
|
||||
"expect": { "stdoutContains": "Information base created successfully" },
|
||||
"noSnapshot": "проверяется выбор платформы по stdout, файлов на выходе нет"
|
||||
}
|
||||
@@ -88,10 +88,12 @@ const FAMILIES = [
|
||||
variants: [
|
||||
// Имя с префиксом _sg_ историческое: функция просто ищет .v8-project.json обходом
|
||||
// вверх. Группа db-* использует её же, чтобы найти запись базы и взять реквизиты
|
||||
// хранилища — задача одна, поэтому семья общая, а не вторая с тем же телом.
|
||||
// хранилища и путь к платформе — задача одна, поэтому семья общая, а не вторая с тем же телом.
|
||||
{ id: 'full', authority: 'cf-edit',
|
||||
consumers: ['cfe-borrow', 'db-cfe-admin', 'db-dump-xml', 'db-load-cf', 'db-load-git', 'db-load-xml', 'db-repo', 'db-update',
|
||||
'epf-build', 'form-add', 'form-compile', 'form-edit', 'help-add', 'interface-edit', 'meta-compile',
|
||||
consumers: ['cfe-borrow', 'db-cfe-admin', 'db-create', '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', 'web-publish',
|
||||
'form-add', 'form-compile', 'form-edit', 'help-add', 'interface-edit', 'meta-compile',
|
||||
'meta-edit', 'meta-remove', 'mxl-compile', 'role-compile', 'role-edit', 'skd-compile', 'skd-edit',
|
||||
'subsystem-compile', 'subsystem-edit', 'template-add', 'xdto-compile', 'xdto-edit'] },
|
||||
],
|
||||
@@ -386,6 +388,16 @@ const FAMILIES = [
|
||||
'db-load-xml', 'db-repo', 'db-run', 'db-update', 'epf-build', 'epf-dump', 'web-publish', 'db-cfe-admin'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
// Обёртка выбора платформы: запись базы → корневой v8path → автопоиск. В PS1 её роль
|
||||
// играет не функция, а блок кода после объявления Find-ProjectV8Path, поэтому ps1: null.
|
||||
name: 'platform: resolve_v8path', py: 'resolve_v8path', ps1: null,
|
||||
variants: [
|
||||
{ id: 'base', authority: 'db-create',
|
||||
consumers: ['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', 'db-cfe-admin'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'platform: find_project_v8path', py: '_find_project_v8path', ps1: 'Find-ProjectV8Path',
|
||||
variants: [
|
||||
@@ -399,18 +411,24 @@ const FAMILIES = [
|
||||
name: 'repository: load hints', py: 'write_repository_hints', ps1: 'Write-RepositoryHints',
|
||||
variants: [{ id: 'base', authority: 'db-load-xml', consumers: ['db-load-git'] }],
|
||||
},
|
||||
// ─── Реквизиты хранилища конфигурации ────────────────────────────────────
|
||||
// База под хранилищем не принимает ни одной операции конфигуратора без реквизитов
|
||||
// доступа, и модель их не передаёт: скрипт сам сопоставляет параметры соединения с
|
||||
// записью в databases[]. Блок копируется во все навыки группы, работающие с
|
||||
// конфигурацией базы.
|
||||
// ─── Запись базы в .v8-project.json ──────────────────────────────────────
|
||||
// Модель не передаёт ни реквизиты хранилища (без них база под хранилищем не принимает
|
||||
// ни одной операции конфигуратора), ни путь к платформе конкретной базы: скрипт сам
|
||||
// сопоставляет параметры соединения с записью в databases[]. Матч один на обе задачи,
|
||||
// поэтому блок копируется во все навыки, запускающие платформу.
|
||||
{
|
||||
name: 'repository: same_path', py: 'same_path', ps1: 'Test-SamePath',
|
||||
variants: [{ id: 'base', authority: 'db-repo', consumers: ['db-dump-xml', 'db-load-git', 'db-load-xml', 'db-update', 'db-cfe-admin'] }],
|
||||
variants: [{ id: 'base', authority: 'db-repo',
|
||||
consumers: ['db-cfe-admin', 'db-create', 'db-dump-cf', 'db-dump-dt', 'db-dump-xml', 'db-load-cf',
|
||||
'db-load-dt', 'db-load-git', 'db-load-xml', 'db-run', 'db-update', 'epf-build', 'epf-dump',
|
||||
'web-publish'] }],
|
||||
},
|
||||
{
|
||||
name: 'repository: find_project_database', py: 'find_project_database', ps1: 'Find-ProjectDatabase',
|
||||
variants: [{ id: 'base', authority: 'db-repo', consumers: ['db-dump-xml', 'db-load-git', 'db-load-xml', 'db-update', 'db-cfe-admin'] }],
|
||||
variants: [{ id: 'base', authority: 'db-repo',
|
||||
consumers: ['db-cfe-admin', 'db-create', 'db-dump-cf', 'db-dump-dt', 'db-dump-xml', 'db-load-cf',
|
||||
'db-load-dt', 'db-load-git', 'db-load-xml', 'db-run', 'db-update', 'epf-build', 'epf-dump',
|
||||
'web-publish'] }],
|
||||
},
|
||||
{
|
||||
name: 'repository: resolve_settings', py: 'resolve_repository_settings', ps1: 'Resolve-RepositorySettings',
|
||||
|
||||
+24
-8
@@ -274,6 +274,25 @@ function cleanupWorkspace(ws) {
|
||||
|
||||
// ─── Arg building ───────────────────────────────────────────────────────────
|
||||
|
||||
// Плейсхолдеры кейса: {workDir} — абсолютный путь рабочего каталога, {fakePlatform} — путь к
|
||||
// фейковой платформе, которую раскладывает writeFakePlatform (имя зависит от ОС, поэтому кейс
|
||||
// адресует её плейсхолдером и остаётся кроссплатформенным). Подстановка нужна не только в
|
||||
// аргументах: путь к фейку кладут и ВНУТРЬ подложенного .v8-project.json — иначе кейс про
|
||||
// выбор платформы пришлось бы писать двумя копиями под osOnly.
|
||||
function substPlaceholders(s, workDir) {
|
||||
const fakePath = join(workDir, process.platform === 'win32' ? 'fake.cmd' : 'fake.sh');
|
||||
return s.replaceAll('{workDir}', workDir).replaceAll('{fakePlatform}', fakePath);
|
||||
}
|
||||
|
||||
function substDeep(value, workDir) {
|
||||
if (typeof value === 'string') return substPlaceholders(value, workDir);
|
||||
if (Array.isArray(value)) return value.map(v => substDeep(v, workDir));
|
||||
if (value && typeof value === 'object') {
|
||||
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, substDeep(v, workDir)]));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Байты входного файла в заданной кодировке. Нужно для кейсов про кодировку: writeFileSync
|
||||
// пишет только UTF-8, а навык обязан одинаково вести себя на UTF-16 с BOM (принять) и на
|
||||
// cp1251 (отвергнуть, а не молча подменить кириллицу на U+FFFD). cp1251 в Node нет — кодируем
|
||||
@@ -355,13 +374,8 @@ function buildArgs(skillConfig, caseData, workDir, inputFilePath, runtime) {
|
||||
}
|
||||
|
||||
// Append extra args from case (for optional params like -Vendor, -Version).
|
||||
// Supports {workDir} substitution for tests that need absolute paths inside the workspace,
|
||||
// and {fakePlatform} — путь к фейковой платформе, которую раскладывает writeFakePlatform.
|
||||
if (caseData.args_extra) {
|
||||
const fakePath = join(workDir, process.platform === 'win32' ? 'fake.cmd' : 'fake.sh');
|
||||
args.push(...caseData.args_extra.map(a => typeof a === 'string'
|
||||
? a.replace('{workDir}', workDir).replace('{fakePlatform}', fakePath)
|
||||
: a));
|
||||
args.push(...caseData.args_extra.map(a => typeof a === 'string' ? substPlaceholders(a, workDir) : a));
|
||||
}
|
||||
|
||||
return { scriptPath, args };
|
||||
@@ -837,9 +851,11 @@ async function runCaseAsync(testCase, opts) {
|
||||
// writeFile step — записать произвольный файл в workDir перед запуском скрипта
|
||||
if (step.writeFile) {
|
||||
const wfPath = join(workDir, step.writeFile.path);
|
||||
// Плейсхолдеры подставляются и здесь. В объектной форме — ДО JSON.stringify: иначе
|
||||
// обратные слэши windows-пути попали бы в готовый JSON неэкранированными.
|
||||
const wfContent = typeof step.writeFile.content === 'string'
|
||||
? step.writeFile.content
|
||||
: JSON.stringify(step.writeFile.content, null, 2);
|
||||
? substPlaceholders(step.writeFile.content, workDir)
|
||||
: JSON.stringify(substDeep(step.writeFile.content, workDir), null, 2);
|
||||
mkdirSync(dirname(wfPath), { recursive: true });
|
||||
writeFileSync(wfPath, wfContent, 'utf8');
|
||||
// Бит исполнения: на *nix навык запускает платформу через exec, и фейк без +x
|
||||
|
||||
Reference in New Issue
Block a user