Speed up Ubuntu *env setup and add CI#7
Conversation
Building Ruby/Python from source made the devcontainer "installing dotfiles" step appear stuck, especially in Codespaces. - Run setup.d/ubuntu scripts in parallel after 001-apt.sh completes, writing per-script logs and failing the whole setup if any job fails - Export MAKE_OPTS="-j$(nproc)" before each *env install - Skip rdoc/ri generation via RUBY_CONFIGURE_OPTS and build Python with --enable-shared - Pull pyenv/goenv on each run so new version definitions are available - Update pinned versions past EOL: Node 18.16.0 -> 24.16.0 (LTS), Ruby 3.2.2 -> 4.0.5, Python 3.11.3 -> 3.14.6, Go 1.19.8 -> 1.26.4
Extract the parallel setup.d/ubuntu runner from setup.sh into script/setup-ubuntu.sh so setup.sh and CI share the same code path, and add a workflow that syntax-checks all shell scripts and runs the Ubuntu setup end-to-end (apt + parallel *env installs), verifying the installed versions and uploading per-script logs as artifacts. Fixes found by running the setup in a devcontainer base image: - 001-apt.sh: python3.8-dev no longer exists on Ubuntu 24.04; use python3-dev and add the dev libraries (zlib, ffi, readline, bz2, sqlite3, lzma, ncurses) required to build Ruby and Python from source - 004-pyenv.sh: put ~/.pyenv/bin on PATH before eval'ing pyenv init, whose output invokes the pyenv command itself on recent pyenv Verified inside mcr.microsoft.com/devcontainers/base:ubuntu (arm64): Node 24.16.0, Ruby 4.0.5, Python 3.14.6, Go 1.26.4 all install successfully.
postgresql-all pins the distro's postgresql-common, which conflicts with the newer PGDG postgresql-common preinstalled on GitHub Actions runners (and other images with the PGDG apt repo), breaking apt with unmet dependencies. The plain postgresql metapackage plus libpq-dev installs cleanly from either repo and covers actual usage.
There was a problem hiding this comment.
Pull request overview
This PR refactors Ubuntu environment setup to be faster and more observable (parallel per-script execution with logs), updates the pinned runtime versions, and adds GitHub Actions CI to run the Ubuntu setup end-to-end.
Changes:
- Added
script/setup-ubuntu.shto runsetup.d/ubuntu/*.shwith001-apt.shfirst, then parallel execution + per-script log files. - Updated Ubuntu setup scripts to pull latest
*envversion definitions and pin newer Node/Ruby/Python/Go versions, with build-speed env vars. - Added
.github/workflows/ci.ymlto lint shell scripts and execute/verify Ubuntu setup in CI.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| setup.sh | Switches Ubuntu setup invocation to the shared script/setup-ubuntu.sh entrypoint. |
| script/setup-ubuntu.sh | New parallel runner for Ubuntu setup scripts with per-script logging and aggregated failure handling. |
| setup.d/ubuntu/001-apt.sh | Updates Ubuntu 24.04 apt packages and adds build dependencies for source builds. |
| setup.d/ubuntu/002-nodenv.sh | Updates pinned Node version and adds MAKE_OPTS for faster source builds. |
| setup.d/ubuntu/003-rbenv.sh | Updates pinned Ruby version and configures faster Ruby builds (parallel + no docs). |
| setup.d/ubuntu/004-pyenv.sh | Updates pinned Python version, fixes PATH/init ordering, and configures faster Python builds. |
| setup.d/ubuntu/005-goenv.sh | Updates pinned Go version and refreshes goenv definitions. |
| .github/workflows/ci.yml | Adds CI: shell syntax lint + Ubuntu setup run with version verification and log artifacts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- setup.sh: Guard $WSL_DISTRO_NAME / $CODESPACES tests with default expansion and quoting so unset vars don't abort setup under set -e; drop the now-unneeded set +u/-u wrapper and use POSIX '=' in tests - ci.yml: Pick bash -n vs sh -n per script shebang so sh-only syntax errors aren't missed by bash -n
Resolves the Dependabot critical alert (arbitrary file read / RCE via the Vitest UI/Browser API server, affecting vitest < 3.2.6) in the turnstile-spin worker template. Also add package-lock.json so Dependabot can determine installed versions and auto-update going forward.
| node --version | ||
| ruby --version | ||
| python --version | ||
| go version | ||
| gcloud --version |
There was a problem hiding this comment.
Fixed in 0eef47d.
The "Verify installed versions" step now asserts that the installed node/ruby/python/go versions match the pinned VERSION= values instead of only printing them. The expected versions are extracted from each setup.d/ubuntu/*.sh script (single source of truth, no drift), and the job now exits non-zero on any mismatch or fallback to system binaries.
- "Verify installed versions" step now asserts node/ruby/python/go match the pinned VERSION= values instead of only printing them - Expected versions are extracted from each setup.d/ubuntu/*.sh script so the check never drifts from the source of truth - CI now fails on version mismatch or fallback to system binaries
| # 新しいバージョン定義を取得するため更新する | ||
| git -C ~/.pyenv pull |
There was a problem hiding this comment.
Fixed in be4b89d.
The update now runs only when ~/.pyenv/.git exists (so a non-git install via package/manual extraction/symlink no longer aborts setup) and uses git pull --ff-only to avoid creating an unintended merge. The same guard was applied to nodenv/rbenv plugin updates for consistency.
| # 新しいバージョン定義を取得するため更新する | ||
| git -C ~/.goenv pull |
| esac | ||
| echo "==> $checker $f" | ||
| $checker "$f" || status=1 | ||
| done < <(find setup.sh script/setup-ubuntu.sh setup.d -name '*.sh' -print0) |
There was a problem hiding this comment.
Fixed in be4b89d.
The lint job now enumerates all tracked shell scripts via git ls-files '*.sh' instead of a hardcoded path list, so env.sh and env.d/*.sh (and any future scripts) are covered. Shebang-less sourced fragments like env.sh / env.d/* are classified as bash so their bash/zsh syntax isn't false-flagged by sh -n. Verified all tracked scripts pass locally.
- *env setup: guard repo updates behind a `.git` check and use `git pull --ff-only` so a non-git install (package/manual/symlink) no longer aborts setup and updates never create an unintended merge (nodenv/rbenv plugin pulls and pyenv/goenv main-repo pulls) - CI lint: lint all tracked shell scripts via `git ls-files '*.sh'` instead of a hardcoded path list, covering env.sh and env.d/*.sh - CI lint: classify shebang-less sourced fragments (env.sh, env.d/*) as bash so their bash/zsh syntax isn't false-flagged by `sh -n`
The "Verify installed versions" step relied on `rbenv init -` / `goenv init -` to put shims on PATH, but those implementations don't prepend shims, so the runner's system ruby (3.2.3) and go (1.24.13) shadowed the rbenv/goenv globals and the assert failed. Explicitly prepend the shims dirs to PATH. Also add AGENTS.md with repo-specific agent guidance (zsh `status` readonly, shebang-less env.d lint, *env version pinning + shims, GnuPG conf generation and signing unlock). CLAUDE.md is now a symlink to AGENTS.md.
Prepending shims fixed node/python/go but ruby still resolved to the runner's system ruby (3.2.3) despite rbenv global 4.0.5 being installed. Use `<env> exec <tool>` so each *env runs its global-managed binary directly, independent of PATH/shims ordering. Dump rbenv/goenv selection on mismatch for debuggability. Also drop a stray `exit $status` left from the variable rename (st).
…rsion Diagnostics revealed rbenv resolved `system` from the repo's own `.ruby-version` (the dotfiles repo intentionally pins itself to system ruby), shadowing the global 4.0.5 that setup installed. Run each `*env exec` from $HOME so the repo-local pin no longer applies and the assert checks the global version setup actually installed.
Summary
Source-building Ruby/Python made the devcontainer "installing dotfiles" step appear stuck, especially in Codespaces. This PR speeds up the Ubuntu setup, updates the pinned language versions past EOL, and adds GitHub Actions CI that actually runs the setup.
Performance (
bf7635b)setup.d/ubuntu/*.shin parallel after001-apt.shcompletes, with per-script logs (/tmp/dotfiles-setup-<ts>/<name>.log); any failure fails the whole setup after all jobs are reapedMAKE_OPTS="-j$(nproc)"before each*env installRUBY_CONFIGURE_OPTS="--disable-install-doc"; build Python with--enable-sharedgit pullpyenv/goenv on each run so new version definitions are availableCI (
3294dbf)script/setup-ubuntu.shsosetup.shand CI share the same code path.github/workflows/ci.yml:lintjob (bash -n over all shell scripts) +ubuntu-setupjob that runs the setup end-to-end, verifiesnode/ruby/python/go/gcloudversions, and uploads per-script logs as artifacts001-apt.shfor Ubuntu 24.04:python3.8-dev→python3-dev, and add dev libraries (zlib, ffi, readline, bz2, sqlite3, lzma, ncurses) required to build Ruby/Python from source004-pyenv.sh: put~/.pyenv/binon PATH before eval'ingpyenv init -, whose output invokes thepyenvcommand itself on recent pyenvTest plan
script/setup-ubuntu.shinsidemcr.microsoft.com/devcontainers/base:ubuntu(arm64) as thevscodeuser — all 5 scripts succeeded andnode v24.16.0/ruby 4.0.5/Python 3.14.6/go1.26.4verifiedubuntu-setupCI job on this PR covers amd64