Skip to content

Commit 51a0e82

Browse files
committed
add create repo/get repo
1 parent cc0d58a commit 51a0e82

File tree

2 files changed

+266
-65
lines changed

2 files changed

+266
-65
lines changed

pkg/harness/connectors.go

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -51,71 +51,6 @@ type ListConnectorRequest struct {
5151
FilterType string `json:"filterType"`
5252
}
5353

54-
// ConnectorResponse represents the response from the connectors API
55-
type ConnectorResponse struct {
56-
Status string `json:"status"`
57-
Data ConnectorData `json:"data"`
58-
MetaData interface{} `json:"metaData"`
59-
CorrelationID string `json:"correlationId"`
60-
ResourcesMetaData interface{} `json:"resourcesMetaData"`
61-
Error ConnectorErrorInfo `json:"error"`
62-
}
63-
64-
// ConnectorData contains the actual connector data
65-
type ConnectorData struct {
66-
TotalItems int `json:"totalItems"`
67-
PageSize int `json:"pageSize"`
68-
PageIndex int `json:"pageIndex"`
69-
Content []Connector `json:"content"`
70-
}
71-
72-
// Connector represents a Harness connector
73-
type Connector struct {
74-
Connector struct {
75-
Name string `json:"name"`
76-
Identifier string `json:"identifier"`
77-
Description string `json:"description"`
78-
OrgIdentifier string `json:"orgIdentifier"`
79-
ProjectIdentifier string `json:"projectIdentifier"`
80-
Tags Tags `json:"tags"`
81-
Type string `json:"type"`
82-
Status string `json:"status"`
83-
CreatedAt time.Time `json:"createdAt"`
84-
LastModifiedAt time.Time `json:"lastModifiedAt"`
85-
EntityValidityDetail struct {
86-
Valid bool `json:"valid"`
87-
Invalid bool `json:"invalid"`
88-
UnableToReach bool `json:"unableToReach"`
89-
ValidationStatus string `json:"validationStatus"`
90-
} `json:"entityValidityDetail"`
91-
} `json:"connector"`
92-
}
93-
94-
// Tags holds connector tags
95-
type Tags struct {
96-
Tags []Tag `json:"tags"`
97-
}
98-
99-
// Tag represents a single tag
100-
type Tag struct {
101-
Key string `json:"key"`
102-
Value string `json:"value"`
103-
}
104-
105-
// ConnectorErrorInfo holds error information
106-
type ConnectorErrorInfo struct {
107-
Code int `json:"code"`
108-
Message string `json:"message"`
109-
ResponseMessages []ResponseMessage `json:"responseMessages"`
110-
}
111-
112-
// ResponseMessage represents error response messages
113-
type ResponseMessage struct {
114-
Code int `json:"code"`
115-
Level string `json:"level"`
116-
Message string `json:"message"`
117-
}
118-
11954
// ListConnectors retrieves connectors from the Harness API
12055
func (c *ConnectorClient) ListConnectors(ctx context.Context, connectorNames []string, connectorIDs []string, types []string) ([]byte, error) {
12156
// Get API key from context

pkg/harness/repositories.go

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
package harness
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"net/http"
10+
"net/url"
11+
12+
"github.com/mark3labs/mcp-go/mcp"
13+
"github.com/mark3labs/mcp-go/server"
14+
)
15+
16+
// CreateRepositoryRequest represents the request to create a repository
17+
type CreateRepositoryRequest struct {
18+
DefaultBranch string `json:"default_branch,omitempty"`
19+
Description string `json:"description,omitempty"`
20+
ForkID int `json:"fork_id,omitempty"`
21+
GitIgnore string `json:"git_ignore,omitempty"`
22+
Identifier string `json:"identifier"`
23+
IsPublic bool `json:"is_public"`
24+
License string `json:"license,omitempty"`
25+
ParentRef string `json:"parent_ref,omitempty"`
26+
Readme bool `json:"readme"`
27+
UID string `json:"uid,omitempty"`
28+
}
29+
30+
// CreateRepository creates a new repository in Harness
31+
func (c *ConnectorClient) CreateRepository(ctx context.Context, request CreateRepositoryRequest) ([]byte, error) {
32+
// Get API key from context
33+
apiKey, err := GetApiKeyFromContext(ctx)
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
// Construct the query parameters
39+
params := url.Values{}
40+
params.Add("accountIdentifier", defaultAccountID)
41+
params.Add("orgIdentifier", defaultOrgID)
42+
params.Add("projectIdentifier", defaultProjectID)
43+
44+
// Marshal the request body to JSON
45+
reqBodyBytes, err := json.Marshal(request)
46+
if err != nil {
47+
return nil, fmt.Errorf("failed to marshal request body: %w", err)
48+
}
49+
50+
// Create a new HTTP request
51+
url := fmt.Sprintf("https://app.harness.io/code/api/v1/repos?%s", params.Encode())
52+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(reqBodyBytes))
53+
if err != nil {
54+
return nil, fmt.Errorf("failed to create HTTP request: %w", err)
55+
}
56+
57+
// Set headers
58+
req.Header.Set("Content-Type", "application/json")
59+
req.Header.Set("x-api-key", apiKey)
60+
61+
// Make the HTTP request
62+
resp, err := c.httpClient.Do(req)
63+
if err != nil {
64+
return nil, fmt.Errorf("failed to make HTTP request: %w", err)
65+
}
66+
defer resp.Body.Close()
67+
68+
// Read the response body
69+
body, err := io.ReadAll(resp.Body)
70+
if err != nil {
71+
return nil, fmt.Errorf("failed to read response body: %w", err)
72+
}
73+
74+
// Check if the response status code is not 2xx
75+
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
76+
return nil, fmt.Errorf("HTTP request failed with status code %d: %s", resp.StatusCode, string(body))
77+
}
78+
79+
// Return the raw JSON response
80+
return body, nil
81+
}
82+
83+
// CreateRepositoryTool creates the create-repository tool
84+
func CreateRepositoryTool(client *ConnectorClient) (mcp.Tool, server.ToolHandlerFunc) {
85+
tool := mcp.NewTool("create-repository",
86+
mcp.WithDescription("Create a new repository in Harness"),
87+
mcp.WithString("identifier",
88+
mcp.Description("Unique identifier for the repository"),
89+
mcp.Required()),
90+
mcp.WithString("default_branch",
91+
mcp.Description("Default branch name")),
92+
mcp.WithString("description",
93+
mcp.Description("Repository description")),
94+
mcp.WithNumber("fork_id",
95+
mcp.Description("ID of the repository to fork from")),
96+
mcp.WithString("git_ignore",
97+
mcp.Description("Git ignore template")),
98+
mcp.WithBoolean("is_public",
99+
mcp.Description("Whether the repository is public"),
100+
mcp.Required()),
101+
mcp.WithString("license",
102+
mcp.Description("License template")),
103+
mcp.WithString("parent_ref",
104+
mcp.Description("Parent reference for the repository")),
105+
mcp.WithBoolean("readme",
106+
mcp.Description("Whether to initialize with a README"),
107+
mcp.Required()),
108+
mcp.WithString("uid",
109+
mcp.Description("Unique ID for the repository")),
110+
)
111+
112+
handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
113+
// Extract required parameters
114+
identifier, err := requiredParam[string](request, "identifier")
115+
if err != nil {
116+
return nil, err
117+
}
118+
119+
isPublic, err := requiredParam[bool](request, "is_public")
120+
if err != nil {
121+
return nil, err
122+
}
123+
124+
readme, err := requiredParam[bool](request, "readme")
125+
if err != nil {
126+
return nil, err
127+
}
128+
129+
// Extract optional parameters
130+
defaultBranch, err := OptionalParam[string](request, "default_branch")
131+
if err != nil {
132+
return nil, err
133+
}
134+
135+
description, err := OptionalParam[string](request, "description")
136+
if err != nil {
137+
return nil, err
138+
}
139+
140+
forkID, err := OptionalParam[int](request, "fork_id")
141+
if err != nil {
142+
return nil, err
143+
}
144+
145+
gitIgnore, err := OptionalParam[string](request, "git_ignore")
146+
if err != nil {
147+
return nil, err
148+
}
149+
150+
license, err := OptionalParam[string](request, "license")
151+
if err != nil {
152+
return nil, err
153+
}
154+
155+
parentRef, err := OptionalParam[string](request, "parent_ref")
156+
if err != nil {
157+
return nil, err
158+
}
159+
160+
uid, err := OptionalParam[string](request, "uid")
161+
if err != nil {
162+
return nil, err
163+
}
164+
165+
// Create the request
166+
createRepoRequest := CreateRepositoryRequest{
167+
Identifier: identifier,
168+
IsPublic: isPublic,
169+
Readme: readme,
170+
DefaultBranch: defaultBranch,
171+
Description: description,
172+
ForkID: forkID,
173+
GitIgnore: gitIgnore,
174+
License: license,
175+
ParentRef: parentRef,
176+
UID: uid,
177+
}
178+
179+
// Call Harness API
180+
jsonResponse, err := client.CreateRepository(ctx, createRepoRequest)
181+
if err != nil {
182+
return nil, err
183+
}
184+
185+
// Return the raw JSON response as a text result
186+
return mcp.NewToolResultText(string(jsonResponse)), nil
187+
}
188+
189+
return tool, handler
190+
}
191+
192+
// GetRepository retrieves a repository by its identifier
193+
func (c *ConnectorClient) GetRepository(ctx context.Context, repoIdentifier string) ([]byte, error) {
194+
// Get API key from context
195+
apiKey, err := GetApiKeyFromContext(ctx)
196+
if err != nil {
197+
return nil, err
198+
}
199+
200+
// Construct the query parameters
201+
params := url.Values{}
202+
params.Add("accountIdentifier", defaultAccountID)
203+
params.Add("orgIdentifier", defaultOrgID)
204+
params.Add("projectIdentifier", defaultProjectID)
205+
206+
// Create a new HTTP request
207+
url := fmt.Sprintf("https://app.harness.io/code/api/v1/repos/%s?%s", repoIdentifier, params.Encode())
208+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
209+
if err != nil {
210+
return nil, fmt.Errorf("failed to create HTTP request: %w", err)
211+
}
212+
213+
// Set headers
214+
req.Header.Set("Content-Type", "application/json")
215+
req.Header.Set("x-api-key", apiKey)
216+
217+
// Make the HTTP request
218+
resp, err := c.httpClient.Do(req)
219+
if err != nil {
220+
return nil, fmt.Errorf("failed to make HTTP request: %w", err)
221+
}
222+
defer resp.Body.Close()
223+
224+
// Read the response body
225+
body, err := io.ReadAll(resp.Body)
226+
if err != nil {
227+
return nil, fmt.Errorf("failed to read response body: %w", err)
228+
}
229+
230+
// Check if the response status code is not 2xx
231+
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
232+
return nil, fmt.Errorf("HTTP request failed with status code %d: %s", resp.StatusCode, string(body))
233+
}
234+
235+
// Return the raw JSON response
236+
return body, nil
237+
}
238+
239+
// GetRepositoryTool creates the get-repository tool
240+
func GetRepositoryTool(client *ConnectorClient) (mcp.Tool, server.ToolHandlerFunc) {
241+
tool := mcp.NewTool("get-repository",
242+
mcp.WithDescription("Get repository information by identifier"),
243+
mcp.WithString("repo_identifier",
244+
mcp.Description("The identifier of the repository to retrieve"),
245+
mcp.Required()),
246+
)
247+
248+
handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
249+
// Extract required parameters
250+
repoIdentifier, err := requiredParam[string](request, "repo_identifier")
251+
if err != nil {
252+
return nil, err
253+
}
254+
255+
// Call Harness API
256+
jsonResponse, err := client.GetRepository(ctx, repoIdentifier)
257+
if err != nil {
258+
return nil, err
259+
}
260+
261+
// Return the raw JSON response as a text result
262+
return mcp.NewToolResultText(string(jsonResponse)), nil
263+
}
264+
265+
return tool, handler
266+
}

0 commit comments

Comments
 (0)