mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-07 07:18:18 +00:00
test: add Pester suite for ZHelpers pure logic + ZCONFIG seam (phases 1-2)
Part of #26. The toolkit had no automated tests at all - including for the functions that decide what goes into a deploy zip, which is where a dev .env reached production (#23). Phase 1 - the seam. Get-ZConfig read a hardcoded $PSScriptRoot\zconfig.json, so nothing config-dependent could be tested without touching the real config. Adds Get-ZConfigPath honoring $env:ZCONFIG (the bash port has always had this, so it also closes a parity gap) and Reset-ZConfigCache to drop the memoised config between fixtures. Deliberately did NOT convert the exit 1 paths to throw: that changes observed CLI output, and the pure functions don't need it. Phase 2 - 61 tests over the functions with no side effects: Get-ArchiveExcludes (common/python/vite/nextjs lists, deploy.exclude merging, dedupe, array shape), Get-ZConfig / Get-ZConfigPath / Get-ZProjectKeys / Get-ZProject (dash tolerance, underscore-key filtering, memoisation), Get-ZEdgeProject, Get-RemoteComposeDir, Get-Ec2Target / Get-Ec2Home, Get-LabelFromBuildJsonObj, Read-JsonBuildVersion. The suite is verified by mutation testing rather than assumed useful - six deliberate regressions were each introduced and confirmed to turn it red, including reintroducing the exact #23 bug and its inverse (backups silently dropping .env/uploads, which would produce restore points that cannot restore). Runs off a fixture config injected via ZCONFIG, so it never reads a real zconfig.json and passes on a machine that has never been configured.
This commit is contained in:
parent
4d086bafae
commit
2397277257
@ -22,6 +22,15 @@ Notable changes to the Evomedia.net Token Savers.
|
|||||||
credentials and RSA signing keys.
|
credentials and RSA signing keys.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- **Test suite (Pester)** — the toolkit now has automated coverage of its own
|
||||||
|
pure logic: `Get-ArchiveExcludes` (including the deploy-vs-backup rule that
|
||||||
|
keeps `.env`/`uploads` out of deploys but *in* backups), config and project
|
||||||
|
lookups, `remote.composeDir` fallback, EC2 target composition, and build-label
|
||||||
|
formatting. Run with `Invoke-Pester .\tests` (Pester 5+). Verified by mutation
|
||||||
|
testing — reintroducing each historical bug turns the suite red.
|
||||||
|
- **`ZCONFIG` environment variable (PowerShell)** — overrides the path to
|
||||||
|
`zconfig.json`, matching the bash port, which has always honored it. Closes a
|
||||||
|
parity gap and gives the test suite a seam for injecting a fixture config.
|
||||||
- **`zec2_rotatekeys` — safely rotate/reset server-side secrets** — a new
|
- **`zec2_rotatekeys` — safely rotate/reset server-side secrets** — a new
|
||||||
tool for when a secret leaks or a deploy overwrites a production `.env`
|
tool for when a secret leaks or a deploy overwrites a production `.env`
|
||||||
with dev values. `-Rotate KEY` regenerates a key **on the server**
|
with dev values. `-Rotate KEY` regenerates a key **on the server**
|
||||||
|
|||||||
14
README.md
14
README.md
@ -49,6 +49,8 @@ notepad zconfig.json
|
|||||||
|
|
||||||
The example config ships with sample projects named by their kind — `pyapp`, `viteapp`, `nextapp`, `edge`, `analytics`. **Rename the keys to your own project names**; the key is what you type as the command argument. Add as many projects as you like — no script edits ever needed.
|
The example config ships with sample projects named by their kind — `pyapp`, `viteapp`, `nextapp`, `edge`, `analytics`. **Rename the keys to your own project names**; the key is what you type as the command argument. Add as many projects as you like — no script edits ever needed.
|
||||||
|
|
||||||
|
Set the `ZCONFIG` environment variable to point at a config somewhere else (both the PowerShell scripts and the bash port honor it) — handy for a second machine profile, or for running against a scratch config without touching your real one.
|
||||||
|
|
||||||
### Config reference
|
### Config reference
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
@ -382,6 +384,18 @@ Give the project a `verify` block instead, and `zdeploy` checks the app **from t
|
|||||||
2. That's it: `zstart`, `zkill`, `zrestart`, `zbackup`, `zdeploy`, `zec2`, `zec2online`, `zrepair`, `zstop` all accept the new key immediately.
|
2. That's it: `zstart`, `zkill`, `zrestart`, `zbackup`, `zdeploy`, `zec2`, `zec2online`, `zrepair`, `zstop` all accept the new key immediately.
|
||||||
3. A project whose deploy doesn't fit the python/vite/nextjs/edge/docker patterns needs its own `Invoke-<Kind>Deploy` function in `zdeploy.ps1` — copy an existing handler; they're all variations on zip → upload → compose up → verify.
|
3. A project whose deploy doesn't fit the python/vite/nextjs/edge/docker patterns needs its own `Invoke-<Kind>Deploy` function in `zdeploy.ps1` — copy an existing handler; they're all variations on zip → upload → compose up → verify.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
The toolkit has its own [Pester](https://pester.dev) suite covering the pure logic — the exclude lists, config lookups, and version-label formatting that the deploy and backup paths depend on:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-Pester .\tests
|
||||||
|
```
|
||||||
|
|
||||||
|
Needs Pester 5+ (`Install-Module Pester -Scope CurrentUser`); Windows ships 3.x, which won't run these. The suite injects a fixture config through `ZCONFIG`, so it never reads your real `zconfig.json` and runs fine on a machine that has never been configured.
|
||||||
|
|
||||||
|
The high-value case is the deploy-vs-backup split: **deploys must exclude `.env` files and `uploads/`, backups must keep them.** Get that backwards in either direction and you either ship secrets to production or quietly write backups that can't restore — neither fails loudly at runtime.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
- **"zconfig.json not found"** — you haven't copied `zconfig.example.json` yet. Every script tells you this and exits.
|
- **"zconfig.json not found"** — you haven't copied `zconfig.example.json` yet. Every script tells you this and exits.
|
||||||
|
|||||||
17
ZHelpers.ps1
17
ZHelpers.ps1
@ -33,9 +33,24 @@ $script:JunkDirNames = @(
|
|||||||
|
|
||||||
$script:ZConfigCache = $null
|
$script:ZConfigCache = $null
|
||||||
|
|
||||||
|
# Where zconfig.json lives. Defaults to next to the scripts; override with the
|
||||||
|
# ZCONFIG environment variable, matching the bash port (zhelpers.sh does the
|
||||||
|
# same). Useful for pointing a run at an alternate config, and it is the seam
|
||||||
|
# the test suite uses to inject a fixture.
|
||||||
|
function Get-ZConfigPath {
|
||||||
|
if ($env:ZCONFIG) { return $env:ZCONFIG }
|
||||||
|
return (Join-Path $PSScriptRoot "zconfig.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Drop the memoised config so the next Get-ZConfig re-reads from disk. Only
|
||||||
|
# needed when the config changes mid-process (tests switching fixtures).
|
||||||
|
function Reset-ZConfigCache {
|
||||||
|
$script:ZConfigCache = $null
|
||||||
|
}
|
||||||
|
|
||||||
function Get-ZConfig {
|
function Get-ZConfig {
|
||||||
if ($null -ne $script:ZConfigCache) { return $script:ZConfigCache }
|
if ($null -ne $script:ZConfigCache) { return $script:ZConfigCache }
|
||||||
$configPath = Join-Path $PSScriptRoot "zconfig.json"
|
$configPath = Get-ZConfigPath
|
||||||
if (-not (Test-Path -LiteralPath $configPath)) {
|
if (-not (Test-Path -LiteralPath $configPath)) {
|
||||||
Write-Host "ERROR: zconfig.json not found at $configPath" -ForegroundColor Red
|
Write-Host "ERROR: zconfig.json not found at $configPath" -ForegroundColor Red
|
||||||
Write-Host " Copy zconfig.example.json to zconfig.json and fill in your values." -ForegroundColor DarkGray
|
Write-Host " Copy zconfig.example.json to zconfig.json and fill in your values." -ForegroundColor DarkGray
|
||||||
|
|||||||
265
tests/ZHelpers.Tests.ps1
Normal file
265
tests/ZHelpers.Tests.ps1
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
# Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers
|
||||||
|
# Created by Kelly Michels · dev@evomedia.net
|
||||||
|
# Licensed under the MIT License. See LICENSE.
|
||||||
|
|
||||||
|
# ZHelpers.Tests.ps1 — Pester 5 suite for the pure/config functions in ZHelpers.ps1.
|
||||||
|
#
|
||||||
|
# Invoke-Pester .\tests
|
||||||
|
#
|
||||||
|
# Scope: functions with no side effects beyond reading a config file. Anything
|
||||||
|
# that SSHes, builds images, or kills processes is deliberately not covered here
|
||||||
|
# (see Invoke-Ec2Step, Stop-ProcessTree and friends) - those need a disposable
|
||||||
|
# server, not a unit test.
|
||||||
|
#
|
||||||
|
# The fixture config is injected via $env:ZCONFIG, the same override the bash
|
||||||
|
# port has always had. No real zconfig.json is read, so this suite is safe to
|
||||||
|
# run on a machine that has never been configured.
|
||||||
|
|
||||||
|
BeforeAll {
|
||||||
|
$script:RepoRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
$script:Fixture = Join-Path $PSScriptRoot "fixtures\zconfig.fixture.json"
|
||||||
|
$script:HelpersPsm = Join-Path $script:RepoRoot "ZHelpers.ps1"
|
||||||
|
|
||||||
|
$env:ZCONFIG = $script:Fixture
|
||||||
|
. $script:HelpersPsm
|
||||||
|
Reset-ZConfigCache
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterAll {
|
||||||
|
Remove-Item Env:\ZCONFIG -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get-ZConfigPath" {
|
||||||
|
It "uses the ZCONFIG override when set" {
|
||||||
|
$env:ZCONFIG = "C:\somewhere\else.json"
|
||||||
|
Get-ZConfigPath | Should -Be "C:\somewhere\else.json"
|
||||||
|
$env:ZCONFIG = $script:Fixture
|
||||||
|
}
|
||||||
|
|
||||||
|
It "falls back to zconfig.json beside the scripts when ZCONFIG is unset" {
|
||||||
|
Remove-Item Env:\ZCONFIG -ErrorAction SilentlyContinue
|
||||||
|
Get-ZConfigPath | Should -Be (Join-Path $script:RepoRoot "zconfig.json")
|
||||||
|
$env:ZCONFIG = $script:Fixture
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get-ZConfig" {
|
||||||
|
BeforeEach { Reset-ZConfigCache }
|
||||||
|
|
||||||
|
It "loads the fixture pointed at by ZCONFIG" {
|
||||||
|
(Get-ZConfig).ec2.ip | Should -Be "203.0.113.10"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "memoises - a second call returns the same object instance" {
|
||||||
|
$a = Get-ZConfig
|
||||||
|
$b = Get-ZConfig
|
||||||
|
[object]::ReferenceEquals($a, $b) | Should -BeTrue
|
||||||
|
}
|
||||||
|
|
||||||
|
It "re-reads after Reset-ZConfigCache" {
|
||||||
|
$a = Get-ZConfig
|
||||||
|
Reset-ZConfigCache
|
||||||
|
$b = Get-ZConfig
|
||||||
|
[object]::ReferenceEquals($a, $b) | Should -BeFalse
|
||||||
|
$b.ec2.user | Should -Be "testuser" # still correct content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get-ZProjectKeys" {
|
||||||
|
It "returns every project key in config order" {
|
||||||
|
Get-ZProjectKeys | Should -Be @("pyapp", "viteapp", "nextapp", "edgeproxy", "dockeronly", "noports")
|
||||||
|
}
|
||||||
|
|
||||||
|
It "omits underscore-prefixed comment keys" {
|
||||||
|
Get-ZProjectKeys | Should -Not -Contain "_note"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get-ZProject" {
|
||||||
|
It "returns the project for a known key" {
|
||||||
|
(Get-ZProject -Key "pyapp").label | Should -Be "Fixture Python App"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "tolerates a leading dash (-pyapp resolves the same as pyapp)" {
|
||||||
|
# Muscle memory from per-project switches; every z-script accepts both.
|
||||||
|
(Get-ZProject -Key "-pyapp").label | Should -Be "Fixture Python App"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "is case-insensitive on the key, as PowerShell property access is" {
|
||||||
|
(Get-ZProject -Key "PyApp").label | Should -Be "Fixture Python App"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get-ZEdgeProject" {
|
||||||
|
It "finds the first edge-kind project and reports its key" {
|
||||||
|
$edge = Get-ZEdgeProject
|
||||||
|
$edge.Key | Should -Be "edgeproxy"
|
||||||
|
$edge.Config.proxyContainer | Should -Be "edge_proxy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get-RemoteComposeDir" {
|
||||||
|
It "prefers remote.composeDir when the project sets one" {
|
||||||
|
Get-RemoteComposeDir -Key "pyapp" | Should -Be "/home/testuser/stack/pyapp/docker"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "falls back to remote.path when composeDir is absent" {
|
||||||
|
Get-RemoteComposeDir -Key "viteapp" | Should -Be "/home/testuser/stack/viteapp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "EC2 target helpers" {
|
||||||
|
It "composes user@ip" {
|
||||||
|
Get-Ec2Target | Should -Be "testuser@203.0.113.10"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "composes the remote home directory from the ssh user" {
|
||||||
|
Get-Ec2Home | Should -Be "/home/testuser"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get-LabelFromBuildJsonObj" {
|
||||||
|
It "formats the label as v{productVersion}.{buildNumber}" {
|
||||||
|
Get-LabelFromBuildJsonObj ([pscustomobject]@{ productVersion = "1.0"; buildNumber = 42 }) |
|
||||||
|
Should -Be "v1.0.42"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "returns null for a null object rather than a bare 'v.'" {
|
||||||
|
Get-LabelFromBuildJsonObj $null | Should -BeNullOrEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
It "coerces a string buildNumber to int (JSON types vary)" {
|
||||||
|
Get-LabelFromBuildJsonObj ([pscustomobject]@{ productVersion = "2.1"; buildNumber = "7" }) |
|
||||||
|
Should -Be "v2.1.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Read-JsonBuildVersion" {
|
||||||
|
BeforeAll {
|
||||||
|
$script:TmpDir = Join-Path ([IO.Path]::GetTempPath()) ("zhelptest-" + [guid]::NewGuid().ToString("N"))
|
||||||
|
New-Item -ItemType Directory -Path $script:TmpDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
AfterAll {
|
||||||
|
Remove-Item -LiteralPath $script:TmpDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
It "parses a valid build-version.json" {
|
||||||
|
$p = Join-Path $script:TmpDir "good.json"
|
||||||
|
'{ "productVersion": "3.4", "buildNumber": 11 }' | Set-Content -LiteralPath $p -Encoding UTF8
|
||||||
|
(Read-JsonBuildVersion $p).buildNumber | Should -Be 11
|
||||||
|
}
|
||||||
|
|
||||||
|
It "returns null for a missing file" {
|
||||||
|
Read-JsonBuildVersion (Join-Path $script:TmpDir "nope.json") | Should -BeNullOrEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
It "returns null for malformed JSON instead of throwing" {
|
||||||
|
$p = Join-Path $script:TmpDir "bad.json"
|
||||||
|
'{ not json at all' | Set-Content -LiteralPath $p -Encoding UTF8
|
||||||
|
Read-JsonBuildVersion $p | Should -BeNullOrEmpty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get-ArchiveExcludes" {
|
||||||
|
BeforeAll {
|
||||||
|
$script:Py = Get-ZProject -Key "pyapp"
|
||||||
|
$script:Vite = Get-ZProject -Key "viteapp"
|
||||||
|
$script:Next = Get-ZProject -Key "nextapp"
|
||||||
|
$script:Dock = Get-ZProject -Key "dockeronly"
|
||||||
|
}
|
||||||
|
|
||||||
|
Context "common excludes (every kind)" {
|
||||||
|
It "always excludes <_>" -ForEach @(".git", ".idea", ".vscode", ".claude", "tmp", "nul", ".DS_Store", "backups") {
|
||||||
|
Get-ArchiveExcludes -Project $script:Py | Should -Contain $_
|
||||||
|
}
|
||||||
|
|
||||||
|
It "applies the common list even to an unrecognised kind" {
|
||||||
|
Get-ArchiveExcludes -Project $script:Dock | Should -Contain ".git"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context "python kind" {
|
||||||
|
It "excludes build/venv cruft: <_>" -ForEach @(".venv", "venv", "__pycache__", ".pytest_cache", ".nicegui", "archive", "dist", "build", "htmlcov") {
|
||||||
|
Get-ArchiveExcludes -Project $script:Py | Should -Contain $_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context "vite kind" {
|
||||||
|
It "excludes node_modules and dist" {
|
||||||
|
$x = Get-ArchiveExcludes -Project $script:Vite
|
||||||
|
$x | Should -Contain "node_modules"
|
||||||
|
$x | Should -Contain "dist"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context "nextjs kind" {
|
||||||
|
It "excludes .next, .vercel and build output" {
|
||||||
|
$x = Get-ArchiveExcludes -Project $script:Next
|
||||||
|
$x | Should -Contain ".next"
|
||||||
|
$x | Should -Contain ".vercel"
|
||||||
|
$x | Should -Contain "next-env.d.ts"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "excludes .env in deploys AND backups (nextjs has no ForBackup gate)" {
|
||||||
|
Get-ArchiveExcludes -Project $script:Next -ForBackup | Should -Contain ".env"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# The regression that motivated this suite: a dev .env shipped to production
|
||||||
|
# in a deploy zip. Deploys must drop secrets and uploads; backups must keep
|
||||||
|
# them, or the backup is not a full restore point.
|
||||||
|
Context "deploy-vs-backup gating (python)" {
|
||||||
|
It "deploy excludes secret <_>" -ForEach @(".env", ".env.local", ".env.production") {
|
||||||
|
Get-ArchiveExcludes -Project $script:Py | Should -Contain $_
|
||||||
|
}
|
||||||
|
|
||||||
|
It "backup KEEPS secret <_>" -ForEach @(".env", ".env.local", ".env.production") {
|
||||||
|
Get-ArchiveExcludes -Project $script:Py -ForBackup | Should -Not -Contain $_
|
||||||
|
}
|
||||||
|
|
||||||
|
It "deploy excludes user uploads" {
|
||||||
|
Get-ArchiveExcludes -Project $script:Py | Should -Contain "uploads"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "backup KEEPS user uploads" {
|
||||||
|
Get-ArchiveExcludes -Project $script:Py -ForBackup | Should -Not -Contain "uploads"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context "deploy-vs-backup gating (vite)" {
|
||||||
|
It "deploy excludes secret <_>" -ForEach @(".env", ".env.local", ".env.production") {
|
||||||
|
Get-ArchiveExcludes -Project $script:Vite | Should -Contain $_
|
||||||
|
}
|
||||||
|
|
||||||
|
It "backup KEEPS secret <_>" -ForEach @(".env", ".env.local", ".env.production") {
|
||||||
|
Get-ArchiveExcludes -Project $script:Vite -ForBackup | Should -Not -Contain $_
|
||||||
|
}
|
||||||
|
|
||||||
|
It "still excludes node_modules in a backup (bulk, not a secret)" {
|
||||||
|
Get-ArchiveExcludes -Project $script:Vite -ForBackup | Should -Contain "node_modules"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context "per-project deploy.exclude" {
|
||||||
|
It "merges the project's own exclude list" {
|
||||||
|
$x = Get-ArchiveExcludes -Project $script:Py
|
||||||
|
$x | Should -Contain "docs"
|
||||||
|
$x | Should -Contain "fixtures-extra"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "omits nothing when the project has no deploy block" {
|
||||||
|
{ Get-ArchiveExcludes -Project $script:Vite } | Should -Not -Throw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context "result shape" {
|
||||||
|
It "contains no duplicates" {
|
||||||
|
$x = @(Get-ArchiveExcludes -Project $script:Py)
|
||||||
|
($x | Select-Object -Unique).Count | Should -Be $x.Count
|
||||||
|
}
|
||||||
|
|
||||||
|
It "returns an array even for a kind with no specific excludes" {
|
||||||
|
, (Get-ArchiveExcludes -Project $script:Dock) | Should -BeOfType [System.Array]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
89
tests/fixtures/zconfig.fixture.json
vendored
Normal file
89
tests/fixtures/zconfig.fixture.json
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"_comment": "Fixture config for the Pester suite. Not a real config - values are deliberately fake and are asserted against in ZHelpers.Tests.ps1. Keys starting with _ must be ignored by Get-ZProjectKeys.",
|
||||||
|
|
||||||
|
"ec2": {
|
||||||
|
"ip": "203.0.113.10",
|
||||||
|
"user": "testuser",
|
||||||
|
"pemKey": "C:\\fixtures\\test.pem",
|
||||||
|
"stackRoot": "/home/testuser/stack"
|
||||||
|
},
|
||||||
|
|
||||||
|
"paths": {
|
||||||
|
"temp": "C:\\fixtures\\temp",
|
||||||
|
"backupsLocal": "C:\\fixtures\\backups\\projects",
|
||||||
|
"backupsEc2": "C:\\fixtures\\backups\\ec2",
|
||||||
|
"scriptsRoot": "C:\\fixtures\\zscripts",
|
||||||
|
"oneDriveBackups": ""
|
||||||
|
},
|
||||||
|
|
||||||
|
"projects": {
|
||||||
|
"_note": "This underscore key must never appear as a project.",
|
||||||
|
|
||||||
|
"pyapp": {
|
||||||
|
"label": "Fixture Python App",
|
||||||
|
"kind": "python",
|
||||||
|
"localRoot": "C:\\fixtures\\pyapp",
|
||||||
|
"startModule": "pyapp.main",
|
||||||
|
"ports": { "dev": 8080 },
|
||||||
|
"domain": "pyapp.example.com",
|
||||||
|
"remote": {
|
||||||
|
"path": "/home/testuser/stack/pyapp",
|
||||||
|
"composeDir": "/home/testuser/stack/pyapp/docker",
|
||||||
|
"appService": "app"
|
||||||
|
},
|
||||||
|
"deploy": {
|
||||||
|
"zipName": "PyAppDeploy.zip",
|
||||||
|
"exclude": ["docs", "fixtures-extra"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"viteapp": {
|
||||||
|
"label": "Fixture Vite Site",
|
||||||
|
"kind": "vite",
|
||||||
|
"localRoot": "C:\\fixtures\\viteapp",
|
||||||
|
"ports": { "dev": 5173 },
|
||||||
|
"domain": "www.example.com",
|
||||||
|
"remote": {
|
||||||
|
"path": "/home/testuser/stack/viteapp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"nextapp": {
|
||||||
|
"label": "Fixture Next App",
|
||||||
|
"kind": "nextjs",
|
||||||
|
"localRoot": "C:\\fixtures\\nextapp",
|
||||||
|
"ports": { "dev": 4173, "prod": 3000 },
|
||||||
|
"remote": {
|
||||||
|
"path": "/home/testuser/stack/nextapp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"edgeproxy": {
|
||||||
|
"label": "Fixture Edge",
|
||||||
|
"kind": "edge",
|
||||||
|
"localRoot": "C:\\fixtures\\edge",
|
||||||
|
"proxyContainer": "edge_proxy",
|
||||||
|
"remote": {
|
||||||
|
"path": "/home/testuser/stack/edge"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"dockeronly": {
|
||||||
|
"label": "Fixture Docker Stack",
|
||||||
|
"kind": "docker",
|
||||||
|
"localRoot": "C:\\fixtures\\dockeronly",
|
||||||
|
"remote": {
|
||||||
|
"path": "/home/testuser/stack/dockeronly"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"noports": {
|
||||||
|
"label": "Fixture No Dev Port",
|
||||||
|
"kind": "python",
|
||||||
|
"localRoot": "C:\\fixtures\\noports",
|
||||||
|
"remote": {
|
||||||
|
"path": "/home/testuser/stack/noports"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user