Skip to content

Devcontainer feature#861

Open
coakenfold wants to merge 29 commits intomicrosoft:mainfrom
coakenfold:feat/717-dev-container
Open

Devcontainer feature#861
coakenfold wants to merge 29 commits intomicrosoft:mainfrom
coakenfold:feat/717-dev-container

Conversation

@coakenfold
Copy link
Copy Markdown
Contributor

Description

Packages apm-cli as a reusable Dev Container Feature under devcontainer/.

The feature installs uv, Python 3.10+, git, and apm-cli inside the container. It supports a version option (latest or semver), declares installsAfter: ghcr.io/devcontainers/features/python for correct ordering, and handles the PEP 668 --break-system-packages retry on Ubuntu 24.04.

Also included: 37 bats unit tests covering every branch of install.sh (stub-based, no Docker needed), and a full integration test matrix across Ubuntu 24.04, Ubuntu 22.04, Debian 12, Alpine 3.20, Fedora 41, and a pinned-version + Python-feature scenario.

See devcontainer/README.md for more info

Fixes #717

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Maintenance / refactor

Testing

  • Tested locally
  • All existing tests pass
  • Added tests for new functionality (if applicable)

Unit tests (no Docker required):

cd devcontainer/test/apm/unit
../../bats/bin/bats install.bats

Integration tests (requires Docker and @devcontainers/cli):

devcontainer features test \
  --features apm \
  --skip-autogenerated \
  --project-folder devcontainer

Copilot AI review requested due to automatic review settings April 23, 2026 02:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a reusable Dev Container Feature under devcontainer/ to install apm-cli (plus prerequisites) in containers, along with unit + integration test coverage for the feature.

Changes:

  • Introduces a devcontainer feature (devcontainer-feature.json + install.sh) that installs uv, ensures Python 3.10+ and git, and installs apm-cli with a PEP 668 retry path.
  • Adds Bats unit tests for install.sh and devcontainer CLI integration scenarios across several base images and configuration variants.
  • Adds supporting docs (devcontainer/README.md), a local sync helper script, and git submodules for the Bats test framework.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
