使用命令行检查nuget包是否存在

Check if nuget package exists using command line

如何在 visual studio 之外使用 powershell 或命令行检查指定包源(nuget 服务器)中是否存在特定版本的 nuget 包?

场景:

我有私人 NuGet 服务器,我想在其中推送我自己的包。我在 TFS 构建期间自动创建了包。我想念的是检查包之前是否已上传并发布到 NuGet 服务器。

如果您使用 PowerShell 5.0,它内置了 PackageManagement cmdlet。您可以使用它们来发现和安装各种包。这里有一个参考[​​=10=]

您还可以通过浏览器(或任何可以发送HTTP-GET 请求的工具)通过获取包描述来检查服务器上是否存在该包。例如,我们收到包 System.Collections.Immutable and we get 404 status code for non existing package 的描述。这些网址区分大小写。

我不知道您的私有 NuGet 服务器是否实现了与 nuget.org 相同的服务器 Api,但我假设是这样。 https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource 描述了 API 可用于检查包是否已发布并获取其版本。与 nuget list 命令不同,它通过包 ID 执行精确匹配。

例如,假设您想知道包 AjaxMin 是否已发布。执行 nuget list ajaxmin 不是很有帮助:

C:\> nuget.exe list ajaxmin
BundleTransformer.MicrosoftAjax 1.10.0
Bundler.NET 1.5.7
CodeSlice.Web.Baler.Extensions.AjaxMinifier 0.2.0
combres 2.3.0.4
combres.log4net 2.3.0.4
combres.mvc 2.3.0.4
Delegate.AjaxMinBuilder 1.1.2
DotLessMinification 0.42.1
AjaxMin 5.14.5506.26202
NUglify 1.5.1
NUglify 1.5.13
Pvc.Ajaxmin 0.0.2
RequestReduce 1.8.76
WebMarkupMin.Core 2.6.0
WebMarkupMin.MsAjax 2.6.0
Web.Optimization.Bundles.AjaxMin 0.0.8
Web.Optimization.Bundles.YUI 0.0.8
C:\>

是的,您可以过滤输出,但我发现它工作量太大。您可以使用服务器 Api 更加精确。观察:

C:\> $url = 'https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/index.json'
C:\> $res = Invoke-RestMethod $url
C:\> $res.items.items.catalogEntry.version
4.12.4057.21792
4.13.4076.28499
4.19.4141.18463
4.30.4295.16112
4.36.4337.24224
4.37.4345.34101
4.39.4362.37207
4.40.4369.35534
4.41.4378.21434
4.42.4387.23950
4.43.4392.20083
4.44.4396.18853
4.45.4416.14249
4.46.4422.26284
4.47.4452.34008
4.48.4489.28432
4.49.4503.16524
4.50.4504.34801
4.51.4507.18296
4.52.4518.14738
4.53.4526.21623
4.54.4533.37029
4.55.4545.19776
4.56.4560.33404
4.58.4566.27257
4.59.4576.13504
4.60.4609.17023
4.61.4617.31171
4.62.4618.15628
4.63.4630.14654
4.64.4630.17932
4.66.4633.35991
4.67.4639.17289
4.68.4663.23906
4.69.4665.24361
4.70.4668.12892
4.71.4679.26350
4.72.4679.35523
4.73.4685.17669
4.74.4698.25434
4.75.4713.17606
4.76.4714.20550
4.77.4723.25304
4.78.4724.23869
4.80.4763.16598
4.81.4769.14860
4.82.4784.14537
4.83.4785.14876
4.84.4790.14417
4.85.4828.21154
4.86.4836.34222
4.89.4861.30057
4.90.4864.13402
4.91.4875.26882
4.92.4896.13361
4.93.4902.12739
4.94.4916.15482
4.95.4924.12392
4.96.4941.15389
4.97.4951.28483
5.0.5007.14585
5.1.5007.23730
5.2.5021.15814
5.3.5068.16463
5.4.5085.25629
5.5.5091.22839
5.6.5100.19204
5.7.5124.21499
5.8.5172.27710
5.9.5229.26438
5.10.5260.16959
5.11.5295.12309
5.12.5436.22734
5.13.5463.15282
5.14.5506.26202
C:\>

我们得到了包的所有版本。现在,如果您想检查某个事先已知的版本是否已发布 - 您可以:

C:\> $url = 'https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/5.14.5506.26202.json'
C:\> $res = Invoke-RestMethod $url
C:\> $res


