chore(devbox): one-shot Taskfile to recreate WSL and open the devcontainer (#315)

* chore(devbox): one-shot Taskfile to recreate WSL and open the devcontainer

- contrib/bootstrap-dev-env.yaml: default recreates WSL and clones the current branch, then runs up; up bootstraps the WSL host, starts the devcontainer with the labels VS Code uses, and opens VS Code in it.
- contrib/bootstrap-dev-env.ps1: no prompts; picks the drive with the most free space, creates the default Linux user, and clones the current branch into /workspaces/dbt-fabricspark with Git Credential Manager.
- contrib/bootstrap-dev-env.sh: fail fast; az login completes through the signed-in Windows browser with single sign-on; ACR login only uses ACR_PASSWORD, since the image pulls anonymously.
- CONTRIBUTING.md: replace the manual WSL steps with the Task command.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cc682684-642c-4667-a3e0-6bad55f87574

* fix(devbox): clone from the WSL home directory

Run from a git worktree, WSL git found the Windows worktree's .git file in the current directory and failed before cloning.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cc682684-642c-4667-a3e0-6bad55f87574

* style(devbox): drop a stray space

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cc682684-642c-4667-a3e0-6bad55f87574

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cc682684-642c-4667-a3e0-6bad55f87574
This commit is contained in:
RakiandCopilot authored and GitHub committed 2026-10-23 10:42:03 -04:00
1 parent b3a4c127d3
commit 00fe1b3dad
4 files changed
+93 -74

No files matched your search

+9 -33
View File
@@ -18,47 +18,23 @@ Therefore, if the tests pass locally, they are highly likely to pass in CI as we
winget install -e --id Microsoft.VisualStudioCode
```
1. Get a fresh new WSL machine up:
1. Clone your fork on Windows, then check out and push the branch you want to work on:
```powershell
$GIT_ROOT = git rev-parse --show-toplevel
& "$GIT_ROOT\contrib\bootstrap-dev-env.ps1"
git clone https://github.com/<your-github-user>/dbt-fabricspark.git
```
1. Clone the repo, and open VSCode in it:
1. From an **elevated PowerShell 7** prompt in the checkout, install [Task](https://taskfile.dev) and run [`contrib/bootstrap-dev-env.yaml`](contrib/bootstrap-dev-env.yaml):
```bash
sudo mkdir -p /workspaces && sudo chmod 777 /workspaces && cd /workspaces
> ⚠️ This **deletes every WSL distribution** on the machine before recreating `Ubuntu-24.04`. Push any work inside WSL first.
read -p "Enter your name (e.g. 'FirstName LastName'): " user_name
read -p "Enter your email (e.g. 'your-alias@foo.com'): " user_email
read -p "Enter your git fork (e.g. 'https://github.com/microsoft/dbt-fabricspark.git'): " git_fork_url
read -p "Enter the existing branch to switch to: (e.g. 'main'): " branch_name
git config --global user.name "$user_name"
git config --global user.email "$user_email"
git clone "$git_fork_url"
cd /workspaces/dbt-fabricspark
git checkout "$branch_name"
code .
```powershell
winget install Task.Task
$env:PATH = [Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' + [Environment]::GetEnvironmentVariable('PATH', 'User')
task --taskfile contrib/bootstrap-dev-env.yaml
```
1. Run the bootstrapper script, that installs all tools idempotently:
```bash
GIT_ROOT=$(git rev-parse --show-toplevel)
chmod +x ${GIT_ROOT}/contrib/bootstrap-dev-env.sh && ${GIT_ROOT}/contrib/bootstrap-dev-env.sh
```
1. Launch the devcontainer:
```bash
cd /workspaces/dbt-fabricspark
HEX=$(printf '%s' "$(wslpath -w .)" | xxd -ps -c 256)
code --folder-uri "vscode-remote://dev-container+${HEX}/workspaces/dbt-fabricspark"
```
Without any prompts, this recreates WSL on the drive with the most free space and clones your current branch into `/workspaces/dbt-fabricspark`. It then runs [`contrib/bootstrap-dev-env.sh`](contrib/bootstrap-dev-env.sh), which signs in the Azure CLI through your signed-in browser with single sign-on (no clicks), then starts the devcontainer and opens it in VS Code. After a restart, run `task --taskfile contrib/bootstrap-dev-env.yaml up` instead; it keeps WSL and reopens the devcontainer.
1. Install recommended developer tooling (optional):
+45 -25
View File
@@ -5,6 +5,7 @@
.NOTES
- Non-interactive: recreates WSL and clones -Branch (default: this checkout's branch) into /workspaces/dbt-fabricspark.
- The script uninstalls Docker Desktop as it interferes with WSL2.
- Must be run as Administrator in PowerShell 7+.
@@ -12,6 +13,11 @@
#Requires -RunAsAdministrator
param(
[string]$Branch = (git -C $PSScriptRoot rev-parse --abbrev-ref HEAD),
[string]$LinuxUser = ($env:USERNAME.ToLower() -replace '[^a-z0-9_-]', '')
)
code --install-extension ms-vscode-remote.remote-wsl
code --install-extension ms-vscode-remote.remote-containers
@@ -20,6 +26,21 @@ if ($PSVersionTable.PSVersion.Major -lt 7) {
exit 1
}
# Git Credential Manager lets git inside WSL reuse this checkout's sign-in; install it if Git for Windows lacks it.
if (-not (git credential-manager --version 2>$null)) {
winget install -e --id Git.GCM --silent --accept-package-agreements --accept-source-agreements --disable-interactivity
$env:PATH = [Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' + [Environment]::GetEnvironmentVariable('PATH', 'User')
}
$gcm = @((Get-Command git-credential-manager -ErrorAction SilentlyContinue).Source, "$(Split-Path (Split-Path (git --exec-path)))\bin\git-credential-manager.exe") |
Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1
# Fail before deleting WSL if the branch can't be cloned without a prompt.
$origin = git -C $PSScriptRoot remote get-url origin
$env:GCM_INTERACTIVE = 'never'
$env:GIT_TERMINAL_PROMPT = '0'
git ls-remote --exit-code --heads $origin $Branch | Out-Null
if ($LASTEXITCODE) { throw "Cannot read $Branch from $origin without a prompt; push it, or run 'git fetch' in $PSScriptRoot once to sign in, then rerun." }
# See: https://github.com/microsoft/vscode-remote-release/issues/11480
$sshDir = Join-Path $env:USERPROFILE ".ssh"
$knownHosts = Join-Path $sshDir "known_hosts"
@@ -55,6 +76,12 @@ if ($pkg) {
}
Remove-Item -Path "$env:PROGRAMFILES\Docker", "$env:PROGRAMDATA\Docker*", "$env:LOCALAPPDATA\Docker*", "$env:APPDATA\Docker*" -Recurse -Force -ErrorAction SilentlyContinue
# VS Code windows attached to WSL go stale when it is recreated, and VS Code would focus them instead of reconnecting.
Add-Type -AssemblyName UIAutomationClient
[Windows.Automation.AutomationElement]::RootElement.FindAll('Children', [Windows.Automation.Condition]::TrueCondition) |
Where-Object { $_.Current.Name -match '\[(Dev Container|WSL)\b.*Visual Studio Code' } |
ForEach-Object { Write-Host "Closing VS Code window: $($_.Current.Name)"; $_.GetCurrentPattern([Windows.Automation.WindowPattern]::Pattern).Close() }
$distros = (wsl -l -q) | Where-Object { $_ -and $_.Trim() } | ForEach-Object { $_.Trim().Replace("`0", "") } | Where-Object { $_ }
foreach ($distro in $distros) {
Write-Host "Unregistering WSL distro: $distro"
@@ -70,15 +97,12 @@ $swap=[math]::Floor($memGB/4)
if ($cpu -lt $RECOMMENDED_CORES) {
Write-Host "WARNING: This machine has $cpu cores, which is below the recommended $RECOMMENDED_CORES cores." -ForegroundColor DarkYellow
$requiredResponse = "I am OK with having a subpar development experience"
do {
$response = Read-Host "Please type '$requiredResponse' **EXACTLY** as is to continue"
} while ($response -ne $requiredResponse)
} else {
Write-Host "(detected $cpu cores, ${memGB}GB RAM)" -ForegroundColor Green
}
$driveOptions = @(Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" |
Where-Object { $_.VolumeName -notmatch 'Temporary' } |
Sort-Object -Property FreeSpace -Descending |
ForEach-Object {
[PSCustomObject]@{
@@ -92,28 +116,12 @@ if ($driveOptions.Count -eq 0) {
exit 1
}
Write-Host ""
Write-Host "Choose a drive to store the WSL VHD (the repo recommends at least ${RECOMMENDED_FREE_GB} GB free):" -ForegroundColor Cyan
for ($i = 0; $i -lt $driveOptions.Count; $i++) {
$opt = $driveOptions[$i]
Write-Host (" [{0}] {1} ({2} GB free)" -f ($i + 1), $opt.Path, $opt.FreeGB)
}
do {
$pick = Read-Host "Pick a drive number [1-$($driveOptions.Count)]"
} while (-not ($pick -as [int]) -or [int]$pick -lt 1 -or [int]$pick -gt $driveOptions.Count)
$wslLocation = $driveOptions[[int]$pick - 1]
$wslLocation = $driveOptions[0]
if ($wslLocation.FreeGB -lt $RECOMMENDED_FREE_GB) {
Write-Host "WARNING: $($wslLocation.Path) has only $($wslLocation.FreeGB) GB free, which is below the recommended ${RECOMMENDED_FREE_GB} GB." -ForegroundColor DarkYellow
$requiredResponse = "I am OK with having my WSL crash when my hard disk fills up"
do {
$response = Read-Host "Please type '$requiredResponse' **EXACTLY** as is to continue"
} while ($response -ne $requiredResponse)
} else {
Write-Host "Using $($wslLocation.Path) for the WSL VHD." -ForegroundColor Green
}
Write-Host "Using $($wslLocation.Path), the drive with the most free space, for the WSL VHD." -ForegroundColor Green
New-Item -ItemType Directory -Path $wslLocation.Path -Force | Out-Null
@@ -158,13 +166,14 @@ memory=${memGB}GB
processors=$cpu
swap=${swap}GB
networkingMode=NAT
[general]
instanceIdleTimeout=-1
"@ | Set-Content -Path "$env:USERPROFILE\.wslconfig"
Write-Host "Restarting WSL to apply settings"
wsl --shutdown
winget install -e --id Microsoft.GitCredentialManagerCore
Write-Host "Updating WSL (the --location flag requires WSL 2.4.4+)"
wsl --update
@@ -189,4 +198,15 @@ if ($wslVersion -lt $minWslVersion) {
Write-Host "WSL version $wslVersion detected." -ForegroundColor Green
Write-Host "Installing Ubuntu to $($wslLocation.Path)"
wsl --install -d Ubuntu-24.04 --location $wslLocation.Path
wsl --install -d Ubuntu-24.04 --location $wslLocation.Path --no-launch --web-download
if ($LASTEXITCODE) { throw "wsl --install failed with exit code $LASTEXITCODE." }
Write-Host "Creating default Linux user $LinuxUser with passwordless sudo"
wsl -d Ubuntu-24.04 -u root --exec bash -c 'useradd -m -s /bin/bash -G sudo "$1" && echo "$1 ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/$1" && install -d -o "$1" /workspaces' bash $LinuxUser
if ($LASTEXITCODE) { throw "Could not create Linux user $LinuxUser." }
wsl --manage Ubuntu-24.04 --set-default-user $LinuxUser
if ($LASTEXITCODE) { throw "Could not make $LinuxUser the default WSL user." }
Write-Host "Cloning $Branch into /workspaces/dbt-fabricspark"
wsl -d Ubuntu-24.04 --cd ~ --exec bash -c 'git config --global user.name "$1" && git config --global user.email "$2" && git config --global credential.helper "$(printf %q "$(wslpath -u "$5")")" && GIT_TERMINAL_PROMPT=0 git clone --branch "$3" "$4" /workspaces/dbt-fabricspark' bash (git -C $PSScriptRoot config user.name) (git -C $PSScriptRoot config user.email) $Branch $origin $gcm
if ($LASTEXITCODE) { throw "Could not clone $Branch into /workspaces/dbt-fabricspark." }
+13 -16
View File
@@ -9,6 +9,8 @@
# ---------------------------------------------------------------------------------------
#
set -eo pipefail
REPO_ROOT=$(git rev-parse --show-toplevel)
ACR_NAME="dbtfabric"
@@ -49,23 +51,16 @@ echo "docker is installed, restarting..."
sudo systemctl restart docker
sudo chmod 666 /var/run/docker.sock
sudo usermod -aG docker "$USER"
docker container ls
docker ps -q | xargs -r docker kill
if grep -q "$ACR_URL" ~/.docker/config.json 2>/dev/null; then
echo "Already logged in to ${ACR_URL}"
else
if [ -n "$ACR_PASSWORD" ]; then
docker_password="$ACR_PASSWORD"
else
read -sp "If you are a Microsoft Employee and you plan on contributing to the Devcontainer image, please ping @mdrrahman and enter Docker Admin password for ${ACR_URL} - otherwise, leave blank and press [ENTER]: " docker_password
echo
fi
if [ -z "$docker_password" ]; then
echo "You left the password empty, skipping docker login"
else
echo "$docker_password" | docker login "$ACR_URL" --username "$ACR_NAME" --password-stdin
fi
elif [ -z "$ACR_PASSWORD" ]; then
echo "ACR_PASSWORD is not set, skipping docker login; only devcontainer image publishers need it"
else
echo "$ACR_PASSWORD" | docker login "$ACR_URL" --username "$ACR_NAME" --password-stdin
fi
docker pull "$(jq -r .image "$REPO_ROOT/.devcontainer/devcontainer.json")"
@@ -79,7 +74,7 @@ else
echo "WSL npm is available."
fi
AZ_PATH=$(which az 2>/dev/null)
AZ_PATH=$(which az 2>/dev/null || true)
if [[ -z "$AZ_PATH" || "$AZ_PATH" == *"/mnt/c"* ]]; then
echo "Native Linux Azure CLI not found, installing..."
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
@@ -88,10 +83,12 @@ if [[ -z "$AZ_PATH" || "$AZ_PATH" == *"/mnt/c"* ]]; then
else
echo "Native Linux Azure CLI already installed at: $AZ_PATH"
fi
az account get-access-token --query "expiresOn" -o tsv >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
if ! az account get-access-token --query "expiresOn" -o tsv >/dev/null 2>&1; then
echo "az is not logged in, logging in..."
az login >/dev/null
# prompt=none lets the signed-in Windows browser complete the login with single sign-on, without clicks.
# Login experience v2 off skips the subscription picker that waits for input in a terminal.
BROWSER='bash -c "exec wslview \"${0/prompt=select_account/prompt=none}\"" %s' AZURE_CORE_LOGIN_EXPERIENCE_V2=off \
az login --output none
fi
cd "$REPO_ROOT"
+26
View File
@@ -0,0 +1,26 @@
version: '3'
vars:
DISTRO: Ubuntu-24.04
REPO: /workspaces/dbt-fabricspark
UNC: \\wsl.localhost\{{.DISTRO}}\workspaces\dbt-fabricspark
tasks:
default:
desc: Delete and recreate WSL, clone the current branch into it, then run the up task
platforms: [windows]
cmds:
- pwsh -NoProfile -NonInteractive -File bootstrap-dev-env.ps1
- task: up
up:
desc: Bootstrap the existing WSL clone, start its devcontainer, and open VS Code (use after a restart)
platforms: [windows]
cmds:
- wsl -d {{.DISTRO}} --cd {{.REPO}} --exec ./contrib/bootstrap-dev-env.sh
# These labels match the ones VS Code uses, so VS Code attaches to this container instead of creating another.
- >-
wsl -d {{.DISTRO}} --cd {{.REPO}} --exec npx --no-install devcontainer up --workspace-folder {{.REPO}}
--id-label 'devcontainer.local_folder={{.UNC}}'
--id-label 'devcontainer.config_file={{.REPO}}/.devcontainer/devcontainer.json'
- code --folder-uri 'vscode-remote://dev-container+{{printf "%x" .UNC}}{{.REPO}}'