diff --git a/pkg/runbooks/queries_test.go b/pkg/runbooks/queries_test.go new file mode 100644 index 00000000..5e65e30e --- /dev/null +++ b/pkg/runbooks/queries_test.go @@ -0,0 +1,59 @@ +package runbooks + +import ( + "net/url" + "testing" + + "github.com/OctopusDeploy/go-octopusdeploy/v2/uritemplates" + "github.com/stretchr/testify/require" +) + +// TestRunbooksQueryExpandsIntoTemplate covers the path Get relies on: RunbooksQuery is +// converted by uritemplates.Struct2map and expanded against the space-wide runbooks +// template. A field present on the struct but absent from the template is silently +// dropped, so assert each filter survives the round trip. +func TestRunbooksQueryExpandsIntoTemplate(t *testing.T) { + parsedTemplate, err := uritemplates.Parse(template) + require.NoError(t, err) + + query := RunbooksQuery{ + IDs: []string{"Runbooks-1", "Runbooks-2"}, + IsClone: true, + PartialName: "Deploy Database", + ProjectIDs: []string{"Projects-1"}, + Skip: 10, + Take: 20, + } + + values, ok := uritemplates.Struct2map(query) + require.True(t, ok) + require.NotNil(t, values) + values["spaceId"] = "Spaces-1" + + expanded, err := parsedTemplate.Expand(values) + require.NoError(t, err) + + expandedURL, err := url.Parse(expanded) + require.NoError(t, err) + require.Equal(t, "/api/Spaces-1/runbooks", expandedURL.Path) + + parameters := expandedURL.Query() + require.Equal(t, "Runbooks-1,Runbooks-2", parameters.Get("ids")) + require.Equal(t, "Deploy Database", parameters.Get("partialName")) + require.Equal(t, "Projects-1", parameters.Get("projectIds")) + require.Equal(t, "10", parameters.Get("skip")) + require.Equal(t, "20", parameters.Get("take")) +} + +func TestRunbooksQueryOmitsEmptyFilters(t *testing.T) { + parsedTemplate, err := uritemplates.Parse(template) + require.NoError(t, err) + + values, ok := uritemplates.Struct2map(RunbooksQuery{}) + require.True(t, ok) + values["spaceId"] = "Spaces-1" + + expanded, err := parsedTemplate.Expand(values) + require.NoError(t, err) + require.Equal(t, "/api/Spaces-1/runbooks", expanded) +} diff --git a/pkg/runbooks/runbook_service.go b/pkg/runbooks/runbook_service.go index e60a32f7..4408b2a2 100644 --- a/pkg/runbooks/runbook_service.go +++ b/pkg/runbooks/runbook_service.go @@ -140,6 +140,13 @@ func DeleteByID(client newclient.Client, spaceID string, ID string) error { return newclient.DeleteByID(client, template, spaceID, ID) } +// Get returns runbooks across a space, in a standard Octopus paginated result structure. +// Use RunbooksQuery to filter by project, name, or ID. To list the runbooks of a single +// project, List is a convenience wrapper over the project-scoped endpoint. +func Get(client newclient.Client, spaceID string, runbooksQuery RunbooksQuery) (*resources.Resources[*Runbook], error) { + return newclient.GetByQuery[Runbook](client, template, spaceID, runbooksQuery) +} + // List returns a list of runbooks from the server, in a standard Octopus paginated result structure. // If you don't specify --limit the server will use a default limit (typically 30) func List(client newclient.Client, spaceID string, projectID string, filter string, limit int) (*resources.Resources[*Runbook], error) {