Fix self-hosted help-bot deploy reconciliation#16
Conversation
📝 WalkthroughWalkthroughModified deployment workflow and startup script to implement live-tree synchronization during deployment, introduce conditional artifact repair logic during startup, and replace service restart mechanisms with NSSM service reconciliation and validation workflows. Changes
Sequence DiagramssequenceDiagram
actor CI as GitHub Actions
participant Deploy as Deployment Target
participant NSSM as NSSM Service
participant Build as Build Process
participant App as Application
CI->>Deploy: Create deployment directories
CI->>Deploy: robocopy src/ and dist/
CI->>Deploy: Copy config files (package.json, etc.)
CI->>Build: Run yarn install --frozen-lockfile
CI->>Build: Run yarn build
Build-->>Deploy: Generate artifacts
alt NSSM service exists
CI->>NSSM: Stop service
else
CI->>NSSM: Install service
end
CI->>NSSM: Configure (Application, AppParameters, AppDirectory, logs)
CI->>NSSM: Set auto-start
CI->>NSSM: Start service
NSSM->>App: Launch startup.ps1
App-->>Deploy: Verify artifacts
App->>App: Start CLI application
sequenceDiagram
participant NSSM as NSSM Service
participant Startup as startup.ps1
participant Check as Artifact Check
participant Repair as Repair Install
participant CLI as CLI Application
NSSM->>Startup: Execute on service start
Startup->>Check: Check dist\cli.js exists
Startup->>Check: Check node_modules exists
alt Artifacts missing
Check-->>Repair: Trigger repair
Repair->>Repair: yarn install --frozen-lockfile
Repair->>Repair: yarn build
Repair-->>Startup: Repair complete
else Artifacts present
Check-->>Startup: Skip install/build
end
Startup->>CLI: Invoke dist\cli.js
CLI-->>NSSM: Application running
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/deploy.yml:
- Around line 118-124: The Write-Error call is triggering the Stop preference
and preventing the subsequent Get-Content tail and exit from running; update the
failure path in the service check (the block that inspects $svc and its .Status
for the 'gameci-help-bot' service) so it logs the error without terminating
early (for example replace Write-Error with Write-Host/Write-Output or call
Write-Error with -ErrorAction SilentlyContinue), ensure you null-check $svc
before accessing $svc.Status, then run Get-Content
"C:\game-ci\help-bot\logs\service.log" -Tail 30 and finally exit 1 so the logs
are always emitted on failure.
- Around line 60-65: The PowerShell steps run native commands (yarn, nssm) that
don't auto-throw on non-zero exit; after each native invocation—specifically
after the yarn install and yarn build calls and after every nssm install, nssm
stop, nssm set and nssm get invocation—check $LASTEXITCODE and abort/throw
(e.g., throw or exit 1) if non-zero so the try/catch and fallback logic
triggers; update the block around Push-Location and the try/catch to add these
$LASTEXITCODE guards immediately after each command.
In `@startup.ps1`:
- Around line 24-37: The try/catch blocks around the yarn calls log success even
when yarn fails because PowerShell 5.1 doesn't throw on native command non-zero
exits; after each yarn invocation (the yarn install and yarn build calls around
the Log(...) and "Build: done" messages) check $LASTEXITCODE and if it's
non-zero, throw or call exit with a non-zero code so the catch path runs; update
the catch handlers to Log the error and terminate (e.g., exit 1) so failures
don't proceed as successes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1034ba7d-22b5-4955-a4a4-68aea6a16ec4
📒 Files selected for processing (2)
.github/workflows/deploy.ymlstartup.ps1
| $ErrorActionPreference = 'Stop' | ||
| $deployRoot = 'C:\game-ci\help-bot' | ||
| Push-Location $deployRoot | ||
| try { | ||
| yarn install --frozen-lockfile | ||
| yarn build |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Windows PowerShell 5.1, do native executables like yarnandnssmthrow on non-zero exit codes when$ErrorActionPreference = 'Stop'is set, or must scripts check$LASTEXITCODE explicitly?
💡 Result:
In Windows PowerShell 5.1, native executables like yarn and nssm do not throw terminating errors on non-zero exit codes when $ErrorActionPreference = 'Stop' is set. Scripts must check #3996 confirms no terminating error from native non-zero exit even with 'Stop', requiring explicit $LASTEXITCODE checks. Stack Overflow answers (e.g., on call operator, bash set -e equivalent) explicitly state the need to check $LASTEXITCODE -ne 0 and throw manually. This changed in PowerShell 7.4+ with $PSNativeCommandUseErrorActionPreference = $true, but not in 5.1. Example: $ErrorActionPreference = 'Stop' yarn --version # Assume non-zero exit if ($LASTEXITCODE -ne 0) { throw "yarn failed with exit code $LASTEXITCODE" } Write-Host "Continues here only if success" Without the if check, execution continues despite failure.
Citations:
- 1: Inconsistent handling of native command stderr PowerShell/PowerShell#3996
- 2: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-5.1
- 3: https://stackoverflow.com/questions/47032005/why-does-a-powershell-script-not-end-when-there-is-a-non-zero-exit-code-using-th
- 4: https://stackoverflow.com/questions/9948517/how-to-stop-a-powershell-script-on-the-first-error
- 5: https://stackoverflow.com/questions/11450153/powershell-analogue-of-bashs-set-e
🏁 Script executed:
# Check if file exists and get its structure
ls -la .github/workflows/deploy.yml
wc -l .github/workflows/deploy.ymlRepository: game-ci/help-bot
Length of output: 170
🏁 Script executed:
# Read the specific line ranges mentioned in the review
echo "=== Lines 60-65 (yarn install/build) ==="
sed -n '55,70p' .github/workflows/deploy.yml
echo ""
echo "=== Lines 82-102 (NSSM calls) ==="
sed -n '78,105p' .github/workflows/deploy.yml
echo ""
echo "=== Lines 108-112 (nssm restart) ==="
sed -n '105,115p' .github/workflows/deploy.yml
echo ""
echo "=== Lines 118-124 (error handling) ==="
sed -n '115,130p' .github/workflows/deploy.ymlRepository: game-ci/help-bot
Length of output: 2924
Native command failures won't fail these steps or trigger the fallback.
These yarn and nssm invocations run under shell: powershell, so non-zero exit codes do not throw. That means the live-repair step can continue after a failed install/build, the NSSM reconciliation can partially fail silently, and the nssm restart catch block never runs.
Suggested pattern
- name: Repair live install
shell: powershell
run: |
$ErrorActionPreference = 'Stop'
$deployRoot = 'C:\game-ci\help-bot'
Push-Location $deployRoot
try {
yarn install --frozen-lockfile
+ if ($LASTEXITCODE -ne 0) { throw "yarn install failed with exit code $LASTEXITCODE" }
yarn build
+ if ($LASTEXITCODE -ne 0) { throw "yarn build failed with exit code $LASTEXITCODE" }
} finally {
Pop-Location
}
…
- try {
- nssm restart gameci-help-bot
- } catch {
- Write-Host "NSSM restart failed, trying service start: $_"
+ nssm restart gameci-help-bot
+ if ($LASTEXITCODE -ne 0) {
+ Write-Host "NSSM restart failed, trying service start"
Start-Service -Name 'gameci-help-bot'
}Apply the same $LASTEXITCODE guard after each nssm install, nssm stop, nssm set, and nssm get call.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $ErrorActionPreference = 'Stop' | |
| $deployRoot = 'C:\game-ci\help-bot' | |
| Push-Location $deployRoot | |
| try { | |
| yarn install --frozen-lockfile | |
| yarn build | |
| $ErrorActionPreference = 'Stop' | |
| $deployRoot = 'C:\game-ci\help-bot' | |
| Push-Location $deployRoot | |
| try { | |
| yarn install --frozen-lockfile | |
| if ($LASTEXITCODE -ne 0) { throw "yarn install failed with exit code $LASTEXITCODE" } | |
| yarn build | |
| if ($LASTEXITCODE -ne 0) { throw "yarn build failed with exit code $LASTEXITCODE" } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/deploy.yml around lines 60 - 65, The PowerShell steps run
native commands (yarn, nssm) that don't auto-throw on non-zero exit; after each
native invocation—specifically after the yarn install and yarn build calls and
after every nssm install, nssm stop, nssm set and nssm get invocation—check
$LASTEXITCODE and abort/throw (e.g., throw or exit 1) if non-zero so the
try/catch and fallback logic triggers; update the block around Push-Location and
the try/catch to add these $LASTEXITCODE guards immediately after each command.
| $ErrorActionPreference = 'Stop' | ||
| Start-Sleep -Seconds 8 | ||
| $svc = Get-Service -Name 'gameci-help-bot' -ErrorAction SilentlyContinue | ||
| if ($svc.Status -ne 'Running') { | ||
| Write-Error "Service is not running: $($svc.Status)" | ||
| Get-Content "C:\game-ci\help-bot\logs\service.log" -Tail 30 | ||
| exit 1 |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
With $ErrorActionPreference = 'Stop', does Write-Error terminate a Windows PowerShell script immediately, or do subsequent statements still run?
💡 Result:
With $ErrorActionPreference = 'Stop', Write-Error terminates a Windows PowerShell script immediately, and subsequent statements do not run.
Citations:
- 1: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.4
- 2: https://stackoverflow.com/questions/9294949/when-should-i-use-write-error-vs-throw-terminating-vs-non-terminating-errors
- 3: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-error?view=powershell-7.5
The log tail is unreachable on the failure path.
With $ErrorActionPreference = 'Stop', Write-Error on line 122 terminates execution immediately and prevents lines 123-124 from running. This loses the service log output exactly when you need it for troubleshooting.
Proposed fix
- if ($svc.Status -ne 'Running') {
- Write-Error "Service is not running: $($svc.Status)"
- Get-Content "C:\game-ci\help-bot\logs\service.log" -Tail 30
- exit 1
- }
+ if (-not $svc -or $svc.Status -ne 'Running') {
+ $status = if ($svc) { $svc.Status } else { 'Missing' }
+ Write-Host "Service is not running: $status"
+ if (Test-Path "C:\game-ci\help-bot\logs\service.log") {
+ Get-Content "C:\game-ci\help-bot\logs\service.log" -Tail 30
+ }
+ throw "gameci-help-bot failed verification"
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $ErrorActionPreference = 'Stop' | |
| Start-Sleep -Seconds 8 | |
| $svc = Get-Service -Name 'gameci-help-bot' -ErrorAction SilentlyContinue | |
| if ($svc.Status -ne 'Running') { | |
| Write-Error "Service is not running: $($svc.Status)" | |
| Get-Content "C:\game-ci\help-bot\logs\service.log" -Tail 30 | |
| exit 1 | |
| $ErrorActionPreference = 'Stop' | |
| Start-Sleep -Seconds 8 | |
| $svc = Get-Service -Name 'gameci-help-bot' -ErrorAction SilentlyContinue | |
| if (-not $svc -or $svc.Status -ne 'Running') { | |
| $status = if ($svc) { $svc.Status } else { 'Missing' } | |
| Write-Host "Service is not running: $status" | |
| if (Test-Path "C:\game-ci\help-bot\logs\service.log") { | |
| Get-Content "C:\game-ci\help-bot\logs\service.log" -Tail 30 | |
| } | |
| throw "gameci-help-bot failed verification" | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/deploy.yml around lines 118 - 124, The Write-Error call is
triggering the Stop preference and preventing the subsequent Get-Content tail
and exit from running; update the failure path in the service check (the block
that inspects $svc and its .Status for the 'gameci-help-bot' service) so it logs
the error without terminating early (for example replace Write-Error with
Write-Host/Write-Output or call Write-Error with -ErrorAction SilentlyContinue),
ensure you null-check $svc before accessing $svc.Status, then run Get-Content
"C:\game-ci\help-bot\logs\service.log" -Tail 30 and finally exit 1 so the logs
are always emitted on failure.
| try { | ||
| Log "Installing dependencies..." | ||
| yarn install --frozen-lockfile 2>&1 | Out-Null | ||
| Log " yarn install: done" | ||
| } catch { | ||
| Log " yarn install failed: $_" | ||
| } | ||
|
|
||
| try { | ||
| Log "Building..." | ||
| yarn build 2>&1 | Out-Null | ||
| Log " Build: done" | ||
| } catch { | ||
| Log " Build failed: $_" |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Windows PowerShell 5.1, do non-zero exit codes from native commands like yarntriggertry/catchor obey$ErrorActionPreference? What is the recommended pattern for logging or failing based on $LASTEXITCODE?
💡 Result:
In Windows PowerShell 5.1, non-zero exit codes from native commands like yarn do not trigger try/catch blocks and are not affected by $ErrorActionPreference. These mechanisms handle PowerShell-native errors (terminating or non-terminating with -ErrorAction Stop), but external executables only set
Citations:
- 1: https://stackoverflow.com/questions/78919824/what-is-the-recommended-way-of-calling-external-commands-in-powershell-including
- 2: Inconsistent handling of native command stderr PowerShell/PowerShell#3996
- 3: https://stackoverflow.com/questions/71018199/get-npm-process-exitcode-as-output-in-powershell
- 4: https://stackoverflow.com/questions/67743279/how-to-get-exit-code-from-powershell-script
- 5: https://learn.microsoft.com/en-us/previous-versions/powershell/module/microsoft.powershell.core/about/about_automatic_variables?view=powershell-6
- 6: https://learn.microsoft.com/en-us/powershell/scripting/learn/shell/running-commands?view=powershell-7.5
- 7: https://stackoverflow.com/questions/12359427/try-catch-on-executable-exe-in-powershell
- 8: https://stackoverflow.com/questions/34755510/handle-command-prompt-error-within-powershell-script
yarn failures are treated as success here.
In PowerShell 5.1, non-zero exit codes from native commands like yarn install or yarn build do not trigger catch blocks—they only set $LASTEXITCODE. The script will execute Log " yarn install: done" even when the command fails, allowing a broken build to proceed.
Proposed fix
try {
Log "Installing dependencies..."
yarn install --frozen-lockfile 2>&1 | Out-Null
- Log " yarn install: done"
+ if ($LASTEXITCODE -eq 0) {
+ Log " yarn install: done"
+ } else {
+ Log " yarn install failed with exit code $LASTEXITCODE"
+ }
} catch {
Log " yarn install failed: $_"
}
try {
Log "Building..."
yarn build 2>&1 | Out-Null
- Log " Build: done"
+ if ($LASTEXITCODE -eq 0) {
+ Log " Build: done"
+ } else {
+ Log " Build failed with exit code $LASTEXITCODE"
+ }
} catch {
Log " Build failed: $_"
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try { | |
| Log "Installing dependencies..." | |
| yarn install --frozen-lockfile 2>&1 | Out-Null | |
| Log " yarn install: done" | |
| } catch { | |
| Log " yarn install failed: $_" | |
| } | |
| try { | |
| Log "Building..." | |
| yarn build 2>&1 | Out-Null | |
| Log " Build: done" | |
| } catch { | |
| Log " Build failed: $_" | |
| try { | |
| Log "Installing dependencies..." | |
| yarn install --frozen-lockfile 2>&1 | Out-Null | |
| if ($LASTEXITCODE -eq 0) { | |
| Log " yarn install: done" | |
| } else { | |
| Log " yarn install failed with exit code $LASTEXITCODE" | |
| } | |
| } catch { | |
| Log " yarn install failed: $_" | |
| } | |
| try { | |
| Log "Building..." | |
| yarn build 2>&1 | Out-Null | |
| if ($LASTEXITCODE -eq 0) { | |
| Log " Build: done" | |
| } else { | |
| Log " Build failed with exit code $LASTEXITCODE" | |
| } | |
| } catch { | |
| Log " Build failed: $_" | |
| } |
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)
[warning] Missing BOM encoding for non-ASCII encoded file 'startup.ps1'
(PSUseBOMForUnicodeEncodedFile)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@startup.ps1` around lines 24 - 37, The try/catch blocks around the yarn calls
log success even when yarn fails because PowerShell 5.1 doesn't throw on native
command non-zero exits; after each yarn invocation (the yarn install and yarn
build calls around the Log(...) and "Build: done" messages) check $LASTEXITCODE
and if it's non-zero, throw or call exit with a non-zero code so the catch path
runs; update the catch handlers to Log the error and terminate (e.g., exit 1) so
failures don't proceed as successes.
Summary
Testing
Summary by CodeRabbit