私有 NuGet 发包
下载地址
https://www.zhengdianxue.com/wp-content/uploads/skills/hynn--nuget-upload.zip将提示词发送给你的 AI 安装该 skills
请根据 https://skillhub.cn/install/skillhub.md,安装 @hynn/nuget-upload。私有 NuGet 发包:给最近有改动的项目升修订版本号,清空包中转目录,dotnet pack 后将 nupkg 挪入并用 nuget.exe 自动推送到私服(无需用户确认)。当用户要求上传/发布/推送 NuGet 包(nupkg)到私服、升版本打包、或推送中转目录中已就绪的包时使用;不适用于推送到 nuget.org 公共源或纯本地打包不发布。
阅读全文 (展开查看完整说明)
概述
固定流程:找改动项目 → 修订号 +1 → 清空中转目录 → 打包 → 挪包 → 推送私服。
适用与不适用
- 适用:把最近有改动的 .NET 类库项目升修订版本并发布到私有 NuGet 源;仅升版本打包;推送中转目录中已就绪的包。
- 不适用:推送到 nuget.org 等公共源;发预发布版本但后缀策略未定(需先与用户确认);纯本地打包不发布。
前置(坐标配置)
正文一律使用占位符,执行任何命令前先读取本机坐标文件并替换(首次使用:复制 [references/coordinates-template.md](references/coordinates-template.md) 为同目录 coordinates.md 并填入本人真实值):
| 占位符 | 语义 |
|---|---|
<MY_PACKAGES_DIR> | 包中转目录(推送时其下所有 nupkg 都会被上传,所以必须先清空) |
<NUGET_EXE> | nuget.exe 绝对路径(不在 PATH 中,必须用绝对路径调用) |
<NUGET_FEED_URL> | 私服推送地址 |
<UPLOAD_BAT> | 内置 API key 的原始上传脚本(运行时提取使用,不要明文写入任何文件;脚本本身因裸调 nuget 缺 PATH 而不可直接运行) |
API key 永不明文写入 coordinates.md 之外的任何文件,运行时用 grep 从 <UPLOAD_BAT> 内的 nuget push 命令行提取。
执行流程
第 1 步:找出要打包的项目(仅最近有改动的项目)
按顺序收集改动文件,拿到即停:
git status --short # 1. 未提交的改动(含暂存与未暂存)
git diff --name-only HEAD~1 HEAD # 2. 无未提交改动时,看最近一次提交将每个改动文件向上追溯到其所属的 .csproj(文件所在目录逐级向上找最近的 csproj),即为目标项目;多个文件属于同一项目只算一次。
- 非 git 仓库、两步都没有改动、或改动文件对不上任何 csproj → 列出候选项目让用户指定,不要自行猜测。
- 目标项目必须是可打包的类库(csproj 中
IsPackable不为 false);测试项目、纯 exe 项目跳过并说明。
第 2 步:版本号修订号 +1
在目标 csproj(或其引用的 Directory.Build.props)中按优先级查找版本节点:<Version> → <FileVersion> → <PackageVersion>。
将末位(修订号)+1,例如 1.2.3 → 1.2.4。
- 多个版本节点同时存在(如同时有
<Version>和<FileVersion>)→ 全部同步 +1,保持一致。 - 版本带预发布后缀(如
1.2.3-beta1)→ 后缀处理方式不确定,向用户确认。 - 找不到任何版本节点 → 在 csproj 第一个
<PropertyGroup>内添加<Version>1.0.1</Version>,并明确告知用户。
第 3 步:清空中转目录
推送会把 <MY_PACKAGES_DIR> 下所有 *.nupkg 全部推送,必须先清空,避免旧包被重复推送:
rm -f "<MY_PACKAGES_DIR>"/*第 4 步:打包
dotnet pack "<目标csproj路径>" -c Releasedotnet pack自带编译,无需先执行dotnet build。- 编译失败 → 按项目工程规范(项目根的 Agent 指导文件或清理约定)修复后重试。
- 若报
NU5026(磁盘上找不到要打包的 dll,常见于清过 obj 后的增量状态)→ 先dotnet build "<目标csproj路径>" -c Release再重试 pack;若项目GeneratePackageOnBuild=true,build 本身就会产出 nupkg,无需再 pack。 - 产物位置:项目目录下
bin/Release/*.nupkg。
第 5 步:挪包到中转目录
只挪文件名中版本号等于第 2 步新版本的 nupkg(自动排除 bin 下的历史旧包):
mv "<项目目录>/bin/Release/<包名>.<新版本>.nupkg" "<MY_PACKAGES_DIR>/"- 挪之前核对文件名中的版本 = 新版本号;若 bin/Release 下只有旧版本文件,说明第 2 步修改的版本未参与打包,回头检查改的是不是同一个 csproj。
- 多个项目 → 逐个挪入。
第 6 步:推送(直接执行)
用户调用本技能即已表达发包意图,无需再次向用户确认,直接推送(此自动化行为已获用户明确授权)。推送前用一句话告知用户正在推送哪些包(包名 + 新版本)。
API_KEY=$(grep -oE '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}' "<UPLOAD_BAT>" | head -1)
"<NUGET_EXE>" push "<MY_PACKAGES_DIR>/<包名>.<新版本>.nupkg" "$API_KEY" -source "<NUGET_FEED_URL>"- 原上传脚本
<UPLOAD_BAT>已弃用直跑:其内部裸调nuget(不在 PATH),且末尾有pause会挂住非交互执行。 - 推送失败且报 409(服务器已存在同版本)→ 说明私服上已有该版本,通常是版本未升成功或此前已推过,报告用户处理,不要自动改版本重推。
- 多个包 → 逐个推送。
- 成功后报告推送了哪些包及版本号。
规则与取舍
- 只发最近有改动的项目:不做全仓库扫描;拿不到明确改动证据时宁可问用户,不猜测。
- 中转目录全量上传是设计前提:清空步骤不可跳过,否则旧版本会混入本次推送。
- 版本只动修订号:不擅自升次版本/主版本;预发布后缀策略必须问用户。
- 409 不自动重试:版本冲突暴露的是流程问题(未升版成功),自动改版本重推会掩盖问题。
Pitfalls(实测)
- NU5026:清过 obj 后的增量状态下
dotnet pack报磁盘找不到 dll → 先dotnet build -c Release再 pack;GeneratePackageOnBuild=true的项目 build 即产包。 - bat 直跑挂死:原始上传脚本裸调
nuget(不在 PATH)且末尾pause,非交互执行会挂住 → 弃用直跑,仅作为 API key 提取源。 - 中转目录残留旧包:推送命令上传目录下全部 nupkg,残留旧包会被重复推送(409)→ 第 3 步清空不可省。
- bin 下旧版本包混入:bin/Release 可能存有历史版本 nupkg → 第 5 步按新版本号过滤文件名再挪。
Verification
- [ ]
dotnet pack输出无 error,bin/Release下出现版本号 = 新版本的 nupkg - [ ] 挪包后
<MY_PACKAGES_DIR>内只有本次要发的 nupkg(文件名版本全部等于新版本) - [ ] nuget push 返回成功(无 409/401/超时)
- [ ] 已向用户报告:推送的包名、新旧版本号
- [ ] 回读验证(可选但推荐):私服支持查询时,按包名查最新版本确认已更新
资源
- [references/coordinates-template.md](references/coordinates-template.md) —— 坐标登记表模板(占位符 + 获取方式;复制为
coordinates.md本地填写,勿提交)