Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
f38a74b
feat: add dev container feature with bats test submodules
coakenfold Apr 22, 2026
93461e3
feat: add curl installation for uv installer and improve pip install …
coakenfold Apr 23, 2026
7738c9e
feat: add generic checks for apm binary in dev container
coakenfold Apr 23, 2026
dac703c
feat: add platform-specific checks for Alpine, Debian, Fedora, and Ub…
coakenfold Apr 23, 2026
372b895
feat: update pinned-version.sh to include scenario-specific checks fo…
coakenfold Apr 23, 2026
b190312
refactor: remove specific apm checks from test script and source gene…
coakenfold Apr 23, 2026
0a62503
feat: update python feature checks to ensure minimum version and simp…
coakenfold Apr 23, 2026
8e55df2
feat: simplify scenarios.json by removing redundant scenario descript…
coakenfold Apr 23, 2026
bfd2148
feat: enhance install tests by refining package manager stubs and imp…
coakenfold Apr 23, 2026
e6c65dc
feat: add local devcontainer configuration for APM development enviro…
coakenfold Apr 23, 2026
0349f28
feat: add comprehensive overview for APM Dev Container Feature
coakenfold Apr 23, 2026
4530135
refactor: renaming devcontainer dir
coakenfold Apr 23, 2026
b5fab35
feat: add BATS testing framework submodules
coakenfold Apr 23, 2026
c207e05
chore: delete test `.devcontainer` dir
coakenfold Apr 23, 2026
a64a243
refactor: file rename
coakenfold Apr 23, 2026
696b9d7
chore: delete dev docs
coakenfold Apr 23, 2026
37894d5
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 23, 2026
5a25a5c
fix: drop non-ascii characters
coakenfold Apr 23, 2026
1620fc0
fix: copilot pr suggestions, ascii chars, and useless assertion
coakenfold Apr 23, 2026
c9dbd51
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 23, 2026
0bd6c49
chore: update ref to original feature
coakenfold Apr 23, 2026
c28f45b
fix: optimize apt-get update calls in install script
coakenfold Apr 23, 2026
a5eb76a
chore: update doc url
coakenfold Apr 23, 2026
f1df272
fix: update error messages in install script and tests for consistency
coakenfold Apr 23, 2026
9726d0b
fix: update grep command in pinned-version.sh for exact match
coakenfold Apr 23, 2026
42f94a5
fix: improve output handling in install_apm function for better error…
coakenfold Apr 23, 2026
6a7c72c
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 23, 2026
249c585
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 23, 2026
db6cab2
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 24, 2026
5dbecc9
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 24, 2026
63f472b
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 24, 2026
7ce6dae
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 24, 2026
a7b331b
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 24, 2026
70cb49d
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 24, 2026
799b4b7
Merge branch 'main' into feat/717-dev-container
danielmeppiel Apr 24, 2026
442887e
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 25, 2026
f38fc30
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 25, 2026
655df9f
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 26, 2026
b3808b7
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 27, 2026
35ca5cc
Merge branch 'main' into feat/717-dev-container
coakenfold Apr 28, 2026
cb2006a
Merge branch 'main' into feat/717-dev-container
danielmeppiel Apr 28, 2026
62cf31d
feat(devcontainer): publish apm-cli feature to GHCR with CI gates
danielmeppiel Apr 28, 2026
5ecff94
Merge branch 'main' into feat/717-dev-container
danielmeppiel Apr 28, 2026
c6a2b67
fix(devcontainer): bats sandbox needs busybox /bin; pinned-version us…
danielmeppiel Apr 28, 2026
fb1cd8a
Merge branch 'main' into feat/717-dev-container
danielmeppiel Apr 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/devcontainer-feature-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Devcontainer Feature - Publish

