ibe*_*dev 7 nuget-package gitlab gitlab-ci dotnet-cli
GitLab now supports nuget public and private feed repository.
I've got a public project (e.g: https://gitlab.com/sunnyatticsoftware/sasw-test-support)
I create an access token for my user with api and write_repository (e.g: AAABBBCCCDDD)
I create a group variable in my CI/CD: SASW_API_ACCESS_TOKEN: AAABBBCCCDDD. All normal.
Then I create the multi stage CI/CD script to build, pack and publish.
When attempting to publish the nuGet package with the following:
dotnet nuget push **/*.nupkg --source https://gitlab.com/api/v4/projects/17141695/packages/nuget/index.json --api-key AAABBBCCCDDD --skip-duplicate
I get the error:
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
Run Code Online (Sandbox Code Playgroud)
The documentation doesn't mention anything special, but I notice that when using the (legacy?) nuget CLI it passes a username. Dotnet CLI, however, doesn't support username, just API KEY.
Any idea why this is not working?
This is my CI/CD script:
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
Run Code Online (Sandbox Code Playgroud)
PS: The project is public, so in case it's needed have a look at: https://gitlab.com/sunnyatticsoftware/sasw-test-support/-/jobs/451080235
UPDATE 1: Further verbosity from my local linux console
$ 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)
Run Code Online (Sandbox Code Playgroud)
UPDATE 2: Alexey's answer is the proper one and up to date as per April 2021. GitLab has improved Nuget support in the last year and now it's possible to easily push packages to the repo package registry and have readacces on Nuget feed at project level or group level using deploy tokens.
按照文档,推送从当前存储库构建的 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
Run Code Online (Sandbox Code Playgroud)
关于安装包的问题,您确实需要一个令牌。但这不是您的个人访问令牌。要让人们从您的提要安装和恢复,您真正需要的是存储库部署令牌。如果组中有多个项目,其中包含多个发布了 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>
Run Code Online (Sandbox Code Playgroud)
我设法以一种完全不直观的方式推动了 nuget。我必须创建一个带有凭据详细信息的 NuGet.Config。这是我不喜欢的,因为将 api 密钥传递给dotnet nuget push命令就足够了。
无论如何,这些是我的步骤:
dotnet new nugetconfig --force在根文件夹中为我的解决方案创建一个 NuGet.Config 然后编辑它以添加一个新源(链接到特定项目。烦人..)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
<!--The feed URL line below. The key can be anything but it must match the section in packageSourceCredentials -->
<add key="gitlab" value="https://gitlab.com/api/v4/projects/17141695/packages/nuget/index.json" />
</packageSources>
<packageSourceCredentials>
<gitlab>
<add key="Username" value="diegosasw" /> <!--My gitlab username-->
<add key="ClearTextPassword" value="cBwt5HPD_hidden_" /> <!--My gitlab access key-->
</gitlab>
</packageSourceCredentials>
</configuration>
Run Code Online (Sandbox Code Playgroud)
然后以下命令将起作用
$ dotnet nuget push **/*.nupkg --source https://gitlab.com/api/v4/projects/17141695/packages/nuget/index.json --skip-duplicate
warn : No API Key was provided and no API Key could be found for 'https://gitlab.com/api/v4/projects/17141695/packages/nuget'. To save an API Key for a source use the 'setApiKey' command.
info : Pushing Sasw.TestSupport.2.0.3.nupkg to 'https://gitlab.com/api/v4/projects/17141695/packages/nuget'...
info : PUT https://gitlab.com/api/v4/projects/17141695/packages/nuget/
info : Created https://gitlab.com/api/v4/projects/17141695/packages/nuget/ 1936ms
info : Your package was pushed.
Run Code Online (Sandbox Code Playgroud)
现在我可以看到可用的包但没有元数据!(不知道为什么)。因此,如果我将相同的 NuGet.Config 添加到任何解决方案文件夹并尝试安装它可以工作的包。
$ dotnet add Foo/Foo.csproj package Sasw.TestSupport
Writing C:\Users\dmsanz\AppData\Local\Temp\tmpF8D4.tmp
info : Adding PackageReference for package 'Sasw.TestSupport' into project 'Foo/Foo.csproj'.
info : Restoring packages for D:\src\sasw\sasw-test-support\Foo\Foo.csproj...
info : CACHE https://api.nuget.org/v3-flatcontainer/sasw.testsupport/index.json
info : CACHE https://gitlab.com/api/v4/projects/17141695/packages/nuget/download/sasw.testsupport/index.json
info : Package 'Sasw.TestSupport' is compatible with all the specified frameworks in project 'Foo/Foo.csproj'.
info : PackageReference for package 'Sasw.TestSupport' version '2.0.3' added to file 'D:\src\sasw\sasw-test-support\Foo\Foo.csproj'.
info : Committing restore...
info : Writing assets file to disk. Path: D:\src\sasw\sasw-test-support\Foo\obj\project.assets.json
log : Restore completed in 1.13 sec for D:\src\sasw\sasw-test-support\Foo\Foo.csproj.
Run Code Online (Sandbox Code Playgroud)
它有效......但我根本不喜欢它。
dotnet restore毫无问题地编译解决方案。但是在 GitLab 中使用这种方法,我需要NuGet.Config在我的解决方案文件夹中有一个包含敏感数据的敏感数据,例如具有写入权限的 api 密钥,以便能够从 CI/CD 管道推送包. 那应该是不能接受的。我是否被迫在我的 CI/CD 管道中做一些技巧来创建一个全新的 NuGet.Config 文件只是为了将敏感凭据放在那里以便发布 nuget 包,只是因为 GitLab 不支持一种好的和干净的方式来推送包到一个根本不需要 NuGet.Config 的简单命令的存储库?我希望是错的。请如果有人有更好的解决方案,我很乐意将其标记为已接受的答案。
| 归档时间: |
|
| 查看次数: |
3828 次 |
| 最近记录: |