@@ -187,6 +187,63 @@ pub fn publish_test_results_step(
187187 . with_input ( "testResultsFiles" , test_results_files)
188188}
189189
190+ /// Returns a [`TaskStep`] for `NuGetCommand@2`.
191+ ///
192+ /// Runs a NuGet command. The `command` parameter selects the operation mode;
193+ /// each mode exposes a different set of optional inputs.
194+ ///
195+ /// - `command` — the NuGet operation: `"restore"`, `"push"`, `"pack"`, or
196+ /// `"custom"`. This is the only required input.
197+ ///
198+ /// **`restore` optional inputs** (applied with `.with_input(…)`):
199+ ///
200+ /// | Input key | Default | Description |
201+ /// |---|---|---|
202+ /// | `solution` | `"**/*.sln"` | Path to solution, `packages.config`, or `project.json`. |
203+ /// | `feedsToUse` | `"select"` | `"select"` (dropdown) or `"config"` (NuGet.config). |
204+ /// | `vstsFeed` | — | Azure Artifacts feed name or ID (when `feedsToUse = select`). |
205+ /// | `includeNuGetOrg` | `"true"` | Include NuGet.org as a package source. |
206+ /// | `nugetConfigPath` | — | Path to `NuGet.config` (when `feedsToUse = config`). |
207+ /// | `externalFeedCredentials` | — | Credentials for external feeds outside the org. |
208+ /// | `noCache` | `"false"` | Disable the local NuGet cache. |
209+ /// | `disableParallelProcessing` | `"false"` | Disable parallel package restore. |
210+ /// | `restoreDirectory` | — | Destination directory for restored packages. |
211+ /// | `verbosityRestore` | `"Detailed"` | Verbosity: `"Quiet"`, `"Normal"`, or `"Detailed"`. |
212+ ///
213+ /// **`push` optional inputs**:
214+ ///
215+ /// | Input key | Default | Description |
216+ /// |---|---|---|
217+ /// | `packagesToPush` | `"$(Build.ArtifactStagingDirectory)/**/*.nupkg;…"` | Glob for `.nupkg` files to publish. |
218+ /// | `nuGetFeedType` | `"internal"` | Feed location: `"internal"` (Azure Artifacts) or `"external"`. |
219+ /// | `publishVstsFeed` | — | Target Azure Artifacts feed (when `nuGetFeedType = internal`). |
220+ /// | `allowPackageConflicts` | `"false"` | Skip duplicate packages instead of failing. |
221+ /// | `publishFeedCredentials` | — | External NuGet server endpoint (when `nuGetFeedType = external`). |
222+ /// | `publishPackageMetadata` | `"true"` | Publish pipeline metadata alongside the package. |
223+ /// | `verbosityPush` | `"Detailed"` | Verbosity: `"Quiet"`, `"Normal"`, or `"Detailed"`. |
224+ ///
225+ /// **`pack` optional inputs**:
226+ ///
227+ /// | Input key | Default | Description |
228+ /// |---|---|---|
229+ /// | `packagesToPack` | `"**/*.csproj"` | Glob for `.csproj` or `.nuspec` files to pack. |
230+ /// | `configuration` | — | Build configuration (e.g. `"Release"`). |
231+ /// | `versioningScheme` | `"off"` | Version strategy: `"off"`, `"byPrereleaseNumber"`, `"byEnvVar"`, `"byBuildNumber"`. |
232+ /// | `verbosityPack` | `"Detailed"` | Verbosity: `"Quiet"`, `"Normal"`, or `"Detailed"`. |
233+ ///
234+ /// **`custom` optional inputs**:
235+ ///
236+ /// | Input key | Default | Description |
237+ /// |---|---|---|
238+ /// | `arguments` | — | Full NuGet command-line arguments (e.g. `"install Foo -Version 1.0 -Source ..."`). **Required** for `custom`. |
239+ ///
240+ /// ADO task reference:
241+ /// <https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/nuget-command-v2>
242+ pub fn nuget_command_step ( command : impl Into < String > ) -> TaskStep {
243+ let cmd: String = command. into ( ) ;
244+ TaskStep :: new ( "NuGetCommand@2" , format ! ( "NuGet {cmd}" ) ) . with_input ( "command" , cmd)
245+ }
246+
190247#[ cfg( test) ]
191248mod tests {
192249 use super :: * ;
@@ -537,4 +594,92 @@ mod tests {
537594 Some ( "**/*.zip\n **/*.tar.gz" )
538595 ) ;
539596 }
597+
598+ // ── NuGetCommand@2 ───────────────────────────────────────────────────
599+
600+ #[ test]
601+ fn nuget_command_step_restore_sets_task_and_command ( ) {
602+ let t = nuget_command_step ( "restore" ) ;
603+ assert_eq ! ( t. task, "NuGetCommand@2" ) ;
604+ assert_eq ! ( t. display_name, "NuGet restore" ) ;
605+ assert_eq ! ( t. inputs. get( "command" ) . map( |s| s. as_str( ) ) , Some ( "restore" ) ) ;
606+ // only the required input is set by default
607+ assert_eq ! ( t. inputs. len( ) , 1 ) ;
608+ }
609+
610+ #[ test]
611+ fn nuget_command_step_custom_with_arguments ( ) {
612+ let t = nuget_command_step ( "custom" ) . with_input (
613+ "arguments" ,
614+ "install My.Package -Version 1.0.0 -Source https://example.com/nuget -NonInteractive" ,
615+ ) ;
616+ assert_eq ! ( t. task, "NuGetCommand@2" ) ;
617+ assert_eq ! ( t. display_name, "NuGet custom" ) ;
618+ assert_eq ! ( t. inputs. get( "command" ) . map( |s| s. as_str( ) ) , Some ( "custom" ) ) ;
619+ assert_eq ! (
620+ t. inputs. get( "arguments" ) . map( |s| s. as_str( ) ) ,
621+ Some ( "install My.Package -Version 1.0.0 -Source https://example.com/nuget -NonInteractive" )
622+ ) ;
623+ assert_eq ! ( t. inputs. len( ) , 2 ) ;
624+ }
625+
626+ #[ test]
627+ fn nuget_command_step_push_with_feed ( ) {
628+ let t = nuget_command_step ( "push" )
629+ . with_input ( "nuGetFeedType" , "internal" )
630+ . with_input (
631+ "packagesToPush" ,
632+ "$(Build.ArtifactStagingDirectory)/**/*.nupkg" ,
633+ )
634+ . with_input ( "publishVstsFeed" , "myorg/myfeed" )
635+ . with_input ( "allowPackageConflicts" , "true" ) ;
636+ assert_eq ! ( t. task, "NuGetCommand@2" ) ;
637+ assert_eq ! ( t. inputs. get( "command" ) . map( |s| s. as_str( ) ) , Some ( "push" ) ) ;
638+ assert_eq ! (
639+ t. inputs. get( "nuGetFeedType" ) . map( |s| s. as_str( ) ) ,
640+ Some ( "internal" )
641+ ) ;
642+ assert_eq ! (
643+ t. inputs. get( "publishVstsFeed" ) . map( |s| s. as_str( ) ) ,
644+ Some ( "myorg/myfeed" )
645+ ) ;
646+ assert_eq ! (
647+ t. inputs. get( "allowPackageConflicts" ) . map( |s| s. as_str( ) ) ,
648+ Some ( "true" )
649+ ) ;
650+ assert_eq ! ( t. inputs. len( ) , 5 ) ;
651+ }
652+
653+ #[ test]
654+ fn nuget_command_step_restore_with_vsts_feed ( ) {
655+ let t = nuget_command_step ( "restore" )
656+ . with_input ( "solution" , "src/MyApp.sln" )
657+ . with_input ( "feedsToUse" , "select" )
658+ . with_input ( "vstsFeed" , "myorg/myproject/myfeed" )
659+ . with_input ( "includeNuGetOrg" , "false" ) ;
660+ assert_eq ! ( t. task, "NuGetCommand@2" ) ;
661+ assert_eq ! (
662+ t. inputs. get( "solution" ) . map( |s| s. as_str( ) ) ,
663+ Some ( "src/MyApp.sln" )
664+ ) ;
665+ assert_eq ! (
666+ t. inputs. get( "vstsFeed" ) . map( |s| s. as_str( ) ) ,
667+ Some ( "myorg/myproject/myfeed" )
668+ ) ;
669+ assert_eq ! (
670+ t. inputs. get( "includeNuGetOrg" ) . map( |s| s. as_str( ) ) ,
671+ Some ( "false" )
672+ ) ;
673+ assert_eq ! ( t. inputs. len( ) , 5 ) ;
674+ }
675+
676+ #[ test]
677+ fn nuget_command_step_accepts_all_supported_commands ( ) {
678+ for cmd in & [ "restore" , "push" , "pack" , "custom" ] {
679+ let t = nuget_command_step ( * cmd) ;
680+ assert_eq ! ( t. task, "NuGetCommand@2" ) ;
681+ assert_eq ! ( t. display_name, format!( "NuGet {cmd}" ) ) ;
682+ assert_eq ! ( t. inputs. get( "command" ) . map( |s| s. as_str( ) ) , Some ( * cmd) ) ;
683+ }
684+ }
540685}
0 commit comments