Skip to content

Commit 513643e

Browse files
feat(ir): add typed helper for NuGetCommand@2 (#1047)
1 parent aae77f6 commit 513643e

1 file changed

Lines changed: 145 additions & 0 deletions

File tree

src/compile/ir/tasks.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)]
191248
mod 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

Comments
 (0)