@halospv3/hce.shared-config 2.6.4 → 3.0.0-develop.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/CHANGELOG.md +452 -101
  2. package/README.md +100 -87
  3. package/dotnet/.github/workflows/_unit_test.yml +3 -3
  4. package/dotnet/.github/workflows/ci.yml +2 -2
  5. package/dotnet/.github/workflows/dotnet-release.yml +28 -28
  6. package/dotnet/.github/workflows/sample-dotnet-build.yml +13 -11
  7. package/dotnet/ExecNupkgDeterministicator.README.md +20 -0
  8. package/dotnet/ExecNupkgDeterministicator.targets +173 -0
  9. package/dotnet/GitVersion.yml +3 -1
  10. package/dotnet/GitVersion6.0.yml +3 -1
  11. package/dotnet/HCE.Shared.sln +34 -0
  12. package/dotnet/HCE.Shared.targets +1 -0
  13. package/dotnet/PublishAll.targets +2 -0
  14. package/dotnet/SignAfterPack.targets +104 -0
  15. package/dotnet/samples/HCE.Shared.DeterministicNupkg/Dummy.cs +6 -0
  16. package/dotnet/samples/HCE.Shared.DeterministicNupkg/HCE.Shared.DeterministicNupkg.csproj +21 -0
  17. package/dotnet/samples/HCE.Shared.SignAfterPack/Class1.cs +6 -0
  18. package/dotnet/samples/HCE.Shared.SignAfterPack/HCE.Shared.SignAfterPack.csproj +21 -0
  19. package/dotnet/samples/HCE.Shared.SignAfterPack/sampleCert.samplepfx +0 -0
  20. package/dotnet/samples/README.md +7 -0
  21. package/mjs/CaseInsensitiveMap.d.ts +12 -0
  22. package/mjs/CaseInsensitiveMap.d.ts.map +1 -0
  23. package/mjs/CaseInsensitiveMap.mjs +33 -0
  24. package/mjs/CaseInsensitiveMap.mjs.map +1 -0
  25. package/mjs/commitlintConfig.d.ts +12 -0
  26. package/mjs/commitlintConfig.d.ts.map +1 -0
  27. package/{cjs/commitlintConfig.cjs → mjs/commitlintConfig.mjs} +3 -4
  28. package/mjs/commitlintConfig.mjs.map +1 -0
  29. package/mjs/debug.d.ts +4 -0
  30. package/{cjs → mjs}/debug.d.ts.map +1 -1
  31. package/mjs/debug.mjs +7 -0
  32. package/mjs/debug.mjs.map +1 -0
  33. package/mjs/dotnet/GithubNugetRegistryInfo.d.ts +38 -0
  34. package/mjs/dotnet/GithubNugetRegistryInfo.d.ts.map +1 -0
  35. package/mjs/dotnet/GithubNugetRegistryInfo.mjs +43 -0
  36. package/mjs/dotnet/GithubNugetRegistryInfo.mjs.map +1 -0
  37. package/mjs/dotnet/GitlabNugetRegistryInfo.d.ts +62 -0
  38. package/mjs/dotnet/GitlabNugetRegistryInfo.d.ts.map +1 -0
  39. package/mjs/dotnet/GitlabNugetRegistryInfo.mjs +99 -0
  40. package/mjs/dotnet/GitlabNugetRegistryInfo.mjs.map +1 -0
  41. package/mjs/dotnet/IsNextVersionAlreadyPublished.cli.d.ts +2 -0
  42. package/mjs/dotnet/IsNextVersionAlreadyPublished.cli.d.ts.map +1 -0
  43. package/mjs/dotnet/IsNextVersionAlreadyPublished.cli.mjs +26 -0
  44. package/mjs/dotnet/IsNextVersionAlreadyPublished.cli.mjs.map +1 -0
  45. package/mjs/dotnet/MSBuildProject.d.ts +256 -0
  46. package/mjs/dotnet/MSBuildProject.d.ts.map +1 -0
  47. package/mjs/dotnet/MSBuildProject.mjs +447 -0
  48. package/mjs/dotnet/MSBuildProject.mjs.map +1 -0
  49. package/mjs/dotnet/MSBuildProjectProperties.d.ts +170 -0
  50. package/mjs/dotnet/MSBuildProjectProperties.d.ts.map +1 -0
  51. package/mjs/dotnet/MSBuildProjectProperties.mjs +260 -0
  52. package/mjs/dotnet/MSBuildProjectProperties.mjs.map +1 -0
  53. package/mjs/dotnet/NugetProjectProperties.d.ts +379 -0
  54. package/mjs/dotnet/NugetProjectProperties.d.ts.map +1 -0
  55. package/mjs/dotnet/NugetProjectProperties.mjs +577 -0
  56. package/mjs/dotnet/NugetProjectProperties.mjs.map +1 -0
  57. package/mjs/dotnet/NugetRegistryInfo.d.ts +384 -0
  58. package/mjs/dotnet/NugetRegistryInfo.d.ts.map +1 -0
  59. package/mjs/dotnet/NugetRegistryInfo.mjs +752 -0
  60. package/mjs/dotnet/NugetRegistryInfo.mjs.map +1 -0
  61. package/mjs/dotnet/helpers.d.ts +63 -0
  62. package/mjs/dotnet/helpers.d.ts.map +1 -0
  63. package/mjs/dotnet/helpers.mjs +354 -0
  64. package/mjs/dotnet/helpers.mjs.map +1 -0
  65. package/mjs/dotnet/index.d.ts +17 -0
  66. package/mjs/dotnet/index.d.ts.map +1 -0
  67. package/mjs/dotnet/index.mjs +9 -0
  68. package/mjs/dotnet/index.mjs.map +1 -0
  69. package/mjs/dotnet.d.ts +3 -0
  70. package/mjs/dotnet.d.ts.map +1 -0
  71. package/mjs/dotnet.mjs +9 -0
  72. package/mjs/dotnet.mjs.map +1 -0
  73. package/mjs/eslintConfig.d.ts +4 -0
  74. package/mjs/eslintConfig.d.ts.map +1 -0
  75. package/mjs/eslintConfig.mjs +98 -0
  76. package/mjs/eslintConfig.mjs.map +1 -0
  77. package/mjs/index.d.ts +3 -0
  78. package/mjs/index.d.ts.map +1 -0
  79. package/mjs/index.mjs +4 -0
  80. package/mjs/index.mjs.map +1 -0
  81. package/mjs/insertPlugins.d.ts +18 -0
  82. package/mjs/insertPlugins.d.ts.map +1 -0
  83. package/mjs/insertPlugins.mjs +73 -0
  84. package/mjs/insertPlugins.mjs.map +1 -0
  85. package/mjs/semantic-release__commit-analyzer.d.mjs +2 -0
  86. package/mjs/semantic-release__commit-analyzer.d.mjs.map +1 -0
  87. package/mjs/semantic-release__exec.d.mjs +2 -0
  88. package/mjs/semantic-release__exec.d.mjs.map +1 -0
  89. package/mjs/semantic-release__git.d.mjs +2 -0
  90. package/mjs/semantic-release__git.d.mjs.map +1 -0
  91. package/mjs/semantic-release__github.d.mjs +2 -0
  92. package/mjs/semantic-release__github.d.mjs.map +1 -0
  93. package/mjs/semanticReleaseConfig.d.ts +97 -0
  94. package/mjs/semanticReleaseConfig.d.ts.map +1 -0
  95. package/mjs/semanticReleaseConfig.mjs +63 -0
  96. package/mjs/semanticReleaseConfig.mjs.map +1 -0
  97. package/mjs/semanticReleaseConfigDotnet.d.ts +109 -0
  98. package/mjs/semanticReleaseConfigDotnet.d.ts.map +1 -0
  99. package/mjs/semanticReleaseConfigDotnet.mjs +267 -0
  100. package/mjs/semanticReleaseConfigDotnet.mjs.map +1 -0
  101. package/mjs/setupGitPluginSpec.d.ts +22 -0
  102. package/mjs/setupGitPluginSpec.d.ts.map +1 -0
  103. package/mjs/setupGitPluginSpec.mjs +144 -0
  104. package/mjs/setupGitPluginSpec.mjs.map +1 -0
  105. package/mjs/utils/Exact.d.ts +20 -0
  106. package/mjs/utils/Exact.d.ts.map +1 -0
  107. package/mjs/utils/Exact.mjs +75 -0
  108. package/mjs/utils/Exact.mjs.map +1 -0
  109. package/mjs/utils/GracefulRecursion.d.mjs +2 -0
  110. package/mjs/utils/GracefulRecursion.d.mjs.map +1 -0
  111. package/mjs/utils/env.d.ts +24 -0
  112. package/mjs/utils/env.d.ts.map +1 -0
  113. package/mjs/utils/env.mjs +39 -0
  114. package/mjs/utils/env.mjs.map +1 -0
  115. package/mjs/utils/execAsync.d.ts +37 -0
  116. package/mjs/utils/execAsync.d.ts.map +1 -0
  117. package/mjs/utils/execAsync.mjs +59 -0
  118. package/mjs/utils/execAsync.mjs.map +1 -0
  119. package/mjs/utils/miscTypes.d.ts +13 -0
  120. package/mjs/utils/miscTypes.d.ts.map +1 -0
  121. package/mjs/utils/miscTypes.mjs +10 -0
  122. package/mjs/utils/miscTypes.mjs.map +1 -0
  123. package/mjs/utils/reflection/FunctionLike.d.mjs +2 -0
  124. package/mjs/utils/reflection/FunctionLike.d.mjs.map +1 -0
  125. package/mjs/utils/reflection/GetterDescriptor.d.mjs +2 -0
  126. package/mjs/utils/reflection/GetterDescriptor.d.mjs.map +1 -0
  127. package/mjs/utils/reflection/InstancePropertyDescriptorMap.d.mjs +2 -0
  128. package/mjs/utils/reflection/InstancePropertyDescriptorMap.d.mjs.map +1 -0
  129. package/mjs/utils/reflection/InstanceTypeOrSelfPropertyDescriptorMap.d.mjs +2 -0
  130. package/mjs/utils/reflection/InstanceTypeOrSelfPropertyDescriptorMap.d.mjs.map +1 -0
  131. package/mjs/utils/reflection/OwnGetterDescriptorMap.d.mjs +2 -0
  132. package/mjs/utils/reflection/OwnGetterDescriptorMap.d.mjs.map +1 -0
  133. package/mjs/utils/reflection/OwnKeyOf.d.mjs +2 -0
  134. package/mjs/utils/reflection/OwnKeyOf.d.mjs.map +1 -0
  135. package/mjs/utils/reflection/OwnPropertyDescriptorMap.d.mjs +2 -0
  136. package/mjs/utils/reflection/OwnPropertyDescriptorMap.d.mjs.map +1 -0
  137. package/mjs/utils/reflection/PropertyDescriptorMap.d.mjs +2 -0
  138. package/mjs/utils/reflection/PropertyDescriptorMap.d.mjs.map +1 -0
  139. package/mjs/utils/reflection/filterForGetters.d.ts +7 -0
  140. package/mjs/utils/reflection/filterForGetters.d.ts.map +1 -0
  141. package/mjs/utils/reflection/filterForGetters.mjs +27 -0
  142. package/mjs/utils/reflection/filterForGetters.mjs.map +1 -0
  143. package/mjs/utils/reflection/getOwnPropertyDescriptors.d.ts +22 -0
  144. package/mjs/utils/reflection/getOwnPropertyDescriptors.d.ts.map +1 -0
  145. package/mjs/utils/reflection/getOwnPropertyDescriptors.mjs +34 -0
  146. package/mjs/utils/reflection/getOwnPropertyDescriptors.mjs.map +1 -0
  147. package/mjs/utils/reflection/getOwnPropertyDescriptorsRecursively.d.ts +56 -0
  148. package/mjs/utils/reflection/getOwnPropertyDescriptorsRecursively.d.ts.map +1 -0
  149. package/mjs/utils/reflection/getOwnPropertyDescriptorsRecursively.mjs +72 -0
  150. package/mjs/utils/reflection/getOwnPropertyDescriptorsRecursively.mjs.map +1 -0
  151. package/mjs/utils/reflection/getPrototypeChainOf.d.ts +16 -0
  152. package/mjs/utils/reflection/getPrototypeChainOf.d.ts.map +1 -0
  153. package/mjs/utils/reflection/getPrototypeChainOf.mjs +55 -0
  154. package/mjs/utils/reflection/getPrototypeChainOf.mjs.map +1 -0
  155. package/mjs/utils/reflection/getPrototypeOf.d.ts +8 -0
  156. package/mjs/utils/reflection/getPrototypeOf.d.ts.map +1 -0
  157. package/mjs/utils/reflection/getPrototypeOf.mjs +10 -0
  158. package/mjs/utils/reflection/getPrototypeOf.mjs.map +1 -0
  159. package/mjs/utils/reflection/inheritance.d.ts +180 -0
  160. package/mjs/utils/reflection/inheritance.d.ts.map +1 -0
  161. package/mjs/utils/reflection/inheritance.mjs +148 -0
  162. package/mjs/utils/reflection/inheritance.mjs.map +1 -0
  163. package/mjs/utils/reflection/isConstructor.d.ts +17 -0
  164. package/mjs/utils/reflection/isConstructor.d.ts.map +1 -0
  165. package/mjs/utils/reflection/isConstructor.mjs +63 -0
  166. package/mjs/utils/reflection/isConstructor.mjs.map +1 -0
  167. package/mjs/utils/reflection/isGetterDescriptor.d.ts +9 -0
  168. package/mjs/utils/reflection/isGetterDescriptor.d.ts.map +1 -0
  169. package/mjs/utils/reflection/isGetterDescriptor.mjs +12 -0
  170. package/mjs/utils/reflection/isGetterDescriptor.mjs.map +1 -0
  171. package/mjs/utils/reflection/listOwnGetters.d.ts +26 -0
  172. package/mjs/utils/reflection/listOwnGetters.d.ts.map +1 -0
  173. package/mjs/utils/reflection/listOwnGetters.mjs +39 -0
  174. package/mjs/utils/reflection/listOwnGetters.mjs.map +1 -0
  175. package/mjs/utils/reflection.d.ts +18 -0
  176. package/mjs/utils/reflection.d.ts.map +1 -0
  177. package/mjs/utils/reflection.mjs +10 -0
  178. package/mjs/utils/reflection.mjs.map +1 -0
  179. package/package.json +77 -78
  180. package/src/CaseInsensitiveMap.ts +34 -0
  181. package/src/commitlintConfig.ts +17 -9
  182. package/src/debug.ts +4 -4
  183. package/src/dotnet/GithubNugetRegistryInfo.ts +68 -0
  184. package/src/dotnet/GitlabNugetRegistryInfo.ts +126 -0
  185. package/src/dotnet/IsNextVersionAlreadyPublished.cli.ts +44 -0
  186. package/src/dotnet/MSBuildProject.ts +702 -76
  187. package/src/dotnet/MSBuildProjectProperties.ts +281 -15
  188. package/src/dotnet/NugetProjectProperties.ts +609 -0
  189. package/src/dotnet/NugetRegistryInfo.ts +1025 -0
  190. package/src/dotnet/helpers.ts +479 -0
  191. package/src/dotnet/index.ts +17 -0
  192. package/src/dotnet.ts +2 -6
  193. package/src/eslintConfig.ts +174 -71
  194. package/src/index.ts +1 -3
  195. package/src/insertPlugins.ts +116 -0
  196. package/src/semantic-release__commit-analyzer.d.ts +44 -38
  197. package/src/semantic-release__exec.d.ts +15 -0
  198. package/src/semantic-release__git.d.ts +85 -88
  199. package/src/semantic-release__github.d.ts +139 -139
  200. package/src/semanticReleaseConfig.ts +111 -47
  201. package/src/semanticReleaseConfigDotnet.ts +397 -104
  202. package/src/setupGitPluginSpec.ts +153 -58
  203. package/src/tsconfig.json +8 -8
  204. package/src/utils/Exact.ts +49 -0
  205. package/src/utils/GracefulRecursion.d.ts +12 -0
  206. package/src/utils/env.ts +44 -0
  207. package/src/utils/execAsync.ts +89 -0
  208. package/src/utils/miscTypes.ts +18 -0
  209. package/src/utils/reflection/FunctionLike.d.ts +17 -0
  210. package/src/utils/reflection/GetterDescriptor.d.ts +8 -0
  211. package/src/utils/reflection/InstancePropertyDescriptorMap.d.ts +32 -0
  212. package/src/utils/reflection/InstanceTypeOrSelfPropertyDescriptorMap.d.ts +20 -0
  213. package/src/utils/reflection/OwnGetterDescriptorMap.d.ts +17 -0
  214. package/src/utils/reflection/OwnKeyOf.d.ts +20 -0
  215. package/src/utils/reflection/OwnPropertyDescriptorMap.d.ts +82 -0
  216. package/src/utils/reflection/PropertyDescriptorMap.d.ts +15 -0
  217. package/src/utils/reflection/filterForGetters.ts +59 -0
  218. package/src/utils/reflection/getOwnPropertyDescriptors.ts +52 -0
  219. package/src/utils/reflection/getOwnPropertyDescriptorsRecursively.ts +127 -0
  220. package/src/utils/reflection/getPrototypeChainOf.ts +85 -0
  221. package/src/utils/reflection/getPrototypeOf.ts +12 -0
  222. package/src/utils/reflection/inheritance.ts +262 -0
  223. package/src/utils/reflection/isConstructor.ts +74 -0
  224. package/src/utils/reflection/isGetterDescriptor.ts +11 -0
  225. package/src/utils/reflection/listOwnGetters.ts +80 -0
  226. package/src/utils/reflection.ts +18 -0
  227. package/cjs/commitlintConfig-wrapper.mjs +0 -6
  228. package/cjs/commitlintConfig.cjs.map +0 -1
  229. package/cjs/commitlintConfig.d.ts +0 -4
  230. package/cjs/commitlintConfig.d.ts.map +0 -1
  231. package/cjs/debug.cjs +0 -13
  232. package/cjs/debug.cjs.map +0 -1
  233. package/cjs/debug.d.ts +0 -4
  234. package/cjs/dotnet/MSBuildProject.cjs +0 -84
  235. package/cjs/dotnet/MSBuildProject.cjs.map +0 -1
  236. package/cjs/dotnet/MSBuildProject.d.ts +0 -42
  237. package/cjs/dotnet/MSBuildProject.d.ts.map +0 -1
  238. package/cjs/dotnet/MSBuildProjectProperties.cjs +0 -22
  239. package/cjs/dotnet/MSBuildProjectProperties.cjs.map +0 -1
  240. package/cjs/dotnet/MSBuildProjectProperties.d.ts +0 -13
  241. package/cjs/dotnet/MSBuildProjectProperties.d.ts.map +0 -1
  242. package/cjs/dotnet/createDummyNupkg.cjs +0 -26
  243. package/cjs/dotnet/createDummyNupkg.cjs.map +0 -1
  244. package/cjs/dotnet/createDummyNupkg.d.ts +0 -2
  245. package/cjs/dotnet/createDummyNupkg.d.ts.map +0 -1
  246. package/cjs/dotnet/dotnetGHPR.cjs +0 -173
  247. package/cjs/dotnet/dotnetGHPR.cjs.map +0 -1
  248. package/cjs/dotnet/dotnetGHPR.d.ts +0 -37
  249. package/cjs/dotnet/dotnetGHPR.d.ts.map +0 -1
  250. package/cjs/dotnet/dotnetGLPR.cjs +0 -41
  251. package/cjs/dotnet/dotnetGLPR.cjs.map +0 -1
  252. package/cjs/dotnet/dotnetGLPR.d.ts +0 -13
  253. package/cjs/dotnet/dotnetGLPR.d.ts.map +0 -1
  254. package/cjs/dotnet/dotnetHelpers.cjs +0 -141
  255. package/cjs/dotnet/dotnetHelpers.cjs.map +0 -1
  256. package/cjs/dotnet/dotnetHelpers.d.ts +0 -26
  257. package/cjs/dotnet/dotnetHelpers.d.ts.map +0 -1
  258. package/cjs/dotnet-wrapper.mjs +0 -6
  259. package/cjs/dotnet.cjs +0 -15
  260. package/cjs/dotnet.cjs.map +0 -1
  261. package/cjs/dotnet.d.ts +0 -7
  262. package/cjs/dotnet.d.ts.map +0 -1
  263. package/cjs/envUtils-wrapper.mjs +0 -6
  264. package/cjs/envUtils.cjs +0 -37
  265. package/cjs/envUtils.cjs.map +0 -1
  266. package/cjs/envUtils.d.ts +0 -15
  267. package/cjs/envUtils.d.ts.map +0 -1
  268. package/cjs/eslintConfig-wrapper.mjs +0 -6
  269. package/cjs/eslintConfig.cjs +0 -52
  270. package/cjs/eslintConfig.cjs.map +0 -1
  271. package/cjs/eslintConfig.d.ts +0 -3
  272. package/cjs/eslintConfig.d.ts.map +0 -1
  273. package/cjs/findStaticConfig-wrapper.mjs +0 -6
  274. package/cjs/findStaticConfig.cjs +0 -34
  275. package/cjs/findStaticConfig.cjs.map +0 -1
  276. package/cjs/findStaticConfig.d.ts +0 -2
  277. package/cjs/findStaticConfig.d.ts.map +0 -1
  278. package/cjs/index-wrapper.mjs +0 -6
  279. package/cjs/index.cjs +0 -10
  280. package/cjs/index.cjs.map +0 -1
  281. package/cjs/index.d.ts +0 -5
  282. package/cjs/index.d.ts.map +0 -1
  283. package/cjs/semantic-release__commit-analyzer.d.cjs +0 -2
  284. package/cjs/semantic-release__commit-analyzer.d.cjs.map +0 -1
  285. package/cjs/semantic-release__git.d.cjs +0 -2
  286. package/cjs/semantic-release__git.d.cjs.map +0 -1
  287. package/cjs/semantic-release__github.d.cjs +0 -2
  288. package/cjs/semantic-release__github.d.cjs.map +0 -1
  289. package/cjs/semanticReleaseConfig-wrapper.mjs +0 -6
  290. package/cjs/semanticReleaseConfig.cjs +0 -33
  291. package/cjs/semanticReleaseConfig.cjs.map +0 -1
  292. package/cjs/semanticReleaseConfig.d.ts +0 -4
  293. package/cjs/semanticReleaseConfig.d.ts.map +0 -1
  294. package/cjs/semanticReleaseConfigDotnet-wrapper.mjs +0 -7
  295. package/cjs/semanticReleaseConfigDotnet.cjs +0 -112
  296. package/cjs/semanticReleaseConfigDotnet.cjs.map +0 -1
  297. package/cjs/semanticReleaseConfigDotnet.d.ts +0 -51
  298. package/cjs/semanticReleaseConfigDotnet.d.ts.map +0 -1
  299. package/cjs/setupGitPluginSpec-wrapper.mjs +0 -6
  300. package/cjs/setupGitPluginSpec.cjs +0 -67
  301. package/cjs/setupGitPluginSpec.cjs.map +0 -1
  302. package/cjs/setupGitPluginSpec.d.ts +0 -19
  303. package/cjs/setupGitPluginSpec.d.ts.map +0 -1
  304. package/src/dotnet/createDummyNupkg.ts +0 -30
  305. package/src/dotnet/dotnetGHPR.ts +0 -232
  306. package/src/dotnet/dotnetGLPR.ts +0 -46
  307. package/src/dotnet/dotnetHelpers.ts +0 -184
  308. package/src/envUtils.ts +0 -36
  309. package/src/findStaticConfig.ts +0 -31
  310. package/static/.releaserc.yml +0 -35