@id            : https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/5.14.5506.26202.json
@type          : {Package, http://schema.nuget.org/catalog#Permalink}
catalogEntry   : https://api.nuget.org/v3/catalog0/data/2018.10.06.23.54.33/ajaxmin.5.14.5506.26202.json
listed         : True
packageContent : https://api.nuget.org/v3-flatcontainer/ajaxmin/5.14.5506.26202/ajaxmin.5.14.5506.26202.nupkg
published      : 2015-01-28T22:45:45.577+00:00
registration   : https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/index.json
@context       : @{@vocab=http://schema.nuget.org/schema#; xsd=http://www.w3.org/2001/XMLSchema#; catalogEntry=; registration=; packageContent=; published=}



C:\>

现在如果我们请求一个不存在的版本会怎样?我们开始吧:

C:\> $url = 'https://api.nuget.org/v3/registration3-gz-semver2/ajaxmin/5.14.5506.26196.json'
C:\> $res = Invoke-RestMethod $url
Invoke-RestMethod : BlobNotFoundThe specified blob does not exist.
RequestId:cd1579e6-801e-007d-5eba-64ac9d000000
Time:2019-09-06T13:53:54.6832811Z
At line:1 char:8
+ $res = Invoke-RestMethod $url
+        ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
C:\>

请求一个不存在的包如何?让我们搜索ajaxmi(没有'n'):

C:\> $url = 'https://api.nuget.org/v3/registration3-gz-semver2/ajaxmi/index.json'
C:\> $res = Invoke-RestMethod $url
Invoke-RestMethod : BlobNotFoundThe specified blob does not exist.
RequestId:23d96274-b01e-0018-3bba-641dc0000000
Time:2019-09-06T13:55:35.5288968Z
At line:1 char:8
+ $res = Invoke-RestMethod $url
+        ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
C:\>

您可以很容易地从 PowerShell 调用此 CMD 脚本,下面有示例。您可以通过 $LastExitCode 来确定如何进行,0 意味着您可以发布:

check_nupkg.bat

@echo off
SetLocal EnableDelayedExpansion EnableExtensions
pushd "%~dp0"

set "pkg_name=%~1"
set "pkg_version=%~2"

call nuget list %pkg_name% -AllVersions -Prerelease|findstr /i /r /c:"^%pkg_name% %pkg_version%$" -N>nul 2>&1

if not "%errorlevel%"=="0" (
    echo This package can be published
    exit /b 0
) else (
    echo This package has already been published.
    exit /b 1
)

C:\stuff>.\check_nupkg.bat "lolspeak" "1.0.0"

This package has already been published.

C:\stuff>check_nupkg.bat "lolspeak" "11.0.0"

This package can be published

我使用的基于其他一些答案的方法最近失效了,因此我想更全面地描述我们如何着手发现 URL 并进行实际验证。

NuGet.org 提供了一个 service index,它提供了按类型索引的基础 URL 列表。此服务索引可在 https://api.nuget.org/v3/index.json.

获得

它returns数据采用以下结构(为简洁起见被截断):

PS> Invoke-RESTmethod -uri 'https://api.nuget.org/v3/index.json'

version resources
------- ---------
3.0.0   {@{@id=https://azuresearch-usnc.nuget.org/query; ... 

换句话说,服务索引提供了一组可用的 API 版本和一组相应的资源(即 endpoints/queryable APIs)。这些资源对应于 URLs,它们具有非常具体的功能并且应该全部记录下来。在撰写本文时,我们只有版本 3.0.0 作为一个选项,所以让我们检查这些资源,我们可以看到这些端点是什么样的,将输出过滤到与 package registration and metadata:

相关的端点
PS> (Invoke-RESTmethod -uri 'https://api.nuget.org/v3/index.json' | `
    ? { $_.version -eq '3.0.0' }).resources | `
    ? { $_.'@type' -like '*Registration*' } | `
    select-object -Property '@id','@type'

@id                                                @type
---                                                -----
https://api.nuget.org/v3/registration4/            RegistrationsBaseUrl
https://api.nuget.org/v3/registration4/            RegistrationsBaseUrl/3.0.0-rc
https://api.nuget.org/v3/registration4/            RegistrationsBaseUrl/3.0.0-beta
https://api.nuget.org/v3/registration4-gz/         RegistrationsBaseUrl/3.4.0
https://api.nuget.org/v3/registration4-gz-semver2/ RegistrationsBaseUrl/3.6.0
https://api.nuget.org/v3/registration4-gz-semver2/ RegistrationsBaseUrl/Versioned

我在输出中留下的一个有用 属性 是 comment 属性 存在,它提供了对端点的有用描述。例如,对于 RegistrationsBaseUrl 我们有以下注释:

Base URL of Azure storage where NuGet package registration info is stored

从上面可以看出,我们的基础 URL 将是左上角 URL 之一。正在检查 the docs@type RegistrationsBaseUrl:

These registrations are not compressed (meaning they use an implied Content-Encoding: identity). SemVer 2.0.0 packages are excluded from this hive.

根据我的需要,我想包含 SemVer 2.0.0,所以我想使用不同的端点。再次检查 the docs:

These registrations are compressed using Content-Encoding: gzip. SemVer 2.0.0 packages are included in this hive.

因此,根据之前的查询结果,我想要以下 url:

https://api.nuget.org/v3/registration4-gz-semver2/

通过阅读文档,我们了解到我们对 Registration Page 我们正在尝试查询的包感兴趣。 URL 语法为:

$BASEURL/<PackageName>/<PackageVersion>.json

使用Newtonsoft.Json作为示例包并展开:

https://api.nuget.org/v3/registration4-gz-semver2/newtonsoft.json/12.0.3.json

现在我们知道了如何获取 URL,以及它会随时间变化并且应该动态检索这一事实,让我们编写一些 PowerShell 来确定 NuGet 包是否已发布到给出的来源:

param (
  [Parameter(Mandatory=$true)] 
  [string]$Id,
  [Parameter(Mandatory=$true)] 
  [string]$Version,
  [Parameter(Mandatory=$false)] 
  [string]$source = "https://api.nuget.org/v3/index.json"
)

$resources = (invoke-restmethod -uri $source | ? { $_.version -eq '3.0.0' }).resources
$baseUrl = ($resources | ? { $_.'@type' -eq 'RegistrationsBaseUrl/3.6.0' }).'@id'

try
{
  $packageName = $Id.ToLowerInvariant()
  $packageVersion = $Version.ToLower()

  # Use supported HEAD method for performance
  Invoke-RestMethod -uri "$($baseUrl)$($packageName)/$($packageVersion).json" -Method HEAD > $null 2>&1
  # method didn't throw so the NuGet package exists
  $true
}
catch
{
  # method threw, so the NuGet package doesn't exist
  $false
}

它的用法如下所示:

PS>  Get-NuGetPackageExists.ps1 -Id Newtonsoft.Json -Version 10.0.2
True