326 lines
13 KiB
PowerShell
326 lines
13 KiB
PowerShell
param(
|
|
[string]$Server = $env:ONEC_SQL_SERVER,
|
|
[string]$Database = $env:ONEC_SQL_DATABASE,
|
|
[string]$User = $env:ONEC_SQL_USER,
|
|
[string]$Password = $env:ONEC_SQL_PASSWORD,
|
|
[string]$OutputDir = "reports\1c-sql\saved-state-object-report",
|
|
[string]$BaseMetadataDir = "reports\1c-sql\upo\structured-metadata-all-kinds",
|
|
[string]$ExtensionGuidIndex = "reports\1c-sql\upo\xml-guid-index-extensions.json",
|
|
[string]$ExtensionManifestSummary = "reports\1c-sql\upo\extension-manifest-xml-part-summary.json",
|
|
[string]$ConfigCASAllDir = "reports\1c-sql\upo\ConfigCAS-all",
|
|
[string]$Python = "python",
|
|
[string]$MarkdownOutput = "",
|
|
[int]$MarkdownMaxDiffLines = 80,
|
|
[switch]$SkipMarkdown
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
if (-not $Server) { throw "Server is required. Use -Server or ONEC_SQL_SERVER." }
|
|
if (-not $Database) { throw "Database is required. Use -Database or ONEC_SQL_DATABASE." }
|
|
if (-not $User) { throw "User is required. Use -User or ONEC_SQL_USER." }
|
|
if (-not $Password) { throw "Password is required. Use -Password or ONEC_SQL_PASSWORD." }
|
|
|
|
$repoRoot = (Resolve-Path ".").ProviderPath
|
|
$resolvedOutput = [System.IO.Path]::GetFullPath($OutputDir)
|
|
New-Item -ItemType Directory -Force -Path $resolvedOutput | Out-Null
|
|
|
|
$comparisonPath = Join-Path $resolvedOutput "saved-state-object-comparison.json"
|
|
$detailPath = Join-Path $resolvedOutput "saved-state-object-details.json"
|
|
$checkPath = Join-Path $resolvedOutput "saved-state-object-report-check.json"
|
|
$configSaveDir = Join-Path $resolvedOutput "ConfigSave"
|
|
$configCASSaveDir = Join-Path $resolvedOutput "ConfigCASSave"
|
|
$activeConfigDir = Join-Path $resolvedOutput "ActiveConfig"
|
|
$activeConfigCASDir = Join-Path $resolvedOutput "ActiveConfigCAS"
|
|
|
|
foreach ($dir in @($configSaveDir, $configCASSaveDir, $activeConfigDir, $activeConfigCASDir)) {
|
|
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
|
}
|
|
|
|
function Invoke-Step {
|
|
param(
|
|
[string]$Name,
|
|
[scriptblock]$Script
|
|
)
|
|
$started = Get-Date
|
|
& $Script
|
|
[pscustomobject]@{
|
|
name = $Name
|
|
started_at = $started.ToString("o")
|
|
finished_at = (Get-Date).ToString("o")
|
|
passed = $true
|
|
}
|
|
}
|
|
|
|
function Read-JsonFile {
|
|
param([string]$Path)
|
|
return Get-Content -LiteralPath $Path -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
}
|
|
|
|
function Export-TableFiles {
|
|
param(
|
|
[string]$Table,
|
|
[string]$TargetDir,
|
|
[string[]]$FileName
|
|
)
|
|
$args = @(
|
|
"-NoProfile", "-ExecutionPolicy", "Bypass",
|
|
"-File", "scripts\export_1c_sql_files.ps1",
|
|
"-Server", $Server,
|
|
"-Database", $Database,
|
|
"-User", $User,
|
|
"-Password", $Password,
|
|
"-Table", $Table,
|
|
"-OutputPath", $TargetDir
|
|
)
|
|
[object[]]$normalizedFileName = @($FileName)
|
|
if (($normalizedFileName | Measure-Object).Count -gt 0) {
|
|
$args += "-FileName"
|
|
$args += $normalizedFileName
|
|
}
|
|
$json = & powershell @args
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Export failed for $Table."
|
|
}
|
|
return ($json | Out-String | ConvertFrom-Json)
|
|
}
|
|
|
|
function Get-JsonProperty {
|
|
param(
|
|
[object]$Object,
|
|
[string]$Name,
|
|
[object]$Default = $null
|
|
)
|
|
if ($null -eq $Object) { return $Default }
|
|
if ($Object.PSObject.Properties.Name -contains $Name) {
|
|
return $Object.$Name
|
|
}
|
|
return $Default
|
|
}
|
|
|
|
function Join-LimitedValues {
|
|
param(
|
|
[object[]]$Values,
|
|
[int]$Limit = 12
|
|
)
|
|
$items = @($Values | Where-Object { $null -ne $_ -and [string]$_ -ne "" } | Select-Object -First $Limit)
|
|
return ,$items
|
|
}
|
|
|
|
function New-AgentSummary {
|
|
param(
|
|
[object]$Comparison,
|
|
[object]$Detail
|
|
)
|
|
$detailByName = @{}
|
|
foreach ($item in @($Detail.object_details)) {
|
|
$fullName = [string](Get-JsonProperty -Object $item -Name "full_name" -Default "")
|
|
if ($fullName) { $detailByName[$fullName] = $item }
|
|
}
|
|
|
|
$objects = @()
|
|
foreach ($change in @($Comparison.object_changes)) {
|
|
$fullName = [string](Get-JsonProperty -Object $change -Name "full_name" -Default (Get-JsonProperty -Object $change -Name "name" -Default ""))
|
|
$item = $null
|
|
if ($fullName -and $detailByName.ContainsKey($fullName)) {
|
|
$item = $detailByName[$fullName]
|
|
}
|
|
|
|
$parts = @()
|
|
$addedTerms = @()
|
|
$removedTerms = @()
|
|
$textDiffParts = 0
|
|
$activeMissingParts = 0
|
|
foreach ($part in @((Get-JsonProperty -Object $item -Name "details" -Default @()))) {
|
|
$payload = Get-JsonProperty -Object $part -Name "payload" -Default $null
|
|
$diff = Get-JsonProperty -Object $payload -Name "text_diff" -Default $null
|
|
$semanticHints = Get-JsonProperty -Object $payload -Name "semantic_hints" -Default $null
|
|
$activeExists = Get-JsonProperty -Object $part -Name "active_exists" -Default $null
|
|
if ($activeExists -eq $false) { $activeMissingParts += 1 }
|
|
if ($null -ne $diff) {
|
|
$textDiffParts += 1
|
|
$addedTerms += @(Get-JsonProperty -Object $semanticHints -Name "added_terms" -Default @())
|
|
$removedTerms += @(Get-JsonProperty -Object $semanticHints -Name "removed_terms" -Default @())
|
|
}
|
|
$parts += [pscustomobject]@{
|
|
file_name = Get-JsonProperty -Object $part -Name "file_name" -Default $null
|
|
payload_role = Get-JsonProperty -Object $part -Name "payload_role" -Default $null
|
|
saved_table = Get-JsonProperty -Object $part -Name "saved_table" -Default $null
|
|
active_table = Get-JsonProperty -Object $part -Name "active_table" -Default $null
|
|
active_exists = $activeExists
|
|
text_comparable = Get-JsonProperty -Object $payload -Name "text_comparable" -Default $null
|
|
summary = Get-JsonProperty -Object $payload -Name "summary" -Default $null
|
|
delta_chars = Get-JsonProperty -Object $diff -Name "delta_chars" -Default $null
|
|
}
|
|
}
|
|
|
|
$objects += [pscustomobject]@{
|
|
full_name = $fullName
|
|
layer = Get-JsonProperty -Object $change -Name "layer" -Default $null
|
|
extension = Get-JsonProperty -Object $change -Name "extension" -Default $null
|
|
kind = Get-JsonProperty -Object $change -Name "kind" -Default $null
|
|
kind_ru = Get-JsonProperty -Object $change -Name "kind_ru" -Default $null
|
|
name = Get-JsonProperty -Object $change -Name "name" -Default $null
|
|
synonym = Get-JsonProperty -Object $change -Name "synonym" -Default $null
|
|
change_state = Get-JsonProperty -Object $change -Name "change_state" -Default $null
|
|
parts_count = ($parts | Measure-Object).Count
|
|
text_diff_parts = $textDiffParts
|
|
active_missing_parts = $activeMissingParts
|
|
added_terms = Join-LimitedValues -Values ($addedTerms | Sort-Object -Unique) -Limit 12
|
|
removed_terms = Join-LimitedValues -Values ($removedTerms | Sort-Object -Unique) -Limit 12
|
|
parts = $parts
|
|
}
|
|
}
|
|
|
|
$systemChanges = @()
|
|
foreach ($change in @($Comparison.system_changes)) {
|
|
$systemChanges += [pscustomobject]@{
|
|
name = Get-JsonProperty -Object $change -Name "name" -Default $null
|
|
layer = Get-JsonProperty -Object $change -Name "layer" -Default $null
|
|
extension = Get-JsonProperty -Object $change -Name "extension" -Default $null
|
|
}
|
|
}
|
|
|
|
return [pscustomobject]@{
|
|
purpose = "Compact agent-facing summary of saved-but-not-applied changes in 1C terms."
|
|
default_next_action = "Inspect object details before generating or applying any code changes."
|
|
object_changes = $objects
|
|
system_changes = $systemChanges
|
|
object_names = @($objects | ForEach-Object { $_.full_name })
|
|
system_change_names = @($systemChanges | ForEach-Object { $_.name })
|
|
}
|
|
}
|
|
|
|
$steps = @()
|
|
|
|
$steps += Invoke-Step "compare_saved_state_objects" {
|
|
& powershell -NoProfile -ExecutionPolicy Bypass -File scripts\compare_1c_saved_state_objects.ps1 `
|
|
-Server $Server `
|
|
-Database $Database `
|
|
-User $User `
|
|
-Password $Password `
|
|
-BaseMetadataDir $BaseMetadataDir `
|
|
-ExtensionGuidIndex $ExtensionGuidIndex `
|
|
-Output $comparisonPath | Out-Null
|
|
if ($LASTEXITCODE -ne 0) { throw "Saved-state object comparison failed." }
|
|
}
|
|
|
|
$comparison = Read-JsonFile $comparisonPath
|
|
|
|
$steps += Invoke-Step "export_config_save" {
|
|
$null = Export-TableFiles -Table "ConfigSave" -TargetDir $configSaveDir
|
|
}
|
|
|
|
$steps += Invoke-Step "export_config_cas_save" {
|
|
$null = Export-TableFiles -Table "ConfigCASSave" -TargetDir $configCASSaveDir
|
|
}
|
|
|
|
$activeConfigFiles = @(
|
|
$comparison.object_changes |
|
|
ForEach-Object { $_.storage } |
|
|
Where-Object { $_.active_table -eq "Config" } |
|
|
ForEach-Object { [string]$_.file_name } |
|
|
Sort-Object -Unique
|
|
)
|
|
$activeConfigCASFiles = @(
|
|
$comparison.object_changes |
|
|
ForEach-Object { $_.storage } |
|
|
Where-Object { $_.active_table -eq "ConfigCAS" -and $_.active_exists } |
|
|
ForEach-Object { [string]$_.file_name } |
|
|
Sort-Object -Unique
|
|
)
|
|
|
|
$steps += Invoke-Step "export_active_config_payloads" {
|
|
if (($activeConfigFiles | Measure-Object).Count -gt 0) {
|
|
$null = Export-TableFiles -Table "Config" -TargetDir $activeConfigDir -FileName $activeConfigFiles
|
|
}
|
|
}
|
|
|
|
$steps += Invoke-Step "export_active_config_cas_payloads" {
|
|
if (($activeConfigCASFiles | Measure-Object).Count -gt 0) {
|
|
$null = Export-TableFiles -Table "ConfigCAS" -TargetDir $activeConfigCASDir -FileName $activeConfigCASFiles
|
|
}
|
|
}
|
|
|
|
$steps += Invoke-Step "analyze_saved_state_object_details" {
|
|
& $Python scripts\analyze_1c_saved_state_object_details.py `
|
|
--comparison $comparisonPath `
|
|
--config-save-dir $configSaveDir `
|
|
--config-dir $activeConfigDir `
|
|
--config-cas-save-dir $configCASSaveDir `
|
|
--config-cas-dir $activeConfigCASDir `
|
|
--extension-manifest-summary $ExtensionManifestSummary `
|
|
--config-cas-all-dir $ConfigCASAllDir `
|
|
--output $detailPath | Out-Null
|
|
if ($LASTEXITCODE -ne 0) { throw "Saved-state detail analysis failed." }
|
|
}
|
|
|
|
$detail = Read-JsonFile $detailPath
|
|
$agentSummary = New-AgentSummary -Comparison $comparison -Detail $detail
|
|
|
|
$reportPath = Join-Path $resolvedOutput "saved-state-object-report.json"
|
|
if (-not $MarkdownOutput) {
|
|
$MarkdownOutput = Join-Path $resolvedOutput "saved-state-object-report.md"
|
|
} else {
|
|
$MarkdownOutput = [System.IO.Path]::GetFullPath($MarkdownOutput)
|
|
}
|
|
|
|
$result = [pscustomobject]@{
|
|
schema = "onec_saved_state_object_report.v1"
|
|
server = $Server
|
|
database = $Database
|
|
report = $reportPath
|
|
markdown = if ($SkipMarkdown) { $null } else { $MarkdownOutput }
|
|
check = $checkPath
|
|
output_dir = $resolvedOutput
|
|
comparison = $comparisonPath
|
|
detail = $detailPath
|
|
agent_summary = $agentSummary
|
|
payload_dirs = [pscustomobject]@{
|
|
config_save = $configSaveDir
|
|
config_cas_save = $configCASSaveDir
|
|
active_config = $activeConfigDir
|
|
active_config_cas = $activeConfigCASDir
|
|
active_config_cas_all = $ConfigCASAllDir
|
|
}
|
|
counts = [pscustomobject]@{
|
|
object_changes = $comparison.counts.object_changes
|
|
system_changes = $comparison.counts.system_changes
|
|
detail_objects = $detail.counts.objects
|
|
detail_parts = $detail.counts.details
|
|
}
|
|
steps = $steps
|
|
safety = [pscustomobject]@{
|
|
read_only = $true
|
|
sql_write_performed = $false
|
|
public_terms_are_1c_objects = $true
|
|
secrets_in_report = $false
|
|
}
|
|
}
|
|
|
|
$result | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $reportPath -Encoding UTF8
|
|
|
|
if (-not $SkipMarkdown) {
|
|
$steps += Invoke-Step "render_saved_state_markdown" {
|
|
& $Python scripts\render_1c_saved_state_object_report_markdown.py `
|
|
--report $reportPath `
|
|
--output $MarkdownOutput `
|
|
--max-diff-lines $MarkdownMaxDiffLines | Out-Null
|
|
if ($LASTEXITCODE -ne 0) { throw "Saved-state Markdown rendering failed." }
|
|
}
|
|
$result.steps = $steps
|
|
$result | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $reportPath -Encoding UTF8
|
|
}
|
|
|
|
$steps += Invoke-Step "check_saved_state_report" {
|
|
& $Python scripts\check_1c_saved_state_object_report.py `
|
|
--report $reportPath `
|
|
--output $checkPath | Out-Null
|
|
if ($LASTEXITCODE -ne 0) { throw "Saved-state report check failed." }
|
|
}
|
|
$result.steps = $steps
|
|
$result | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $reportPath -Encoding UTF8
|
|
|
|
$result | ConvertTo-Json -Depth 12
|