mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-06 07:08:17 +00:00
fix(zdeploy): build docker stacks that come from a Dockerfile, instead of restarting the old image (#81)
* fix(zdeploy): build docker stacks that come from a Dockerfile Mirrors the fix in the private scripts repo; the code is identical in both, only the config differs. The docker kind ran `docker compose pull` then `docker compose up -d`. That is right for a stack of published images and wrong for one built from a Dockerfile in the tree, where there is nothing to pull. `up -d` builds only when the image is MISSING, so the first deploy works and every one after it uploads the new code, starts the old image, and reports success. A project opts into building with deploy.build, which runs `docker compose build --pull` so the base image is refreshed at the same time. Stacks that pull are unaffected. The example config documents the flag on the docker project, next to the existing note about startApp, because the failure is silent and nobody goes looking for a setting they do not know exists. CHECKSUMS.txt regenerated, since two covered scripts changed. 286 tests pass, 1 skipped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(checksums): hash the scripts as git checks them out, not as a tool wrote them CI failed on the two files this branch touches while the same suite passed here. The manifest was right about the wrong bytes. .gitattributes pins *.ps1 to eol=crlf, and its comment says why: it makes these files byte-identical on every platform, which is what lets CHECKSUMS.txt hold one hash per file rather than one per OS. The edit that added Get-DockerImageStep was applied by a script that wrote LF, so the working copy stopped matching the pin. zchecksums then faithfully recorded the LF hashes, and every checkout that honours .gitattributes - including CI - disagreed. Nothing was wrong with the committed content: git normalises on the way in, so the objects were always correct. Only the local working copy and the manifest taken from it were off. Re-materialised both files through git so they carry the endings the attribute pins, then regenerated the manifest from those. 286 tests pass, 1 skipped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
0e7b80b4ae
commit
f2e6302d00
14
CHANGELOG.md
14
CHANGELOG.md
@ -10,6 +10,20 @@ Notable changes to the Evomedia.net Token Savers.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Fixed
|
||||
|
||||
- **`zdeploy` on a docker stack built from source shipped nothing after the
|
||||
first deploy.** The docker kind ran `docker compose pull` and then
|
||||
`docker compose up -d`, which is right for a stack of published images and
|
||||
wrong for one built from a `Dockerfile` in the tree: there is nothing to
|
||||
pull, and `up -d` builds only when the image is *missing*. So the first
|
||||
deploy worked and every one after it uploaded the new code, started the old
|
||||
image, and reported success — worse than an error, because the deploy is
|
||||
green and the container is healthy. A project now opts into building with
|
||||
`"deploy": { "build": true }`, which runs `docker compose build --pull` so
|
||||
the base image is refreshed at the same time. Stacks that pull are
|
||||
unaffected.
|
||||
|
||||
## v1.0.0.0.25 - 2026-09-12
|
||||
|
||||
### Added
|
||||
|
||||
@ -10,6 +10,21 @@ Notable changes to the Evomedia.net Token Savers.
|
||||
Unreleased
|
||||
----------
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
||||
- **zdeploy on a docker stack built from source shipped nothing after the
|
||||
first deploy.** The docker kind ran docker compose pull and then
|
||||
docker compose up -d, which is right for a stack of published images and
|
||||
wrong for one built from a Dockerfile in the tree: there is nothing to
|
||||
pull, and up -d builds only when the image is missing. So the first
|
||||
deploy worked and every one after it uploaded the new code, started the old
|
||||
image, and reported success — worse than an error, because the deploy is
|
||||
green and the container is healthy. A project now opts into building with
|
||||
"deploy": { "build": true }, which runs docker compose build --pull so
|
||||
the base image is refreshed at the same time. Stacks that pull are
|
||||
unaffected.
|
||||
|
||||
v1.0.0.0.25 - 2026-09-12
|
||||
------------------------
|
||||
|
||||
|
||||
@ -8,14 +8,14 @@ dcc50b5f8597a5f0086be56faf3c90e0218343960daa07abaf74e61a7170ffec zbackup_ec2.cm
|
||||
0cd580b2b09f664003bab6754a0e35a29333dfdb7ca1f7dd4820662bd83f1d2d zchecksums.cmd
|
||||
be392bd3663c1daa4ce659d22b1431c44c1b19fbabd0efaf48502ca8f9f86e56 zchecksums.ps1
|
||||
72b1c87a13e7121ce8d8ce835cd69a806b5b7a229261d667d9e656219818b208 zdeploy.cmd
|
||||
687239e3d44e8a865dbe00c5405f1656add02f23703bda86de9bfc9172a96e12 zdeploy.ps1
|
||||
e50a69c3fb9b1b3e524a94f8cd52f4967fdec5ad7d0180da759d1e6ebbef6aa2 zdeploy.ps1
|
||||
fb9435852c344d8a0719041d0ca4968f9769243ddf925e424b78920b42de6e0b zec2.cmd
|
||||
42990e046d30c392b4434bb38808f10f629ca4c16f4b086affe9ce8dcb3adeb4 zec2.ps1
|
||||
91448ee9128e8e70fade9dbd8f744cce2d60fad180577ee276fad2a206495cac zec2_rotatekeys.cmd
|
||||
cc6cbae0d50768690691c5dd27a67688aa5e1073e3363d4b4e3cc38b236aac32 zec2_rotatekeys.ps1
|
||||
c78509f5a705e1db3efcee310706035f7e6983d4bfe1b4ea22627451a0151a83 zec2online.cmd
|
||||
d7f67c2aa1fb91fc12e04ebf54506e8b4a00264178b5b128a9eead05df0f8916 zec2online.ps1
|
||||
1af45fd810b171593e8e0cc79a1ef8a1eaf546c327ac095e9838aae30b0015ed ZHelpers.ps1
|
||||
a10faa604863030053eb33aea2d6362772a79a80b862f6bb0fdfb2c7b577087a ZHelpers.ps1
|
||||
386c4ce64544584cb9fcd2f28099742cc3590fb1afe75bb7ea884a8bca7b6ed3 zkill.cmd
|
||||
5f6c0e00dbcc62981252b6b43e3159fc84840f947ed15ca0fdf77b8fa7cece44 zkill.ps1
|
||||
21a1d371947c10bfe2b86f1a51c6cfc3992b4e084f61097bad851736032d4bdb ZKiller.ps1
|
||||
|
||||
27
ZHelpers.ps1
27
ZHelpers.ps1
@ -105,6 +105,33 @@ function Get-ZEdgeProject {
|
||||
}
|
||||
|
||||
# Remote compose directory for a project: remote.composeDir if set, else remote.path.
|
||||
# How a docker stack gets its images: built here, or pulled from a registry.
|
||||
#
|
||||
# `docker compose pull` is right for a stack of published images and wrong for
|
||||
# one built from a Dockerfile in the tree - there is nothing to pull. The trap
|
||||
# is what happens next: `docker compose up -d` builds only when the image is
|
||||
# MISSING. So the FIRST deploy of a build-from-source stack works, and every
|
||||
# one after it uploads the new code, starts the old image, and reports success.
|
||||
# That is worse than an error, because nothing looks wrong: the deploy is
|
||||
# green, the container is up, and the change simply is not in it.
|
||||
#
|
||||
# deploy.build opts a project into building instead. --pull refreshes the base
|
||||
# image at the same time, so a rebuild also picks up its security updates
|
||||
# rather than pinning whatever happened to be on the box the first time.
|
||||
function Get-DockerImageStep {
|
||||
param($Proj, [Parameter(Mandatory)][string]$RemotePath)
|
||||
if ($Proj -and $Proj.deploy -and $Proj.deploy.build) {
|
||||
return @{
|
||||
Label = 'docker compose build'
|
||||
Command = "cd $RemotePath && sudo docker compose build --pull"
|
||||
}
|
||||
}
|
||||
return @{
|
||||
Label = 'docker compose pull'
|
||||
Command = "cd $RemotePath && sudo docker compose pull"
|
||||
}
|
||||
}
|
||||
|
||||
function Get-RemoteComposeDir {
|
||||
param([Parameter(Mandatory)][string]$Key)
|
||||
$proj = Get-ZProject -Key $Key
|
||||
|
||||
82
tests/DockerImageStep.Tests.ps1
Normal file
82
tests/DockerImageStep.Tests.ps1
Normal file
@ -0,0 +1,82 @@
|
||||
# How a docker stack gets its images, and the deploy that shipped nothing.
|
||||
#
|
||||
# Invoke-Pester .\tests
|
||||
#
|
||||
# `docker compose pull` is right for a stack of published images - Prometheus,
|
||||
# Grafana, docker-mailserver - and wrong for one built from a Dockerfile in the
|
||||
# tree, where there is nothing to pull.
|
||||
#
|
||||
# The trap is what happens after. `docker compose up -d` builds only when the
|
||||
# image is MISSING, so the first deploy of a build-from-source stack works and
|
||||
# every one after it uploads the new code, starts the OLD image, and reports
|
||||
# success. Green deploy, healthy container, and the change is not in it. That
|
||||
# is the failure this helper exists to prevent, and it is worse than an error
|
||||
# because nothing about it looks wrong.
|
||||
#
|
||||
# ZHelpers.ps1 is dot-sourced rather than zdeploy.ps1: zdeploy executes its
|
||||
# main flow on load, helpers only define functions.
|
||||
|
||||
BeforeAll {
|
||||
. (Join-Path (Split-Path -Parent $PSScriptRoot) "ZHelpers.ps1")
|
||||
|
||||
function New-Proj { param($Build)
|
||||
if ($null -eq $Build) { return [pscustomobject]@{ deploy = [pscustomobject]@{ gitPull = $true } } }
|
||||
return [pscustomobject]@{ deploy = [pscustomobject]@{ build = $Build } }
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'Get-DockerImageStep - build here, or pull from a registry' {
|
||||
|
||||
It 'pulls by default, so every existing docker stack is unaffected' {
|
||||
$step = Get-DockerImageStep -Proj (New-Proj $null) -RemotePath '/home/u/stack/x'
|
||||
$step.Command | Should -BeLike '*docker compose pull*'
|
||||
$step.Command | Should -Not -BeLike '*build*'
|
||||
}
|
||||
|
||||
It 'pulls for a project with no deploy block at all' {
|
||||
$step = Get-DockerImageStep -Proj ([pscustomobject]@{}) -RemotePath '/home/u/stack/x'
|
||||
$step.Command | Should -BeLike '*docker compose pull*'
|
||||
}
|
||||
|
||||
It 'builds when the project asks to be built' {
|
||||
$step = Get-DockerImageStep -Proj (New-Proj $true) -RemotePath '/home/u/stack/x'
|
||||
$step.Command | Should -BeLike '*docker compose build*'
|
||||
$step.Command | Should -Not -BeLike '*compose pull*'
|
||||
}
|
||||
|
||||
It 'still pulls when build is explicitly false' {
|
||||
$step = Get-DockerImageStep -Proj (New-Proj $false) -RemotePath '/home/u/stack/x'
|
||||
$step.Command | Should -BeLike '*docker compose pull*'
|
||||
}
|
||||
|
||||
It 'refreshes the base image on a build, so a rebuild is not pinned to the first one' {
|
||||
$step = Get-DockerImageStep -Proj (New-Proj $true) -RemotePath '/home/u/stack/x'
|
||||
$step.Command | Should -BeLike '*--pull*'
|
||||
}
|
||||
|
||||
It 'runs in the project directory: <Build>' -ForEach @(
|
||||
@{ Build = $true }
|
||||
@{ Build = $false }
|
||||
) {
|
||||
$step = Get-DockerImageStep -Proj (New-Proj $Build) -RemotePath '/home/u/stack/ablecamera'
|
||||
$step.Command | Should -BeLike 'cd /home/u/stack/ablecamera &&*'
|
||||
}
|
||||
|
||||
It 'labels the step with what it actually does: <Build>' -ForEach @(
|
||||
@{ Build = $true; Expected = 'docker compose build' }
|
||||
@{ Build = $false; Expected = 'docker compose pull' }
|
||||
) {
|
||||
(Get-DockerImageStep -Proj (New-Proj $Build) -RemotePath '/x').Label | Should -Be $Expected
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'the docker deploy uses it' {
|
||||
|
||||
It 'no longer hardcodes compose pull' {
|
||||
$text = Get-Content -Raw (Join-Path (Split-Path -Parent $PSScriptRoot) "zdeploy.ps1")
|
||||
$body = $text.Substring($text.IndexOf('function Invoke-DockerDeploy'))
|
||||
$body = $body.Substring(0, $body.IndexOf('function Invoke-ZTokensPublish'))
|
||||
$body | Should -Match 'Get-DockerImageStep'
|
||||
$body | Should -Not -Match '"docker compose pull"'
|
||||
}
|
||||
}
|
||||
@ -122,6 +122,7 @@
|
||||
"analytics": {
|
||||
"label": "Analytics (any docker compose app)",
|
||||
"kind": "docker",
|
||||
"_build_note": "Images pulled from a registry need nothing here. If the image is BUILT from a Dockerfile in this tree, add \"deploy\": { \"build\": true } \u2014 without it a redeploy uploads the new code and restarts the OLD image, and reports success.",
|
||||
"localRoot": "C:\\YourRoot\\analytics",
|
||||
"domain": "analytics.yourdomain.com",
|
||||
"remote": {
|
||||
|
||||
@ -1254,7 +1254,10 @@ function Invoke-DockerDeploy {
|
||||
if ($LASTEXITCODE -ne 0) { throw "SCP failed for $($d.Name) (exit $LASTEXITCODE)" }
|
||||
}
|
||||
|
||||
Invoke-Ec2Step "docker compose pull" "cd $remotePath && sudo docker compose pull"
|
||||
# Built here or pulled from a registry - see Get-DockerImageStep for why
|
||||
# a build-from-source stack cannot use `pull` and silently ships nothing.
|
||||
$imageStep = Get-DockerImageStep -Proj $Proj -RemotePath $remotePath
|
||||
Invoke-Ec2Step $imageStep.Label $imageStep.Command
|
||||
Invoke-Ec2Step "docker compose up -d" "cd $remotePath && sudo docker compose up -d"
|
||||
|
||||
Invoke-Ec2PostDeployCleanup -Label $Key
|
||||
|
||||
Loading…
Reference in New Issue
Block a user