diff --git a/src/dotnet-install.sh b/src/dotnet-install.sh index 42c201af4c..9400783829 100644 --- a/src/dotnet-install.sh +++ b/src/dotnet-install.sh @@ -638,7 +638,7 @@ get_version_from_latestversion_file() { # args: # json_file - $1 -parse_globaljson_file_for_version() { +parse_globaljson_file() { eval $invocation local json_file="$1" @@ -657,31 +657,84 @@ parse_globaljson_file_for_version() { sdk_list=${sdk_list//[\" ]/} sdk_list=${sdk_list//,/$'\n'} - local version_info="" while read -r line; do IFS=: while read -r key value; do if [[ "$key" == "version" ]]; then - version_info=$value + globaljson_version=$value + elif [[ "$key" == "rollForward" ]]; then + globaljson_roll_forward=$value fi done <<< "$line" done <<< "$sdk_list" - if [ -z "$version_info" ]; then - say_err "Unable to find the SDK:version node in \`$json_file\`" - return 1 - fi unset IFS; - echo "$version_info" return 0 } +process_globaljson_file() { + if [[ -n "$json_file" ]]; then + globaljson_version="" + globaljson_roll_forward="" + parse_globaljson_file "$json_file" || return 1 + + # https://learn.microsoft.com/en-us/dotnet/core/tools/global-json#matching-rules + if [[ -z "$globaljson_roll_forward" ]]; then + if [[ -z "$globaljson_version" ]]; then + globaljson_roll_forward="latestMajor" + else + globaljson_roll_forward="latestPatch" + fi + fi + + if [[ -n "$globaljson_version" ]]; then + IFS='.' + read -ra parts <<<"$globaljson_version" + unset IFS + + local major="${parts[0]}" + local minor="${parts[1]}" + local featureBand="${parts[2]:0:1}" + fi + + case "$globaljson_roll_forward" in + disable|major|minor|feature|patch) + version="$globaljson_version"; + ;; + + latestMajor) + version="latest" + channel="STS" # TODO this doesn't do what it should https://github.com/dotnet/install-scripts/issues/418 + ;; + + latestMinor) + version="latest" + channel="${major}.x" # TODO this doesn't work + ;; + + latestFeature) + version="latest" + channel="${major}.${minor}" + ;; + + latestPatch) + version="latest" + channel="${major}.${minor}.${featureBand}xx" + ;; + + *) + say_err "Unsupported rollForward option: $globaljson_roll_forward" + return 1 + ;; + esac + fi +} + # args: # azure_feed - $1 # channel - $2 # normalized_architecture - $3 # version - $4 -# json_file - $5 get_specific_version_from_version() { eval $invocation @@ -689,23 +742,15 @@ get_specific_version_from_version() { local channel="$2" local normalized_architecture="$3" local version="$(to_lowercase "$4")" - local json_file="$5" - - if [ -z "$json_file" ]; then - if [[ "$version" == "latest" ]]; then - local version_info - version_info="$(get_version_from_latestversion_file "$azure_feed" "$channel" "$normalized_architecture" false)" || return 1 - say_verbose "get_specific_version_from_version: version_info=$version_info" - echo "$version_info" | get_version_from_latestversion_file_content - return 0 - else - echo "$version" - return 0 - fi - else + + if [[ "$version" == "latest" ]]; then local version_info - version_info="$(parse_globaljson_file_for_version "$json_file")" || return 1 - echo "$version_info" + version_info="$(get_version_from_latestversion_file "$azure_feed" "$channel" "$normalized_architecture" false)" || return 1 + say_verbose "get_specific_version_from_version: version_info=$version_info" + echo "$version_info" | get_version_from_latestversion_file_content + return 0 + else + echo "$version" return 0 fi } @@ -1361,8 +1406,8 @@ generate_akams_links() { return 1 fi - if [[ -n "$json_file" || "$normalized_version" != "latest" ]]; then - # aka.ms links are not needed when exact version is specified via command or json file + if [[ "$normalized_version" != "latest" ]]; then + # aka.ms links are not needed when exact version is specified via command return fi @@ -1416,7 +1461,7 @@ generate_regular_links() { local feed="$1" local valid_legacy_download_link=true - specific_version=$(get_specific_version_from_version "$feed" "$channel" "$normalized_architecture" "$version" "$json_file") || specific_version='0' + specific_version=$(get_specific_version_from_version "$feed" "$channel" "$normalized_architecture" "$version") || specific_version='0' if [[ "$specific_version" == '0' ]]; then say_verbose "Failed to resolve the specific version number using feed '$feed'" @@ -1503,6 +1548,7 @@ calculate_vars() { say_verbose "Normalized product: '$normalized_product'." install_root="$(resolve_installation_path "$install_dir")" say_verbose "InstallRoot: '$install_root'." + say_verbose "Version: '$version'." normalized_architecture="$(get_normalized_architecture_for_specific_sdk_version "$version" "$normalized_channel" "$normalized_architecture")" @@ -1799,7 +1845,6 @@ do echo " -SkipNonVersionedFiles" echo " --no-cdn,-NoCdn Disable downloading from the Azure CDN, and use the uncached feed directly." echo " --jsonfile Determines the SDK version from a user specified global.json file." - echo " Note: global.json must have a value for 'SDK:Version'" echo " --keep-zip,-KeepZip If set, downloaded file is kept." echo " --zip-path, -ZipPath If set, downloaded file is stored at the specified path." echo " -?,--?,-h,--help,-Help Shows this help message" @@ -1836,6 +1881,7 @@ if [ "$internal" = true ] && [ -z "$(echo $feed_credential)" ]; then fi check_min_reqs +process_globaljson_file calculate_vars # generate_regular_links call below will 'exit' if the determined version is already installed. generate_download_links diff --git a/tests/Install-Scripts.Test/Assets/GlobalJson/Disable.json b/tests/Install-Scripts.Test/Assets/GlobalJson/Disable.json new file mode 100644 index 0000000000..2244195a20 --- /dev/null +++ b/tests/Install-Scripts.Test/Assets/GlobalJson/Disable.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.100", + "rollForward": "disable" + } +} diff --git a/tests/Install-Scripts.Test/Assets/GlobalJson/LatestFeature.json b/tests/Install-Scripts.Test/Assets/GlobalJson/LatestFeature.json new file mode 100644 index 0000000000..391ba3c2a3 --- /dev/null +++ b/tests/Install-Scripts.Test/Assets/GlobalJson/LatestFeature.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.100", + "rollForward": "latestFeature" + } +} diff --git a/tests/Install-Scripts.Test/Assets/GlobalJson/LatestMajor.json b/tests/Install-Scripts.Test/Assets/GlobalJson/LatestMajor.json new file mode 100644 index 0000000000..d07970ac26 --- /dev/null +++ b/tests/Install-Scripts.Test/Assets/GlobalJson/LatestMajor.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.100", + "rollForward": "latestMajor" + } +} diff --git a/tests/Install-Scripts.Test/Assets/GlobalJson/LatestMinor.json b/tests/Install-Scripts.Test/Assets/GlobalJson/LatestMinor.json new file mode 100644 index 0000000000..c19a2e057c --- /dev/null +++ b/tests/Install-Scripts.Test/Assets/GlobalJson/LatestMinor.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.100", + "rollForward": "latestMinor" + } +} diff --git a/tests/Install-Scripts.Test/Assets/GlobalJson/LatestPatch.json b/tests/Install-Scripts.Test/Assets/GlobalJson/LatestPatch.json new file mode 100644 index 0000000000..b75deba61a --- /dev/null +++ b/tests/Install-Scripts.Test/Assets/GlobalJson/LatestPatch.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.100", + "rollForward": "latestPatch" + } +} diff --git a/tests/Install-Scripts.Test/Assets/GlobalJson/NoFields.json b/tests/Install-Scripts.Test/Assets/GlobalJson/NoFields.json new file mode 100644 index 0000000000..9823519c74 --- /dev/null +++ b/tests/Install-Scripts.Test/Assets/GlobalJson/NoFields.json @@ -0,0 +1,4 @@ +{ + "sdk": { + } +} diff --git a/tests/Install-Scripts.Test/Assets/GlobalJson/VersionOnly.json b/tests/Install-Scripts.Test/Assets/GlobalJson/VersionOnly.json new file mode 100644 index 0000000000..5ce8495514 --- /dev/null +++ b/tests/Install-Scripts.Test/Assets/GlobalJson/VersionOnly.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "8.0.100" + } +} diff --git a/tests/Install-Scripts.Test/GivenThatIWantToGetTheSdkLinksFromAScript.cs b/tests/Install-Scripts.Test/GivenThatIWantToGetTheSdkLinksFromAScript.cs index 1997e59685..3732686aac 100644 --- a/tests/Install-Scripts.Test/GivenThatIWantToGetTheSdkLinksFromAScript.cs +++ b/tests/Install-Scripts.Test/GivenThatIWantToGetTheSdkLinksFromAScript.cs @@ -44,6 +44,32 @@ public void WhenJsonFileIsPassedToInstallScripts(string filename) commandResult.Should().HaveStdOutMatching(@"URL\s#0\s-\s(legacy|primary|aka\.ms):\shttps://"); } + [Theory] + [InlineData("NoFields.json", "STS")] + [InlineData("VersionOnly.json", "8.0.1xx")] + [InlineData("LatestPatch.json", "8.0.1xx")] + [InlineData("LatestFeature.json", "8.0")] + [InlineData("LatestMinor.json", "8.x")] + [InlineData("LatestMajor.json", "STS")] + [InlineData("Disable.json", "LTS", "8.0.100")] + public void WhenGlobalJsonFileIsPassedToInstallScripts(string filename, string channel, string version = "latest") + { + var installationScriptTestsJsonFile = Path.Combine(Environment.CurrentDirectory, "Assets", "GlobalJson", filename); + + var args = new List { "-verbose", "-dryrun", "-jsonfile", installationScriptTestsJsonFile }; + + var commandResult = CreateInstallCommand(args) + .CaptureStdOut() + .CaptureStdErr() + .Execute(); + + commandResult.Should().Pass(); + commandResult.Should().NotHaveStdOutContaining("dryrun"); + commandResult.Should().NotHaveStdOutContaining("jsonfile"); + commandResult.Should().HaveStdOutContaining($"Normalized channel: '{channel}'."); + commandResult.Should().HaveStdOutContaining($"Version: '{version}'."); + } + [Theory] [InlineData("-nopath", "")] [InlineData("-verbose", "")] diff --git a/tests/Install-Scripts.Test/Install-Scripts.Test.csproj b/tests/Install-Scripts.Test/Install-Scripts.Test.csproj index 6e12f37241..7154f68d28 100644 --- a/tests/Install-Scripts.Test/Install-Scripts.Test.csproj +++ b/tests/Install-Scripts.Test/Install-Scripts.Test.csproj @@ -27,6 +27,9 @@ Always + + Always +