Making Builds Suck Less on Windows
Let’s make builds on Windows a bit friendlier for Unix/Linux types.
VM Based Build Nodes
Consider these when
- Visual Studio 2013 or older is in the mix
- You have a lot of files to be processed during build
- You have a manual build process
- Your build process depends on build node changes the previous build made
Vagrant and Virtualbox provide a reasonable environment to develop your infrastructure as code describing your build nodes. Rui Lopes provides a clean windows 2016 vagrant box for virtualbox and vsphere.
Ideally most of your Vagrantfile will use provisioners like
config.vm.provision 'whatever',
type: 'shell',
inline: 'sh -c /vagrant/whatever.sh; if ($LASTEXITCODE -ne 0) {Throw "whatever.sh failed exit code: $($LATEXITCODE)"}'
You won’t need to do as much error handling if you use the catcherror template from the next snippet
These Vagrantfile snippets provide reasonable stop on failure behavior.
catcherror = <<-SCRIPT
$ErrorActionPreference = 'Stop'
%<cmd>s
if ($LASTEXITCODE -ne 0) { Throw "%<cmd>s exit code: $($LASTEXITCODE)"}
SCRIPT
bootstrap = format(catcherror, cmd: '/vagrant/bootstrap.bat')
...
config.vm.provision 'bootstrap',
type: 'shell',
inline: bootstrap
The catcherror template is cleaner.
This bootstrap.bat provides chocolatey and git and nvm for windows places sh.exe and nvm on the path.
"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command " [System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
if errorlevel 1 (exit /b 1)
choco feature disable --name showDownloadProgress
choco upgrade --install-if-not-installed --allow-downgrade -y git.install --params '/GitAndUnixToolsOnPath'
if errorlevel 1 (exit /b 1)
choco upgrade --install-if-not-installed --allow-downgrade -y nvm.portable
if errorlevel 1 (exit /b 1)
call refreshenv
The chocolatey folks are always refining their one liner. Reference Install with cmd.exe for updates.
And that allows a whatever.sh like
#!/bin/bash -eu
# winrm declares failure when powershell has stderr
exec 2>&1
# For tracing
set -x
Whatever() {
nvm install 10.16.3
nvm use 10.16.3
# Magic sleep waiting for windows symlinks to settle
sleep 2
npm install --global windows-build-tools
exit 0
}
# Bash acts weird when a scriptfile is edited while it's run
Whatever "$@"
Warnings and gotchas
- Some versions of git for windows break the ‘cmdThatUsesInputFile <(cmdThatGeneratesInputFileOnStdOut)’ construct
- You need the chocolatey package ‘findutils’ to have a Unix find instead of the “grep” equivalent for Windows
- git for windows includes curl. It does not include wget.