Skip to content

Commit 9735099

Browse files
authored
[powershell] - Add lts, stable and preview, also remove deprecated versions. (#1562)
* [powershell] - Add `lts` and remove deprecated versions. * re-triggger test * Re-trigger the test. * Support powershell installation in debian trixie(13) * Supporting `lts`, `preview` and `stable`. * Remove extra dot(.) * Retrigger test * Added tests for almalinux * Added one more test * Remove duplicate code comment
1 parent c85af4d commit 9735099

16 files changed

+360
-17
lines changed

src/powershell/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Installs PowerShell along with needed dependencies. Useful for base Dockerfiles
77

88
```json
99
"features": {
10-
"ghcr.io/devcontainers/features/powershell:1": {}
10+
"ghcr.io/devcontainers/features/powershell:2": {}
1111
}
1212
```
1313

src/powershell/devcontainer-feature.json

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"id": "powershell",
3-
"version": "1.5.1",
3+
"version": "2.0.0",
44
"name": "PowerShell",
55
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/powershell",
66
"description": "Installs PowerShell along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like gpg.",
@@ -9,18 +9,20 @@
99
"type": "string",
1010
"proposals": [
1111
"latest",
12+
"lts",
13+
"preview",
14+
"stable",
1215
"none",
13-
"7.4",
14-
"7.3",
15-
"7.2"
16+
"7.5",
17+
"7.4"
1618
],
1719
"default": "latest",
1820
"description": "Select or enter a version of PowerShell."
1921
},
2022
"modules": {
2123
"type": "string",
2224
"default": "",
23-
"description": "Optional comma separated list of PowerShell modules to install. If you need to install a specific version of a module, use '==' to specify the version (e.g. 'az.resources==2.5.0')"
25+
"description": "Optional comma separated list of PowerShell modules to install. If you need to install a specific version of a module, use '==' to specify the version (e.g. 'az.resources==2.5.0')."
2426
},
2527
"powershellProfileURL": {
2628
"type": "string",

src/powershell/install.sh

Lines changed: 115 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,26 @@ clean_cache() {
4848
rm -rf /var/cache/dnf/*
4949
fi
5050
}
51+
# Function to resolve PowerShell version from Microsoft redirect URLs
52+
resolve_powershell_version() {
53+
local version_tag="$1"
54+
local redirect_url="https://aka.ms/powershell-release?tag=${version_tag}"
55+
56+
# Follow the redirect and extract the version from the final URL
57+
local resolved_url
58+
resolved_url=$(curl -sSL -o /dev/null -w '%{url_effective}' "${redirect_url}")
59+
60+
# Extract version from URL (e.g., https://github.com/PowerShell/PowerShell/releases/tag/v7.4.7 -> 7.4.7)
61+
local resolved_version
62+
resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-\w+\.\d+)?' || echo "")
63+
64+
if [ -z "${resolved_version}" ]; then
65+
echo "Failed to resolve version for tag: ${version_tag}" >&2
66+
return 1
67+
fi
68+
69+
echo "${resolved_version}"
70+
}
5171
# Install dependencies for RHEL/CentOS/AlmaLinux (DNF-based systems)
5272
install_using_dnf() {
5373
dnf remove -y curl-minimal
@@ -100,6 +120,58 @@ detect_package_manager() {
100120
fi
101121
}
102122

123+
# Function to find the latest preview version from git tags
124+
find_preview_version_from_git_tags() {
125+
local variable_name=$1
126+
local requested_version=${!variable_name}
127+
local repository_url=$2
128+
129+
if [ -z "${googlegit_cmd_name}" ]; then
130+
if type git > /dev/null 2>&1; then
131+
git_cmd_name="git"
132+
else
133+
echo "Git not found. Cannot determine preview version."
134+
return 1
135+
fi
136+
fi
137+
138+
# Fetch tags from remote repository
139+
local tags
140+
tags=$(git ls-remote --tags "${repository_url}" 2>/dev/null | grep -oP 'refs/tags/v\K[0-9]+\.[0-9]+\.[0-9]+-preview\.[0-9]+' | sort -V)
141+
142+
if [ -z "${tags}" ]; then
143+
echo "No preview tags found in repository."
144+
return 1
145+
fi
146+
147+
local version=""
148+
149+
if [ "${requested_version}" = "preview" ] || [ "${requested_version}" = "latest" ]; then
150+
# Get the latest preview version
151+
version=$(echo "${tags}" | tail -n 1)
152+
elif [[ "${requested_version}" =~ ^[0-9]+\.[0-9]+$ ]]; then
153+
# Partial version provided (e.g., "7.6"), find latest preview matching that major.minor
154+
version=$(echo "${tags}" | grep "^${requested_version}\." | tail -n 1)
155+
elif [[ "${requested_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-preview$ ]]; then
156+
# Version like "7.6.0-preview" provided, find latest preview for that version
157+
local base_version="${requested_version%-preview}"
158+
version=$(echo "${tags}" | grep "^${base_version}-preview\." | tail -n 1)
159+
elif [[ "${requested_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-preview\.[0-9]+$ ]]; then
160+
# Exact preview version provided, verify it exists
161+
if echo "${tags}" | grep -q "^${requested_version}$"; then
162+
version="${requested_version}"
163+
fi
164+
fi
165+
166+
if [ -z "${version}" ]; then
167+
echo "Could not find matching preview version for: ${requested_version}"
168+
return 1
169+
fi
170+
171+
declare -g "${variable_name}=${version}"
172+
echo "${variable_name}=${version}"
173+
}
174+
103175
# Figure out correct version of a three part version number is not passed
104176
find_version_from_git_tags() {
105177
local variable_name=$1
@@ -159,7 +231,8 @@ apt_get_update()
159231
for package in "$@"; do
160232
if ! dnf list installed "$package" > /dev/null 2>&1; then
161233
echo "Package $package not installed. Installing using dnf..."
162-
dnf install -y "$package"
234+
# Use --allowerasing to handle conflicts like curl-minimal vs curl
235+
dnf install -y --allowerasing "$package"
163236
else
164237
echo "Package $package is already installed (DNF)."
165238
fi
@@ -292,16 +365,30 @@ install_pwsh() {
292365

293366
install_using_github() {
294367
# Fall back on direct download if no apt package exists in microsoft pool
295-
check_packages curl ca-certificates gnupg2 dirmngr libc6 libgcc1 libgssapi-krb5-2 libstdc++6 libunwind8 libuuid1 zlib1g libicu[0-9][0-9]
368+
if command -v apt-get > /dev/null 2>&1; then
369+
# Debian/Ubuntu dependencies
370+
check_packages curl ca-certificates gnupg2 dirmngr libc6 libgcc1 libgssapi-krb5-2 libstdc++6 libunwind8 libuuid1 zlib1g libicu[0-9][0-9]
371+
elif command -v dnf > /dev/null 2>&1; then
372+
# AlmaLinux/RHEL dependencies
373+
check_packages curl ca-certificates gnupg2 glibc libgcc krb5-libs libstdc++ libuuid zlib libicu wget tar
374+
fi
296375
if ! type git > /dev/null 2>&1; then
297376
check_packages git
298377
fi
299-
300-
if [ "${architecture}" = "amd64" ]; then
378+
if [ "${architecture}" = "amd64" ] || [ "${architecture}" = "x86_64" ]; then
301379
architecture="x64"
380+
elif [ "${architecture}" = "aarch64" ]; then
381+
architecture="arm64"
302382
fi
303383
pwsh_url="https://github.com/PowerShell/PowerShell"
304-
find_version_from_git_tags POWERSHELL_VERSION $pwsh_url
384+
# Check if we need to find a preview version or stable version
385+
if [[ "${POWERSHELL_VERSION}" == *"preview"* ]] || [ "${POWERSHELL_VERSION}" = "preview" ]; then
386+
echo "Finding preview version..."
387+
find_preview_version_from_git_tags POWERSHELL_VERSION "${pwsh_url}"
388+
else
389+
find_version_from_git_tags POWERSHELL_VERSION "${pwsh_url}"
390+
fi
391+
305392
install_pwsh "${POWERSHELL_VERSION}"
306393
if grep -q "Not Found" "${powershell_filename}"; then
307394
install_prev_pwsh $pwsh_url
@@ -312,7 +399,6 @@ install_using_github() {
312399
mkdir ~/powershell
313400
tar -xvf powershell-${POWERSHELL_VERSION}-linux-x64.tar.gz -C ~/powershell
314401

315-
316402
powershell_archive_sha256="$(cat release.html | tr '\n' ' ' | sed 's|<[^>]*>||g' | grep -oP "${powershell_filename}\s+\K[0-9a-fA-F]{64}" || echo '')"
317403
if [ -z "${powershell_archive_sha256}" ]; then
318404
echo "(!) WARNING: Failed to retrieve SHA256 for archive. Skipping validaiton."
@@ -323,13 +409,33 @@ install_using_github() {
323409
tar xf "${powershell_filename}" -C "${powershell_target_path}"
324410
chmod 755 "${powershell_target_path}/pwsh"
325411
ln -sf "${powershell_target_path}/pwsh" /usr/bin/pwsh
326-
add-shell "/usr/bin/pwsh"
412+
# Add pwsh to /etc/shells
413+
if command -v add-shell > /dev/null 2>&1; then
414+
# Debian/Ubuntu - use add-shell
415+
add-shell "/usr/bin/pwsh"
416+
else
417+
# AlmaLinux/RHEL - manually add to /etc/shells - add-shell is not available in almalinux repos and manual approach is simpler than adding a dependency just for this
418+
if ! grep -q "/usr/bin/pwsh" /etc/shells; then
419+
echo "/usr/bin/pwsh" >> /etc/shells
420+
fi
421+
fi
327422
cd /tmp
328423
rm -rf /tmp/pwsh
329424
}
330425

331426
if ! type pwsh >/dev/null 2>&1; then
332427
export DEBIAN_FRONTEND=noninteractive
428+
if [ "${POWERSHELL_VERSION}" = "lts" ] || [ "${POWERSHELL_VERSION}" = "stable" ] || [ "${POWERSHELL_VERSION}" = "preview" ]; then
429+
echo "Resolving PowerShell '${POWERSHELL_VERSION}' version from Microsoft..."
430+
resolved_version=$(resolve_powershell_version "${POWERSHELL_VERSION}")
431+
if [ -n "${resolved_version}" ]; then
432+
echo "Resolved '${POWERSHELL_VERSION}' to version: ${resolved_version}"
433+
POWERSHELL_VERSION="${resolved_version}"
434+
else
435+
echo "Warning: Could not resolve '${POWERSHELL_VERSION}' version. Falling back to 'latest'."
436+
POWERSHELL_VERSION="latest"
437+
fi
438+
fi
333439

334440
# Source /etc/os-release to get OS info
335441
. /etc/os-release
@@ -340,11 +446,10 @@ if ! type pwsh >/dev/null 2>&1; then
340446
POWERSHELL_ARCHIVE_ARCHITECTURES="${POWERSHELL_ARCHIVE_ARCHITECTURES_ALMALINUX}"
341447
fi
342448

343-
if [[ "${POWERSHELL_ARCHIVE_ARCHITECTURES}" = *"${POWERSHELL_ARCHIVE_ARCHITECTURES_UBUNTU}"* ]] && [[ "${POWERSHELL_ARCHIVE_VERSION_CODENAMES}" = *"${VERSION_CODENAME}"* ]]; then
449+
if [[ "${POWERSHELL_ARCHIVE_ARCHITECTURES}" = *"${POWERSHELL_ARCHIVE_ARCHITECTURES_UBUNTU}"* ]] && [[ "${POWERSHELL_ARCHIVE_VERSION_CODENAMES}" = *"${VERSION_CODENAME}"* ]] && [[ "${POWERSHELL_VERSION}" != *"preview"* ]]; then
344450
install_using_apt || use_github="true"
345-
elif [[ "${POWERSHELL_ARCHIVE_ARCHITECTURES}" = *"${POWERSHELL_ARCHIVE_ARCHITECTURES_ALMALINUX}"* ]]; then
451+
elif [[ "${POWERSHELL_ARCHIVE_ARCHITECTURES}" = *"${POWERSHELL_ARCHIVE_ARCHITECTURES_ALMALINUX}"* ]] && [[ "${POWERSHELL_VERSION}" != *"preview"* ]]; then
346452
install_using_dnf && install_powershell_dnf || use_github="true"
347-
348453
else
349454
use_github="true"
350455
fi

test/powershell/install_modules.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ set -e
55
# Import test library for `check` command
66
source dev-container-features-test-lib
77

8+
check "pwsh is installed" bash -c "command -v pwsh"
9+
check "pwsh version is LTS (not preview)" bash -c "pwsh --version | grep -v 'preview'"
10+
811
# Extension-specific tests
912
check "az.resources" pwsh -Command "(Get-Module -ListAvailable -Name Az.Resources).Version.ToString()"
1013
check "az.storage" pwsh -Command "(Get-Module -ListAvailable -Name Az.Storage).Version.ToString()"

test/powershell/install_powershell_fallback_test.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,10 @@ install_pwsh() {
148148

149149
install_using_github() {
150150
mode=$1
151-
if [ "${architecture}" = "amd64" ]; then
151+
if [ "${architecture}" = "amd64" ] || [ "${architecture}" = "x86_64" ]; then
152152
architecture="x64"
153+
elif [ "${architecture}" = "aarch64" ]; then
154+
architecture="arm64"
153155
fi
154156
pwsh_url="https://github.com/PowerShell/PowerShell"
155157
POWERSHELL_VERSION="7.4.xyz"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Import test library for `check` command
6+
source dev-container-features-test-lib
7+
8+
# Test LTS version installation on AlmaLinux
9+
check "pwsh is installed" bash -c "command -v pwsh"
10+
check "pwsh version is LTS (not preview)" bash -c "pwsh --version | grep -v 'preview'"
11+
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"
12+
13+
# Report result
14+
reportResults
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Import test library for `check` command
6+
source dev-container-features-test-lib
7+
8+
# Test LTS version installation on Debian
9+
check "pwsh is installed" bash -c "command -v pwsh"
10+
check "pwsh version is LTS (not preview)" bash -c "pwsh --version | grep -v 'preview'"
11+
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"
12+
13+
# Report result
14+
reportResults
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Import test library for `check` command
6+
source dev-container-features-test-lib
7+
8+
# Test preview version installation
9+
check "pwsh is installed" bash -c "command -v pwsh"
10+
check "pwsh version is preview" bash -c "pwsh --version | grep -i 'preview'"
11+
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"
12+
13+
# Report result
14+
reportResults
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Import test library for `check` command
6+
source dev-container-features-test-lib
7+
8+
# Test preview version installation on AlmaLinux
9+
check "pwsh is installed" bash -c "command -v pwsh"
10+
check "pwsh version is preview" bash -c "pwsh --version | grep -i 'preview'"
11+
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"
12+
13+
# Report result
14+
reportResults
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Import test library for `check` command
6+
source dev-container-features-test-lib
7+
8+
# Test preview version installation on Debian
9+
check "pwsh is installed" bash -c "command -v pwsh"
10+
check "pwsh version is preview" bash -c "pwsh --version | grep -i 'preview'"
11+
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"
12+
13+
# Report result
14+
reportResults

0 commit comments

Comments
 (0)