@@ -0,0 +1,1025 @@
1
+ /* JSDoc Types */
2
+ /* eslint-disable @typescript-eslint/no-unused-vars */
3
+ import type { SemanticReleaseConfigDotnet } from '../semanticReleaseConfigDotnet.js';
4
+ import type { NugetProjectProperties } from './NugetProjectProperties.js';
5
+ /* eslint-enable @typescript-eslint/no-unused-vars */
6
+
7
+ import { config as configDotenv } from '@dotenvx/dotenvx';
8
+ import { type } from 'arktype';
9
+ import { detectFile, detectFileSync } from 'chardet';
10
+ import { ok } from 'node:assert/strict';
11
+ import type { ExecException } from 'node:child_process';
12
+ import { existsSync, writeFileSync } from 'node:fs';
13
+ import { writeFile } from 'node:fs/promises';
14
+ import { tmpdir } from 'node:os';
15
+ import node_path from 'node:path';
16
+ import { cwd, env } from 'node:process';
17
+ import { setTimeout } from 'node:timers/promises';
18
+ import { isNativeError } from 'node:util/types';
19
+ import sanitizeFileName from 'sanitize-filename';
20
+ import { getEnvVarValue } from '../utils/env.js';
21
+ import { execAsync } from '../utils/execAsync.js';
22
+ import { catchCsc2012, MSBuildEvaluationOutput, MSBuildProject } from './MSBuildProject.js';
23
+ import type { ObjectType } from 'arktype/internal/methods/object.ts';
24
+ import type { Default } from 'arktype/internal/attributes.ts';
25
+
26
+ type TmpDirNamespace_Unix = `${ReturnType<typeof tmpdir>}/HCE.Shared/.NET/Dummies`;
27
+ type TmpDirNamespace_Win = `${ReturnType<typeof tmpdir>}\\HCE.Shared\\.NET\\Dummies`;
28
+ const tmpDirNamespace = node_path.join(tmpdir(), 'HCE.Shared', '.NET', 'Dummies') as TmpDirNamespace_Unix | TmpDirNamespace_Win;
29
+ const defaultNugetSource = 'https://api.nuget.org/v3/index.json';
30
+ const key_OutputPackItems = '_OutputPackItems';
31
+ /**
32
+ * Read the contents of $GITHUB_OUTPUT (if its value is a file path) or $TEMP/GITHUB_OUTPUT.
33
+ * If the file doesn't exist, it is created.
34
+ * @returns If successful, a promised object with a parsed key.
35
+ */
36
+ export async function getGithubOutput(): Promise<ReturnType<typeof configDotenv>['parsed']> {
37
+ if (env['GITHUB_OUTPUT'] === undefined || !existsSync(env['GITHUB_OUTPUT'])) {
38
+ const githubOutputPath: string = node_path.join(tmpdir(), 'GITHUB_OUTPUT');
39
+ if (!existsSync(githubOutputPath))
40
+ await writeFile(githubOutputPath, '');
41
+ env['GITHUB_OUTPUT'] = githubOutputPath;
42
+ }
43
+
44
+ const encoding = await detectFile(env['GITHUB_OUTPUT']);
45
+ const envOutput = configDotenv({
46
+ path: env['GITHUB_OUTPUT'],
47
+ override: true,
48
+ encoding: encoding ?? undefined,
49
+ processEnv: {},
50
+ });
51
+
52
+ if (isNativeError(envOutput.error))
53
+ throw envOutput.error;
54
+ return envOutput.parsed;
55
+ }
56
+
57
+ /**
58
+ * Read the contents of $GITHUB_OUTPUT (if its value is a file path) or $TEMP/GITHUB_OUTPUT.
59
+ * If the file doesn't exist, it is created.
60
+ * @returns An object with a parsed key if successful.
61
+ */
62
+ export function getGithubOutputSync(): NonNullable<ReturnType<typeof configDotenv>['parsed']> {
63
+ if (env['GITHUB_OUTPUT'] === undefined || !existsSync(env['GITHUB_OUTPUT'])) {
64
+ const githubOutputPath: string = node_path.join(tmpdir(), 'GITHUB_OUTPUT');
65
+ if (!existsSync(githubOutputPath))
66
+ writeFileSync(githubOutputPath, '');
67
+ env['GITHUB_OUTPUT'] = githubOutputPath;
68
+ }
69
+
70
+ const encoding = detectFileSync(env['GITHUB_OUTPUT']);
71
+ const envOutput = configDotenv({
72
+ path: env['GITHUB_OUTPUT'],
73
+ override: true,
74
+ encoding: encoding ?? undefined,
75
+ processEnv: {},
76
+ }) as { error: Error }
77
+ | { parsed: NonNullable<ReturnType<typeof configDotenv>['parsed']> };
78
+
79
+ if ('error' in envOutput)
80
+ throw envOutput.error;
81
+ return envOutput.parsed;
82
+ }
83
+
84
+ type DummiesDir<T> = T extends undefined
85
+ ? `${TmpDirNamespace_Unix}/` | `${TmpDirNamespace_Win}\\`
86
+ : T extends MSBuildProject
87
+ ? `${TmpDirNamespace_Unix}/${T['Properties']['PackageId']}/` | `${TmpDirNamespace_Win}\\${T['Properties']['PackageId']}\\`
88
+ : never;
89
+
90
+ function getDummiesDir<T extends MSBuildProject | undefined = undefined>(project?: T): DummiesDir<T>;
91
+ function getDummiesDir<T extends MSBuildProject>(project: T): DummiesDir<T>;
92
+ /**
93
+ * Get HCE.Shared's temporary directory for .NET projects' dummy packages.
94
+ * @param project The MSBuild project whose PackageId will be used to create a
95
+ * directory for its dummy packages.
96
+ * @returns a platform-specific path like
97
+ * `${tmpdir()}/HCE.Shared/.NET/Dummies/${project.Properties.PackageId}` if
98
+ * {@link project} is defined. Else `${tmpdir()}/HCE.Shared/.NET/Dummies`
99
+ */
100
+ function getDummiesDir<T extends MSBuildProject | undefined = undefined>(project?: T): DummiesDir<typeof project> {
101
+ switch (true) {
102
+ case project === undefined: {
103
+ return node_path.join(tmpDirNamespace, node_path.sep) as
104
+ DummiesDir<typeof project> satisfies
105
+ ReturnType<typeof getDummiesDir>;
106
+ }
107
+ case project instanceof MSBuildProject: {
108
+ return node_path.join(tmpDirNamespace, project.Properties.PackageId, node_path.sep) as
109
+ DummiesDir<typeof project> satisfies
110
+ ReturnType<typeof getDummiesDir<MSBuildProject>>;
111
+ }
112
+ default: {
113
+ throw new Error('The type of argument `project` must be `undefined` or `MSBuildProject`.');
114
+ }
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Get the environment variables as key-value pairs.
120
+ * @param tokenEnvVars The name of the environment variables whose values are
121
+ * NuGet API keys.
122
+ * @returns an array of key-value pairs of the given environment variables and
123
+ * their values, filtered to only those whose values are not undefined.
124
+ * @throws {Error} when none of the provided environment variables are defined.
125
+ */
126
+ function _GetTokenEnvVariables(tokenEnvVars: readonly string[]): undefined | [readonly [string, string], ...readonly [string, string][]] {
127
+ const definedTokens = Object.freeze(
128
+ tokenEnvVars
129
+ .map((key: string) => [key, getEnvVarValue(key)] as const)
130
+ .filter((envVarTuple: readonly [string, string | undefined]): envVarTuple is [string, string] =>
131
+ envVarTuple[1] !== undefined,
132
+ ),
133
+ );
134
+
135
+ if (definedTokens.length > 0)
136
+ return definedTokens as [readonly [string, string], ...readonly [string, string][]];
137
+ return undefined;
138
+ }
139
+
140
+ export class NugetRegistryInfo {
141
+ private _canPushPackagesToSource: Promise<true> | undefined = undefined;
142
+ private readonly _project: MSBuildProject;
143
+ private readonly _resolvedEnvVariable: string | undefined;
144
+ private readonly _source: string;
145
+
146
+ public static readonly DefaultTokenEnvVars: readonly ['NUGET_TOKEN']
147
+ = Object.freeze(['NUGET_TOKEN'] as const);
148
+
149
+ /**
150
+ * Convert a URL string to a filesystem folder name.
151
+ *
152
+ * Intended usage: modify the output path of `dotnet pack` based on the NuGet
153
+ * Source the package should be pushed to. This is extra work is usually
154
+ * unnecessary and you'd typically push the same file to multiple sources.
155
+ * This is for the edge-case scenario of creating multiple nupkgs and signing
156
+ * each one with a different certificate corresponding to a given NuGet
157
+ * Source. This is only useful if the Sources have different certificates
158
+ * registered for a given package/user/organization.
159
+ * @param source The URL of the NuGet Source
160
+ * @returns A string suitable for a local filesystem folder name, formatted as
161
+ * `${hostname}_${pathname.replace('/', '_')}`.
162
+ */
163
+ static GetDirNameForSource(source: string): string {
164
+ return sanitizeFileName(
165
+ source.replaceAll(/\/index.json$/g, ''),
166
+ { replacement: '_' },
167
+ );
168
+ }
169
+
170
+ /**
171
+ * Creates an instance of NugetRegistryInfo.\
172
+ * This class enables the ability to push a given {@link project}'s
173
+ * package(s) to the {@link source} of a given NuGet Source's API endpoint with
174
+ * a user-defined API key. This API key, herein referred to as a "token", is
175
+ * derived from the {@link tokenEnvVars} array. This array is iterated through
176
+ * until one of the items is discovered to be an existing environment variable
177
+ * (or is defined in a file named '.env' in the current working directory for
178
+ * LOCAL TESTING ONLY! Do NOT `git add` your private keys!).
179
+ * \
180
+ * WARNING:
181
+ * - The token value is stored privately within this class, but it is plain text.
182
+ * - This private key may be copied to command line strings stored in Semantic
183
+ * Release's config object for later use by `@semantic-release/exec`.
184
+ * - Other EcmaScript modules can access the environment variable(s) and steal
185
+ * your key. Be aware of malicious dependencies!
186
+ * @param opts The input type of {@link NRIOpts.from}
187
+ * @param opts.project The project whose package(s) will be
188
+ * pushed.\
189
+ * - Its {@link NugetProjectProperties#PackageId} will be read.\
190
+ * - Its {@link NugetProjectProperties#PackageVersion} will be overridden via CLI args when creating a dummy package. The real package's
191
+ * `PackageVersion` will *not* be overridden.
192
+ * @param [opts.tokenEnvVars] The environment variables
193
+ * whose values are tokens with permission to push a package to the NuGet
194
+ * package registry. The array is iterated through until one token is found.
195
+ * If none of the environment variables are defined, this constructor will
196
+ * throw an {@link Error}.
197
+ * @param [opts.source] A NuGet package registry's API endpoint URL or name. Default: 'https://api.nuget.org/v3/index.json'
198
+ */
199
+ constructor(opts: typeof NRIOpts['inferIn']) {
200
+ // note: you can reassign `opts` only when typeof `inferOut` is assignable
201
+ // to typeof `inferIn`.
202
+ const validOpts = NRIOpts.from(opts);
203
+ this._project = validOpts.project;
204
+ /**
205
+ * May throw! Assign key of the first key-value pair to
206
+ * {@link resolvedEnvVariable}
207
+ */
208
+ const tokenVars = _GetTokenEnvVariables(validOpts.tokenEnvVars);
209
+ if (tokenVars)
210
+ this._resolvedEnvVariable = tokenVars[0][0];
211
+ this._source = validOpts.source;
212
+ }
213
+
214
+ public get project(): MSBuildProject {
215
+ return this._project;
216
+ }
217
+
218
+ /**
219
+ * This is not useful without it being executed as part of a Semantic Release
220
+ * plugin. Deferring this to @semantic-release/exec's prepareCmd is possible,
221
+ * but impractical. You'd need to configure prepareCmd to invoke something
222
+ * like `node customScriptFile.mjs`. It's not worth the hassle.
223
+ * @returns `true` if the token can be used to push nupkg to the given Nuget registry
224
+ * @throws {TypeError | Error | import('../utils/execAsync.js').ChildProcessSpawnException }
225
+ * - {@link Error} | {@link module:utils/execAsync:ChildProcessSpawnException ChildProcessSpawnException}
226
+ * - The token is invalid, of the wrong token type, or lacks permission to push packages
227
+ * - The URL does not exist or a connection could not be established
228
+ * - The command line string is malformed.
229
+ * @deprecated Call during the `verifyConditions` step of Semantic Release! Additionally, {@link GetIsNextVersionAlreadyPublishedCommand}'s return value should be assigned to `prepareCmd` to prevent package version collision errors.
230
+ */
231
+ public get canPushPackagesToSource(): Promise<true> {
232
+ if (this._canPushPackagesToSource !== undefined)
233
+ return this._canPushPackagesToSource;
234
+
235
+ let tokenValue: string | undefined;
236
+ if (this.resolvedEnvVariable !== undefined)
237
+ tokenValue = NRI._GetTokenValue(this.resolvedEnvVariable);
238
+
239
+ if (tokenValue?.startsWith('github_pat_')) {
240
+ const errMsg = `The value of the token in 'resolvedEnvVariable' ${String(this.resolvedEnvVariable)} begins with 'github_pat_', indicating it's a Fine-Grained token. At the time of writing, GitHub Fine-Grained tokens cannot push packages. If you believe this is statement is outdated, report the issue at https://github.com/halospv3/hce.shared/issues/new. For more information, see https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-nuget-registry.`;
241
+ const err = new Error(errMsg);
242
+ return this._canPushPackagesToSource = Promise.reject(err);
243
+ }
244
+
245
+ return this._canPushPackagesToSource = this.PackDummyPackage({})
246
+ .then(async () => await this._PushDummyPackages({
247
+ apiKey: tokenValue,
248
+ }))
249
+ .then<true>((execAsyncReturn) => {
250
+ ok(execAsyncReturn);
251
+ return true as const;
252
+ });
253
+ }
254
+
255
+ /**
256
+ * The first environment variable found to have a defined value. Set by
257
+ * {@link _GetTokenEnvVariables} in the constructor.
258
+ * @returns The first environment variable found to have a defined value.
259
+ */
260
+ get resolvedEnvVariable(): string | undefined {
261
+ return this._resolvedEnvVariable;
262
+ }
263
+
264
+ get source(): string {
265
+ return this._source;
266
+ }
267
+
268
+ /**
269
+ * Get the API token from {@link NugetRegistryInfo#resolvedEnvVariable}
270
+ * @param resolvedEnvVariable The name of the environment variable(s) whose
271
+ * value is a NuGet API key. Typically, the value of
272
+ * {@link NugetRegistryInfo#resolvedEnvVariable}.
273
+ * @returns The value of the first defined environment variable.
274
+ * @throws {Error} when none of the provided environment variables are defined.
275
+ */
276
+ private static _GetTokenValue(resolvedEnvVariable: string): string {
277
+ type.string.assert(resolvedEnvVariable);
278
+
279
+ const tokenValue = getEnvVarValue(resolvedEnvVariable);
280
+ if (tokenValue === undefined) {
281
+ throw new Error(`\
282
+ The environment variable ${resolvedEnvVariable} was specified \
283
+ as the source of the token to push a NuGet package, \
284
+ but the environment variable is empty or undefined.`);
285
+ }
286
+ return tokenValue;
287
+ }
288
+
289
+ // #region Pack
290
+
291
+ /**
292
+ * The type for options and arguments of `dotnet pack`. See https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-pack.
293
+ *
294
+ * {@link NRI.PackPackagesOptionsType.t.propertyOverrides `propertyOverrides`}
295
+ * is a wrapper for MSBuild's `-property:<n>=<v>` properties override arg.
296
+ */
297
+ static readonly PackPackagesOptionsType: ObjectType<{
298
+ propertyOverrides?: Record<string, string> | undefined;
299
+ artifactsPath?: string | undefined;
300
+ configuration?: 'Release' | 'Debug' | undefined;
301
+ disableBuildServers?: boolean | undefined;
302
+ force?: boolean | undefined;
303
+ includeSource?: boolean | undefined;
304
+ includeSymbols?: boolean | undefined;
305
+ interactive?: boolean | undefined;
306
+ noBuild?: boolean | undefined;
307
+ noLogo?: boolean | undefined;
308
+ noRestore?: boolean | undefined;
309
+ output?: string | undefined;
310
+ runtime?: string | undefined;
311
+ serviceable?: boolean | undefined;
312
+ terminalLogger?: 'auto' | 'on' | 'off' | undefined;
313
+ useCurrentRuntime?: boolean | undefined;
314
+ verbosity?: 'quiet' | 'minimal' | 'normal' | 'detailed' | 'diagnostic' | undefined;
315
+ versionSuffix?: string | undefined;
316
+ '-GetItem'?: readonly string[] | string[] | undefined;
317
+ }> = Object.freeze(
318
+ type({
319
+ /**
320
+ * a custom arg for handling MSBuild's `-property:<n>=<v>` argument for overriding MSBuild properties.
321
+ */
322
+ 'propertyOverrides?': type('Record<string,string>'),
323
+ 'artifactsPath?': 'string',
324
+ 'configuration?': '"Release" | "Debug"',
325
+ 'disableBuildServers?': 'boolean',
326
+ 'force?': 'boolean',
327
+ 'includeSource?': 'boolean',
328
+ 'includeSymbols?': 'boolean',
329
+ 'interactive?': 'boolean',
330
+ 'noBuild?': 'boolean',
331
+ 'noLogo?': 'boolean',
332
+ 'noRestore?': 'boolean',
333
+ 'output?': 'string',
334
+ 'runtime?': 'string',
335
+ 'serviceable?': 'boolean',
336
+ 'terminalLogger?': '"auto" | "on" | "off"',
337
+ 'useCurrentRuntime?': 'boolean',
338
+ 'verbosity?': '"quiet" | "minimal" | "normal" | "detailed" | "diagnostic"',
339
+ 'versionSuffix?': 'string',
340
+ /**
341
+ * MSBuild evaluation option. Added to get the output Nupkgs' file paths.
342
+ * @todo consider adding -GetProperty, -GetTarget
343
+ */
344
+ '-GetItem?': type.string.array().readonly().or('string[]'),
345
+ }),
346
+ );
347
+
348
+ public static readonly PackDummyPackagesOptionsType: ObjectType<{
349
+ propertyOverrides?: Record<string, string> | undefined;
350
+ artifactsPath?: string | undefined;
351
+ configuration?: 'Release' | 'Debug' | undefined;
352
+ disableBuildServers?: boolean | undefined;
353
+ force?: boolean | undefined;
354
+ includeSource?: boolean | undefined;
355
+ includeSymbols?: boolean | undefined;
356
+ interactive?: boolean | undefined;
357
+ noBuild?: boolean | undefined;
358
+ noLogo?: boolean | undefined;
359
+ noRestore?: boolean | undefined;
360
+ runtime?: string | undefined;
361
+ serviceable?: boolean | undefined;
362
+ terminalLogger?: 'auto' | 'on' | 'off' | undefined;
363
+ useCurrentRuntime?: boolean | undefined;
364
+ verbosity?: 'quiet' | 'minimal' | 'normal' | 'detailed' | 'diagnostic' | undefined;
365
+ versionSuffix?: string | undefined;
366
+ '-GetItem'?: readonly string[] | string[] | undefined;
367
+ }>
368
+ = this.PackPackagesOptionsType.omit('output');
369
+
370
+ /**
371
+ * Get a `dotnet pack` command line string, outputting the package(s) to a
372
+ * path determined by this method's parameters.
373
+ * When pushing the package(s), you only need to supply the main .nupkg's path
374
+ * or its directory to the dotnet CLI—by default, it will also push the
375
+ * symbols package, if present.
376
+ * @param opts Options passed to
377
+ * `dotnet pack`, excluding the required `<PROJECT | SOLUTION>` argument. The
378
+ * {@link PackPackagesOptionsType.t.output} path is modified according to the
379
+ * {@link usePerSourceSubfolder} and {@link usePerPackageIdSubfolder}
380
+ * arguments.
381
+ * @param usePerSourceSubfolder If true, the path of the package output will
382
+ * include a subfolder named after the NuGet Source.
383
+ * @param usePerPackageIdSubfolder If true, the path of the package output
384
+ * will include a subfolder named after the NuGet package's ID.
385
+ * @returns `dotnet pack "${this.project.Properties.MSBuildProjectFullPath}"
386
+ * -o "${outDir}"` where outDir may be `${cwd()}/publish/${NugetRegistryInfo.GetNameForURL(this.source)}/${this._project.Properties.PackageId}`
387
+ */
388
+ GetPackCommand(
389
+ opts: typeof NRI.PackPackagesOptionsType.inferIn,
390
+ usePerSourceSubfolder = false,
391
+ usePerPackageIdSubfolder = false,
392
+ ): string {
393
+ const validOpts = NRI.PackPackagesOptionsType.from(opts);
394
+ type.boolean.assert(usePerSourceSubfolder);
395
+ type.boolean.assert(usePerPackageIdSubfolder);
396
+
397
+ validOpts.output ??= node_path.join(cwd(), 'publish');
398
+ if (usePerSourceSubfolder)
399
+ validOpts.output = node_path.join(validOpts.output, NugetRegistryInfo.GetDirNameForSource(this.source), node_path.sep);
400
+ if (usePerPackageIdSubfolder)
401
+ validOpts.output = node_path.join(validOpts.output, this._project.Properties.PackageId, node_path.sep);
402
+
403
+ const packCmdArr: string[] = [
404
+ 'dotnet',
405
+ 'pack',
406
+ `"${this._project.Properties.MSBuildProjectFullPath}"`,
407
+ ];
408
+ if (validOpts.artifactsPath !== undefined)
409
+ packCmdArr.push('--artifactsPath', `"${validOpts.artifactsPath}"`);
410
+ if (validOpts.configuration !== undefined)
411
+ packCmdArr.push('--configuration', validOpts.configuration);
412
+ if (validOpts.disableBuildServers === true)
413
+ packCmdArr.push('--disable-build-servers');
414
+ if (validOpts.force === true) packCmdArr.push('--force');
415
+ if (validOpts.includeSource === true) packCmdArr.push('--include-source');
416
+ if (validOpts.includeSymbols === true) packCmdArr.push('--include-symbols');
417
+ if (validOpts.interactive === true) packCmdArr.push('--interactive');
418
+ if (validOpts.noBuild === true) packCmdArr.push('--no-build');
419
+ if (validOpts.noLogo === true) packCmdArr.push('--nologo');
420
+ if (validOpts.noRestore === true) packCmdArr.push('--no-restore');
421
+ if (validOpts.runtime !== undefined)
422
+ packCmdArr.push('--runtime', validOpts.runtime);
423
+ if (validOpts.serviceable === true) packCmdArr.push('--serviceable');
424
+ if (validOpts.terminalLogger !== undefined)
425
+ packCmdArr.push('--tl', validOpts.terminalLogger);
426
+ if (validOpts.useCurrentRuntime === true)
427
+ packCmdArr.push('--use-current-runtime');
428
+ if (validOpts.verbosity !== undefined)
429
+ packCmdArr.push('--verbosity', validOpts.verbosity);
430
+ if (validOpts.versionSuffix !== undefined)
431
+ packCmdArr.push('--version-suffix', validOpts.versionSuffix);
432
+ /**
433
+ * Haphazard. I need to override the Version and I'm not considering side
434
+ * effects of arbitrary overrides.
435
+ */
436
+ if (validOpts.propertyOverrides) {
437
+ /** convert propertyOverrides record to "-p:n0=v0;n1=v1;n2=v2" et cetera */
438
+ const assignments: string = '-p:' + Object.entries(validOpts.propertyOverrides)
439
+ .map(v => `${v[0]}=${v[1]}`).join(';');
440
+ packCmdArr.push(`"${assignments}"`);
441
+ }
442
+ if (validOpts['-GetItem'] && validOpts['-GetItem'].length > 0) {
443
+ // -GetItem:_OutputPackItems,MyCustomItem
444
+ packCmdArr.push(`-GetItem:${validOpts['-GetItem'].join(',')}`);
445
+ }
446
+ // MSBuild parses everything after -o as the path.
447
+ packCmdArr.push('-o', `"${validOpts.output}"`);
448
+
449
+ return packCmdArr.join(' ');
450
+ }
451
+
452
+ /**
453
+ * !Not ready for use! Remove private modifier and commit as `feat(dotnet)` when ready for release!
454
+ * Blocking Issue: convert all dotnet-related functionality to a Semantic Release plugin!
455
+ * The current {@link SemanticReleaseConfigDotnet} leverages
456
+ * `@semantic-release/exec` to invoke dotnet commands. This is fine for
457
+ * relatively short command lines, but chaining commands with ' && ' results
458
+ * in quickly-growing complexity.
459
+ * NuGet packages should be created during the `prepare` step, but complex
460
+ * configuration of `dotnet pack` via command lines intended to be invoked by
461
+ * `@semantic-release/exec` is impractical.
462
+ * @param opts `dotnet pack` options. See `dotnet pack -h`,
463
+ * https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-pack, and
464
+ * {@link PackPackagesOptionsType}.
465
+ * {@link opts['-GetItem']} will _always_ have '_OutputPackItems'.
466
+ * @param [usePerSourceSubfolder] If `true`, modify the output path to
467
+ * include a subfolder bearing a path-safe encoding of the NuGet Source that
468
+ * will receive the nupkg.
469
+ * @param [usePerPackageIdSubfolder] If `true`, modify the output path
470
+ * to include a subfolder named after the the PackageId.
471
+ * @returns a string[] containing the full file paths of all new packages i.e.
472
+ * .nupkg, .symbols.nupkg, .snupkg
473
+ */
474
+ // @ts-expect-error Todo: publicize to dismiss this "unused" error.
475
+ private async _PackPackages(
476
+ opts: typeof NRI.PackPackagesOptionsType.inferIn,
477
+ usePerSourceSubfolder = false,
478
+ usePerPackageIdSubfolder = false,
479
+ ): Promise<string[]> {
480
+ opts['-GetItem'] = [...opts['-GetItem'] ?? [], key_OutputPackItems];
481
+
482
+ const packCmd = this.GetPackCommand(
483
+ opts,
484
+ usePerSourceSubfolder,
485
+ usePerPackageIdSubfolder,
486
+ );
487
+ let packOutput: undefined | { stdout: string; stderr: string } = undefined;
488
+ while (packOutput === undefined) {
489
+ packOutput = await setTimeout(
490
+ 1000,
491
+ execAsync(packCmd, true),
492
+ )
493
+ .then(async p => await p)
494
+ .catch<undefined>(catchCsc2012);
495
+ }
496
+ // may include .snupkg
497
+ const nupkgFullPaths: string[] | undefined = new MSBuildEvaluationOutput(packOutput.stdout)
498
+ .Items
499
+ ?.[key_OutputPackItems]
500
+ ?.filter(item => item.Extension !== '.nuspec')
501
+ .map(item => item.FullPath);
502
+ return nupkgFullPaths ?? [];
503
+ }
504
+
505
+ /**
506
+ * Create a dummy package for the current {@link project} by executing a
507
+ * command line like \``dotnet pack ${this.project.Properties.MSBuildProjectFullPath} -p:Version=0.0.1-DUMMY -output ${getDummiesDir(this._project)}/${GetNameForURL(this.source)}`\`
508
+ * @param opts Options passed to
509
+ * `dotnet pack`, excluding the required `<PROJECT | SOLUTION>` argument.
510
+ * - The `output` field is ignored and overwritten. It is replaced with
511
+ * ${{@link getDummiesDir}({@link project})}/${{@link GetDirNameForSource}({@link source})}
512
+ * - The `output` path will be affixed with a folder named after this
513
+ * {@link NugetRegistryInfo#source}, but will not include a subfolder for the
514
+ * {@link NugetRegistryInfo#project NugetRegistryInfo.project}.{@link MSBuildProject#Properties Properties}.{@link MSBuildProject#Properties#PackageId PackageId}.
515
+ * @returns the full paths of all nupkg, symbols.nupkg, and snupkg files
516
+ * created by the Pack target, as extracted from the dotnet process's STDOUT.
517
+ * If mixed with other nupkgs, filter for the {@link NugetProjectProperties#PackageId}
518
+ */
519
+ public async PackDummyPackage(
520
+ opts: typeof NRI.PackDummyPackagesOptionsType.inferIn,
521
+ ): Promise<string[]> {
522
+ const packCmd: string = this.GetPackCommand(
523
+ {
524
+ ...opts,
525
+ output: getDummiesDir(this._project),
526
+ propertyOverrides: { ...opts.propertyOverrides, Version: '0.0.1-DUMMY' },
527
+ '-GetItem': [...opts['-GetItem'] ?? [], key_OutputPackItems],
528
+ },
529
+ true,
530
+ );
531
+
532
+ let packOutput: undefined | { stdout: string; stderr: string } = undefined;
533
+ while (packOutput === undefined) {
534
+ packOutput = await setTimeout(
535
+ 1000,
536
+ execAsync(packCmd, true),
537
+ )
538
+ .then(async p => await p)
539
+ .catch<undefined>(catchCsc2012);
540
+ }
541
+ // may include .snupkg
542
+ const nupkgFullPaths: string[] | undefined = new MSBuildEvaluationOutput(packOutput.stdout)
543
+ .Items
544
+ ?.['outputPackItems']
545
+ ?.filter(item => item.Extension !== '.nuspec')
546
+ .map(item => item.FullPath);
547
+ return nupkgFullPaths ?? [];
548
+ }
549
+
550
+ // #endregion Pack
551
+ // #region Push
552
+
553
+ /**
554
+ * Also includes required argument 'ROOT': the directory in which packages
555
+ * should be present and ready to be pushed the default or specified Source.
556
+ * The ROOT may also include wildcards e.g. `*.nupkg`, `**\\*.nupkg`
557
+ * See https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-push
558
+ *
559
+ * Specific to this API:
560
+ * If you want to use this API's default root value (\`${cwd()}/publish`), assign an empty string.
561
+ */
562
+ static readonly PushPackagesOptionsType: ObjectType<{
563
+ root: string;
564
+ apiKey?: string | undefined;
565
+ configFile?: string | undefined;
566
+ disableBuffering?: boolean | undefined;
567
+ forceEnglishOutput?: boolean | undefined;
568
+ interactive?: boolean | undefined;
569
+ noServiceEndpoint?: boolean | undefined;
570
+ noSymbols?: boolean | undefined;
571
+ skipDuplicate?: boolean | undefined;
572
+ source?: string | undefined;
573
+ symbolApiKey?: string | undefined;
574
+ symbolSource?: string | undefined;
575
+ timeout?: number | undefined;
576
+ }> = Object.freeze(
577
+ type({
578
+ /** If an empty string is passed, this property is overridden to `./publish` */
579
+ root: 'string',
580
+ /** The API key for the server. NOTE: if `undefined` or an empty string, the `dotnet nuget` client will lookup credentials set via `dotnet nuget {add|update} source`. */
581
+ 'apiKey?': 'string',
582
+ /** The NuGet configuration file (nuget.config) to use. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see {@link https://learn.microsoft.com/en-us/nuget/consume-packages/configuring-nuget-behavior Common NuGet Configurations}. */
583
+ 'configFile?': 'string',
584
+ /** Disables buffering when pushing to an HTTP(S) server to reduce memory usage. */
585
+ 'disableBuffering?': 'boolean',
586
+ /** Forces the application to run using an invariant, English-based culture. */
587
+ 'forceEnglishOutput?': 'boolean',
588
+ /** Allows the command to stop and wait for user input or action. For example, to complete authentication. Available since .NET Core 3.0 SDK. */
589
+ 'interactive?': 'boolean',
590
+ /** Doesn't append "api/v2/package" to the source URL. */
591
+ 'noServiceEndpoint?': 'boolean',
592
+ 'noSymbols?': 'boolean',
593
+ /** When pushing multiple packages to an HTTP(S) server, treats any 409 Conflict response as a warning so that other pushes can continue. */
594
+ 'skipDuplicate?': 'boolean',
595
+ /**
596
+ * Specifies the server URL. NuGet identifies a UNC or local folder source and simply copies the file there instead of pushing it using HTTP.
597
+ *
598
+ * ### Important
599
+ * > Starting with NuGet 3.4.2, this is a mandatory parameter unless the NuGet config file specifies a `DefaultPushSource` value. For more information, see {@link https://learn.microsoft.com/en-us/nuget/consume-packages/configuring-nuget-behavior Configuring NuGet behavior}.
600
+ */
601
+ 'source?': 'string',
602
+ /** The API key for the symbol server. NOTE: if `undefined`, the `dotnet nuget` client will lookup credentials set via `dotnet nuget {add|update} source`.` */
603
+ 'symbolApiKey?': 'string',
604
+ /** Specifies the symbol server URL. */
605
+ 'symbolSource?': 'string',
606
+ /** Specifies the timeout for pushing to a server in seconds. Defaults to 300 seconds (5 minutes). Specifying 0 applies the default value. */
607
+ 'timeout?': 'number',
608
+ }),
609
+ );
610
+
611
+ /**
612
+ * {@link NRI.PushPackagesOptionsType} sans {@link NRI.PushPackagesOptionsType.t.root}.
613
+ * The result of {@link getDummiesDir} is used, instead.
614
+ */
615
+ public static readonly PushDummyPackagesOptionsType: ObjectType<{
616
+ apiKey?: string | undefined;
617
+ configFile?: string | undefined;
618
+ disableBuffering?: boolean | undefined;
619
+ forceEnglishOutput?: boolean | undefined;
620
+ interactive?: boolean | undefined;
621
+ noServiceEndpoint?: boolean | undefined;
622
+ noSymbols?: boolean | undefined;
623
+ source?: string | undefined;
624
+ symbolApiKey?: string | undefined;
625
+ symbolSource?: string | undefined;
626
+ timeout?: number | undefined;
627
+ skipDuplicate: Default<true, true>;
628
+ }>
629
+ = NugetRegistryInfo.PushPackagesOptionsType.merge({
630
+ skipDuplicate: 'true = true',
631
+ }).omit('root');
632
+
633
+ /**
634
+ * Create a `dotnet nuget push` command line from the given options and
635
+ * optional boolean parameters.
636
+ * @param opts See {@link PushPackagesOptionsType}
637
+ * @param usePerSourceSubfolder If `true`, the NuGet Source name or URL is formatted
638
+ * to a folder name and appended to the ROOT as a subfolder. Do not use
639
+ * wildcards in ROOT with this set to `true`!
640
+ * @param usePerPackageIdSubfolder If `true`, the
641
+ * {@link project}'s {@link NugetProjectProperties#PackageId}
642
+ * is appended to the ROOT as a subfolder. Do not use wildcards in
643
+ * ROOT with this set to `true`!
644
+ * @returns A `dotnet nuget push` command line formatted with the
645
+ * appropriate arguments.
646
+ */
647
+ GetPushCommand(
648
+ opts: typeof NRI.PushPackagesOptionsType.inferIn,
649
+ usePerSourceSubfolder = false,
650
+ usePerPackageIdSubfolder = false,
651
+ ): string {
652
+ const validOpts = NRI.PushPackagesOptionsType.from(opts);
653
+ type.boolean.assert(usePerSourceSubfolder);
654
+ type.boolean.assert(usePerPackageIdSubfolder);
655
+
656
+ validOpts.root = validOpts.root === '' ? `${cwd()}/publish` : validOpts.root;
657
+ if (usePerSourceSubfolder)
658
+ validOpts.root = node_path.join(validOpts.root, NugetRegistryInfo.GetDirNameForSource(this.source), node_path.sep);
659
+ if (usePerPackageIdSubfolder)
660
+ validOpts.root = node_path.join(validOpts.root, this._project.Properties.PackageId, node_path.sep);
661
+
662
+ const packCmdArr: string[] = [
663
+ 'dotnet',
664
+ 'nuget',
665
+ 'push',
666
+ `"${node_path.join(validOpts.root, '*.nupkg')}"`,
667
+ ];
668
+
669
+ if (this.resolvedEnvVariable)
670
+ validOpts.apiKey ??= NRI._GetTokenValue(this.resolvedEnvVariable);
671
+ /**
672
+ * If apiKey is an empty string, defer to the dotnet CLI's NuGet client
673
+ * ability to lookup API keys saved via `dotnet nuget add source` or NuGet config
674
+ * files.
675
+ */
676
+ if (validOpts.apiKey && validOpts.apiKey !== '')
677
+ packCmdArr.push('--api-key', validOpts.apiKey);
678
+ if (validOpts.configFile)
679
+ packCmdArr.push('--configfile', validOpts.configFile);
680
+ if (validOpts.disableBuffering === true)
681
+ packCmdArr.push('--disable-buffering');
682
+ if (validOpts.forceEnglishOutput === true)
683
+ packCmdArr.push('--force-english-output');
684
+ if (validOpts.interactive === true)
685
+ packCmdArr.push('--interactive');
686
+ if (validOpts.noServiceEndpoint === true)
687
+ packCmdArr.push('--no-service-endpoint');
688
+ if (validOpts.noSymbols === true)
689
+ packCmdArr.push('--no-symbols');
690
+ if (validOpts.skipDuplicate === true)
691
+ packCmdArr.push('--skip-duplicate');
692
+ validOpts.source ??= this.source;
693
+ packCmdArr.push('--source', validOpts.source);
694
+ if (validOpts.symbolApiKey !== undefined)
695
+ packCmdArr.push('--symbol-api-key', validOpts.symbolApiKey);
696
+ if (validOpts.symbolSource !== undefined)
697
+ packCmdArr.push('--symbol-source', validOpts.symbolSource);
698
+ if (validOpts.timeout !== undefined)
699
+ packCmdArr.push('--timeout', validOpts.timeout.toString());
700
+
701
+ return packCmdArr.join(' ');
702
+ }
703
+
704
+ /**
705
+ * Immediately push packages. The input path may be modified according to the
706
+ * {@link usePerSourceSubfolder} and {@link usePerPackageIdSubfolder}
707
+ * arguments.
708
+ * @param opts The `dotnet nuget push` command line options, including the
709
+ * ROOT argument, the directory containing local nuget packages ready to be
710
+ * pushed.
711
+ * @param usePerSourceSubfolder If `true`, the NuGet Source name or URL is formatted
712
+ * to a folder name and appended to the ROOT as a subfolder. Do not use
713
+ * wildcards in ROOT with this set to `true`!
714
+ * @param usePerPackageIdSubfolder If `true`, the current {@link project}'s
715
+ * PackageId is appended to the ROOT as a subfolder. Do not use wildcards in
716
+ * ROOT with this set to `true`!
717
+ */
718
+ // @ts-expect-error Todo: publicize to dismiss this "unused" error.
719
+ private async _PushPackages(
720
+ opts: typeof NRI.PushPackagesOptionsType.inferIn,
721
+ usePerSourceSubfolder = false,
722
+ usePerPackageIdSubfolder = false,
723
+ ) {
724
+ // const pushOutput =
725
+ await execAsync(
726
+ this.GetPushCommand(
727
+ opts,
728
+ usePerSourceSubfolder,
729
+ usePerPackageIdSubfolder,
730
+ ),
731
+ true,
732
+ ).catch((error: unknown) => {
733
+ const _error: Error = isNativeError(error) ? error : new Error(JSON.stringify(error));
734
+ throw opts.apiKey
735
+ ? _censorTokenInError(_error, opts.apiKey)
736
+ : _error;
737
+ });
738
+ }
739
+
740
+ /**
741
+ *
742
+ * Get a `dotnet nuget push` command for pushing one or more nupkg/snupkg
743
+ * files created by {@link GetPackCommand} or {@link _PackPackages}.\
744
+ * Like {@link PackDummyPackage}, the output/ROOT path will include a
745
+ * folder named after this NRI instance's {@link NugetRegistryInfo#source},
746
+ * but will not include a subfolder for the
747
+ * {@link NugetRegistryInfo#project NugetRegistryInfo.project}.{@link MSBuildProject#Properties Properties}.{@link MSBuildProject#Properties#PackageId PackageId}
748
+ * @example
749
+ * ```ts
750
+ * const packAndPushDummyCmd = [
751
+ * nri.GetPackCommand(
752
+ * NugetRegistryInfo.PackPackagesOptionsType.from({ root: '' }),
753
+ * false,
754
+ * false,
755
+ * ),
756
+ * nri.GetPushDummyPackageCommand(pushOpts, false, false),
757
+ * ].join(' && ')
758
+ * ```
759
+ * @param opts options for `dotnet nuget push`. The following
760
+ * fields are overwritten:
761
+ * - root: getDummiesDir(this.project)
762
+ * - skipDuplicates: true
763
+ * @returns a `dotnet nuget push` command to push a dummy package
764
+ * (created by executing {@link PackDummyPackage}) to {@link source}
765
+ */
766
+ GetPushDummyCommand(
767
+ opts: typeof NRI.PushDummyPackagesOptionsType.inferIn,
768
+ ): string {
769
+ return this.GetPushCommand(
770
+ {
771
+ ...NRI.PushDummyPackagesOptionsType.from(opts),
772
+ root: getDummiesDir(this._project),
773
+ },
774
+ true,
775
+ );
776
+ }
777
+
778
+ /**
779
+ * Call {@link GetPushDummyCommand} and immediately execute it.
780
+ * @throws {Error} when the process exits with an error code indicating
781
+ * failure i.e. the command line is invalid, the process fails to start,
782
+ * the push fails, et cetera.
783
+ * @param opts the ROOT arg and options for `dotnet nuget push`. The following
784
+ * fields are overwritten:
785
+ * - root: getDummiesDir(this.project)
786
+ * - skipDuplicates: true
787
+ * @returns The return type of {@link execAsync} i.e. a {@link Promise} resolving to `{ stdout: string; stderr: string }`.
788
+ */
789
+ private async _PushDummyPackages(
790
+ opts: typeof NRI.PushDummyPackagesOptionsType.inferIn,
791
+ ): ReturnType<typeof execAsync> {
792
+ const pushCmd: string = this.GetPushDummyCommand(opts);
793
+ return await execAsync(pushCmd, true)
794
+ .catch((error: unknown) => {
795
+ const _error: Error = isNativeError(error) ? error : new Error(String(error));
796
+ throw opts.apiKey
797
+ ? _censorTokenInError(_error, opts.apiKey)
798
+ : _error;
799
+ });
800
+ }
801
+
802
+ // #endregion Push
803
+
804
+ // if non-exact-match is needed, learn how to make a parameter-driven type.
805
+ private static readonly _NugetSearchReturnTypes = {
806
+ ExactMatch: {
807
+ v2: type({
808
+ version: '2',
809
+ problems: 'unknown[]',
810
+ searchResult: [
811
+ {
812
+ sourceName: 'string',
813
+ packages: type({
814
+ id: 'string',
815
+ version: type.keywords.string.semver,
816
+ }).array(),
817
+ },
818
+ ],
819
+ }),
820
+ },
821
+ };
822
+
823
+ private static readonly _ParseNugetSearchReturn = type(
824
+ 'string.json.parse',
825
+ ).to(this._NugetSearchReturnTypes.ExactMatch.v2);
826
+
827
+ /**
828
+ * !WARNING: this method requires the Nuget Source to be configured via `dotnet nuget add source` or `dotnet nuget update source`. `NUGET_TOKEN` works, but it may be vulnerable to supply chain attacks.\
829
+ * Call during the `prepare` step of a Semantic Release run.\
830
+ * Determine if the `nextVersion` generated during the `analyze` Semantic
831
+ * Release step was already published to the NuGet {@link source}.
832
+ * @param source The name or URI of the NuGet Source to search. If this API
833
+ * endpoint does not support searches, the operation will fail. If this API
834
+ * endpoint requires authentication (e.g. GitHub), it must be configured via
835
+ * `dotnet nuget add source` or `dotnet nuget update source` before calling
836
+ * this method.
837
+ * @param packageId The ID of the NuGet package to search for.
838
+ * @param nextVersion The nextVersion value generated by semantic-release's hidden ["Create Git tag" step](https://semantic-release.gitbook.io/semantic-release#:~:text=the%20last%20release.-,Create%20Git%20tag,-Create%20a%20Git).
839
+ * @returns A promised boolean.
840
+ * If the promise resolves to `true`, the semantic release run should be
841
+ * cancelled immediately.
842
+ * Otherwise, the release should proceed.
843
+ * @todo utilize in custom plugin inserted at the beginning of `prepare`
844
+ */
845
+ static async IsNextVersionAlreadyPublished(
846
+ source: string,
847
+ packageId: string,
848
+ nextVersion: string,
849
+ ): Promise<boolean> {
850
+ if (nextVersion === '')
851
+ throw new Error('The value of nextVersion is empty');
852
+ return await execAsync(
853
+ `dotnet package search --format JSON --exact-match --source ${source} --prerelease ${packageId}`,
854
+ true,
855
+ )
856
+ .then(stdPair => stdPair.stdout)
857
+ .then(json => this._ParseNugetSearchReturn(json))
858
+ .then(errsOrObj => errsOrObj instanceof type.errors ? errsOrObj.throw() : errsOrObj)
859
+ .then(obj => obj.searchResult)
860
+ .then(results => results[0].packages)
861
+ .then(pkgs =>
862
+ pkgs.find(p => p.version === type('string.semver').from(nextVersion)),
863
+ )
864
+ .then(pkg => pkg !== undefined);
865
+ }
866
+
867
+ /**
868
+ * !WARNING: GITHUB_OUTPUT must be the full path to an environment file.
869
+ * The plugin "semantic-release-output-variables" next-release-version
870
+ *
871
+ * !WARNING: NuGet Source API Key mus tbe configured via `dotnet nuget add source` or `dotnet nuget update source`.
872
+ * Some Sources (e.g. GitHub) require authentication for package searches.
873
+ *
874
+ * # Authenticating NuGet Package Searches
875
+ *
876
+ * ## GitHub NuGet Registry authentication
877
+ * - {@link https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-nuget-registry#authenticating-in-a-github-actions-workflow Authenticating in a GitHub Actions workflow}
878
+ * - {@link https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-nuget-registry#authenticating-with-a-personal-access-token Authenticating with a personal access token}.
879
+ * ## For GitLab NuGet Registry authentication, see
880
+ * - {@link https://docs.gitlab.com/ee/user/packages/nuget_repository/#add-a-source-with-the-net-cli Add a source with the .NET CLI}
881
+ * @returns a string containing a Node.JS command line invoking {@link ./IsNextVersionAlreadyPublished.cli.ts}
882
+ * @see {@link ./IsNextVersionAlreadyPublished.cli.ts}, {@link ./IsNextVersionAlreadyPublished.cli.js}
883
+ */
884
+ GetIsNextVersionAlreadyPublishedCommand(): string {
885
+ // if GITHUB_OUTPUT unset or its file does not exist, create it. ''
886
+ getGithubOutputSync();
887
+ // The script will run
888
+ return `node ${node_path.join(import.meta.dirname, './IsNextVersionAlreadyPublished.cli.js')} --packageId ${this._project.Properties.PackageId} --source ${this.source}`;
889
+ }
890
+
891
+ /*
892
+ * Copy https://github.com/joelharkes/nuget-push when we split off our dotnet
893
+ * modules to a semantic-release plugin.
894
+ */
895
+
896
+ /*
897
+ * If you want a deterministic nupkg, do so with a custom MSBuild target with
898
+ * AfterTargets="Pack" to restore and execute the dotnet tool "Kuinox.NupkgDeterministicator" .
899
+ */
900
+ }
901
+
902
+ // shorthand/alias for NugetRegistryInfo
903
+ const NRI: typeof NugetRegistryInfo = NugetRegistryInfo;
904
+
905
+ /**
906
+ * The base type for {@link NRIOpts} and related types. Extend this type while
907
+ * overriding member types via {@link NRIOptsBase.merge}
908
+ */
909
+ export const NRIOptsBase: ObjectType<{
910
+ project: MSBuildProject | {
911
+ readonly Items: Readonly<Required<MSBuildEvaluationOutput>['Items']>;
912
+ readonly Properties: Readonly<NugetProjectProperties>;
913
+ readonly Targets: readonly string[];
914
+ readonly TargetResults: Required<MSBuildEvaluationOutput>['TargetResults'][];
915
+ };
916
+ source: string;
917
+ tokenEnvVars: readonly string[];
918
+ }> = type({
919
+ /**
920
+ * The environment variables whose values are tokens with permission to push a
921
+ * package to the NuGet package registry. The array is iterated through until
922
+ * one token is found. If none of the environment variables are defined,
923
+ * {@link NugetRegistryInfo}'s constructor will throw an {@link Error}.
924
+ */
925
+ project: type
926
+ .instanceOf(MSBuildProject)
927
+ .or(type.instanceOf(MSBuildProject).readonly()),
928
+ /**
929
+ * A NuGet package registry's API endpoint URL -OR- the name assigned via the
930
+ * client e.g. `dotnet nuget add source --name ${source} ${source's URL}`
931
+ */
932
+ source: type.string,
933
+ /**
934
+ * WARNING: If possible, set credentials via `dotnet nuget {add|update}
935
+ * source` as recommended by Microsoft! This is more secure than exposing
936
+ * credentials to the Node.JS runtime and all its loaded modules.
937
+ *
938
+ * The environment variables whose values are tokens with permission to push a
939
+ * package to the NuGet package registry.The array is iterated through until
940
+ * one token is found.If none of the environment variables are defined,
941
+ * {@link NugetRegistryInfo}'s constructor will throw an {@link Error}.
942
+ *
943
+ * If none of these are defined in the `.env` or process environment variables (.vault.env is impractical in CI), the `--api-key/-k` argument is excluded from `dotnet nuget push` commands.
944
+ * Instead, the NuGet client relies on credentials configured for the
945
+ * given NuGet source. If the NuGet client does not find credentials saved for the
946
+ * NuGet {@link NRIOptsBase.t.source source} and they are required, the command will fail.
947
+ *
948
+ * Use the `dotnet` CLI to configure credentials for existing NuGet sources
949
+ * ({@link https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-update-source `dotnet nuget update source`})
950
+ * -OR- configure credentials for non-default NuGet sources
951
+ * ({@link https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-add-source `dotnet nuget add source`}).\
952
+ * Alternatively, use the `nuget.exe` CLI to add/update sources. See
953
+ * {@link https://learn.microsoft.com/en-us/nuget/reference/cli-reference/cli-ref-sources `nuget sources` (NuGet CLI)}.
954
+ *
955
+ * The credentials will be validated during the `verifyConditions` step of Semantic Release.
956
+ */
957
+ tokenEnvVars: type.string.array().readonly(),
958
+ });
959
+
960
+ /**
961
+ * The type of the parameter for {@link NugetRegistryInfo}'s constructor.
962
+ */
963
+ export const NRIOpts: ObjectType<{
964
+ project: MSBuildProject | {
965
+ readonly Items: Readonly<Required<MSBuildEvaluationOutput>['Items']>;
966
+ readonly Properties: Readonly<NugetProjectProperties>;
967
+ readonly Targets: readonly string[];
968
+ readonly TargetResults: Required<MSBuildEvaluationOutput>['TargetResults'][];
969
+ };
970
+ tokenEnvVars: Default<readonly string[], readonly ['NUGET_TOKEN']>;
971
+ source: Default<string, string>;
972
+ }> = NRIOptsBase.merge({
973
+ /**
974
+ * Defaults to {@link NugetRegistryInfo.DefaultTokenEnvVars}
975
+ * @see {@link NRIOptsBase.t.tokenEnvVars}
976
+ */
977
+ tokenEnvVars: NRIOptsBase.get('tokenEnvVars').default(
978
+ () => NugetRegistryInfo.DefaultTokenEnvVars,
979
+ ),
980
+ /**
981
+ * A NuGet package registry's API endpoint URL -OR- the name assigned to it
982
+ * via your NuGet client.
983
+ * @default 'https://api.nuget.org/v3/index.json' (name: 'nuget.org')
984
+ * @see {@link NRIOptsBase.t.source}
985
+ */
986
+ source: NRIOptsBase.get('source').default(() => defaultNugetSource),
987
+ });
988
+
989
+ // #region token censorship
990
+
991
+ /**
992
+ * Replace all occurrences of {@link token} in the {@link string} with '***'.
993
+ * @param string The string in which a {@link token} may be found.
994
+ * @param token The NuGet API token you definitely don't want to leak!
995
+ * @returns A modified copy of the {@link string} with all occurrences of the
996
+ * {@link token} replaced with '***'.
997
+ */
998
+ function _censorToken(string: string, token: string): string {
999
+ return string.replaceAll(token, '***');
1000
+ }
1001
+
1002
+ /**
1003
+ * Censor all occurrences of an API {@link token} in an {@link error}.
1004
+ * @param error A {@link ExecException} in which the NuGet API {@link token} may be found.
1005
+ * @param token The value of the NuGet API token
1006
+ * @returns A modified copy of the provided exception sans any occurrence of the
1007
+ * NuGet API token.
1008
+ */
1009
+ function _censorTokenInError(error: ExecException, token: string): ExecException {
1010
+ return Object.assign(
1011
+ error,
1012
+ JSON.parse(
1013
+ _censorToken(
1014
+ JSON.stringify({
1015
+ ...error,
1016
+ message: error.message,
1017
+ stack: error.stack,
1018
+ }),
1019
+ token,
1020
+ ),
1021
+ ) as ExecException,
1022
+ );
1023
+ }
1024
+
1025
+ // #endregion token censorship