diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index 5636b5ff9b7..eb134b15753 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -719,7 +719,17 @@ function InitializeToolset() {
$downloadArgs += "--configfile"
$downloadArgs += $nugetConfig
}
- DotNet @downloadArgs
+
+ # 'dotnet package download' fails outright if any source in the repo's NuGet.config is
+ # unavailable (for example a transport feed that was decommissioned after a release). The
+ # Arcade SDK is always published to the public dotnet-eng feed, so if the config-driven
+ # download fails, retry once against that feed directly (which ignores the other sources)
+ # before giving up, so a single dead source doesn't block the build.
+ $downloadExitCode = DotNet -ignoreFailure @downloadArgs
+ if ($downloadExitCode) {
+ Write-Host "Restoring the Arcade SDK from the configured sources failed; retrying from the public dotnet-eng feed."
+ DotNet @downloadArgs --source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json"
+ }
$packageDir = Join-Path $nugetPackageCachePath (Join-Path 'microsoft.dotnet.arcade.sdk' $toolsetVersion)
$packageToolsetDir = Join-Path $packageDir 'toolset'
@@ -848,7 +858,7 @@ function MSBuild() {
# Executes a dotnet command with arguments passed to the function.
# Terminates the script if the command fails.
#
-function DotNet() {
+function DotNet([switch]$ignoreFailure) {
$dotnetRoot = InitializeDotNetCli -install:$restore
$dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet')
@@ -867,6 +877,12 @@ function DotNet() {
$exitCode = Exec-Process $dotnetPath $cmdArgs
if ($exitCode -ne 0) {
+ # When -ignoreFailure is set, return the exit code to the caller so it can implement
+ # its own fallback logic instead of terminating the script.
+ if ($ignoreFailure) {
+ return $exitCode
+ }
+
Write-Host "dotnet command failed with exit code $exitCode. Check errors above." -ForegroundColor Red
if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR) {
diff --git a/eng/common/tools.sh b/eng/common/tools.sh
index 3d09adab28b..502589a61ee 100755
--- a/eng/common/tools.sh
+++ b/eng/common/tools.sh
@@ -452,7 +452,16 @@ function InitializeToolset {
if [[ -n "$nuget_config" ]]; then
download_args+=("--configfile" "$nuget_config")
fi
- DotNet "${download_args[@]}"
+
+ # 'dotnet package download' fails outright if any source in the repo's NuGet.config is
+ # unavailable (for example a transport feed that was decommissioned after a release). The
+ # Arcade SDK is always published to the public dotnet-eng feed, so if the config-driven
+ # download fails, retry once against that feed directly (which ignores the other sources)
+ # before giving up, so a single dead source doesn't block the build.
+ if ! DotNet true "${download_args[@]}"; then
+ echo "Restoring the Arcade SDK from the configured sources failed; retrying from the public dotnet-eng feed."
+ DotNet "${download_args[@]}" --source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json"
+ fi
local package_dir="$_InitializeNuGetPackageCachePath/microsoft.dotnet.arcade.sdk/$toolset_version"
@@ -491,6 +500,15 @@ function StopProcesses {
}
function DotNet {
+ # When the first argument is 'true' or 'false' it controls the exit behavior on failure:
+ # 'true' returns the dotnet exit code to the caller (so it can implement its own fallback),
+ # while the default terminates the script. Any other first argument is treated as a dotnet argument.
+ local ignore_failure=false
+ if [[ "$1" == 'true' || "$1" == 'false' ]]; then
+ ignore_failure="$1"
+ shift
+ fi
+
InitializeDotNetCli $restore
local dotnet_path="$_InitializeDotNetCli/dotnet"
@@ -499,6 +517,11 @@ function DotNet {
"$dotnet_path" "$@" || {
local exit_code=$?
+
+ if [[ "$ignore_failure" == true ]]; then
+ return $exit_code
+ fi
+
echo "dotnet command failed with exit code $exit_code. Check errors above."
if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$from_vmr" != true ]]; then
diff --git a/src/Microsoft.DotNet.Arcade.Sdk/tools/ProjectDefaults.props b/src/Microsoft.DotNet.Arcade.Sdk/tools/ProjectDefaults.props
index 11de5f8aabe..1d06487c851 100644
--- a/src/Microsoft.DotNet.Arcade.Sdk/tools/ProjectDefaults.props
+++ b/src/Microsoft.DotNet.Arcade.Sdk/tools/ProjectDefaults.props
@@ -71,6 +71,14 @@
{TargetFrameworkDirectory};
{RawFileName};
+
+
+ true