From 105e240244516d1699228f6e60bbb6fa40a2def8 Mon Sep 17 00:00:00 2001 From: DanliaQwerty20 Date: Mon, 14 Sep 2026 23:37:30 +0300 Subject: [PATCH] fix: support Windows PowerShell local workflow --- README.md | 14 +++++++------- docs/runbook.md | 6 +++--- scripts/check-apps.ps1 | 10 ++++++++-- scripts/check-chart.ps1 | 2 +- scripts/check-compose.ps1 | 6 +++--- scripts/check-config.ps1 | 2 +- scripts/check-docs.ps1 | 2 +- scripts/check-keycloak.ps1 | 4 ++-- scripts/new-service.ps1 | 16 +++++++++++++--- scripts/smoke-k3d.ps1 | 2 +- scripts/start-local.ps1 | 7 ++++--- scripts/stop-local.ps1 | 5 +++-- scripts/test-new-service.ps1 | 2 +- 13 files changed, 48 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 0998447..9d07bc4 100644 --- a/README.md +++ b/README.md @@ -21,20 +21,20 @@ - Helm 4.2.4; - k3d 5.9.0; - kubectl; -- PowerShell 7. +- Windows PowerShell 5.1 или PowerShell 7. Создай локальный файл настроек и запусти инфраструктуру: ```powershell Copy-Item .env.example .env -pwsh ./scripts/start-local.ps1 -Observe +./scripts/start-local.ps1 -Observe ``` Чтобы поднять проверяемый путь `Channel → Agent → Action → Gateway → Calendar`, используй: ```powershell -pwsh ./scripts/start-local.ps1 -Apps -pwsh ./scripts/check-apps.ps1 +./scripts/start-local.ps1 -Apps +./scripts/check-apps.ps1 ``` `check-apps.ps1` отправляет demo-команду в Channel Gateway, проверяет предложение, создаёт и @@ -81,19 +81,19 @@ Worker, Temporal UI и Linux Compose используют внутренний Все быстрые проверки: ```powershell -pwsh ./scripts/check-config.ps1 +./scripts/check-config.ps1 ``` Полная проверка: ```powershell -pwsh ./scripts/smoke-k3d.ps1 +./scripts/smoke-k3d.ps1 ``` Подготовить delivery-файлы нового сервиса: ```powershell -pwsh ./scripts/new-service.ps1 -Name sample-api -Image ghcr.io/portable-agent/sample-api -Port 8080 +./scripts/new-service.ps1 -Name sample-api -Image ghcr.io/portable-agent/sample-api -Port 8080 ``` Архитектура и следующий шаг описаны в [docs/index.md](docs/index.md). Правила для разработчиков и diff --git a/docs/runbook.md b/docs/runbook.md index f741741..014a04b 100644 --- a/docs/runbook.md +++ b/docs/runbook.md @@ -17,12 +17,12 @@ ## Приложения не запускаются -1. Выполни `pwsh ./scripts/check-compose.ps1`. +1. Выполни `./scripts/check-compose.ps1` из Windows PowerShell 5.1 или PowerShell 7. 2. Проверь, что рядом лежат репозитории `portable-agent-channel-gateway`, `portable-agent-agent-runtime`, `portable-agent-action-service`, `portable-agent-mcp-gateway` и `portable-agent-calendar-mcp`, либо задай их `*_CONTEXT` в `.env`. 3. Если Keycloak сообщает о старом fixture, локально выполни - `pwsh ./scripts/stop-local.ps1 -DeleteData`. Команда удаляет только volumes этого Compose project. + `./scripts/stop-local.ps1 -DeleteData`. Команда удаляет только volumes этого Compose project. 4. Проверь `/health/live` Channel Gateway и Agent Runtime, `/actuator/health/readiness` Action Service и `/health` двух MCP-сервисов. 5. Не включай Calendar test API вне локального профиля `apps`. @@ -30,7 +30,7 @@ После запуска проверь весь backend-путь одной командой: ```powershell -pwsh ./scripts/check-apps.ps1 +./scripts/check-apps.ps1 ``` Она отправляет текст через Channel Gateway, затем создаёт действие с тем же случайным `requestKey`, diff --git a/scripts/check-apps.ps1 b/scripts/check-apps.ps1 index e3af537..b4797b5 100644 --- a/scripts/check-apps.ps1 +++ b/scripts/check-apps.ps1 @@ -1,4 +1,4 @@ -param([int]$TimeoutSeconds = 30) +param([int]$TimeoutSeconds = 30) $ErrorActionPreference = "Stop" function Get-LocalSetting([string]$Name) { @@ -63,10 +63,16 @@ function Invoke-JsonRequest( Headers = $Headers } if ($Body) { - $request.ContentType = "application/json" + $request.ContentType = "application/json; charset=utf-8" $request.Body = $Body } + if ($PSVersionTable.PSEdition -eq "Desktop") { + $request.UseBasicParsing = $true + } $response = Invoke-WebRequest @request + if ($PSVersionTable.PSEdition -eq "Desktop") { + return $response.Content | ConvertFrom-Json + } return $response.Content | ConvertFrom-Json -DateKind String } $proposalRequest = @{ diff --git a/scripts/check-chart.ps1 b/scripts/check-chart.ps1 index 29c7c41..17c716a 100644 --- a/scripts/check-chart.ps1 +++ b/scripts/check-chart.ps1 @@ -1,4 +1,4 @@ -$ErrorActionPreference = "Stop" +$ErrorActionPreference = "Stop" if (-not (Get-Command helm -ErrorAction SilentlyContinue)) { throw "Helm не найден. Установи Helm 4.2.4 или запусти проверку в CI." diff --git a/scripts/check-compose.ps1 b/scripts/check-compose.ps1 index 3c7c285..9bc9e66 100644 --- a/scripts/check-compose.ps1 +++ b/scripts/check-compose.ps1 @@ -1,4 +1,4 @@ -$ErrorActionPreference = "Stop" +$ErrorActionPreference = "Stop" $linuxFiles = Get-ChildItem -Recurse -File -Filter "*.sh" | ForEach-Object { $_.FullName } foreach ($file in $linuxFiles) { $bytes = [System.IO.File]::ReadAllBytes($file) @@ -142,10 +142,10 @@ foreach ($required in @("CHANNEL_GATEWAY_PORT", "/api/v1/messages", "requestKey" } } $versions = Get-Content -Raw -LiteralPath "config/versions.env" -if ($versions -notmatch '(?m)^AGENT_RUNTIME_IMAGE=ghcr\.io/portable-agent/agent-runtime:[0-9a-f]{40}$') { +if ($versions -notmatch '(?m)^AGENT_RUNTIME_IMAGE=ghcr\.io/portable-agent/agent-runtime:[0-9a-f]{40}\r?$') { throw "Agent Runtime image должен быть закреплён полным Git SHA." } -if ($versions -notmatch '(?m)^CHANNEL_GATEWAY_IMAGE=ghcr\.io/portable-agent/channel-gateway:[0-9a-f]{40}$') { +if ($versions -notmatch '(?m)^CHANNEL_GATEWAY_IMAGE=ghcr\.io/portable-agent/channel-gateway:[0-9a-f]{40}\r?$') { throw "Channel Gateway image должен быть закреплён полным Git SHA." } foreach ($oldName in @("utterance", "actor_id", "available_connectors", "requires_approval")) { diff --git a/scripts/check-config.ps1 b/scripts/check-config.ps1 index f11963a..5aec464 100644 --- a/scripts/check-config.ps1 +++ b/scripts/check-config.ps1 @@ -1,4 +1,4 @@ -$ErrorActionPreference = "Stop" +$ErrorActionPreference = "Stop" & "$PSScriptRoot/check-chart.ps1" & "$PSScriptRoot/test-new-service.ps1" if (Get-Command docker -ErrorAction SilentlyContinue) { & "$PSScriptRoot/check-compose.ps1" } diff --git a/scripts/check-docs.ps1 b/scripts/check-docs.ps1 index ccd0281..fd872dd 100644 --- a/scripts/check-docs.ps1 +++ b/scripts/check-docs.ps1 @@ -1,4 +1,4 @@ -$ErrorActionPreference = "Stop" +$ErrorActionPreference = "Stop" $requiredFiles = @( "README.md", diff --git a/scripts/check-keycloak.ps1 b/scripts/check-keycloak.ps1 index a1d12f8..500acf7 100644 --- a/scripts/check-keycloak.ps1 +++ b/scripts/check-keycloak.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory = $true)][string]$BaseUrl, [Parameter(Mandatory = $true)][string]$ServiceSecret, [Parameter(Mandatory = $true)][string]$ExpectedTenant @@ -53,7 +53,7 @@ try { throw "Service token action-service не содержит нужные claims." } } catch { - throw "Локальный Keycloak не соответствует compose/keycloak/portable-agent-realm.json. Для обновления тестовых данных выполни 'pwsh ./scripts/stop-local.ps1 -DeleteData', затем запусти стенд снова. Причина: $($_.Exception.Message)" + throw "Локальный Keycloak не соответствует compose/keycloak/portable-agent-realm.json. Для обновления тестовых данных выполни './scripts/stop-local.ps1 -DeleteData', затем запусти стенд снова. Причина: $($_.Exception.Message)" } Write-Host "Keycloak fixture прошёл runtime-проверку." diff --git a/scripts/new-service.ps1 b/scripts/new-service.ps1 index d9d5da4..854e03f 100644 --- a/scripts/new-service.ps1 +++ b/scripts/new-service.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory)][string]$Name, [Parameter(Mandatory)][string]$Image, [int]$Port = 8080, @@ -6,6 +6,7 @@ param( ) $ErrorActionPreference = "Stop" +$utf8WithoutBom = New-Object System.Text.UTF8Encoding($false) if ($Name -notmatch '^[a-z][a-z0-9-]{1,61}[a-z0-9]$') { throw "Name должен быть DNS-именем: маленькие латинские буквы, цифры и дефис." } @@ -39,11 +40,20 @@ config: APP_ENV: $($environment.name) secretRefs: [] "@ - Set-Content -Path (Join-Path $folder "values.yaml") -Value $values -Encoding utf8NoBOM + [System.IO.File]::WriteAllText( + (Join-Path $folder "values.yaml"), + $values + [Environment]::NewLine, + $utf8WithoutBom + ) } $catalog.items += [pscustomobject]@{ name = $Name; image = $Image; port = $Port } $catalog.items = @($catalog.items | Sort-Object name) -$catalog | ConvertTo-Json -Depth 10 | Set-Content $catalogPath -Encoding utf8NoBOM +$catalogJson = $catalog | ConvertTo-Json -Depth 10 +[System.IO.File]::WriteAllText( + $catalogPath, + $catalogJson + [Environment]::NewLine, + $utf8WithoutBom +) Write-Host "Сервис $Name добавлен во все окружения. Проверь tag и secretRefs перед commit." diff --git a/scripts/smoke-k3d.ps1 b/scripts/smoke-k3d.ps1 index 377b36d..5294ed3 100644 --- a/scripts/smoke-k3d.ps1 +++ b/scripts/smoke-k3d.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ClusterName = "portable-agent-smoke", [string]$ChartPath = "charts/platform-base", [string]$ServiceChartPath = "charts/service" diff --git a/scripts/start-local.ps1 b/scripts/start-local.ps1 index 45417bd..74a0461 100644 --- a/scripts/start-local.ps1 +++ b/scripts/start-local.ps1 @@ -1,9 +1,10 @@ -param([switch]$Observe, [switch]$Apps) +param([switch]$Observe, [switch]$Apps) $ErrorActionPreference = "Stop" $envFiles = @("--env-file", ".env.example", "--env-file", "config/versions.env") if (Test-Path .env) { $envFiles += @("--env-file", ".env") } $composeFiles = @("-f", "compose/compose.yaml") -if ($IsWindows) { $composeFiles += @("-f", "compose/windows.local.yaml") } +$runningOnWindows = $PSVersionTable.PSEdition -eq "Desktop" -or $IsWindows +if ($runningOnWindows) { $composeFiles += @("-f", "compose/windows.local.yaml") } function Get-LocalSetting([string]$Name) { $value = [Environment]::GetEnvironmentVariable($Name) foreach ($path in @(".env", ".env.example")) { @@ -41,4 +42,4 @@ if ($Apps) { @appProfiles up -d --build --wait --scale temporal-namespace=0 if ($LASTEXITCODE -ne 0) { throw "Приложения локального среза не запустились." } } -Write-Host "Локальная инфраструктура готова. Для остановки: pwsh ./scripts/stop-local.ps1" +Write-Host "Локальная инфраструктура готова. Для остановки: ./scripts/stop-local.ps1" diff --git a/scripts/stop-local.ps1 b/scripts/stop-local.ps1 index 5f6c61a..6fdeb56 100644 --- a/scripts/stop-local.ps1 +++ b/scripts/stop-local.ps1 @@ -1,9 +1,10 @@ -param([switch]$DeleteData) +param([switch]$DeleteData) $ErrorActionPreference = "Stop" $args = @("compose", "--env-file", ".env.example", "--env-file", "config/versions.env") if (Test-Path .env) { $args += @("--env-file", ".env") } $args += @("-f", "compose/compose.yaml") -if ($IsWindows) { $args += @("-f", "compose/windows.local.yaml") } +$runningOnWindows = $PSVersionTable.PSEdition -eq "Desktop" -or $IsWindows +if ($runningOnWindows) { $args += @("-f", "compose/windows.local.yaml") } $args += @("--profile", "core", "--profile", "observe", "--profile", "apps", "down") if ($DeleteData) { $args += "--volumes" } & docker @args diff --git a/scripts/test-new-service.ps1 b/scripts/test-new-service.ps1 index de86c6e..e75b70e 100644 --- a/scripts/test-new-service.ps1 +++ b/scripts/test-new-service.ps1 @@ -1,4 +1,4 @@ -$ErrorActionPreference = "Stop" +$ErrorActionPreference = "Stop" $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("pa-service-" + [guid]::NewGuid()) try { New-Item -ItemType Directory -Path "$tempRoot/services", "$tempRoot/environments" | Out-Null