Question

I have setup a custom NuGet server for my company. It all works great - I can publish, view packages, etc.

My only concern is that I can publish a package with the same name and version number, thereby overwriting the existing package. This is not ideal and I would like the NuGet server to return an error if a package with the same name and version already exists.

Any clues on how I can accomplish this?

Was it helpful?

Solution

I would also greatly appreciate disallowing to overwrite existing packages. However, it does not seem to be possible using the NuGet server out of the box. A similar feature request has been closed about two years ago.

But looking at the source code opens some options. Have a look at the CreatePackage()-method. It uses an IPackageAuthenticationService to check if the specified package is allowed to be added (only checks the API Key) and a IServerPackageRepository to actually add the package:

// Make sure they can access this package
if (Authenticate(context, apiKey, package.Id))
{
    _serverRepository.AddPackage(package);
    WriteStatus(context, HttpStatusCode.Created, "");
}

Both are passed in using constructor injection so it is easy to extend the behaviour by passing custom implementations (Modify the Ninject bindings for that).

At first sight i would go for a custom IServerPackageRepository. The current implementation uses IFileSystem.AddFile(...) to add the package. You can use IFileSystem.FileExists(...) to check whether the package already exists.

From a continuous integration perspective it makes totally sense to disallow overwriting an existing package since NuGet follows Semantic Versioning. Thus, a new build should incorporate a bugfix, a new feature or a breaking change. I would choose to allow overwriting snapshots/pre-releases, however.

Update: It seems v2.8 will have an option allowOverrideExistingPackageOnPush which defaults to true for backwards compatibility. It has been comitted with 1e7345624d. I realized that after forking. Seems i was too late again ;-)

OTHER TIPS

I ran into the same problem. I run my own SymbolSource server. I decided to maintain a log of published packages. Before I publish a package, I can check the log to see if it has already been published and then not publish it. This is all done in an MS-DOS batch file. See below.

@echo off

rem Requires that the Visual Studio directory is in your 
rem PATH environment variable. It will be something like:
rem C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE

rem API key for publishing to SymbolSource server
set apiKey=<<<GUID>>>

rem URL of the SymbolSource web app
set lib=http://<<<address>>>

rem Path to a simple text file on a file share - which happens to be the 
rem same place that the SymbolSource server web app is published.
set log=\\<<<path>>>\publish_log.txt

rem Path to the Visual Studio solution that contains the projects to be published.
set sln=..\<<<solution name>>>.sln

rem Build all projects in the solution.
devenv %sln% /rebuild Debug

rem Delete packages produced during last run.
del *.nupkg

rem Each line in projects.txt is a path to a .csproj file that we want to 
rem create a nuget package for. Each .csproj file has a corresponding .nuspec 
rem file that lives in the same directory.
for /F %%i in (projects.txt) do nuget.exe pack %%i -IncludeReferencedProjects -Prop Configuration=Debug -Symbols

rem Delete any local packages that have already been published.
for /F %%i in (%log%) do if exist %%i del %%i

for %%F in (".\*.symbols.nupkg") do nuget push %%~nxF %apiKey% -source %lib%

rem Log information about published packages so, in the next run,
rem we can tell what has been published and what has not.
for %%F in (".\*.symbols.nupkg") do echo %%~nxF >> %log%

I wrote a PowerShell script that deletes the existing package version but only if it matches the version which I wish to push:

param (
    [string]$buildconfiguration = "Debug"
 )

function Update-Package ([string]$package,[string]$version,[string]$path)
{
    dotnet nuget delete $package $version -s https://<mynugetserver>/nuget -k <my access code if used> --non-interactive
    dotnet nuget push "$path\bin\$buildconfiguration\$package.$version.nupkg" -s https://<mynugetserver>/nuget -k <my access code if used>
}

Update-Package -package "My.Package" -version "2.2.0" -path "MyPackage"

The major drawback to this is the possibility of a change to the package while forgetting to update the package version in the NuSpec or vsproj package section as well as forgetting to change the version number in the script file.

I would never use this technique on a public NuGet server.

I also use a version of this file that doesn't push, just deletes which is used as a PowerShell task in my Azure DevOps (VSTS) build.

I know that NuGet says it will list versions available, but I didn't really feel like writing a script which could read back the result of a list to determine if the version number that I'm building already exists.

The one good thing is that if the new version number doesn't exist, the CLI call to delete doesn't complain too much and no package version is affected.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top