# Publishes the apm-cli devcontainer feature to GHCR as
# ghcr.io/microsoft/apm/apm-cli
# whenever the feature source changes on main. The official
# `devcontainers/action@v1` handles OCI tag fan-out (e.g. version "1.0.0"
# fans out to :1, :1.0, :1.0.0, :latest).
#
# Notes:
# - We set `disable-repo-tagging: 'true'` because microsoft/apm already
# uses `v*` git tags for apm-cli releases; letting the action push its
# own feature tags would clutter that namespace.
# - With repo-tagging disabled, `permissions: contents: read` is enough
# (`packages: write` is what GHCR push needs).
# - `concurrency.cancel-in-progress: false` -- a publish run that races
# another publish must not be cancelled mid-push, or we leave a partial
# manifest in GHCR.
# - `workflow_dispatch` enables manual republish if the first run fails
# before maintainers flip the package to public.
#
# First-run ceremony (one-time, by maintainer, after the first successful
# run): GHCR -> packages -> apm-cli -> Package settings -> change visibility
# to Public, then "Manage Actions access" -> add microsoft/apm with Write.

on:
push:
branches: [ main ]
paths:
- 'devcontainer/src/**'
- '.github/workflows/devcontainer-feature-publish.yml'
workflow_dispatch:

permissions:
contents: read
packages: write

concurrency:
group: devcontainer-feature-publish
cancel-in-progress: false

jobs:
publish:
name: Publish to GHCR
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4

- name: Publish features
uses: devcontainers/action@v1
with:
publish-features: 'true'
base-path-to-features: './devcontainer/src'
generate-docs: 'false'
disable-repo-tagging: 'true'
133 changes: 133 additions & 0 deletions .github/workflows/devcontainer-feature-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
name: Devcontainer Feature - Test

# Runs the official `devcontainer features test` matrix from @devcontainers/cli
# whenever the feature source or test fixtures change. PRs run a 4-scenario
# subset (one per package-manager family + option-coverage scenarios); the full
# 6-scenario matrix runs nightly to catch base-image drift on Debian and Fedora
# without blocking PR throughput.
#
# A single aggregation job ("Devcontainer Feature - Test Result") is what gets
# wired into branch protection -- adding/removing matrix legs does not require
# editing the required-checks list.
#
# Reference: https://containers.dev/implementors/features-distribution/

on:
pull_request:
branches: [ main ]
paths:
- 'devcontainer/**'
- '.github/workflows/devcontainer-feature-test.yml'
merge_group:
branches: [ main ]
types: [ checks_requested ]
schedule:
# Nightly full matrix at 06:00 UTC catches base-image drift (glibc, musl,
# apt/apk/dnf) within 24h independent of PR activity.
- cron: '0 6 * * *'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: devcontainer-feature-test-${{ github.ref }}
cancel-in-progress: true

jobs:
unit-bats:
name: bats unit tests
runs-on: ubuntu-24.04
# The bats sandbox uses PATH="$STUB_BIN:/bin" to isolate install.sh from
# the real environment. On Ubuntu 24.04 /bin is a symlink to /usr/bin
# (merged-/usr), so real apt-get / pip / curl shadow the stubs and
# negative-path tests false-pass. Alpine 3.20 keeps /bin as busybox-only
# (apk lives in /sbin which is not on the test PATH), so the stubs work
# exactly as the test author designed.
container:
image: alpine:3.20
permissions:
contents: read
steps:
- name: Install bash + git (bats needs bash; submodule checkout needs git)
run: apk add --no-cache bash git

- uses: actions/checkout@v4
with:
submodules: recursive

- name: Run bats unit tests
working-directory: devcontainer/test/apm-cli/unit
run: ../../bats/bin/bats install.bats

