Skip to content

Commit b15e018

Browse files
authored
Merge branch 'main' into docker-compose-latest
2 parents 8ea2231 + 372e2d2 commit b15e018

11 files changed

Lines changed: 136 additions & 82 deletions

src/dotnet/NOTES.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Installing only the .NET Runtime or the ASP.NET Core Runtime. (The SDK includes
5757
"ghcr.io/devcontainers/features/dotnet:2": {
5858
"version": "none",
5959
"dotnetRuntimeVersions": "latest, lts",
60-
"aspnetCoreRuntimeVersions": "latest, lts",
60+
"aspNetCoreRuntimeVersions": "latest, lts",
6161
}
6262
}
6363
```
@@ -67,7 +67,7 @@ Installing .NET workloads. Multiple workloads can be specified as comma-separate
6767
``` json
6868
"features": {
6969
"ghcr.io/devcontainers/features/dotnet:2": {
70-
"workloads": "aspire, wasm-tools"
70+
"workloads": "wasm-tools"
7171
}
7272
}
7373
```
@@ -80,7 +80,7 @@ Installing prerelease builds. Supports `preview` and `daily` suffixes.
8080
"version": "10.0-preview",
8181
"additionalVersions": "10.0.1xx-daily",
8282
"dotnetRuntimeVersions": "10.0-daily",
83-
"aspnetCoreRuntimeVersions": "10.0-daily"
83+
"aspNetCoreRuntimeVersions": "10.0-daily"
8484
}
8585
}
8686
```
@@ -90,3 +90,21 @@ Installing prerelease builds. Supports `preview` and `daily` suffixes.
9090
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
9191

9292
`bash` is required to execute the `install.sh` script.
93+
94+
## Tab completions
95+
96+
When using .NET SDK 10 or newer, tab completions for the `dotnet` CLI are automatically installed for bash, zsh, and fish. The completion scripts are placed in the standard system-wide directories so they work for all users:
97+
98+
- **Bash**: `/usr/share/bash-completion/completions/dotnet`
99+
- **Zsh**: `/usr/share/zsh/site-functions/_dotnet`
100+
- **Fish**: `/usr/share/fish/vendor_completions.d/dotnet.fish`
101+
102+
To disable this, set `tabCompletions` to `false`:
103+
104+
``` json
105+
"features": {
106+
"ghcr.io/devcontainers/features/dotnet:2": {
107+
"tabCompletions": false
108+
}
109+
}
110+
```

src/dotnet/README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ This Feature installs the latest .NET SDK, which includes the .NET CLI and the s
1515

1616
| Options Id | Description | Type | Default Value |
1717
|-----|-----|-----|-----|
18-
| version | Select or enter a .NET SDK version. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | latest |
19-
| additionalVersions | Enter additional .NET SDK versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | - |
20-
| dotnetRuntimeVersions | Enter additional .NET runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | - |
21-
| aspNetCoreRuntimeVersions | Enter additional ASP.NET Core runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | - |
18+
| version | Select or enter a .NET SDK version. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version, 'X.Y-preview' or 'X.Y-daily' for prereleases. | string | latest |
19+
| additionalVersions | Enter additional .NET SDK versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version, 'X.Y-preview' or 'X.Y-daily' for prereleases. | string | - |
20+
| dotnetRuntimeVersions | Enter additional .NET runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version, 'X.Y-preview' or 'X.Y-daily' for prereleases. | string | - |
21+
| aspNetCoreRuntimeVersions | Enter additional ASP.NET Core runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version, 'X.Y-preview' or 'X.Y-daily' for prereleases. | string | - |
2222
| workloads | Enter additional .NET SDK workloads, separated by commas. Use 'dotnet workload search' to learn what workloads are available to install. | string | - |
23+
| tabCompletions | Install shell tab completions for the dotnet CLI. Requires SDK 10 or newer. | boolean | true |
2324

2425
## Customizations
2526

