Search code examples
.netnugetnuget-packagecicdnuget-package-restore

Clash between development and production NuGet config files


My .net project is built locally by me during development, and remotely by my ci/cd server.

The project has project-level config in myproject/nuget.config. It is used by my ci/cd server, which provides some environment variables:

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="custom" value="https://example.com/api/nuget/index.json" />
  </packageSources>

  <packageSourceCredentials>
    <custom>
      <!-- env vars provided by pipeline -->
      <add key="Username" value="%USERNAME%" />
      <add key="ClearTextPassword" value="%API_KEY%" />
    </custom>
  </packageSourceCredentials>

  <packageSourceMapping>
    <!-- get other packages from nuget server -->
    <packageSource key="nuget.org">
      <package pattern="*" />
    </packageSource>
    <!-- get own packages from private server -->
    <packageSource key="custom">
      <package pattern="MyOrg.*" />
    </packageSource>
  </packageSourceMapping>

</configuration>

My local machine has user-level config in ~/.nuget/Nuget/Nuget.Config, which is the same, except for different credentials:

  <packageSourceCredentials>
    <custom>
      <add key="Username" value="my_username" />
      <add key="ClearTextPassword" value="my_personal_api_key" />
    </custom>
  </packageSourceCredentials>

That works in the ci/cd server, i.e. in production.

But locally (i.e. in development), I get 401/Unauthorized errors when running dotnet restore (etc.) - because the project-level config (which requires extra env vars) overwrites the user-level config. (I have many other repos with the same issue, so I don't want to export env vars or add stuff to my .bashrc: it's messy, I don't want to do that.)

This seems to be the opposite to how it's typically done, where there is some "default" checked into source control, and it can be customised during development (with overriding config files) and production (with config files or env vars).

How do I do this?

(Cross-posted to repo.)


Solution

  • Project config in nuget.config:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    
      <packageSources>
        <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
        <add key="custom" value="https://example.com/api/nuget/index.json" />
      </packageSources>
    
      <packageSourceCredentials>
        <!-- env vars provided by ci -->
        <custom>
          <add key="Username" value="%USERNAME%" />
          <add key="ClearTextPassword" value="%API_KEY%" />
        </custom>
      </packageSourceCredentials>
    
    </configuration>
    

    User config in ~/.nuget/NuGet/NuGet.Config:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    
      <!-- add this -->
      <disabledPackageSources>
        <add key="custom" value="true" />
      </disabledPackageSources>
    
      <packageSources>
        <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
        <!-- add this -->
        <add key="custom-dev" value="https://example.com/api/nuget/index.json" />
      </packageSources>
    
      <packageSourceCredentials>
        <!-- add this -->
        <custom-dev>
          <add key="Username" value="username" />
          <add key="ClearTextPassword" value="password" />
        </custom>
      </packageSourceCredentials>
    
    </configuration>
    

    The trick is in the user config file: one must disable the package source, and then readd it under a different name and with different credentials.