diff --git a/src/copilot-cli/devcontainer-feature.json b/src/copilot-cli/devcontainer-feature.json index bfd97286c..f4db33ced 100644 --- a/src/copilot-cli/devcontainer-feature.json +++ b/src/copilot-cli/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "copilot-cli", - "version": "1.1.2", + "version": "1.1.3", "name": "GitHub Copilot CLI", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/copilot-cli", "description": "Installs the GitHub Copilot CLI.", diff --git a/src/copilot-cli/install.sh b/src/copilot-cli/install.sh index 47c2e3aca..d4c27ad1a 100755 --- a/src/copilot-cli/install.sh +++ b/src/copilot-cli/install.sh @@ -45,6 +45,16 @@ download_from_github() { rm -rf /tmp/copilotcli } +# Resolves the latest prerelease version tag from a remote repository. +# Filters to well-formed vX.Y.Z or vX.Y.Z-N tags and sorts by version. +resolve_prerelease_version() { + local repo_url="${1:?resolve_prerelease_version requires a repository URL}" + git ls-remote --tags "${repo_url}" \ + | awk '{print $2}' | sed 's|refs/tags/||' \ + | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' \ + | sort -V | tail -n1 +} + install_using_github() { check_packages wget tar ca-certificates git echo "Finished setting up dependencies" @@ -63,7 +73,7 @@ install_using_github() { if [ "${CLI_VERSION}" = "latest" ]; then download_from_github "https://github.com/github/copilot-cli/releases/latest/download/${cli_filename}" elif [ "${CLI_VERSION}" = "prerelease" ]; then - prerelease_version="$(git ls-remote --tags https://github.com/github/copilot-cli | tail -1 | awk -F/ '{print $NF}')" + prerelease_version="$(resolve_prerelease_version "https://github.com/github/copilot-cli")" download_from_github "https://github.com/github/copilot-cli/releases/download/${prerelease_version}/${cli_filename}" else # Install specific version diff --git a/test/copilot-cli/resolve_prerelease_version.sh b/test/copilot-cli/resolve_prerelease_version.sh new file mode 100644 index 000000000..8369788c8 --- /dev/null +++ b/test/copilot-cli/resolve_prerelease_version.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +# Define the function under test (matches src/copilot-cli/install.sh) +resolve_prerelease_version() { + local repo_url="${1:?resolve_prerelease_version requires a repository URL}" + git ls-remote --tags "${repo_url}" \ + | awk '{print $2}' | sed 's|refs/tags/||' \ + | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' \ + | sort -V | tail -n1 +} + +# Create a mock git script that returns controlled output +MOCK_DIR="$(mktemp -d)" +cat > "${MOCK_DIR}/git" << 'SCRIPT' +#!/bin/bash +# Return mock ls-remote output based on the repo URL argument +repo="${*: -1}" +case "${repo}" in + "mock://basic") + printf 'abc1234\trefs/tags/v1.0.1\ndef5678\trefs/tags/v1.0.9\nghi9012\trefs/tags/v1.0.10\njkl3456\trefs/tags/v1.0.45\nmno7890\trefs/tags/v1.0.2\n' + ;; + "mock://prerelease") + printf 'abc1234\trefs/tags/v1.0.44\ndef5678\trefs/tags/v1.0.45-1\nghi9012\trefs/tags/v1.0.45-10\njkl3456\trefs/tags/v1.0.45-2\nmno7890\trefs/tags/v1.0.45\n' + ;; + "mock://stray") + printf 'abc1234\trefs/tags/latest\ndef5678\trefs/tags/v1.0.3\nghi9012\trefs/tags/nightly\njkl3456\trefs/tags/v1.0.20\n' + ;; +esac +SCRIPT +chmod +x "${MOCK_DIR}/git" +export PATH="${MOCK_DIR}:${PATH}" + +# Test: version sort picks v1.0.45, not v1.0.9 +result="$(resolve_prerelease_version "mock://basic")" +check "picks highest version (v1.0.45)" bash -c "[ '${result}' = 'v1.0.45' ]" + +# Test: prerelease numeric suffixes sort correctly +result2="$(resolve_prerelease_version "mock://prerelease")" +check "picks highest prerelease (v1.0.45-10)" bash -c "[ '${result2}' = 'v1.0.45-10' ]" + +# Test: filters out non-version tags +result3="$(resolve_prerelease_version "mock://stray")" +check "ignores non-version tags" bash -c "[ '${result3}' = 'v1.0.20' ]" + +# Cleanup +rm -rf "${MOCK_DIR}" + +# Report result +reportResults diff --git a/test/copilot-cli/scenarios.json b/test/copilot-cli/scenarios.json new file mode 100644 index 000000000..87fcc541d --- /dev/null +++ b/test/copilot-cli/scenarios.json @@ -0,0 +1,10 @@ +{ + "resolve_prerelease_version": { + "image": "ubuntu:noble", + "features": { + "copilot-cli": { + "version": "latest" + } + } + } +}