@@ -85,7 +86,7 @@ Installing only the .NET Runtime or the ASP.NET Core Runtime. (The SDK includes
8586
"ghcr.io/devcontainers/features/dotnet:2": {
8687
"version": "none",
8788
"dotnetRuntimeVersions": "latest, lts",
88-
"aspnetCoreRuntimeVersions": "latest, lts",
89+
"aspNetCoreRuntimeVersions": "latest, lts",
8990
}
9091
}
9192
```
@@ -95,7 +96,7 @@ Installing .NET workloads. Multiple workloads can be specified as comma-separate
9596
``` json
9697
"features": {
9798
"ghcr.io/devcontainers/features/dotnet:2": {
98-
"workloads": "aspire, wasm-tools"
99+
"workloads": "wasm-tools"
99100
}
100101
}
101102
```

src/dotnet/devcontainer-feature.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"id": "dotnet",
3-
"version": "2.4.2",
3+
"version": "2.5.0",
44
"name": "Dotnet CLI",
55
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/dotnet",
66
"description": "This Feature installs the latest .NET SDK, which includes the .NET CLI and the shared runtime. Options are provided to choose a different version or additional versions.",
@@ -39,6 +39,11 @@
3939
"type": "string",
4040
"default": "",
4141
"description": "Enter additional .NET SDK workloads, separated by commas. Use 'dotnet workload search' to learn what workloads are available to install."
42+
},
43+
"tabCompletions": {
44+
"type": "boolean",
45+
"default": true,
46+
"description": "Install shell tab completions for the dotnet CLI. Requires SDK 10 or newer."
4247
}
4348
},
4449
"containerEnv": {
@@ -64,4 +69,4 @@
6469
"installsAfter": [
6570
"ghcr.io/devcontainers/features/common-utils"
6671
]
67-
}
72+
}

src/dotnet/install.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ADDITIONAL_VERSIONS="${ADDITIONALVERSIONS:-""}"
1111
DOTNET_RUNTIME_VERSIONS="${DOTNETRUNTIMEVERSIONS:-""}"
1212
ASPNETCORE_RUNTIME_VERSIONS="${ASPNETCORERUNTIMEVERSIONS:-""}"
1313
WORKLOADS="${WORKLOADS:-""}"
14+
TAB_COMPLETIONS="${TABCOMPLETIONS:-"true"}"
1415

1516
# Prevent "Welcome to .NET" message from dotnet
1617
export DOTNET_NOLOGO=true
@@ -105,7 +106,7 @@ done
105106

106107
# Install .NET versions and dependencies
107108
# icu-devtools includes dependencies for .NET
108-
check_packages wget ca-certificates icu-devtools
109+
check_packages wget ca-certificates icu-devtools jq
109110

110111
for version in "${versions[@]}"; do
111112
read -r clean_version quality < <(parse_version_and_quality "$version")
@@ -146,6 +147,10 @@ if [ ! -e /usr/bin/dotnet ]; then
146147
ln --symbolic "$DOTNET_ROOT/dotnet" /usr/bin/dotnet
147148
fi
148149

150+
if [ "$TAB_COMPLETIONS" = "true" ]; then
151+
install_completions
152+
fi
153+
149154
# Add .NET Core SDK tools to PATH for bash and zsh users
150155
# This is where 'dotnet tool install --global <tool>' installs tools to
151156
# Use single-quoted EOF to defer $PATH expansion until sourcing the file

src/dotnet/scripts/dotnet-helpers.sh

Lines changed: 80 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,49 @@
88
# Maintainer: The Dev Container spec maintainers
99
DOTNET_SCRIPTS=$(dirname "${BASH_SOURCE[0]}")
1010
DOTNET_INSTALL_SCRIPT="$DOTNET_SCRIPTS/vendor/dotnet-install.sh"
11+
DOTNET_RELEASES_INDEX_URL="https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json"
1112

12-
# Prints the latest dotnet version in the specified channel
13-
# Usage: fetch_latest_version_in_channel <channel> [<runtime>]
14-
# Example: fetch_latest_version_in_channel "LTS"
15-
# Example: fetch_latest_version_in_channel "6.0" "dotnet"
16-
# Example: fetch_latest_version_in_channel "6.0" "aspnetcore"
17-
fetch_latest_version_in_channel() {
18-
local channel="$1"
19-
local runtime="$2"
20-
if [ "$runtime" = "dotnet" ]; then
21-
wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Runtime/$channel/latest.version"
22-
elif [ "$runtime" = "aspnetcore" ]; then
23-
wget -qO- "https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$channel/latest.version"
24-
else
25-
wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Sdk/$channel/latest.version"
26-
fi
27-
}
28-
29-
# Prints the latest dotnet version
30-
# Usage: fetch_latest_version [<runtime>]
13+
# Prints the latest active dotnet version from the releases index.
14+
# Usage: fetch_latest_version [<target>]
15+
# With no target, resolves the latest SDK version.
16+
# With "sdk", resolves the latest SDK version explicitly.
17+
# With "dotnet" or "aspnetcore", resolves the latest runtime version.
18+
# Note: the upstream releases index only distinguishes SDK vs runtime for
19+
# latest resolution, so "dotnet" and "aspnetcore" currently resolve to the
20+
# same version.
3121
# Example: fetch_latest_version
22+
# Example: fetch_latest_version "sdk"
3223
# Example: fetch_latest_version "dotnet"
3324
# Example: fetch_latest_version "aspnetcore"
3425
fetch_latest_version() {
35-
local runtime="$1"
36-
local sts_version
37-
local lts_version
38-
sts_version=$(fetch_latest_version_in_channel "STS" "$runtime")
39-
lts_version=$(fetch_latest_version_in_channel "LTS" "$runtime")
40-
if [[ "$sts_version" > "$lts_version" ]]; then
41-
echo "$sts_version"
42-
else
43-
echo "$lts_version"
44-
fi
26+
local target="$1"
27+
local version_field=""
28+
local releases_index=""
29+
30+
case "$target" in
31+
""|sdk)
32+
version_field="latest-sdk"
33+
;;
34+
dotnet|aspnetcore)
35+
version_field="latest-runtime"
36+
;;
37+
*)
38+
echo "Unsupported target '$target'. Expected 'sdk', 'dotnet', or 'aspnetcore'." >&2
39+
return 1
40+
;;
41+
esac
42+
43+
releases_index="$(wget -qO- "$DOTNET_RELEASES_INDEX_URL")" || return $?
44+
45+
printf '%s\n' "$releases_index" \
46+
| jq -er --arg version_field "$version_field" '
47+
.["releases-index"]
48+
| map(
49+
select(."support-phase" == "active")
50+
| .[$version_field]
51+
)
52+
| .[0]
53+
'
4554
}
4655

4756
# Installs a version of the .NET SDK
@@ -184,4 +193,46 @@ parse_version_and_quality() {
184193
quality=""
185194
fi
186195
echo "$clean_version" "$quality"
196+
}
197+
198+
# Checks if the installed .NET SDK is at least the given major version.
199+
# Returns 0 (true) if the SDK major version >= the specified version, 1 otherwise.
200+
# Also returns 1 if no SDK is installed (e.g. runtime-only installs).
201+
# Usage: is_at_least_sdk_version <major_version>
202+
# Example: is_at_least_sdk_version 10
203+
is_at_least_sdk_version() {
204+
local required_major="$1"
205+
local dotnet_version
206+
dotnet_version=$("$DOTNET_ROOT/dotnet" --version 2>/dev/null || true)
207+
local major_version="${dotnet_version%%.*}"
208+
[[ "$major_version" =~ ^[0-9]+$ ]] && [ "$major_version" -ge "$required_major" ]
209+
}
210+
211+
# Sets up dotnet tab completions for bash, zsh, and fish.
212+
# The 'dotnet completions script' command is only available in .NET SDK 10+.
213+
# Older SDKs and runtime-only installs will naturally skip this since the
214+
# command won't be available.
215+
# Reference: https://learn.microsoft.com/en-us/dotnet/core/tools/enable-tab-autocomplete
216+
# Completion scripts are generated at install time and placed in the standard
217+
# system-wide completion directories, which are auto-discovered by
218+
# bash-completion, zsh, and fish without modifying any rc files.
219+
install_completions() {
220+
if ! is_at_least_sdk_version 10; then
221+
echo "Skipping dotnet tab completions (requires SDK 10+)."
222+
return
223+
fi
224+
225+
echo "Setting up dotnet tab completions..."
226+
227+
# Bash: drop into the standard bash-completion directory
228+
mkdir -p /usr/share/bash-completion/completions
229+
"$DOTNET_ROOT/dotnet" completions script bash > /usr/share/bash-completion/completions/dotnet
230+
231+
# Zsh: drop into the standard site-functions directory
232+
mkdir -p /usr/share/zsh/site-functions
233+
"$DOTNET_ROOT/dotnet" completions script zsh > /usr/share/zsh/site-functions/_dotnet
234+
235+
# Fish: drop into the standard vendor completions directory
236+
mkdir -p /usr/share/fish/vendor_completions.d
237+
"$DOTNET_ROOT/dotnet" completions script fish > /usr/share/fish/vendor_completions.d/dotnet.fish
187238
}

test/dotnet/dotnet_helpers.sh

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,7 @@
11
#!/bin/bash
22

3-
# Prints the latest dotnet version in the specified channel
4-
# Usage: fetch_latest_version_in_channel <channel> [<runtime>]
5-
# Example: fetch_latest_version_in_channel "LTS"
6-
# Example: fetch_latest_version_in_channel "6.0" "dotnet"
7-
# Example: fetch_latest_version_in_channel "6.0" "aspnetcore"
8-
fetch_latest_version_in_channel() {
9-
local channel="$1"
10-
local runtime="$2"
11-
if [ "$runtime" = "dotnet" ]; then
12-
wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Runtime/$channel/latest.version"
13-
elif [ "$runtime" = "aspnetcore" ]; then
14-
wget -qO- "https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/$channel/latest.version"
15-
else
16-
wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Sdk/$channel/latest.version"
17-
fi
18-
}
19-
20-
# Prints the latest dotnet version
21-
# Usage: fetch_latest_version [<runtime>]
22-
# Example: fetch_latest_version
23-
# Example: fetch_latest_version "dotnet"
24-
# Example: fetch_latest_version "aspnetcore"
25-
fetch_latest_version() {
26-
local runtime="$1"
27-
local sts_version
28-
local lts_version
29-
sts_version=$(fetch_latest_version_in_channel "STS" "$runtime")
30-
lts_version=$(fetch_latest_version_in_channel "LTS" "$runtime")
31-
if [[ "$sts_version" > "$lts_version" ]]; then
32-
echo "$sts_version"
33-
else
34-
echo "$lts_version"
35-
fi
36-
}
3+
# Include the same helper functions used by the install script
4+
source ".devcontainer/dotnet/scripts/dotnet-helpers.sh"
375

386
# Asserts that the specified .NET SDK version is installed
397
# Returns a non-zero exit code if the check fails

test/dotnet/install_dotnet_lts.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ source dev-container-features-test-lib
1313
source dotnet_env.sh
1414
source dotnet_helpers.sh
1515

16-
expected=$(fetch_latest_version_in_channel "LTS")
16+
expected=$(wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Sdk/LTS/latest.version")
1717

1818
check "Latest LTS version installed" \
1919
is_dotnet_sdk_version_installed "$expected"

test/dotnet/install_dotnet_specific_release.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ source dev-container-features-test-lib
1313
source dotnet_env.sh
1414
source dotnet_helpers.sh
1515

16-
expected=$(fetch_latest_version_in_channel "10.0")
16+
expected=$(wget -qO- "https://builds.dotnet.microsoft.com/dotnet/Sdk/10.0/latest.version")
1717

1818
check ".NET Core SDK 10.0 installed" \
1919
is_dotnet_sdk_version_installed "$expected"

test/dotnet/install_dotnet_workloads.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ source dev-container-features-test-lib
1313
source dotnet_env.sh
1414
source dotnet_helpers.sh
1515

16-
check "Aspire is installed" \
17-
is_dotnet_workload_installed "aspire"
18-
1916
check "WASM tools are installed" \
2017
is_dotnet_workload_installed "wasm-tools"
2118

test/dotnet/scenarios.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
"features": {
9090
"dotnet": {
9191
"version": "latest",
92-
"workloads": "aspire, wasm-tools"
92+
"workloads": "wasm-tools"
9393
}
9494
}
9595
}

0 commit comments

Comments
 (0)