devcontainer/src/apm/install.sh Feature install script: uv install, Python/git setup, pip install of apm-cli with PEP 668 retry
devcontainer/src/apm/devcontainer-feature.json Feature manifest and version option + installsAfter ordering
devcontainer/test/apm/scenarios.json Integration test matrix (distros + pinned version + python feature)
devcontainer/test/apm/*.sh Scenario validation scripts + shared generic checks
devcontainer/test/apm/unit/install.bats Stub-based unit tests covering install.sh branches
devcontainer/scripts/sync-local-devcontainer.sh Helper to copy the local feature into .devcontainer/ for VS Code consumption
devcontainer/README.md Feature usage, structure, and test documentation
.gitmodules Adds bats-core, bats-support, bats-assert as submodules

Comment thread devcontainer/README.md Outdated
Comment thread devcontainer/src/apm/install.sh Outdated
Comment thread devcontainer/test/apm/unit/install.bats
Comment thread devcontainer/test/apm/default-ubuntu-24.sh
Comment thread devcontainer/test/apm/default-debian-12.sh
Comment thread devcontainer/test/apm/default-alpine-3.sh
Comment thread devcontainer/test/apm/default-fedora.sh
Comment thread devcontainer/README.md Outdated
Comment thread devcontainer/src/apm/install.sh Outdated
Comment thread devcontainer/src/apm/devcontainer-feature.json Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Comment thread devcontainer/test/apm/pinned-version.sh Outdated
Comment thread devcontainer/test/apm/unit/install.bats
Comment thread devcontainer/test/apm/unit/install.bats
Comment thread devcontainer/src/apm/install.sh Outdated
Comment thread devcontainer/test/apm/unit/install.bats
@coakenfold coakenfold requested a review from Copilot April 23, 2026 12:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Comment thread devcontainer/README.md Outdated
Comment thread devcontainer/src/apm/install.sh
Comment on lines +16 to +27
mkdir -p .devcontainer
rm -rf .devcontainer/apm-feature
cp -R devcontainer/src/apm .devcontainer/apm-feature

cat > .devcontainer/devcontainer.json <<'EOF'
{
"name": "APM Development",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"features": {
"./apm-feature": {}
}
}
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper script writes .devcontainer/devcontainer.json and copies the feature into .devcontainer/apm-feature, but the repo does not appear to gitignore .devcontainer/. Running it will leave untracked files that are easy to accidentally commit. Consider either (a) adding .devcontainer/ to .gitignore, or (b) having the script emit a clear warning / require an explicit flag before overwriting an existing .devcontainer/devcontainer.json.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not certain if adding .devcontainer to gitignore works with the repo. Not implementing unless directed otherwise

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Comment thread devcontainer/src/apm/devcontainer-feature.json Outdated
Comment thread devcontainer/src/apm/install.sh
Comment on lines +20 to +24
cat > .devcontainer/devcontainer.json <<'EOF'
{
"name": "APM Development",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"features": {
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper overwrites .devcontainer/devcontainer.json via cat > .... If a contributor already has a local devcontainer config, this will clobber it. Consider failing when the file exists unless --force is passed, or writing to a different filename and printing instructions.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Comment on lines +50 to +54
echo "Installing uv..."
_uv_tmp="$(mktemp /tmp/uv_install.XXXXXX)"
trap 'rm -f "$_uv_tmp"' EXIT INT TERM
curl -LsSf https://astral.sh/uv/install.sh > "$_uv_tmp"
UV_INSTALL_DIR=/usr/local/bin sh "$_uv_tmp"
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The uv installation downloads and executes a remote shell script as root (curl https://astral.sh/uv/install.sh then sh), without any integrity verification or pinning. This is a supply-chain risk for devcontainer builds. Consider installing uv via the distro package manager when available, or pinning/verifying the installer (e.g., checksum/signature or a versioned release artifact) before executing it.

Copilot uses AI. Check for mistakes.
Comment thread devcontainer/src/apm/install.sh Outdated
Comment thread devcontainer/test/apm/pinned-version.sh Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.

}
EOF

echo "Synced .devcontainer/apm-feature from devcontainer/src/apm"
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper script writes .devcontainer/devcontainer.json and copies a local feature into .devcontainer/apm-feature, but .devcontainer/ is not currently ignored by git in this repo. Running it will leave untracked files that are easy to accidentally commit. Consider adding .devcontainer/ to .gitignore (or writing into a clearly-temporary path) and/or printing an explicit note that these files are intended to remain uncommitted.

Suggested change
echo "Synced .devcontainer/apm-feature from devcontainer/src/apm"
echo "[+] Synced .devcontainer/apm-feature from devcontainer/src/apm"
echo "[!] Generated .devcontainer/ content is for local development only and should remain uncommitted."
if ! git check-ignore -q .devcontainer 2>/dev/null; then
echo "[!] .devcontainer/ is not ignored by git in this repo. Review 'git status' and do not commit these generated files."
fi

Copilot uses AI. Check for mistakes.
Comment on lines +109 to +116
python3 -m ensurepip --upgrade 2>/dev/null || true
if command -v pip3 >/dev/null 2>&1; then
PIP_CMD="pip3"
elif command -v pip >/dev/null 2>&1; then
PIP_CMD="pip"
else
echo "[x] pip is not available and could not be bootstrapped." >&2
exit 1
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a base image already has python3 but does not have pip3/pip on PATH (common on Debian/Ubuntu where ensurepip is often split into python3-venv and pip lives in python3-pip), the script falls through to python3 -m ensurepip and then exits 1 if that module isn't available. To make the feature more robust, consider installing the distro pip package when a package manager is available (apt: python3-pip, apk: py3-pip, dnf: python3-pip) instead of relying solely on ensurepip.

Suggested change
python3 -m ensurepip --upgrade 2>/dev/null || true
if command -v pip3 >/dev/null 2>&1; then
PIP_CMD="pip3"
elif command -v pip >/dev/null 2>&1; then
PIP_CMD="pip"
else
echo "[x] pip is not available and could not be bootstrapped." >&2
exit 1
if command -v apt-get >/dev/null 2>&1; then
apt_update_once
apt-get install -y -qq --no-install-recommends python3-pip
elif command -v apk >/dev/null 2>&1; then
apk add --no-cache py3-pip
elif command -v dnf >/dev/null 2>&1; then
dnf install -y python3-pip
fi
if command -v pip3 >/dev/null 2>&1; then
PIP_CMD="pip3"
elif command -v pip >/dev/null 2>&1; then
PIP_CMD="pip"
else
python3 -m ensurepip --upgrade 2>/dev/null || true
if command -v pip3 >/dev/null 2>&1; then
PIP_CMD="pip3"
elif command -v pip >/dev/null 2>&1; then
PIP_CMD="pip"
else
echo "[x] pip is not available and could not be bootstrapped." >&2
exit 1
fi

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Create a Devcontainer feature

2 participants