feat: add Windows PowerShell scripts for cloud-deployment example#900
feat: add Windows PowerShell scripts for cloud-deployment example#900spandey1702 wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces Windows PowerShell equivalents (deploy.ps1, cleanup.ps1, and verify.ps1) for the existing bash deployment scripts, along with updated documentation in the README.md. The code review feedback identifies several critical issues in the PowerShell scripts, primarily concerning Windows compatibility. These include a syntax error with here-string redirection, missing dependency checks for Maven and the container tool, and potential failures in string comparisons due to trailing carriage returns (\r) in output captured from external CLI tools like kubectl, docker/podman, and kind.
14da7a7 to
58311ac
Compare
|
Addressed all Gemini review comments — added .Trim() for CRLF handling, \r? in the kind cluster regex, -match "^True\s*$" in verify.ps1, and dependency checks for Maven and the container tool. |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces Windows PowerShell scripts (deploy.ps1, cleanup.ps1, and verify.ps1) as equivalents to the existing bash scripts for the cloud deployment example, along with corresponding updates to the README.md. The review feedback highlights several critical issues in the new PowerShell scripts: incorrect package names for the test client in deploy.ps1 and verify.ps1 that would cause a ClassNotFoundException, potential runtime exceptions from calling .Trim() on null values when inspecting containers, and a lack of error checking after kubectl wait commands which allows the deployment script to silently continue upon failure.
|
Hi @spandey1702 thank you. I think it could be good to have these scripts tested on CI, similar to what we do for Linux in https://github.com/a2aproject/a2a-java/blob/main/.github/workflows/cloud-deployment-example.yml AIUI GH Actions also provides Windows runners. |
|
Hi @kabir , |
|
Hi @spandey1702 thank you! Unfortunately it seems wee have a failure building the server, and something is failing in the BOM verification. I will see if I can add a job to test this on Windows and fix it. Then you can rebase. |
|
@spandey1702 This fixes the BOM verification on Windows #907 But I also added full testing on Windows. We will see if that passes! |
…ct#395) Add deploy.ps1, cleanup.ps1, and verify.ps1 as Windows equivalents of the existing bash scripts. Fixes a2aproject#395. - deploy.ps1: full cluster setup (Kind, registry, Strimzi, PostgreSQL, Kafka, agent) with -ContainerTool docker|podman parameter - cleanup.ps1: reverse-order teardown with confirmation prompt - verify.ps1: health checks for all deployed components Key translation notes: - Bash heredocs -> PowerShell here-strings piped to kubectl/docker stdin - export VAR=val -> $env:VAR = 'val' - grep/|| true -> -match / $LASTEXITCODE checks - sleep N -> Start-Sleep -Seconds N - curl -> curl.exe (avoids PowerShell Invoke-WebRequest alias) - SKIP_ENTITY_OPERATOR_WAIT and SKIP_AGENT_DEPLOY env vars supported Also updates README.md with Windows quick-start instructions, PowerShell execution policy note, and updated project structure table.
- Add missing dependency checks for Maven and container tool - Trim docker/podman inspect output to handle CRLF on Windows - Use \r? in kind cluster regex to match Windows line endings - Use -match '^True\s*$' instead of -eq 'True' in verify.ps1 to handle trailing whitespace/carriage returns in kubectl output
Adds a GitHub Actions workflow on windows-latest that mirrors the existing Linux cloud-deployment-example.yml, running deploy.ps1, verify.ps1, and cleanup.ps1 on a Windows runner. Adds a -Force switch to cleanup.ps1 to skip the interactive Read-Host confirmation prompt in CI environments.
When the Kind cluster is not reachable (e.g. failed deploy in CI), kubectl falls back to localhost:8080 and all delete commands fail with connection errors. Added a cluster-info connectivity check before resource deletion — if unreachable, skip straight to kind delete cluster since resources are removed with the cluster anyway.
898ce65 to
1e2c5be
Compare
|
@spandey1702 I merged the Windows fix and have rebased your PR on the latest main. Let's see what CI says 🤞 |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces Windows-compatible PowerShell scripts (deploy.ps1, cleanup.ps1, and verify.ps1) as equivalents to the existing bash scripts for deploying, cleaning up, and verifying the A2A Cloud example deployment, alongside corresponding documentation updates in the README.md. The review feedback highlights several robustness issues in the new PowerShell scripts. These include potential MethodInvocationException errors when calling .Trim() on commands that might return null, a missing Start-Sleep in the Kafka deployment wait loop that causes premature timeouts, unhandled carriage returns (\r) in node names on Windows, and a logic flaw in cleanup.ps1 when kubectl is missing from the system PATH.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| $running = (& $ContainerTool inspect -f '{{.State.Running}}' $RegName 2>$null).Trim() | ||
| if ($running -ne "true") { |
There was a problem hiding this comment.
Calling .Trim() directly on the output of the container tool inspect command will throw a MethodInvocationException ("You cannot call a method on a null-valued expression") on the very first run of the script because the kind-registry container does not exist yet, causing the command to return $null.
To prevent this, cast the command output to [string] before calling .Trim(). This is safe and fully compatible with PowerShell 5.1+.
$running = [string](& $ContainerTool inspect -f '{{.State.Running}}' $RegName 2>$null)
if ($running.Trim() -ne "true") {
| for ($i = 1; $i -le 60; $i++) { | ||
| Write-Host "Checking Kafka status (attempt $i/60)..." | ||
| kubectl get kafka -n kafka -o wide 2>$null | ||
| kubectl get pods -n kafka -l strimzi.io/cluster=a2a-kafka 2>$null | ||
|
|
||
| $null = kubectl wait --for=condition=Ready kafka/a2a-kafka -n kafka --timeout=10s 2>$null | ||
| if ($LASTEXITCODE -eq 0) { | ||
| Write-Host "✓ Kafka deployed" -ForegroundColor Green | ||
| break | ||
| } | ||
|
|
||
| if ($i -eq 60) { | ||
| Write-Host "ERROR: Timeout waiting for Kafka" -ForegroundColor Red | ||
| kubectl describe kafka/a2a-kafka -n kafka | ||
| kubectl get events -n kafka --sort-by='.lastTimestamp' | ||
| exit 1 | ||
| } | ||
| } |
There was a problem hiding this comment.
In the else block of the Kafka deployment wait loop, there is no Start-Sleep call. If kubectl wait fails immediately (for example, if the kafka/a2a-kafka resource has not been created yet), the loop will spin extremely fast, executing 60 times in less than a second and failing with a timeout error.
Add Start-Sleep -Seconds 5 at the end of the loop iteration, matching the behavior of the if block's loop.
for ($i = 1; $i -le 60; $i++) {
Write-Host "Checking Kafka status (attempt $i/60)..."
kubectl get kafka -n kafka -o wide 2>$null
kubectl get pods -n kafka -l strimzi.io/cluster=a2a-kafka 2>$null
$null = kubectl wait --for=condition=Ready kafka/a2a-kafka -n kafka --timeout=10s 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "✓ Kafka deployed" -ForegroundColor Green
break
}
if ($i -eq 60) {
Write-Host "ERROR: Timeout waiting for Kafka" -ForegroundColor Red
kubectl describe kafka/a2a-kafka -n kafka
kubectl get events -n kafka --sort-by='.lastTimestamp'
exit 1
}
Start-Sleep -Seconds 5
}
| $networkInfo = (& $ContainerTool inspect -f '{{json .NetworkSettings.Networks.kind}}' $RegName 2>$null).Trim() | ||
| if ($networkInfo -eq "null" -or [string]::IsNullOrEmpty($networkInfo)) { |
There was a problem hiding this comment.
Similar to the registry running check, calling .Trim() directly on the output of the inspect command can throw a MethodInvocationException if the command returns $null.
Cast the output to [string] first to ensure safe trimming.
$networkInfo = [string](& $ContainerTool inspect -f '{{json .NetworkSettings.Networks.kind}}' $RegName 2>$null)
$networkInfo = $networkInfo.Trim()
if ($networkInfo -eq "null" -or [string]::IsNullOrEmpty($networkInfo)) {
| foreach ($node in (kind get nodes)) { | ||
| & $ContainerTool exec $node mkdir -p $RegistryDir | ||
| "[host.`"http://${RegName}:5000`"]" | & $ContainerTool exec -i $node sh -c "cat > ${RegistryDir}/hosts.toml" | ||
| } |
There was a problem hiding this comment.
On Windows, external command outputs (like kind get nodes) often contain trailing carriage return characters (\r). If $node contains a trailing \r, executing & $ContainerTool exec $node ... will fail because the container name will be invalid.
Trim each node name to ensure compatibility on Windows.
foreach ($node in (kind get nodes)) {
$node = $node.Trim()
if ([string]::IsNullOrEmpty($node)) { continue }
& $ContainerTool exec $node mkdir -p $RegistryDir
"[host.""http://${RegName}:5000"""]" | & $ContainerTool exec -i $node sh -c "cat > ${RegistryDir}/hosts.toml"
}
| $null = kubectl cluster-info 2>$null | ||
| if ($LASTEXITCODE -eq 0) { | ||
| Write-Host "✓ Cluster reachable, deleting resources..." -ForegroundColor Green | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Deleting A2A Agent..." | ||
| kubectl delete -f "..\k8s\05-agent-deployment.yaml" --ignore-not-found=true | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Deleting ConfigMap..." | ||
| kubectl delete -f "..\k8s\04-agent-configmap.yaml" --ignore-not-found=true | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Deleting Kafka topic..." | ||
| kubectl delete -f "..\k8s\03-kafka-topic.yaml" --ignore-not-found=true | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Deleting Kafka..." | ||
| kubectl delete -f "..\k8s\02-kafka.yaml" --ignore-not-found=true | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Deleting PostgreSQL..." | ||
| kubectl delete -f "..\k8s\01-postgres.yaml" --ignore-not-found=true | ||
|
|
||
| Write-Host "" | ||
| Write-Host "Deleting namespace..." | ||
| kubectl delete -f "..\k8s\00-namespace.yaml" --ignore-not-found=true | ||
| } else { | ||
| Write-Host "⚠ Cluster not reachable, skipping resource deletion — resources will be removed with the cluster." -ForegroundColor Yellow | ||
| } |
There was a problem hiding this comment.
If kubectl is not installed or not in the system PATH, calling kubectl cluster-info will throw a command-not-found exception in PowerShell. Since $LASTEXITCODE is not updated when a command-not-found error occurs, it will retain whatever value it had from the parent session. If that value was 0, the script will incorrectly enter the if block and attempt to run multiple kubectl delete commands, throwing a series of noisy errors.
Check if kubectl is available using Get-Command before executing it, similar to how it is done in deploy.ps1.
if (Get-Command kubectl -ErrorAction SilentlyContinue) {
$null = kubectl cluster-info 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "✓ Cluster reachable, deleting resources..." -ForegroundColor Green
Write-Host ""
Write-Host "Deleting A2A Agent..."
kubectl delete -f "..\k8s\05-agent-deployment.yaml" --ignore-not-found=true
Write-Host ""
Write-Host "Deleting ConfigMap..."
kubectl delete -f "..\k8s\04-agent-configmap.yaml" --ignore-not-found=true
Write-Host ""
Write-Host "Deleting Kafka topic..."
kubectl delete -f "..\k8s\03-kafka-topic.yaml" --ignore-not-found=true
Write-Host ""
Write-Host "Deleting Kafka..."
kubectl delete -f "..\k8s\02-kafka.yaml" --ignore-not-found=true
Write-Host ""
Write-Host "Deleting PostgreSQL..."
kubectl delete -f "..\k8s\01-postgres.yaml" --ignore-not-found=true
Write-Host ""
Write-Host "Deleting namespace..."
kubectl delete -f "..\k8s\00-namespace.yaml" --ignore-not-found=true
} else {
Write-Host "⚠ Cluster not reachable, skipping resource deletion — resources will be removed with the cluster." -ForegroundColor Yellow
}
} else {
Write-Host "⚠ kubectl not found, skipping resource deletion — resources will be removed with the cluster." -ForegroundColor Yellow
}
Add deploy.ps1, cleanup.ps1, and verify.ps1 as Windows equivalents of the existing bash scripts. Fixes #395.
Key translation notes: