mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-14 07:23:22 +03:00
fix(db-load-git,db-update): ловить тихие отказы платформы, как db-load-xml
Платформа рапортует об успехе (exit 0) и одновременно пишет в /Out-лог, что часть метаданных отброшена. Детектор этого был только в db-load-xml, хотя db-load-git гоняет тот же /LoadConfigFromFiles (и дописывает /UpdateDBCfg в тот же вызов), а db-update — вторую половину той же цепочки. Оба лог печатали, но не разбирали. Детектор извлечён в Find-SilentRejections / find_silent_rejections и внесён в реестр семей check-inline-drift: инлайн-код гард сверять не умеет, а именно расхождение копий и было бы главным риском такого дублирования. Добавлен восьмой паттерн — «Для работы с конфигурацией необходима версия платформы не меньше». Замерено при работе над issue #63: конфигурация с режимом совместимости выше платформы грузится с кодом 0, db-update тоже отвечает 0, объекты в базу не попадают, а отказ приходит только в рантайме. Строка обрезана до инвариантной части — конкретная версия в сообщении меняется. Текст предупреждения переписан. Убрана подсказка «pass -StrictLog to treat as error»: ключ предназначен для регрессов (его передаёт verify-snapshots), а совет бессмысленный — операция уже выполнена, и повторять её ради того же текста незачем. Формулировка больше не утверждает «dropped properties/refs»: класс проблемы разный, а строки лога печатаются следом и говорят за себя. Две правки по дороге: - `return ,$found` в паре с `@()` у вызывающего давал массив из одного пустого массива, то есть предупреждение «1 problem(s)» на чистом логе. Возврат без запятой-обёртки. - py-порт писал предупреждение в stderr, PS1 — в stdout. В самом py-порте stderr занят исключительно фатальными «Error:» перед exit 1, так что не-фатальное предупреждение там было единственным исключением. Приведено к stdout — и к соглашению своего же файла, и к поведению PS1; verify-snapshots на падении читает `stderr || stdout`, поэтому диагностика не теряется. Тесты: фейковая платформа .cmd, которая вычитывает путь из /Out и кладёт туда готовый лог, — по четыре кейса на db-load-xml и db-update (отбраковка, она же под -StrictLog, новый паттерн, чистый лог без предупреждения). Раньше детектор не был покрыт вообще. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
06f21ab3d1
commit
a024b7da9c
@@ -1,4 +1,4 @@
|
||||
# db-load-git v1.19 — Load Git changes into 1C database
|
||||
# db-load-git v1.20 — Load Git changes into 1C database
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||
<#
|
||||
@@ -110,6 +110,12 @@ param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$UpdateDB,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
# Ключ для регрессов и верификации снапшотов, не для повседневного вызова: в SKILL.md
|
||||
# намеренно не выносится. Поднимает код возврата, если платформа отчиталась об успехе,
|
||||
# но в логе есть отбраковка.
|
||||
[switch]$StrictLog,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string[]]$AdditionalV8Arguments = @(),
|
||||
|
||||
@@ -394,6 +400,41 @@ function Write-PlatformOutput {
|
||||
Write-Host "--- End ---"
|
||||
}
|
||||
|
||||
# Строки лога, о которых платформа сообщает, НЕ поднимая код возврата: метаданные отброшены или
|
||||
# конфигурация нерабочая, а операция при этом «успешна». Возвращает подошедшие строки.
|
||||
#
|
||||
# Копия этой функции есть в каждом навыке, который читает /Out-лог загрузки (навыки автономны).
|
||||
# Держать копии одинаковыми — сознательно: разошедшиеся копии сводят на нет весь смысл.
|
||||
function Find-SilentRejections {
|
||||
param([string]$LogText)
|
||||
$patterns = @(
|
||||
'Неверное свойство объекта метаданных',
|
||||
'не входит в состав объекта метаданных',
|
||||
'Неизвестное имя типа',
|
||||
'Неизвестный объект метаданных',
|
||||
'Ни один из документов не является регистратором для регистра',
|
||||
'Неверное значение перечисления',
|
||||
'не может быть приведен к типу',
|
||||
# Режим совместимости выше платформы: объекты в базу не попадают, отказ приходит в рантайме.
|
||||
# Обрезано до инвариантной части — конкретная версия в сообщении меняется.
|
||||
'Для работы с конфигурацией необходима версия платформы не меньше'
|
||||
)
|
||||
$found = @()
|
||||
if ($LogText) {
|
||||
foreach ($line in ($LogText -split "`r?`n")) {
|
||||
foreach ($pat in $patterns) {
|
||||
if ($line -match [regex]::Escape($pat)) {
|
||||
$found += $line.Trim()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# Возвращаем массив БЕЗ запятой-обёртки: вызывающий берёт результат в @(), а `return ,$found`
|
||||
# дал бы массив из одного пустого массива — фантомное срабатывание на чистом логе.
|
||||
return $found
|
||||
}
|
||||
|
||||
|
||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||
if ($engine -eq "ibcmd") {
|
||||
@@ -667,6 +708,7 @@ try {
|
||||
Write-Host "Error loading configuration (code: $exitCode)$(Get-ExitAnnotation $exitCode)" -ForegroundColor Red
|
||||
}
|
||||
|
||||
$logContent = $null
|
||||
if (Test-Path $outFile) {
|
||||
$logContent = Get-Content $outFile -Raw -ErrorAction SilentlyContinue
|
||||
if ($logContent) {
|
||||
@@ -677,6 +719,16 @@ try {
|
||||
}
|
||||
Write-PlatformOutput $__v8.Output
|
||||
|
||||
# Причину не называем: строки лога печатаются следом и говорят за себя, а класс проблемы
|
||||
# разный — от отброшенного свойства до нерабочей на этой платформе конфигурации. Подсказку
|
||||
# про -StrictLog не даём: операция уже выполнена, повторять её ради того же текста незачем.
|
||||
$silentFailures = @(Find-SilentRejections $logContent)
|
||||
if ($silentFailures.Count -gt 0) {
|
||||
Write-Host "[warning] platform reported success, but the log contains $($silentFailures.Count) problem(s):" -ForegroundColor Yellow
|
||||
foreach ($f in $silentFailures) { Write-Host " $f" -ForegroundColor Yellow }
|
||||
if ($StrictLog -and $exitCode -eq 0) { $exitCode = 1 }
|
||||
}
|
||||
|
||||
exit $exitCode
|
||||
|
||||
} finally {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# db-load-git v1.19 — Load Git changes into 1C database
|
||||
# db-load-git v1.20 — Load Git changes into 1C database
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
@@ -344,6 +344,38 @@ def print_platform_output(result):
|
||||
print("--- End ---")
|
||||
|
||||
|
||||
def find_silent_rejections(log_text):
|
||||
"""Строки лога, о которых платформа сообщает, НЕ поднимая код возврата.
|
||||
|
||||
Метаданные отброшены или конфигурация нерабочая, а операция при этом «успешна».
|
||||
Возвращает подошедшие строки.
|
||||
|
||||
Копия этой функции есть в каждом навыке, который читает /Out-лог загрузки (навыки
|
||||
автономны). Держать копии одинаковыми — сознательно: разошедшиеся копии сводят на нет
|
||||
весь смысл.
|
||||
"""
|
||||
patterns = [
|
||||
"Неверное свойство объекта метаданных",
|
||||
"не входит в состав объекта метаданных",
|
||||
"Неизвестное имя типа",
|
||||
"Неизвестный объект метаданных",
|
||||
"Ни один из документов не является регистратором для регистра",
|
||||
"Неверное значение перечисления",
|
||||
"не может быть приведен к типу",
|
||||
# Режим совместимости выше платформы: объекты в базу не попадают, отказ приходит в
|
||||
# рантайме. Обрезано до инвариантной части — конкретная версия в сообщении меняется.
|
||||
"Для работы с конфигурацией необходима версия платформы не меньше",
|
||||
]
|
||||
found = []
|
||||
if log_text:
|
||||
for line in log_text.splitlines():
|
||||
for pat in patterns:
|
||||
if pat in line:
|
||||
found.append(line.strip())
|
||||
break
|
||||
return found
|
||||
|
||||
|
||||
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||
"""Run an ibcmd command non-interactively.
|
||||
|
||||
@@ -446,6 +478,10 @@ def main():
|
||||
)
|
||||
parser.add_argument("-DryRun", action="store_true", help="Only show what would be loaded (no actual load)")
|
||||
parser.add_argument("-UpdateDB", action="store_true", help="Also update database configuration after load")
|
||||
# Ключ для регрессов и верификации снапшотов, не для повседневного вызова: в SKILL.md
|
||||
# намеренно не выносится. Поднимает код возврата, если платформа отчиталась об успехе,
|
||||
# но в логе есть отбраковка.
|
||||
parser.add_argument("-StrictLog", action="store_true")
|
||||
parser.add_argument("-AdditionalV8Arguments", nargs="*", default=[],
|
||||
help="Extra 1cv8 arguments, e.g. /UseHwLicenses+")
|
||||
parser.add_argument("-AdditionalIbcmdArguments", nargs="*", default=[],
|
||||
@@ -705,6 +741,7 @@ def main():
|
||||
else:
|
||||
print(f"Error loading configuration (code: {exit_code}){describe_exit(exit_code)}", file=sys.stderr)
|
||||
|
||||
log_content = ""
|
||||
if os.path.isfile(out_file):
|
||||
try:
|
||||
with open(out_file, "r", encoding="utf-8-sig") as f:
|
||||
@@ -717,6 +754,21 @@ def main():
|
||||
pass
|
||||
|
||||
print_platform_output(result)
|
||||
|
||||
# Причину не называем: строки лога печатаются следом и говорят за себя, а класс проблемы
|
||||
# разный — от отброшенного свойства до нерабочей на этой платформе конфигурации. Подсказку
|
||||
# про -StrictLog не даём: операция уже выполнена, повторять её ради того же текста незачем.
|
||||
silent_failures = find_silent_rejections(log_content)
|
||||
if silent_failures:
|
||||
print(
|
||||
f"[warning] platform reported success, but the log contains "
|
||||
f"{len(silent_failures)} problem(s):"
|
||||
)
|
||||
for line in silent_failures:
|
||||
print(f" {line}")
|
||||
if args.StrictLog and exit_code == 0:
|
||||
exit_code = 1
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
finally:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# db-load-xml v1.20 — Load 1C configuration from XML files
|
||||
# db-load-xml v1.21 — Load 1C configuration from XML files
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||
<#
|
||||
@@ -416,6 +416,41 @@ function Write-PlatformOutput {
|
||||
Write-Host "--- End ---"
|
||||
}
|
||||
|
||||
# Строки лога, о которых платформа сообщает, НЕ поднимая код возврата: метаданные отброшены или
|
||||
# конфигурация нерабочая, а операция при этом «успешна». Возвращает подошедшие строки.
|
||||
#
|
||||
# Копия этой функции есть в каждом навыке, который читает /Out-лог загрузки (навыки автономны).
|
||||
# Держать копии одинаковыми — сознательно: разошедшиеся копии сводят на нет весь смысл.
|
||||
function Find-SilentRejections {
|
||||
param([string]$LogText)
|
||||
$patterns = @(
|
||||
'Неверное свойство объекта метаданных',
|
||||
'не входит в состав объекта метаданных',
|
||||
'Неизвестное имя типа',
|
||||
'Неизвестный объект метаданных',
|
||||
'Ни один из документов не является регистратором для регистра',
|
||||
'Неверное значение перечисления',
|
||||
'не может быть приведен к типу',
|
||||
# Режим совместимости выше платформы: объекты в базу не попадают, отказ приходит в рантайме.
|
||||
# Обрезано до инвариантной части — конкретная версия в сообщении меняется.
|
||||
'Для работы с конфигурацией необходима версия платформы не меньше'
|
||||
)
|
||||
$found = @()
|
||||
if ($LogText) {
|
||||
foreach ($line in ($LogText -split "`r?`n")) {
|
||||
foreach ($pat in $patterns) {
|
||||
if ($line -match [regex]::Escape($pat)) {
|
||||
$found += $line.Trim()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# Возвращаем массив БЕЗ запятой-обёртки: вызывающий берёт результат в @(), а `return ,$found`
|
||||
# дал бы массив из одного пустого массива — фантомное срабатывание на чистом логе.
|
||||
return $found
|
||||
}
|
||||
|
||||
|
||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||
|
||||
@@ -607,28 +642,7 @@ try {
|
||||
}
|
||||
|
||||
# --- Scan log for silent rejections ---
|
||||
# Platform often writes load-time rejections into /Out but exits with code 0.
|
||||
# These patterns flag cases where metadata was dropped or rejected silently.
|
||||
$fatalLogPatterns = @(
|
||||
'Неверное свойство объекта метаданных',
|
||||
'не входит в состав объекта метаданных',
|
||||
'Неизвестное имя типа',
|
||||
'Неизвестный объект метаданных',
|
||||
'Ни один из документов не является регистратором для регистра',
|
||||
'Неверное значение перечисления',
|
||||
'не может быть приведен к типу'
|
||||
)
|
||||
$silentFailures = @()
|
||||
if ($logContent) {
|
||||
foreach ($line in ($logContent -split "`r?`n")) {
|
||||
foreach ($pat in $fatalLogPatterns) {
|
||||
if ($line -match [regex]::Escape($pat)) {
|
||||
$silentFailures += $line.Trim()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$silentFailures = @(Find-SilentRejections $logContent)
|
||||
|
||||
# --- Result ---
|
||||
# Default: mirror platform's verdict via exit code. Log content (including any
|
||||
@@ -647,10 +661,11 @@ try {
|
||||
}
|
||||
Write-PlatformOutput $__v8.Output
|
||||
|
||||
# Причину не называем: строки лога печатаются следом и говорят за себя, а класс проблемы
|
||||
# разный — от отброшенного свойства до нерабочей на этой платформе конфигурации. Подсказку
|
||||
# про -StrictLog не даём: загрузка уже выполнена, повторять её ради того же текста незачем.
|
||||
if ($silentFailures.Count -gt 0) {
|
||||
$msg = "[warning] log contains $($silentFailures.Count) rejection(s) — platform loaded config but dropped properties/refs"
|
||||
if (-not $StrictLog) { $msg += " (pass -StrictLog to treat as error)" }
|
||||
Write-Host $msg -ForegroundColor Yellow
|
||||
Write-Host "[warning] platform reported success, but the log contains $($silentFailures.Count) problem(s):" -ForegroundColor Yellow
|
||||
foreach ($f in $silentFailures) { Write-Host " $f" -ForegroundColor Yellow }
|
||||
if ($StrictLog -and $exitCode -eq 0) { $exitCode = 1 }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# db-load-xml v1.20 — Load 1C configuration from XML files
|
||||
# db-load-xml v1.21 — Load 1C configuration from XML files
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
@@ -344,6 +344,38 @@ def print_platform_output(result):
|
||||
print("--- End ---")
|
||||
|
||||
|
||||
def find_silent_rejections(log_text):
|
||||
"""Строки лога, о которых платформа сообщает, НЕ поднимая код возврата.
|
||||
|
||||
Метаданные отброшены или конфигурация нерабочая, а операция при этом «успешна».
|
||||
Возвращает подошедшие строки.
|
||||
|
||||
Копия этой функции есть в каждом навыке, который читает /Out-лог загрузки (навыки
|
||||
автономны). Держать копии одинаковыми — сознательно: разошедшиеся копии сводят на нет
|
||||
весь смысл.
|
||||
"""
|
||||
patterns = [
|
||||
"Неверное свойство объекта метаданных",
|
||||
"не входит в состав объекта метаданных",
|
||||
"Неизвестное имя типа",
|
||||
"Неизвестный объект метаданных",
|
||||
"Ни один из документов не является регистратором для регистра",
|
||||
"Неверное значение перечисления",
|
||||
"не может быть приведен к типу",
|
||||
# Режим совместимости выше платформы: объекты в базу не попадают, отказ приходит в
|
||||
# рантайме. Обрезано до инвариантной части — конкретная версия в сообщении меняется.
|
||||
"Для работы с конфигурацией необходима версия платформы не меньше",
|
||||
]
|
||||
found = []
|
||||
if log_text:
|
||||
for line in log_text.splitlines():
|
||||
for pat in patterns:
|
||||
if pat in line:
|
||||
found.append(line.strip())
|
||||
break
|
||||
return found
|
||||
|
||||
|
||||
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||
"""Run an ibcmd command non-interactively.
|
||||
|
||||
@@ -636,22 +668,7 @@ def main():
|
||||
# --- Scan log for silent rejections ---
|
||||
# Platform often writes load-time rejections into /Out but exits with code 0.
|
||||
# These patterns flag cases where metadata was dropped or rejected silently.
|
||||
fatal_log_patterns = [
|
||||
"Неверное свойство объекта метаданных",
|
||||
"не входит в состав объекта метаданных",
|
||||
"Неизвестное имя типа",
|
||||
"Неизвестный объект метаданных",
|
||||
"Ни один из документов не является регистратором для регистра",
|
||||
"Неверное значение перечисления",
|
||||
"не может быть приведен к типу",
|
||||
]
|
||||
silent_failures = []
|
||||
if log_content:
|
||||
for line in log_content.splitlines():
|
||||
for pat in fatal_log_patterns:
|
||||
if pat in line:
|
||||
silent_failures.append(line.strip())
|
||||
break
|
||||
silent_failures = find_silent_rejections(log_content)
|
||||
|
||||
# --- Result ---
|
||||
# Default: mirror platform's verdict via exit code. Log content (including any
|
||||
@@ -668,15 +685,19 @@ def main():
|
||||
print("--- End ---")
|
||||
|
||||
print_platform_output(result)
|
||||
# Причину не называем: строки лога печатаются следом и говорят за себя, а класс проблемы
|
||||
# разный — от отброшенного свойства до нерабочей на этой платформе конфигурации. Подсказку
|
||||
# про -StrictLog не даём: загрузка уже выполнена, повторять её ради того же текста незачем.
|
||||
# Поток — stdout, как у PS1-порта: предупреждение относится к содержимому загрузки, а не к
|
||||
# отказу навыка, и при code 0 остаётся предупреждением. Раньше py писал его в stderr —
|
||||
# наблюдаемое поведение портов расходилось, и один кейс не мог проверить оба.
|
||||
if silent_failures:
|
||||
suffix = "" if args.StrictLog else " (pass -StrictLog to treat as error)"
|
||||
print(
|
||||
f"[warning] log contains {len(silent_failures)} rejection(s) — "
|
||||
f"platform loaded config but dropped properties/refs{suffix}",
|
||||
file=sys.stderr,
|
||||
f"[warning] platform reported success, but the log contains "
|
||||
f"{len(silent_failures)} problem(s):"
|
||||
)
|
||||
for f in silent_failures:
|
||||
print(f" {f}", file=sys.stderr)
|
||||
print(f" {f}")
|
||||
if args.StrictLog and exit_code == 0:
|
||||
exit_code = 1
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# db-update v1.14 — Update 1C database configuration
|
||||
# db-update v1.15 — Update 1C database configuration
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||
<#
|
||||
@@ -91,6 +91,12 @@ param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$WarningsAsErrors,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
# Ключ для регрессов и верификации снапшотов, не для повседневного вызова: в SKILL.md
|
||||
# намеренно не выносится. Поднимает код возврата, если платформа отчиталась об успехе,
|
||||
# но в логе есть отбраковка.
|
||||
[switch]$StrictLog,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string[]]$AdditionalV8Arguments = @(),
|
||||
|
||||
@@ -395,6 +401,41 @@ function Write-PlatformOutput {
|
||||
Write-Host "--- End ---"
|
||||
}
|
||||
|
||||
# Строки лога, о которых платформа сообщает, НЕ поднимая код возврата: метаданные отброшены или
|
||||
# конфигурация нерабочая, а операция при этом «успешна». Возвращает подошедшие строки.
|
||||
#
|
||||
# Копия этой функции есть в каждом навыке, который читает /Out-лог загрузки (навыки автономны).
|
||||
# Держать копии одинаковыми — сознательно: разошедшиеся копии сводят на нет весь смысл.
|
||||
function Find-SilentRejections {
|
||||
param([string]$LogText)
|
||||
$patterns = @(
|
||||
'Неверное свойство объекта метаданных',
|
||||
'не входит в состав объекта метаданных',
|
||||
'Неизвестное имя типа',
|
||||
'Неизвестный объект метаданных',
|
||||
'Ни один из документов не является регистратором для регистра',
|
||||
'Неверное значение перечисления',
|
||||
'не может быть приведен к типу',
|
||||
# Режим совместимости выше платформы: объекты в базу не попадают, отказ приходит в рантайме.
|
||||
# Обрезано до инвариантной части — конкретная версия в сообщении меняется.
|
||||
'Для работы с конфигурацией необходима версия платформы не меньше'
|
||||
)
|
||||
$found = @()
|
||||
if ($LogText) {
|
||||
foreach ($line in ($LogText -split "`r?`n")) {
|
||||
foreach ($pat in $patterns) {
|
||||
if ($line -match [regex]::Escape($pat)) {
|
||||
$found += $line.Trim()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# Возвращаем массив БЕЗ запятой-обёртки: вызывающий берёт результат в @(), а `return ,$found`
|
||||
# дал бы массив из одного пустого массива — фантомное срабатывание на чистом логе.
|
||||
return $found
|
||||
}
|
||||
|
||||
|
||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||
|
||||
@@ -496,6 +537,7 @@ try {
|
||||
Write-Host "Error updating database configuration (code: $exitCode)$(Get-ExitAnnotation $exitCode)" -ForegroundColor Red
|
||||
}
|
||||
|
||||
$logContent = $null
|
||||
if (Test-Path $outFile) {
|
||||
$logContent = Get-Content $outFile -Raw -ErrorAction SilentlyContinue
|
||||
if ($logContent) {
|
||||
@@ -506,6 +548,16 @@ try {
|
||||
}
|
||||
Write-PlatformOutput $__v8.Output
|
||||
|
||||
# Причину не называем: строки лога печатаются следом и говорят за себя, а класс проблемы
|
||||
# разный — от отброшенного свойства до нерабочей на этой платформе конфигурации. Подсказку
|
||||
# про -StrictLog не даём: операция уже выполнена, повторять её ради того же текста незачем.
|
||||
$silentFailures = @(Find-SilentRejections $logContent)
|
||||
if ($silentFailures.Count -gt 0) {
|
||||
Write-Host "[warning] platform reported success, but the log contains $($silentFailures.Count) problem(s):" -ForegroundColor Yellow
|
||||
foreach ($f in $silentFailures) { Write-Host " $f" -ForegroundColor Yellow }
|
||||
if ($StrictLog -and $exitCode -eq 0) { $exitCode = 1 }
|
||||
}
|
||||
|
||||
exit $exitCode
|
||||
|
||||
} finally {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# db-update v1.14 — Update 1C database configuration
|
||||
# db-update v1.15 — Update 1C database configuration
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
@@ -344,6 +344,38 @@ def print_platform_output(result):
|
||||
print("--- End ---")
|
||||
|
||||
|
||||
def find_silent_rejections(log_text):
|
||||
"""Строки лога, о которых платформа сообщает, НЕ поднимая код возврата.
|
||||
|
||||
Метаданные отброшены или конфигурация нерабочая, а операция при этом «успешна».
|
||||
Возвращает подошедшие строки.
|
||||
|
||||
Копия этой функции есть в каждом навыке, который читает /Out-лог загрузки (навыки
|
||||
автономны). Держать копии одинаковыми — сознательно: разошедшиеся копии сводят на нет
|
||||
весь смысл.
|
||||
"""
|
||||
patterns = [
|
||||
"Неверное свойство объекта метаданных",
|
||||
"не входит в состав объекта метаданных",
|
||||
"Неизвестное имя типа",
|
||||
"Неизвестный объект метаданных",
|
||||
"Ни один из документов не является регистратором для регистра",
|
||||
"Неверное значение перечисления",
|
||||
"не может быть приведен к типу",
|
||||
# Режим совместимости выше платформы: объекты в базу не попадают, отказ приходит в
|
||||
# рантайме. Обрезано до инвариантной части — конкретная версия в сообщении меняется.
|
||||
"Для работы с конфигурацией необходима версия платформы не меньше",
|
||||
]
|
||||
found = []
|
||||
if log_text:
|
||||
for line in log_text.splitlines():
|
||||
for pat in patterns:
|
||||
if pat in line:
|
||||
found.append(line.strip())
|
||||
break
|
||||
return found
|
||||
|
||||
|
||||
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||
"""Run an ibcmd command non-interactively.
|
||||
|
||||
@@ -411,6 +443,10 @@ def main():
|
||||
parser.add_argument("-Dynamic", default="", choices=["", "+", "-"])
|
||||
parser.add_argument("-Server", action="store_true")
|
||||
parser.add_argument("-WarningsAsErrors", action="store_true")
|
||||
# Ключ для регрессов и верификации снапшотов, не для повседневного вызова: в SKILL.md
|
||||
# намеренно не выносится. Поднимает код возврата, если платформа отчиталась об успехе,
|
||||
# но в логе есть отбраковка.
|
||||
parser.add_argument("-StrictLog", action="store_true")
|
||||
parser.add_argument("-AdditionalV8Arguments", nargs="*", default=[],
|
||||
help="Extra 1cv8 arguments, e.g. /UseHwLicenses+")
|
||||
parser.add_argument("-AdditionalIbcmdArguments", nargs="*", default=[],
|
||||
@@ -527,6 +563,7 @@ def main():
|
||||
else:
|
||||
print(f"Error updating database configuration (code: {exit_code}){describe_exit(exit_code)}", file=sys.stderr)
|
||||
|
||||
log_content = ""
|
||||
if os.path.isfile(out_file):
|
||||
try:
|
||||
with open(out_file, "r", encoding="utf-8-sig") as f:
|
||||
@@ -539,6 +576,21 @@ def main():
|
||||
pass
|
||||
|
||||
print_platform_output(result)
|
||||
|
||||
# Причину не называем: строки лога печатаются следом и говорят за себя, а класс проблемы
|
||||
# разный — от отброшенного свойства до нерабочей на этой платформе конфигурации. Подсказку
|
||||
# про -StrictLog не даём: операция уже выполнена, повторять её ради того же текста незачем.
|
||||
silent_failures = find_silent_rejections(log_content)
|
||||
if silent_failures:
|
||||
print(
|
||||
f"[warning] platform reported success, but the log contains "
|
||||
f"{len(silent_failures)} problem(s):"
|
||||
)
|
||||
for line in silent_failures:
|
||||
print(f" {line}")
|
||||
if args.StrictLog and exit_code == 0:
|
||||
exit_code = 1
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
finally:
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"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Загрузка завершена. Суммарное время выполнения операции: 780 миллисекунд.\r\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "ib/1Cv8.1CD",
|
||||
"content": "stub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{workDir}\\fake.cmd",
|
||||
"-InfoBasePath",
|
||||
"{workDir}\\ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}\\src"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutNotContains": "[warning] platform reported success, but the log contains"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "Режим совместимости выше платформы: сообщение классифицируется как отказ (issue #63)",
|
||||
"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": "Для работы с конфигурацией необходима версия платформы не меньше, чем 8.3.27.\r\nТекущая версия 8.3.24.1691.\r\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "ib/1Cv8.1CD",
|
||||
"content": "stub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{workDir}\\fake.cmd",
|
||||
"-InfoBasePath",
|
||||
"{workDir}\\ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}\\src"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": [
|
||||
"[warning] platform reported success, but the log contains 1 problem(s):",
|
||||
"необходима версия платформы не меньше"
|
||||
]
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "Тихий отказ в логе: платформа вернула 0, навык предупреждает (fake platform)",
|
||||
"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Неверное свойство объекта метаданных. Свойство LineNumberLength не входит в состав объекта метаданных TabularSection. - LineNumberLength\r\nЗагрузка завершена.\r\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "ib/1Cv8.1CD",
|
||||
"content": "stub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{workDir}\\fake.cmd",
|
||||
"-InfoBasePath",
|
||||
"{workDir}\\ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}\\src"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": [
|
||||
"[warning] platform reported success, but the log contains 1 problem(s):",
|
||||
"Свойство LineNumberLength не входит в состав объекта метаданных"
|
||||
],
|
||||
"stdoutNotContains": "-StrictLog"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "Тот же лог под -StrictLog: код возврата поднимается до 1 (fake platform)",
|
||||
"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Неверное свойство объекта метаданных. Свойство LineNumberLength не входит в состав объекта метаданных TabularSection. - LineNumberLength\r\nЗагрузка завершена.\r\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "ib/1Cv8.1CD",
|
||||
"content": "stub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "src/Configuration.xml",
|
||||
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{workDir}\\fake.cmd",
|
||||
"-InfoBasePath",
|
||||
"{workDir}\\ib",
|
||||
"-ConfigDir",
|
||||
"{workDir}\\src",
|
||||
"-StrictLog"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": "[warning] platform reported success, but the log contains 1 problem(s):"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы",
|
||||
"expectError": true
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"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Загрузка завершена. Суммарное время выполнения операции: 780 миллисекунд.\r\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "ib/1Cv8.1CD",
|
||||
"content": "stub"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{workDir}\\fake.cmd",
|
||||
"-InfoBasePath",
|
||||
"{workDir}\\ib"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutNotContains": "[warning] platform reported success, but the log contains"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "Режим совместимости выше платформы: сообщение классифицируется как отказ (issue #63)",
|
||||
"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": "Для работы с конфигурацией необходима версия платформы не меньше, чем 8.3.27.\r\nТекущая версия 8.3.24.1691.\r\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "ib/1Cv8.1CD",
|
||||
"content": "stub"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{workDir}\\fake.cmd",
|
||||
"-InfoBasePath",
|
||||
"{workDir}\\ib"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": [
|
||||
"[warning] platform reported success, but the log contains 1 problem(s):",
|
||||
"необходима версия платформы не меньше"
|
||||
]
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "Тихий отказ в логе: платформа вернула 0, навык предупреждает (fake platform)",
|
||||
"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Неверное свойство объекта метаданных. Свойство LineNumberLength не входит в состав объекта метаданных TabularSection. - LineNumberLength\r\nЗагрузка завершена.\r\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "ib/1Cv8.1CD",
|
||||
"content": "stub"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{workDir}\\fake.cmd",
|
||||
"-InfoBasePath",
|
||||
"{workDir}\\ib"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": [
|
||||
"[warning] platform reported success, but the log contains 1 problem(s):",
|
||||
"Свойство LineNumberLength не входит в состав объекта метаданных"
|
||||
],
|
||||
"stdoutNotContains": "-StrictLog"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "Тот же лог под -StrictLog: код возврата поднимается до 1 (fake platform)",
|
||||
"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Неверное свойство объекта метаданных. Свойство LineNumberLength не входит в состав объекта метаданных TabularSection. - LineNumberLength\r\nЗагрузка завершена.\r\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"writeFile": {
|
||||
"path": "ib/1Cv8.1CD",
|
||||
"content": "stub"
|
||||
}
|
||||
}
|
||||
],
|
||||
"args_extra": [
|
||||
"-V8Path",
|
||||
"{workDir}\\fake.cmd",
|
||||
"-InfoBasePath",
|
||||
"{workDir}\\ib",
|
||||
"-StrictLog"
|
||||
],
|
||||
"expect": {
|
||||
"stdoutContains": "[warning] platform reported success, but the log contains 1 problem(s):"
|
||||
},
|
||||
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы",
|
||||
"expectError": true
|
||||
}
|
||||
@@ -214,6 +214,15 @@ const FAMILIES = [
|
||||
},
|
||||
|
||||
// ─── Обвязка вызова платформы 1С (db-* и потребители) ────────────────────
|
||||
// Детектор строк, о которых платформа сообщает, НЕ поднимая код возврата. Живёт во всех
|
||||
// навыках, читающих /Out-лог загрузки: разъехавшийся список паттернов означал бы, что один
|
||||
// навык ловит тихий отказ, а соседний по той же операции — нет.
|
||||
{
|
||||
name: 'platform: silent_rejections', py: 'find_silent_rejections', ps1: 'Find-SilentRejections',
|
||||
variants: [
|
||||
{ id: 'base', authority: 'db-load-xml', consumers: ['db-load-git', 'db-update'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'platform: resolve_extra_args', py: 'resolve_extra_args', ps1: 'Resolve-ExtraArgs',
|
||||
variants: [
|
||||
|
||||
Reference in New Issue
Block a user