Skip to content

Commit e74cf55

Browse files
Swarnendu GuptaHarness
authored andcommitted
chore: [ML-1304]: Add tool for Input Set and List Input Set (#25)
* chore: [ML-1304]: Resolved comments Signed-off-by: Saranya-jena <[email protected]> * chore: [ML-1304]: Resolved comments Signed-off-by: Saranya-jena <[email protected]> * Delete file pkg/.DS_Store * Delete file cmd/.DS_Store * Delete file client/.DS_Store * Delete file .DS_Store * Delete file pkg/harness/.DS_Store * chore: [ML-1304]: Add list and get pipeline inputsets tool Signed-off-by: Saranya-jena <[email protected]> * chore: [ML-1304]: Add list and get pipeline inputsets tool Signed-off-by: Saranya-jena <[email protected]> * Input Set and List Input Set
1 parent 3d03322 commit e74cf55

File tree

6 files changed

+518
-7
lines changed

6 files changed

+518
-7
lines changed

client/dto/pipeline.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,91 @@ type User struct {
178178
UserName string `json:"userName,omitempty"`
179179
CreatedAt int64 `json:"createdAt,omitempty"`
180180
}
181+
182+
// InputSetListOptions represents the options for listing input sets
183+
type InputSetListOptions struct {
184+
PaginationOptions
185+
PipelineIdentifier string `json:"pipelineIdentifier,omitempty"`
186+
SearchTerm string `json:"searchTerm,omitempty"`
187+
}
188+
189+
// InputSetListItem represents an item in the input set list
190+
type InputSetListItem struct {
191+
Identifier string `json:"identifier,omitempty"`
192+
Name string `json:"name,omitempty"`
193+
PipelineIdentifier string `json:"pipelineIdentifier,omitempty"`
194+
Description string `json:"description,omitempty"`
195+
InputSetType string `json:"inputSetType,omitempty"`
196+
Tags map[string]string `json:"tags,omitempty"`
197+
GitDetails GitDetails `json:"gitDetails,omitempty"`
198+
CreatedAt int64 `json:"createdAt,omitempty"`
199+
LastUpdatedAt int64 `json:"lastUpdatedAt,omitempty"`
200+
IsOutdated bool `json:"isOutdated,omitempty"`
201+
InputSetErrorDetails InputSetErrorDetails `json:"inputSetErrorDetails,omitempty"`
202+
OverlaySetErrorDetails map[string]string `json:"overlaySetErrorDetails,omitempty"`
203+
EntityValidityDetails EntityValidityDetails `json:"entityValidityDetails,omitempty"`
204+
Modules []string `json:"modules,omitempty"`
205+
}
206+
207+
// InputSetErrorDetails represents error details for input sets
208+
type InputSetErrorDetails struct {
209+
ErrorPipelineYaml string `json:"errorPipelineYaml,omitempty"`
210+
UuidToErrorResponseMap map[string]interface{} `json:"uuidToErrorResponseMap,omitempty"`
211+
InvalidInputSetReferences []string `json:"invalidInputSetReferences,omitempty"`
212+
Type string `json:"type,omitempty"`
213+
}
214+
215+
// InputSetListResponse represents the full response structure for listing input sets
216+
type InputSetListResponse struct {
217+
Status string `json:"status,omitempty"`
218+
Data InputSetListData `json:"data,omitempty"`
219+
MetaData map[string]interface{} `json:"metaData,omitempty"`
220+
CorrelationId string `json:"correlationId,omitempty"`
221+
}
222+
223+
// InputSetListData represents the data field of input set list response
224+
type InputSetListData struct {
225+
TotalPages int `json:"totalPages,omitempty"`
226+
TotalItems int `json:"totalItems,omitempty"`
227+
PageItemCount int `json:"pageItemCount,omitempty"`
228+
PageSize int `json:"pageSize,omitempty"`
229+
Content []InputSetListItem `json:"content,omitempty"`
230+
PageIndex int `json:"pageIndex,omitempty"`
231+
Empty bool `json:"empty,omitempty"`
232+
PageToken string `json:"pageToken,omitempty"`
233+
}
234+
235+
// InputSetDetail represents the detailed information of a specific input set
236+
type InputSetDetail struct {
237+
AccountId string `json:"accountId,omitempty"`
238+
OrgIdentifier string `json:"orgIdentifier,omitempty"`
239+
ProjectIdentifier string `json:"projectIdentifier,omitempty"`
240+
PipelineIdentifier string `json:"pipelineIdentifier,omitempty"`
241+
Identifier string `json:"identifier,omitempty"`
242+
InputSetYaml string `json:"inputSetYaml,omitempty"`
243+
Name string `json:"name,omitempty"`
244+
Description string `json:"description,omitempty"`
245+
Tags map[string]string `json:"tags,omitempty"`
246+
InputSetErrorWrapper InputSetErrorWrapper `json:"inputSetErrorWrapper,omitempty"`
247+
GitDetails GitDetails `json:"gitDetails,omitempty"`
248+
EntityValidityDetails EntityValidityDetails `json:"entityValidityDetails,omitempty"`
249+
Outdated bool `json:"outdated,omitempty"`
250+
ErrorResponse bool `json:"errorResponse,omitempty"`
251+
}
252+
253+
// InputSetErrorWrapper represents the error wrapper for input sets
254+
type InputSetErrorWrapper struct {
255+
ErrorPipelineYaml string `json:"errorPipelineYaml,omitempty"`
256+
UuidToErrorResponseMap map[string]interface{} `json:"uuidToErrorResponseMap,omitempty"`
257+
InvalidInputSetReferences []string `json:"invalidInputSetReferences,omitempty"`
258+
Type string `json:"type,omitempty"`
259+
}
260+
261+
// InputSetResponse represents the full response structure for getting a specific input set
262+
type InputSetResponse struct {
263+
Status string `json:"status,omitempty"`
264+
Data InputSetDetail `json:"data,omitempty"`
265+
MetaData map[string]interface{} `json:"metaData,omitempty"`
266+
CorrelationId string `json:"correlationId,omitempty"`
267+
}
268+

client/pipelines.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ const (
1313
pipelineExecutionPath = "/api/pipelines/execution/url"
1414
pipelineExecutionGetPath = "/api/pipelines/execution/v2/%s"
1515
pipelineExecutionSummaryPath = "/api/pipelines/execution/summary"
16+
pipelineInputSetListPath = "/api/inputSets"
17+
pipelineInputSetPath = "/api/inputSets/%s"
1618
)
1719

1820
type PipelineService struct {
@@ -196,3 +198,71 @@ func (p *PipelineService) FetchExecutionURL(
196198

197199
return urlResponse.Data, nil
198200
}
201+
202+
func (p *PipelineService) ListInputSets(
203+
ctx context.Context,
204+
scope dto.Scope,
205+
opts *dto.InputSetListOptions,
206+
) (*dto.InputSetListResponse, error) {
207+
path := pipelineInputSetListPath
208+
209+
// Prepare query parameters
210+
params := make(map[string]string)
211+
addScope(scope, params)
212+
213+
// Handle nil options by creating default options
214+
if opts == nil {
215+
opts = &dto.InputSetListOptions{}
216+
}
217+
218+
// Set default pagination
219+
setDefaultPagination(&opts.PaginationOptions)
220+
221+
// Add pagination parameters
222+
params["page"] = fmt.Sprintf("%d", opts.Page)
223+
params["size"] = fmt.Sprintf("%d", opts.Size)
224+
225+
// Add optional parameters if provided
226+
if opts.PipelineIdentifier != "" {
227+
params["pipelineIdentifier"] = opts.PipelineIdentifier
228+
}
229+
if opts.SearchTerm != "" {
230+
params["searchTerm"] = opts.SearchTerm
231+
}
232+
233+
// Initialize the response object
234+
response := &dto.InputSetListResponse{}
235+
236+
// Make the GET request
237+
err := p.Client.Get(ctx, path, params, map[string]string{}, response)
238+
if err != nil {
239+
return nil, fmt.Errorf("failed to list input sets: %w", err)
240+
}
241+
242+
return response, nil
243+
}
244+
245+
func (p *PipelineService) GetInputSet(
246+
ctx context.Context,
247+
scope dto.Scope,
248+
pipelineIdentifier, inputSetIdentifier string,
249+
) (*dto.InputSetResponse, error) {
250+
pathTemplate := pipelineInputSetPath
251+
path := fmt.Sprintf(pathTemplate, inputSetIdentifier)
252+
253+
// Prepare query parameters
254+
params := make(map[string]string)
255+
addScope(scope, params)
256+
params["pipelineIdentifier"] = pipelineIdentifier
257+
258+
// Initialize the response object
259+
response := &dto.InputSetResponse{}
260+
261+
// Make the GET request
262+
err := p.Client.Get(ctx, path, params, map[string]string{}, response)
263+
if err != nil {
264+
return nil, fmt.Errorf("failed to get input set: %w", err)
265+
}
266+
267+
return response, nil
268+
}

pkg/harness/dto/connectors.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ type Connector struct {
5858
Spec map[string]interface{} `json:"spec"`
5959
}
6060

61+
// EntityValidityDetails represents the validity information of a connector.
62+
type EntityValidityDetails struct {
63+
Valid bool `json:"valid"`
64+
InvalidYaml string `json:"invalidYaml"`
65+
}
66+
6167
// ConnectorStatus represents the status information of a connector.
6268
type ConnectorStatus struct {
6369
Status string `json:"status"`
@@ -86,9 +92,3 @@ type GitDetails struct {
8692
Valid bool `json:"valid"`
8793
InvalidYaml string `json:"invalidYaml"`
8894
}
89-
90-
// EntityValidityDetails represents the validity information of a connector.
91-
type EntityValidityDetails struct {
92-
Valid bool `json:"valid"`
93-
InvalidYaml string `json:"invalidYaml"`
94-
}

pkg/harness/tools/pipelines.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
78
"github.com/harness/harness-mcp/client"
89
"github.com/harness/harness-mcp/client/dto"
910
"github.com/harness/harness-mcp/cmd/harness-mcp-server/config"
@@ -245,3 +246,103 @@ func ListExecutionsTool(config *config.Config, client *client.PipelineService) (
245246
return mcp.NewToolResultText(string(r)), nil
246247
}
247248
}
249+
250+
func ListInputSetsTool(config *config.Config, client *client.PipelineService) (tool mcp.Tool, handler server.ToolHandlerFunc) {
251+
return mcp.NewTool("list_input_sets",
252+
mcp.WithDescription("List input sets for a pipeline."),
253+
mcp.WithString("pipeline_identifier",
254+
mcp.Required(),
255+
mcp.Description("Pipeline identifier to filter input sets."),
256+
),
257+
mcp.WithString("search_term",
258+
mcp.Description("Optional search term to filter out Input Sets based on name, identifier, tags."),
259+
),
260+
WithScope(config, true),
261+
WithPagination(),
262+
),
263+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
264+
scope, err := FetchScope(config, request, true)
265+
if err != nil {
266+
return mcp.NewToolResultError(err.Error()), nil
267+
}
268+
269+
page, size, err := FetchPagination(request)
270+
if err != nil {
271+
return mcp.NewToolResultError(err.Error()), nil
272+
}
273+
274+
pipelineIdentifier, err := OptionalParam[string](request, "pipeline_identifier")
275+
if err != nil {
276+
return mcp.NewToolResultError(err.Error()), nil
277+
}
278+
279+
searchTerm, err := OptionalParam[string](request, "search_term")
280+
if err != nil {
281+
return mcp.NewToolResultError(err.Error()), nil
282+
}
283+
284+
opts := &dto.InputSetListOptions{
285+
PipelineIdentifier: pipelineIdentifier,
286+
SearchTerm: searchTerm,
287+
PaginationOptions: dto.PaginationOptions{
288+
Page: page,
289+
Size: size,
290+
},
291+
}
292+
293+
data, err := client.ListInputSets(ctx, scope, opts)
294+
if err != nil {
295+
return nil, fmt.Errorf("failed to list input sets: %w", err)
296+
}
297+
298+
r, err := json.Marshal(data)
299+
if err != nil {
300+
return nil, fmt.Errorf("failed to marshal input sets list: %w", err)
301+
}
302+
303+
return mcp.NewToolResultText(string(r)), nil
304+
}
305+
}
306+
307+
func GetInputSetTool(config *config.Config, client *client.PipelineService) (tool mcp.Tool, handler server.ToolHandlerFunc) {
308+
return mcp.NewTool("get_input_set",
309+
mcp.WithDescription("Get details of a specific input set for a pipeline in Harness."),
310+
mcp.WithString("pipeline_identifier",
311+
mcp.Required(),
312+
mcp.Description("The identifier of the pipeline."),
313+
),
314+
mcp.WithString("input_set_identifier",
315+
mcp.Required(),
316+
mcp.Description("The identifier of the input set."),
317+
),
318+
WithScope(config, true),
319+
),
320+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
321+
pipelineIdentifier, err := RequiredParam[string](request, "pipeline_identifier")
322+
if err != nil {
323+
return mcp.NewToolResultError(err.Error()), nil
324+
}
325+
326+
inputSetIdentifier, err := RequiredParam[string](request, "input_set_identifier")
327+
if err != nil {
328+
return mcp.NewToolResultError(err.Error()), nil
329+
}
330+
331+
scope, err := FetchScope(config, request, true)
332+
if err != nil {
333+
return mcp.NewToolResultError(err.Error()), nil
334+
}
335+
336+
data, err := client.GetInputSet(ctx, scope, pipelineIdentifier, inputSetIdentifier)
337+
if err != nil {
338+
return nil, fmt.Errorf("failed to get input set: %w", err)
339+
}
340+
341+
r, err := json.Marshal(data.Data)
342+
if err != nil {
343+
return nil, fmt.Errorf("failed to marshal input set: %w", err)
344+
}
345+
346+
return mcp.NewToolResultText(string(r)), nil
347+
}
348+
}

pkg/modules/core.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ func RegisterPipelines(config *config.Config, tsg *toolsets.ToolsetGroup) error
173173
toolsets.NewServerTool(tools.FetchExecutionURLTool(config, pipelineClient)),
174174
toolsets.NewServerTool(tools.GetExecutionTool(config, pipelineClient)),
175175
toolsets.NewServerTool(tools.ListExecutionsTool(config, pipelineClient)),
176+
toolsets.NewServerTool(tools.GetInputSetTool(config, pipelineClient)),
177+
toolsets.NewServerTool(tools.ListInputSetsTool(config, pipelineClient)),
176178
)
177179

178180
// Add toolset to the group

0 commit comments

Comments
 (0)