diff --git a/docs/DEV-BUILD-TEST.md b/docs/DEV-BUILD-TEST.md index b2269f3b..4db2abd7 100644 --- a/docs/DEV-BUILD-TEST.md +++ b/docs/DEV-BUILD-TEST.md @@ -1,26 +1,41 @@ # ShopDB dev build - quick test -Two dev builds you can stand up on a Windows box with Docker Desktop. Each is a -single PowerShell line: it clones the repo, checks your dependencies (offers to +Two dev builds you can stand up on a Windows box with Docker Desktop. You run +one PowerShell script: it clones the repo, checks your dependencies (offers to winget-install anything missing), then builds and starts the stack in Docker. -## Stable (main) +## What you need - $env:SHOPDB_CHANNEL='stable'; iex (irm https://raw.githubusercontent.com/ge-aero/shopdb-flask/wilm/scripts/get.ps1) +- Windows with Docker Desktop running. +- Git for Windows (`winget install Git.Git`). +- A GitHub login for this private repo already stored on the box. If you have + cloned this repo before, or signed in to GitHub in Visual Studio or VS Code, + you already have it - the script uses that stored credential automatically, so + there is no token to paste. If you have never signed in, do one manual + `git clone https://github.com/ge-aero/shopdb-flask.git` first (it will prompt + you to sign in), then delete that clone - it is only to seed the credential. -Comes up at https://localhost:5001. No DEV badge. +## Get the launcher + +You will be sent `Start-ShopDBDev.ps1` directly. Save it anywhere (for example +your Downloads folder) and open PowerShell in that folder. ## Bleeding edge (dev-be) - $env:SHOPDB_CHANNEL='edge'; iex (irm https://raw.githubusercontent.com/ge-aero/shopdb-flask/wilm/scripts/get.ps1) + powershell -ExecutionPolicy Bypass -File .\Start-ShopDBDev.ps1 -Channel edge Comes up at https://localhost:5011. Red DEV badge in the sidebar. +## Stable (main) + + powershell -ExecutionPolicy Bypass -File .\Start-ShopDBDev.ps1 -Channel stable + +Comes up at https://localhost:5001. No DEV badge. + ## Notes -- You need Git and Docker Desktop. If Git is missing, install it first - (`winget install Git.Git`); the script handles the rest with a prompt. - Both builds can run at the same time - they use different ports and separate Docker volumes, so they do not collide and each keeps its own database. +- The code is cloned to `%USERPROFILE%\shopdb-dev` (override with `-TargetDir`). - First page load shows a self-signed cert warning (expected for a dev box). - Stop a stack: `docker compose -p shopdb-stable down` (or `shopdb-edge`). diff --git a/scripts/Start-ShopDBDev.ps1 b/scripts/Start-ShopDBDev.ps1 new file mode 100644 index 00000000..cbd25699 --- /dev/null +++ b/scripts/Start-ShopDBDev.ps1 @@ -0,0 +1,86 @@ +<# +.SYNOPSIS + Save-and-run launcher for a ShopDB dev workstation (stable or edge). + +.DESCRIPTION + Download this one file and run it. It clones (or updates) the repo at the + channel branch into a local path, then hands off to scripts/dev-bootstrap.ps1 + for the real dependency-check / build / up work. + + ge-aero/shopdb-flask is a PRIVATE repo, but this needs no token pasting: the + clone uses a plain https URL and Git Credential Manager supplies your stored + GitHub credential automatically - the same way `git clone` works in the wiki + DEVELOPMENT-SETUP procedure. If you have ever cloned this repo or signed in to + GitHub in Visual Studio / VS Code on this box, GCM already has what it needs. + + This is a downloaded FILE, not a web `iex` one-liner, precisely because a + private repo cannot be fetched anonymously from raw.githubusercontent.com. A + saved script sidesteps that entirely - only the git operations need auth, and + GCM handles those. + +.PARAMETER Channel + 'stable' (main) or 'edge' (dev-be). Defaults to 'stable'. + +.PARAMETER TargetDir + Where to clone. Defaults to %USERPROFILE%\shopdb-dev, a separate working copy + from any repo you already have open. + +.EXAMPLE + # Bleeding edge: + powershell -ExecutionPolicy Bypass -File .\Start-ShopDBDev.ps1 -Channel edge + +.EXAMPLE + # Stable: + powershell -ExecutionPolicy Bypass -File .\Start-ShopDBDev.ps1 -Channel stable + +.NOTES + ASCII only, no emoji or smart punctuation, per repo style. PowerShell 5.1+. + Needs Git (with Credential Manager, the Git-for-Windows default); + dev-bootstrap.ps1 offers to winget-install anything else that is missing. +#> +[CmdletBinding()] +param( + [ValidateSet('stable', 'edge')] + [string]$Channel = 'stable', + + [string]$TargetDir +) + +$ErrorActionPreference = 'Stop' + +# Plain https URL. No token in the URL: Git Credential Manager injects the +# stored GitHub credential for github.com, so clone/fetch authenticate against +# the private repo without anything sensitive touching this script or disk. +$repoUrl = 'https://github.com/ge-aero/shopdb-flask.git' +$branch = if ($Channel -eq 'edge') { 'dev-be' } else { 'main' } +$target = if ($TargetDir) { $TargetDir } else { Join-Path $env:USERPROFILE 'shopdb-dev' } + +Write-Host "ShopDB dev launcher" -ForegroundColor White +Write-Host " Channel : $Channel ($branch)" -ForegroundColor White +Write-Host " Target : $target" -ForegroundColor White + +if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + throw 'git is required. Install Git for Windows (winget install Git.Git) and re-run.' +} + +if (Test-Path (Join-Path $target '.git')) { + Write-Host "==> Updating existing clone" -ForegroundColor Cyan + git -C $target fetch origin $branch + if ($LASTEXITCODE -ne 0) { throw "git fetch failed ($LASTEXITCODE). If this is an auth error, clone the repo once in Visual Studio / VS Code so Credential Manager stores your GitHub login." } + git -C $target checkout $branch + if ($LASTEXITCODE -ne 0) { throw "git checkout failed ($LASTEXITCODE)." } + git -C $target pull --ff-only origin $branch + if ($LASTEXITCODE -ne 0) { throw "git pull failed ($LASTEXITCODE)." } +} else { + Write-Host "==> Cloning $branch" -ForegroundColor Cyan + git clone --branch $branch $repoUrl $target + if ($LASTEXITCODE -ne 0) { throw "git clone failed ($LASTEXITCODE). If this is an auth error, sign in to GitHub once in Visual Studio / VS Code (or run 'git clone $repoUrl' manually) so Credential Manager stores your login, then re-run." } +} + +$bootstrap = Join-Path $target 'scripts\dev-bootstrap.ps1' +if (-not (Test-Path $bootstrap)) { + throw "dev-bootstrap.ps1 not found at $bootstrap. Is the '$branch' branch correct?" +} + +Write-Host "==> Handing off to dev-bootstrap.ps1" -ForegroundColor Cyan +& $bootstrap -Channel $Channel diff --git a/scripts/get.ps1 b/scripts/get.ps1 deleted file mode 100644 index 0003aa5c..00000000 --- a/scripts/get.ps1 +++ /dev/null @@ -1,95 +0,0 @@ -<# -.SYNOPSIS - One-line web launcher for a ShopDB dev workstation. - -.DESCRIPTION - The piece that makes `iex (irm .../get.ps1)` work. dev-bootstrap.ps1 operates - on a local clone, so it cannot be run straight from the web. This launcher - fills that gap: it clones (or updates) the repo at the channel branch into a - stable local path, then hands off to scripts/dev-bootstrap.ps1 for the real - dependency-check / build / up work. - - Channel is chosen by an environment variable so a pure `iex` pipe (which - cannot pass parameters) still selects stable vs edge: - - # Bleeding edge (dev-be): - $env:SHOPDB_CHANNEL='edge' - $env:SHOPDB_TOKEN='ghp_yourtoken' - $h=@{ Authorization="token $env:SHOPDB_TOKEN" } - iex (irm -Headers $h https://raw.githubusercontent.com/ge-aero/shopdb-flask/wilm/scripts/get.ps1) - - ge-aero/shopdb-flask is a PRIVATE repo, so both the raw fetch of this - launcher AND the git clone it performs need a GitHub token. The raw fetch is - authenticated by the -Headers on irm above; the clone is authenticated here - by reading the same token from the environment (SHOPDB_TOKEN, or GITHUB_TOKEN - as a fallback) and using it in the clone URL. Anonymous access returns 404. - - SHOPDB_DIR overrides the clone location (default %USERPROFILE%\shopdb-dev). - -.NOTES - ASCII only, no emoji or smart punctuation, per repo style. PowerShell 5.1+. - Runs git-checkout of the channel branch, so it needs Git; dev-bootstrap.ps1 - offers to winget-install anything else that is missing. -#> - -$ErrorActionPreference = 'Stop' - -# Private-repo access token, used for the git clone/fetch below. The same token -# authenticated the raw fetch of this script (via irm -Headers). Prefer the -# ShopDB-specific var so a pilot can keep an unrelated GITHUB_TOKEN in place. -$token = if ($env:SHOPDB_TOKEN) { $env:SHOPDB_TOKEN } elseif ($env:GITHUB_TOKEN) { $env:GITHUB_TOKEN } else { '' } -if (-not $token) { - throw 'No token found. Set $env:SHOPDB_TOKEN (a GitHub PAT with repo read) before running; the repo is private.' -} - -# x-access-token is GitHub's documented username for token-in-URL auth; it works -# for classic PATs and fine-grained tokens alike. Kept out of any Write-Host so -# the secret never lands in the transcript. -$repoUrl = "https://x-access-token:$token@github.com/ge-aero/shopdb-flask.git" -$channel = if ($env:SHOPDB_CHANNEL) { $env:SHOPDB_CHANNEL } else { 'stable' } -if ($channel -notin @('stable', 'edge')) { - throw "SHOPDB_CHANNEL must be 'stable' or 'edge' (got '$channel')." -} -$branch = if ($channel -eq 'edge') { 'dev-be' } else { 'main' } -$target = if ($env:SHOPDB_DIR) { $env:SHOPDB_DIR } else { Join-Path $env:USERPROFILE 'shopdb-dev' } - -Write-Host "ShopDB web launcher" -ForegroundColor White -Write-Host " Channel : $channel ($branch)" -ForegroundColor White -Write-Host " Target : $target" -ForegroundColor White - -if (-not (Get-Command git -ErrorAction SilentlyContinue)) { - throw 'git is required to clone the repo. Install Git (winget install Git.Git) and re-run.' -} - -if (Test-Path (Join-Path $target '.git')) { - Write-Host "==> Updating existing clone" -ForegroundColor Cyan - # Fetch by explicit tokenized URL, not `origin`: origin is deliberately the - # clean tokenless URL (see the clone path below), so a bare `fetch origin` - # would 404 against the private repo. Passing the URL keeps the token off - # disk while still authenticating this pull. - git -C $target fetch $repoUrl $branch - if ($LASTEXITCODE -ne 0) { throw "git fetch failed ($LASTEXITCODE)." } - git -C $target checkout $branch - if ($LASTEXITCODE -ne 0) { throw "git checkout failed ($LASTEXITCODE)." } - git -C $target merge --ff-only FETCH_HEAD - if ($LASTEXITCODE -ne 0) { throw "git merge --ff-only failed ($LASTEXITCODE)." } -} else { - Write-Host "==> Cloning $branch" -ForegroundColor Cyan - git clone --branch $branch $repoUrl $target - if ($LASTEXITCODE -ne 0) { throw "git clone failed ($LASTEXITCODE)." } - # Scrub the token out of the persisted remote: `git clone` writes the full - # URL (token included) into .git/config. Reset origin to the clean URL so the - # secret does not sit on disk. Fetch/pull above still work because this only - # runs on the fresh-clone path; a returning pilot re-fetches with a clean - # origin and their own credential helper / token as usual. - git -C $target remote set-url origin 'https://github.com/ge-aero/shopdb-flask.git' - if ($LASTEXITCODE -ne 0) { throw "git remote set-url failed ($LASTEXITCODE)." } -} - -$bootstrap = Join-Path $target 'scripts\dev-bootstrap.ps1' -if (-not (Test-Path $bootstrap)) { - throw "dev-bootstrap.ps1 not found at $bootstrap. Is the branch correct?" -} - -Write-Host "==> Handing off to dev-bootstrap.ps1" -ForegroundColor Cyan -& $bootstrap -Channel $channel