integration-matrix:
name: features test (${{ matrix.scenario }})
runs-on: ubuntu-24.04
permissions:
contents: read
strategy:
fail-fast: false
matrix:
# PR + merge_group: cheap representative subset (one per pkg-manager
# family + option/ordering coverage). schedule/workflow_dispatch adds
# default-debian-12 + default-fedora to catch base-image drift.
scenario:
- default-ubuntu-24
- default-alpine-3
- pinned-version
- with-python-feature
include:
- scenario: default-debian-12
nightly_only: true
- scenario: default-fedora
nightly_only: true
steps:
- name: Skip nightly-only leg on PR
id: gate
run: |
if [ "${{ matrix.nightly_only }}" = "true" ] && [ "${{ github.event_name }}" != "schedule" ] && [ "${{ github.event_name }}" != "workflow_dispatch" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Skipping ${{ matrix.scenario }} (nightly-only)."
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- uses: actions/checkout@v4
if: steps.gate.outputs.skip == 'false'

- name: Set up Node
if: steps.gate.outputs.skip == 'false'
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install @devcontainers/cli
if: steps.gate.outputs.skip == 'false'
run: npm install -g @devcontainers/cli@latest

- name: Run devcontainer features test
if: steps.gate.outputs.skip == 'false'
run: |
devcontainer features test \
--features apm-cli \
--filter "${{ matrix.scenario }}" \
--skip-autogenerated \
--project-folder devcontainer

test-result:
name: Devcontainer Feature - Test Result
if: always()
needs: [ unit-bats, integration-matrix ]
runs-on: ubuntu-24.04
steps:
- name: Aggregate
run: |
if [ "${{ needs.unit-bats.result }}" != "success" ]; then
echo "unit-bats failed: ${{ needs.unit-bats.result }}"
exit 1
fi
if [ "${{ needs.integration-matrix.result }}" != "success" ] && [ "${{ needs.integration-matrix.result }}" != "skipped" ]; then
echo "integration-matrix failed: ${{ needs.integration-matrix.result }}"
exit 1
fi
echo "All devcontainer feature tests passed."
9 changes: 9 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[submodule "devcontainer/test/bats"]
path = devcontainer/test/bats
url = https://github.com/bats-core/bats-core
[submodule "devcontainer/test/test_helper/bats-support"]
path = devcontainer/test/test_helper/bats-support
url = https://github.com/bats-core/bats-support
[submodule "devcontainer/test/test_helper/bats-assert"]
path = devcontainer/test/test_helper/bats-assert
url = https://github.com/bats-core/bats-assert
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **Dev Container Feature** `ghcr.io/microsoft/apm/apm-cli` -- one-line install of the APM CLI into any `devcontainer.json`, GitHub Codespace, or JetBrains Gateway workspace. Supports a `version` option (`latest` or pinned semver), declares `installsAfter` for the official Python feature, handles PEP 668 on Ubuntu 24.04+. Ships with 37 bats unit tests and a 6-distro Docker integration matrix (Ubuntu 24.04, Ubuntu 22.04, Debian 12, Alpine 3.20, Fedora 41, plus Python-feature combo). (#861)
- `shared/apm.md` gh-aw workflow gains an `apps:` array input for cross-org private packages: each entry mints its own GitHub App installation token via `actions/create-github-app-token` and packs only its declared packages, with a matrix fan-out one replica per credential group. The single-app top-level form (`app-id`, `private-key`, `owner`, `repositories`) shipped earlier in this cycle is preserved as the canonical shorthand for one-org users; `apps[]` is purely additive. Multi-bundle restore uses the `bundles-file:` input from `microsoft/apm-action@v1.5.0` (microsoft/apm-action#30, microsoft/apm-action#29).
- `shared/apm.md` gh-aw workflow now accepts `app-id`, `private-key`, `owner`, and `repositories` inputs to mint a GitHub App installation token for fetching cross-org private APM packages, restoring parity with the deprecated `dependencies.github-app` form. The default `GH_AW_PLUGINS_TOKEN || GH_AW_GITHUB_TOKEN || GITHUB_TOKEN` cascade still applies when no app-id is supplied.

Expand Down
Loading
Loading