首页 > 解决方案 > 由于未经授权的错误,无法使用 dotnet CLI 将 nuGet 包推送到 GitLab

问题描述

GitLab 现在支持 nuget 公共和私人提要存储库。我有一个公共项目(例如:https ://gitlab.com/sunnyatticsoftware/sasw-test-support)我为我的用户创建了一个访问令牌apiwrite_repository(例如:AAABBBCCCDDD)

我在 CI/CD: 中创建了一个组SASW_API_ACCESS_TOKEN变量AAABBBCCCDDD。一切正常。

然后我创建多阶段 CI/CD 脚本来构建、打包和发布。尝试使用以下内容发布 nuGet 包时: dotnet nuget push **/*.nupkg --source https://gitlab.com/api/v4/projects/17141695/packages/nuget/index.json --api-key AAABBBCCCDDD --skip-duplicate

我得到错误:

info : Pushing Sasw.TestSupport.2.0.2.nupkg to 'https://gitlab.com/api/v4/projects/17141695/packages/nuget'...
info :   PUT https://gitlab.com/api/v4/projects/17141695/packages/nuget/
info :   Unauthorized https://gitlab.com/api/v4/projects/17141695/packages/nuget/ 397ms
error: Response status code does not indicate success: 401 (Unauthorized).
ERROR: Job failed: exit code 1

文档没有提及任何特别之处,但我注意到在使用(旧版?)nuget CLI 时,它会传递一个用户名。然而,Dotnet CLI 不支持用户名,只支持 API KEY。

知道为什么这不起作用吗?

这是我的 CI/CD 脚本:

variables:
  GITLAB_RUNNER_DOTNET_CORE: mcr.microsoft.com/dotnet/core/sdk:3.1
  NUGET_REPOSITORY: https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/nuget/index.json
  NUGET_API_KEY: $SASW_API_ACCESS_TOKEN
  NUGET_FOLDER_NAME: nupkgs
  NUGET_VERSION_SUFFIX: $SASW_PRERELEASE_SUFFIX

stages:
  - build
  - pack
  - release
  
#Docker image
image: $GITLAB_RUNNER_DOTNET_CORE

#Jobs
ci:
  stage: build
  script:
    - dotnet restore --no-cache --force
    - dotnet build --configuration Release --no-restore
    #- dotnet vstest test/*UnitTests/bin/Release/**/*UnitTests.dll
    #- dotnet vstest test/*IntegrationTests/bin/Release/**/*IntegrationTests.dll
    
pack-prerelease:
  stage: pack
  script:
    - dotnet pack *.sln --configuration Release --output $NUGET_FOLDER_NAME --version-suffix $NUGET_VERSION_SUFFIX --include-symbols -p:SymbolPackageFormat=snupkg
  artifacts:
    paths:
    - $NUGET_FOLDER_NAME
    expire_in: 1 week
  except:
    - master

pack-release:
  stage: pack
  script:
    - dotnet pack *.sln --configuration Release --output $NUGET_FOLDER_NAME
  artifacts:
    paths:
    - $NUGET_FOLDER_NAME
    expire_in: 1 week
  only:
    - master

publish-nuget:
  stage: release
  script:
    - dotnet nuget push **/*.nupkg --source $NUGET_REPOSITORY --api-key $NUGET_API_KEY --skip-duplicate

PS:该项目是公开的,所以如果需要查看:https ://gitlab.com/sunnyatticsoftware/sasw-test-support/-/jobs/451080235


更新 1:来自我的本地 linux 控制台的更多详细信息

$ dotnet nuget -v Debug push **/*.nupkg --source https://gitlab.com/api/v4/projects/17141695/packages/nuget/index.json --api-key cBwt5_hidden_ --skip-duplicate
trace: NuGet Command Line Version: 5.4.0.2
info : Pushing Sasw.TestSupport.2.0.2.nupkg to 'https://gitlab.com/api/v4/projects/17141695/packages/nuget'...
info :   PUT https://gitlab.com/api/v4/projects/17141695/packages/nuget/
info :   Unauthorized https://gitlab.com/api/v4/projects/17141695/packages/nuget/ 1159ms
error: Response status code does not indicate success: 401 (Unauthorized).
trace: System.AggregateException: One or more errors occurred. (Response status code does not indicate success: 401 (Unauthorized).)
trace:  ---> System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized).
trace:    at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.EnsureSuccessStatusCode(HttpResponseMessage response, Nullable`1 codeNotToThrow, ILogger logger)
trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.<>c__DisplayClass23_0.<PushPackageToServer>b__0(HttpResponseMessage response)
trace:    at NuGet.Protocol.HttpSource.ProcessResponseAsync[T](HttpSourceRequest request, Func`2 processAsync, SourceCacheContext cacheContext, ILogger log, CancellationToken token)
trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.PushPackageToServer(String source, String apiKey, String pathToPackage, Int64 packageSize, Boolean noServiceEndpoint, Boolean skipDuplicate, TimeSpan requestTimeout, ILogger logger, CancellationToken token)
trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.PushPackageCore(String source, String apiKey, String packageToPush, Boolean noServiceEndpoint, Boolean skipDuplicate, TimeSpan requestTimeout, ILogger log, CancellationToken token)
trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.PushPackage(String packagePath, String source, String apiKey, Boolean noServiceEndpoint, Boolean skipDuplicate, TimeSpan requestTimeout, ILogger log, CancellationToken token, Boolean isSnupkgPush)
trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.Push(String packagePath, String symbolSource, Int32 timeoutInSecond, Boolean disableBuffering, Func`2 getApiKey, Func`2 getSymbolApiKey, Boolean noServiceEndpoint, Boolean skipDuplicate, SymbolPackageUpdateResourceV3 symbolPackageUpdateResource, ILogger log)
trace:    at NuGet.Commands.PushRunner.Run(ISettings settings, IPackageSourceProvider sourceProvider, String packagePath, String source, String apiKey, String symbolSource, String symbolApiKey, Int32 timeoutSeconds, Boolean disableBuffering, Boolean noSymbols, Boolean noServiceEndpoint, Boolean skipDuplicate, ILogger logger)
trace:    at NuGet.CommandLine.XPlat.PushCommand.<>c__DisplayClass0_1.<<Register>b__1>d.MoveNext()
trace:    --- End of inner exception stack trace ---
trace:    at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
trace:    at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
trace:    at System.Threading.Tasks.Task`1.get_Result()
trace:    at Microsoft.Extensions.CommandLineUtils.CommandLineApplication.<>c__DisplayClass56_0.<OnExecute>b__0()
trace:    at Microsoft.Extensions.CommandLineUtils.CommandLineApplication.Execute(String[] args)
trace:    at NuGet.CommandLine.XPlat.Program.MainInternal(String[] args, CommandOutputLogger log)

更新 2:Alexey 的答案是正确的,并且截至 2021 年 4 月是最新的。GitLab 在去年改进了对 Nuget 的支持,现在可以轻松地将包推送到 repo 包注册表并在项目级别对 Nuget 提要进行读取访问或使用部署令牌的组级别。

标签: gitlabgitlab-cinuget-packagedotnet-cli

解决方案


按照文档推送从当前存储库构建的 NuGet 包非常容易。您不需要NuGet.config文件来推送包,因为可以为dotnet push命令指定凭据。您也不需要将凭据保存在 CI 文件中,因为 CI 变量包含将包推送到项目包注册表所需的所有临时凭据。

这是我的工作文件的一个片段,我.gitlab-ci.yml从文档中复制粘贴。所有必要的信息都来自 CI 变量,所以这个片段是完全可重用的。

nuget:
  stage: deploy
  image: mcr.microsoft.com/dotnet/sdk:5.0-buster-slim
  script:
    - dotnet pack -c Release -o $PWD/nuget
    - dotnet nuget add source "$CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/packages/nuget/index.json" --name gitlab --username gitlab-ci-token --password $CI_JOB_TOKEN --store-password-in-clear-text
    - dotnet nuget push "$PWD/nuget/*.nupkg" --source gitlab
  only:
    - master
    - tags

关于安装软件包的问题,​​您确实需要一个令牌。但这不是您的个人访问令牌。要让人们从您的提要中安装和恢复,您真正需要的只是存储库部署令牌。如果您在一个组中有多个项目,则不必在项目级别定义它,该组包含多个已发布 NuGet 包的项目。您还可以为整个组创建部署令牌。您为此目的创建的部署令牌只需要具有read_package_registry权限,它不会授予获得此令牌的用户任何其他权限。

创建部署令牌后,令牌名称用作用户名,令牌本身就是密码。您将这两个都放入NuGet.config文件中,其中列出了您的项目或组提要。

例如:

<?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="myfeed" value="https://gitlab.mydomain.dev/api/v4/groups/19/-/packages/nuget/index.json" />
    </packageSources>
    <packageSourceCredentials>
        <myfeed>
            <add key="Username" value="gitlab+deploy-token-14" />
            <add key="ClearTextPassword" value="thetokenvalue" />
        </myfeed>
    </packageSourceCredentials>
</configuration>

推荐阅读