Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/scripts/resolve-nuget-config.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<#
.SYNOPSIS
Creates a local nuget.config for development, picking the right template based
on whether the machine can reach the public nuget.org feed.

.DESCRIPTION
Some managed devices (e.g. corporate networks with restricted egress) block
direct TLS access to api.nuget.org and instead require routing package
restore through an internal proxy feed. This script probes nuget.org and
copies nuget.config.template (public) if it's reachable, or
nuget.config.managed.template (proxy) if it's not, so a fresh clone builds
successfully regardless of the network the developer is on.

Both templates map the same *Foundry* pattern to the ORT feed, which is
required regardless of network: it's the only feed hosting the exact
Microsoft.ML.OnnxRuntime.Foundry version needed by
Microsoft.AI.Foundry.Local.Core.WinML (nuget.org only has a differently
versioned build, which triggers a NU1603 warning that fails the build
given this repo's TreatWarningsAsErrors=true setting).

nuget.config is gitignored (see .gitignore) and only ever generated locally;
it is never committed. If nuget.config already exists, this script does
nothing, so any manual override a developer has made is preserved.

.PARAMETER RepoRoot
Root of the repository containing nuget.config.template / nuget.config.managed.template.
Defaults to the directory this script lives in, two levels up.
#>
param(
[string]$RepoRoot = (Resolve-Path "$PSScriptRoot\..\..").Path
)

$configPath = Join-Path $RepoRoot "nuget.config"
$publicTemplatePath = Join-Path $RepoRoot "nuget.config.template"
$managedTemplatePath = Join-Path $RepoRoot "nuget.config.managed.template"

if (Test-Path $configPath) {
# Respect any existing local config (manual override or already generated).
exit 0
}

if (-not (Test-Path $publicTemplatePath)) {
Write-Warning "nuget.config.template not found at $publicTemplatePath; skipping nuget.config generation."
exit 0
}

$publicNuGetReachable = $false
try {
Invoke-WebRequest -Uri "https://api.nuget.org/v3/index.json" -UseBasicParsing -TimeoutSec 5 | Out-Null
$publicNuGetReachable = $true
} catch {
$publicNuGetReachable = $false
}

if ($publicNuGetReachable) {
Copy-Item -Path $publicTemplatePath -Destination $configPath
Write-Host "Created nuget.config from nuget.config.template (nuget.org reachable)."
} elseif (Test-Path $managedTemplatePath) {
Copy-Item -Path $managedTemplatePath -Destination $configPath
Write-Host "Created nuget.config from nuget.config.managed.template (nuget.org unreachable; using internal proxy feed)."
} else {
# No proxy template available; fall back to the public template so restore
# at least attempts nuget.org directly and surfaces a clear network error.
Copy-Item -Path $publicTemplatePath -Destination $configPath
Write-Warning "nuget.org unreachable and nuget.config.managed.template not found; falling back to nuget.config.template."
}
24 changes: 13 additions & 11 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
<PackageReference Include="StyleCop.Analyzers" PrivateAssets="All" />
</ItemGroup>

<!-- Auto-create nuget.config from template for local development -->
<!--
Auto-create nuget.config from template for local development. This probes
whether nuget.org is directly reachable and picks the public or the
internal-proxy template accordingly, so a fresh clone restores correctly
whether or not the developer is on a managed device with restricted
network egress. See .github/scripts/resolve-nuget-config.ps1.
-->
<Target Name="EnsureNuGetConfig" BeforeTargets="CollectPackageReferences;Restore">
<PropertyGroup>
<NuGetConfigTemplate>$(MSBuildThisFileDirectory)nuget.config.template</NuGetConfigTemplate>
<NuGetConfigTarget>$(MSBuildThisFileDirectory)nuget.config</NuGetConfigTarget>
<ResolveNuGetConfigScript>$(MSBuildThisFileDirectory).github\scripts\resolve-nuget-config.ps1</ResolveNuGetConfigScript>
</PropertyGroup>
<Message Text="Checking for nuget.config..." Importance="low" />
<Copy SourceFiles="$(NuGetConfigTemplate)"
DestinationFiles="$(NuGetConfigTarget)"
Condition="Exists('$(NuGetConfigTemplate)') And !Exists('$(NuGetConfigTarget)')"
SkipUnchangedFiles="true">
<Output TaskParameter="CopiedFiles" ItemName="NuGetConfigCreated" />
</Copy>
<Message Text="Created nuget.config from template for local development"
Importance="high"
Condition="'@(NuGetConfigCreated)' != ''" />
<Exec Command="powershell.exe -NoProfile -ExecutionPolicy Bypass -File &quot;$(ResolveNuGetConfigScript)&quot; -RepoRoot &quot;$(MSBuildThisFileDirectory.TrimEnd('\'))&quot;"
Condition="Exists('$(ResolveNuGetConfigScript)') And !Exists('$(NuGetConfigTarget)') And '$(OS)' == 'Windows_NT'" />
<Message Text="Created nuget.config for local development"
Importance="high"
Condition="Exists('$(NuGetConfigTarget)')" />
</Target>
</Project>
27 changes: 27 additions & 0 deletions nuget.config.managed.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Used for local development on managed devices where direct access to nuget.org
is blocked by network policy. Routes package restore through the organization's
NuGet proxy feed instead. See .github/scripts/resolve-nuget-config.ps1, which
selects this template automatically when api.nuget.org is unreachable.

The ORT feed mapping is kept identical to nuget.config.template, and for the
same reason: it supplies the exact Microsoft.ML.OnnxRuntime.Foundry build that
Microsoft.AI.Foundry.Local.Core.WinML requires. The similarly-named build on
nuget.org is not a drop-in substitute - see nuget.config.template for details.
-->
<configuration>
<packageSources>
<clear />
<add key="azure-default" value="https://packagefeedproxy.microsoft.io/nuget/v3/index.json" protocolVersion="3" />
<add key="ORT" value="https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/ORT/nuget/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="azure-default">
<package pattern="*" />
</packageSource>
<packageSource key="ORT">
<package pattern="*Foundry*" />
</packageSource>
</packageSourceMapping>
</configuration>
26 changes: 26 additions & 0 deletions nuget.config.template
Original file line number Diff line number Diff line change
@@ -1,4 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Do not remove the ORT feed. It is not a convenience mirror of nuget.org: the
Microsoft.ML.OnnxRuntime.Foundry builds published to the two feeds are
materially different packages.

Microsoft.AI.Foundry.Local.Core.WinML (pulled in transitively by
Microsoft.AI.Foundry.Local.WinML) requires Microsoft.ML.OnnxRuntime.Foundry
1.23.2. That exact version is published only to the ORT feed. nuget.org
publishes 1.23.2.3 instead, which NuGet will happily resolve as a compatible
minimum-version match - but it breaks the build in three separate ways:

1. NU1603, because the requested version was not found. Directory.Build.props
sets TreatWarningsAsErrors for Release, so this fails the build outright.
2. The nuget.org build takes an extra dependency on
Microsoft.ML.OnnxRuntime.Gpu.Linux, which the ORT build does not. MSIX
packaging then fails with MSB3030 trying to copy a win-arm64 native
onnxruntime.dll out of a Linux-only package.
3. It ships its own runtimes/win-*/native/onnxruntime.dll, which collides
with the copy from Microsoft.Windows.AI.MachineLearning and fails MSIX
packaging with APPX1101 (duplicate payload path).

Pinning Microsoft.ML.OnnxRuntime.Foundry to 1.23.2.3 explicitly resolves (1)
but not (2) or (3). Newer versions on nuget.org (up to at least 1.26.0) still
carry the Gpu.Linux dependency, so upgrading Microsoft.AI.Foundry.Local.WinML
would also require reworking AIDevGallery/ExcludeExtraLibs.props.
-->
<configuration>
<packageSources>
<clear />
Expand Down
Loading