• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jfrog / froggit-go / 21108064176

18 Jan 2026 07:27AM UTC coverage: 84.034% (-0.1%) from 84.167%
21108064176

Pull #176

github

orto17
fixed linter issues
Pull Request #176: Upload Code Scanning With Ref To Github

18 of 32 new or added lines in 5 files covered. (56.25%)

1 existing line in 1 file now uncovered.

4537 of 5399 relevant lines covered (84.03%)

6.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.01
/vcsclient/gitlab.go
1
package vcsclient
2

3
import (
4
        "bytes"
5
        "context"
6
        "encoding/base64"
7
        "errors"
8
        "fmt"
9
        "net/http"
10
        "sort"
11
        "strconv"
12
        "strings"
13
        "time"
14

15
        "github.com/jfrog/gofrog/datastructures"
16
        "github.com/xanzy/go-gitlab"
17

18
        "github.com/jfrog/froggit-go/vcsutils"
19
)
20

21
// GitLabClient API version 4
22
type GitLabClient struct {
23
        glClient *gitlab.Client
24
        vcsInfo  VcsInfo
25
        logger   vcsutils.Log
26
}
27

28
// NewGitLabClient create a new GitLabClient
29
func NewGitLabClient(vcsInfo VcsInfo, logger vcsutils.Log) (*GitLabClient, error) {
82✔
30
        var client *gitlab.Client
82✔
31
        var err error
82✔
32
        if vcsInfo.APIEndpoint != "" {
130✔
33
                client, err = gitlab.NewClient(vcsInfo.Token, gitlab.WithBaseURL(vcsInfo.APIEndpoint))
48✔
34
        } else {
82✔
35
                client, err = gitlab.NewClient(vcsInfo.Token)
34✔
36
        }
34✔
37
        if err != nil {
83✔
38
                return nil, err
1✔
39
        }
1✔
40

41
        return &GitLabClient{
81✔
42
                glClient: client,
81✔
43
                vcsInfo:  vcsInfo,
81✔
44
                logger:   logger,
81✔
45
        }, nil
81✔
46
}
47

48
// TestConnection on GitLab
49
func (client *GitLabClient) TestConnection(ctx context.Context) error {
3✔
50
        _, _, err := client.glClient.Projects.ListProjects(nil, gitlab.WithContext(ctx))
3✔
51
        return err
3✔
52
}
3✔
53

54
// ListRepositories on GitLab
55
func (client *GitLabClient) ListRepositories(ctx context.Context) (map[string][]string, error) {
1✔
56
        simple := true
1✔
57
        results := make(map[string][]string)
1✔
58
        membership := true
1✔
59
        for pageID := 1; ; pageID++ {
3✔
60
                options := &gitlab.ListProjectsOptions{ListOptions: gitlab.ListOptions{Page: pageID}, Simple: &simple, Membership: &membership}
2✔
61
                projects, response, err := client.glClient.Projects.ListProjects(options, gitlab.WithContext(ctx))
2✔
62
                if err != nil {
2✔
63
                        return nil, err
×
64
                }
×
65
                for _, project := range projects {
27✔
66
                        owner := project.Namespace.Path
25✔
67
                        results[owner] = append(results[owner], project.Path)
25✔
68
                }
25✔
69
                if pageID >= response.TotalPages {
3✔
70
                        break
1✔
71
                }
72
        }
73
        return results, nil
1✔
74
}
75

76
// ListAppRepositories returns an error since this is not supported in GitLab
77
func (client *GitLabClient) ListAppRepositories(ctx context.Context) ([]AppRepositoryInfo, error) {
×
78
        return nil, errGitLabListAppRepositories
×
79
}
×
80

81
// ListBranches on GitLab
82
func (client *GitLabClient) ListBranches(ctx context.Context, owner, repository string) ([]string, error) {
1✔
83
        branches, _, err := client.glClient.Branches.ListBranches(getProjectID(owner, repository), nil,
1✔
84
                gitlab.WithContext(ctx))
1✔
85
        if err != nil {
1✔
86
                return nil, err
×
87
        }
×
88

89
        results := make([]string, 0, len(branches))
1✔
90
        for _, branch := range branches {
3✔
91
                results = append(results, branch.Name)
2✔
92
        }
2✔
93
        return results, nil
1✔
94
}
95

96
// AddSshKeyToRepository on GitLab
97
func (client *GitLabClient) AddSshKeyToRepository(ctx context.Context, owner, repository, keyName, publicKey string, permission Permission) error {
7✔
98
        err := validateParametersNotBlank(map[string]string{
7✔
99
                "owner":      owner,
7✔
100
                "repository": repository,
7✔
101
                "key name":   keyName,
7✔
102
                "public key": publicKey,
7✔
103
        })
7✔
104
        if err != nil {
12✔
105
                return err
5✔
106
        }
5✔
107

108
        canPush := permission == ReadWrite
2✔
109
        options := &gitlab.AddDeployKeyOptions{
2✔
110
                Title:   &keyName,
2✔
111
                Key:     &publicKey,
2✔
112
                CanPush: &canPush,
2✔
113
        }
2✔
114
        _, _, err = client.glClient.DeployKeys.AddDeployKey(getProjectID(owner, repository), options, gitlab.WithContext(ctx))
2✔
115
        return err
2✔
116
}
117

118
// CreateWebhook on GitLab
119
func (client *GitLabClient) CreateWebhook(ctx context.Context, owner, repository, branch, payloadURL string,
120
        webhookEvents ...vcsutils.WebhookEvent) (string, string, error) {
1✔
121
        token := vcsutils.CreateToken()
1✔
122
        projectHook := createProjectHook(branch, payloadURL, webhookEvents...)
1✔
123
        options := &gitlab.AddProjectHookOptions{
1✔
124
                Token:                  &token,
1✔
125
                URL:                    &projectHook.URL,
1✔
126
                MergeRequestsEvents:    &projectHook.MergeRequestsEvents,
1✔
127
                PushEvents:             &projectHook.PushEvents,
1✔
128
                PushEventsBranchFilter: &projectHook.PushEventsBranchFilter,
1✔
129
                TagPushEvents:          &projectHook.TagPushEvents,
1✔
130
        }
1✔
131
        response, _, err := client.glClient.Projects.AddProjectHook(getProjectID(owner, repository), options,
1✔
132
                gitlab.WithContext(ctx))
1✔
133
        if err != nil {
1✔
134
                return "", "", err
×
135
        }
×
136
        return strconv.Itoa(response.ID), token, nil
1✔
137
}
138

139
// UpdateWebhook on GitLab
140
func (client *GitLabClient) UpdateWebhook(ctx context.Context, owner, repository, branch, payloadURL, token,
141
        webhookID string, webhookEvents ...vcsutils.WebhookEvent) error {
1✔
142
        projectHook := createProjectHook(branch, payloadURL, webhookEvents...)
1✔
143
        options := &gitlab.EditProjectHookOptions{
1✔
144
                Token:                  &token,
1✔
145
                URL:                    &projectHook.URL,
1✔
146
                MergeRequestsEvents:    &projectHook.MergeRequestsEvents,
1✔
147
                PushEvents:             &projectHook.PushEvents,
1✔
148
                PushEventsBranchFilter: &projectHook.PushEventsBranchFilter,
1✔
149
                TagPushEvents:          &projectHook.TagPushEvents,
1✔
150
        }
1✔
151
        intWebhook, err := strconv.Atoi(webhookID)
1✔
152
        if err != nil {
1✔
153
                return err
×
154
        }
×
155
        _, _, err = client.glClient.Projects.EditProjectHook(getProjectID(owner, repository), intWebhook, options,
1✔
156
                gitlab.WithContext(ctx))
1✔
157
        return err
1✔
158
}
159

160
// DeleteWebhook on GitLab
161
func (client *GitLabClient) DeleteWebhook(ctx context.Context, owner, repository, webhookID string) error {
1✔
162
        intWebhook, err := strconv.Atoi(webhookID)
1✔
163
        if err != nil {
1✔
164
                return err
×
165
        }
×
166
        _, err = client.glClient.Projects.DeleteProjectHook(getProjectID(owner, repository), intWebhook,
1✔
167
                gitlab.WithContext(ctx))
1✔
168
        return err
1✔
169
}
170

171
// SetCommitStatus on GitLab
172
func (client *GitLabClient) SetCommitStatus(ctx context.Context, commitStatus CommitStatus, owner, repository, ref,
173
        title, description, detailsURL string) error {
1✔
174
        options := &gitlab.SetCommitStatusOptions{
1✔
175
                State:       gitlab.BuildStateValue(getGitLabCommitState(commitStatus)),
1✔
176
                Ref:         &ref,
1✔
177
                Name:        &title,
1✔
178
                Description: &description,
1✔
179
                TargetURL:   &detailsURL,
1✔
180
        }
1✔
181
        _, _, err := client.glClient.Commits.SetCommitStatus(getProjectID(owner, repository), ref, options,
1✔
182
                gitlab.WithContext(ctx))
1✔
183
        return err
1✔
184
}
1✔
185

186
// GetCommitStatuses on GitLab
187
func (client *GitLabClient) GetCommitStatuses(ctx context.Context, _, repository, ref string) (status []CommitStatusInfo, err error) {
3✔
188
        statuses, _, err := client.glClient.Commits.GetCommitStatuses(repository, ref, nil, gitlab.WithContext(ctx))
3✔
189
        if err != nil {
4✔
190
                return nil, err
1✔
191
        }
1✔
192
        results := make([]CommitStatusInfo, 0)
2✔
193
        for _, singleStatus := range statuses {
5✔
194
                results = append(results, CommitStatusInfo{
3✔
195
                        State:         commitStatusAsStringToStatus(singleStatus.Status),
3✔
196
                        Description:   singleStatus.Description,
3✔
197
                        DetailsUrl:    singleStatus.TargetURL,
3✔
198
                        Creator:       singleStatus.Author.Name,
3✔
199
                        LastUpdatedAt: extractTimeWithFallback(singleStatus.FinishedAt),
3✔
200
                        CreatedAt:     extractTimeWithFallback(singleStatus.CreatedAt),
3✔
201
                })
3✔
202
        }
3✔
203
        return results, nil
2✔
204
}
205

206
// DownloadRepository on GitLab
207
func (client *GitLabClient) DownloadRepository(ctx context.Context, owner, repository, branch, localPath string) error {
1✔
208
        format := "tar.gz"
1✔
209
        options := &gitlab.ArchiveOptions{
1✔
210
                Format: &format,
1✔
211
                SHA:    &branch,
1✔
212
        }
1✔
213
        response, _, err := client.glClient.Repositories.Archive(getProjectID(owner, repository), options,
1✔
214
                gitlab.WithContext(ctx))
1✔
215
        if err != nil {
1✔
216
                return err
×
217
        }
×
218
        client.logger.Info(repository, vcsutils.SuccessfulRepoDownload)
1✔
219
        err = vcsutils.Untar(localPath, bytes.NewReader(response), true)
1✔
220
        if err != nil {
1✔
221
                return err
×
222
        }
×
223

224
        repositoryInfo, err := client.GetRepositoryInfo(ctx, owner, repository)
1✔
225
        if err != nil {
1✔
226
                return err
×
227
        }
×
228

229
        client.logger.Info(vcsutils.SuccessfulRepoExtraction)
1✔
230
        return vcsutils.CreateDotGitFolderWithRemote(localPath, vcsutils.RemoteName, repositoryInfo.CloneInfo.HTTP)
1✔
231
}
232

233
func (client *GitLabClient) GetPullRequestCommentSizeLimit() int {
×
234
        return gitlabMergeRequestCommentSizeLimit
×
235
}
×
236

237
func (client *GitLabClient) GetPullRequestDetailsSizeLimit() int {
×
238
        return gitlabMergeRequestDetailsSizeLimit
×
239
}
×
240

241
// CreatePullRequest on GitLab
242
func (client *GitLabClient) CreatePullRequest(ctx context.Context, owner, repository, sourceBranch, targetBranch,
243
        title, description string) error {
1✔
244
        options := &gitlab.CreateMergeRequestOptions{
1✔
245
                Title:        &title,
1✔
246
                Description:  &description,
1✔
247
                SourceBranch: &sourceBranch,
1✔
248
                TargetBranch: &targetBranch,
1✔
249
        }
1✔
250
        client.logger.Debug("creating new merge request:", title)
1✔
251
        _, _, err := client.glClient.MergeRequests.CreateMergeRequest(getProjectID(owner, repository), options,
1✔
252
                gitlab.WithContext(ctx))
1✔
253
        return err
1✔
254
}
1✔
255

256
// UpdatePullRequest on GitLab
257
func (client *GitLabClient) UpdatePullRequest(ctx context.Context, owner, repository, title, body, targetBranchName string, prId int, state vcsutils.PullRequestState) error {
4✔
258
        options := &gitlab.UpdateMergeRequestOptions{
4✔
259
                Title:        &title,
4✔
260
                Description:  &body,
4✔
261
                TargetBranch: &targetBranchName,
4✔
262
                StateEvent:   mapGitLabPullRequestState(&state),
4✔
263
        }
4✔
264
        client.logger.Debug("updating details of merge request ID:", prId)
4✔
265
        _, _, err := client.glClient.MergeRequests.UpdateMergeRequest(getProjectID(owner, repository), prId, options, gitlab.WithContext(ctx))
4✔
266
        return err
4✔
267
}
4✔
268

269
// ListOpenPullRequestsWithBody on GitLab
270
func (client *GitLabClient) ListOpenPullRequestsWithBody(ctx context.Context, owner, repository string) ([]PullRequestInfo, error) {
1✔
271
        return client.getOpenPullRequests(ctx, owner, repository, true)
1✔
272
}
1✔
273

274
// ListOpenPullRequests on GitLab
275
func (client *GitLabClient) ListOpenPullRequests(ctx context.Context, owner, repository string) ([]PullRequestInfo, error) {
1✔
276
        return client.getOpenPullRequests(ctx, owner, repository, false)
1✔
277
}
1✔
278

279
func (client *GitLabClient) getOpenPullRequests(ctx context.Context, owner, repository string, withBody bool) ([]PullRequestInfo, error) {
2✔
280
        openState := "opened"
2✔
281
        allScope := "all"
2✔
282
        options := &gitlab.ListProjectMergeRequestsOptions{
2✔
283
                State: &openState,
2✔
284
                Scope: &allScope,
2✔
285
        }
2✔
286
        mergeRequests, _, err := client.glClient.MergeRequests.ListProjectMergeRequests(getProjectID(owner, repository), options, gitlab.WithContext(ctx))
2✔
287
        if err != nil {
2✔
288
                return []PullRequestInfo{}, err
×
289
        }
×
290
        return client.mapGitLabMergeRequestToPullRequestInfoList(mergeRequests, owner, repository, withBody)
2✔
291
}
292

293
// GetPullRequestInfoById on GitLab
294
func (client *GitLabClient) GetPullRequestByID(_ context.Context, owner, repository string, pullRequestId int) (pullRequestInfo PullRequestInfo, err error) {
2✔
295
        client.logger.Debug("fetching merge requests by ID in", repository)
2✔
296
        mergeRequest, glResponse, err := client.glClient.MergeRequests.GetMergeRequest(getProjectID(owner, repository), pullRequestId, nil)
2✔
297
        if err != nil {
3✔
298
                return PullRequestInfo{}, err
1✔
299
        }
1✔
300
        if glResponse != nil {
2✔
301
                if err = vcsutils.CheckResponseStatusWithBody(glResponse.Response, http.StatusOK); err != nil {
1✔
302
                        return PullRequestInfo{}, err
×
303
                }
×
304
        }
305
        pullRequestInfo, err = client.mapGitLabMergeRequestToPullRequestInfo(mergeRequest, false, owner, repository)
1✔
306
        return
1✔
307
}
308

309
// AddPullRequestComment on GitLab
310
func (client *GitLabClient) AddPullRequestComment(ctx context.Context, owner, repository, content string, pullRequestID int) error {
5✔
311
        err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository, "content": content})
5✔
312
        if err != nil {
9✔
313
                return err
4✔
314
        }
4✔
315
        options := &gitlab.CreateMergeRequestNoteOptions{
1✔
316
                Body: &content,
1✔
317
        }
1✔
318
        _, _, err = client.glClient.Notes.CreateMergeRequestNote(getProjectID(owner, repository), pullRequestID, options,
1✔
319
                gitlab.WithContext(ctx))
1✔
320

1✔
321
        return err
1✔
322
}
323

324
// AddPullRequestReviewComments adds comments to a pull request on GitLab.
325
func (client *GitLabClient) AddPullRequestReviewComments(ctx context.Context, owner, repository string, pullRequestID int, comments ...PullRequestComment) error {
2✔
326
        // Validate parameters
2✔
327
        if err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository}); err != nil {
2✔
328
                return err
×
329
        }
×
330

331
        // Check if comments are provided
332
        if len(comments) == 0 {
2✔
333
                return errors.New("could not add merge request review comments, no comments provided")
×
334
        }
×
335

336
        projectID := getProjectID(owner, repository)
2✔
337

2✔
338
        // Get merge request diff versions
2✔
339
        versions, err := client.getMergeRequestDiffVersions(ctx, projectID, pullRequestID)
2✔
340
        if err != nil {
2✔
341
                return fmt.Errorf("could not get merge request diff versions: %w", err)
×
342
        }
×
343

344
        // Get merge request details
345
        mergeRequestChanges, err := client.getMergeRequestDiff(ctx, projectID, pullRequestID)
2✔
346
        if err != nil {
2✔
347
                return fmt.Errorf("could not get merge request changes: %w", err)
×
348
        }
×
349

350
        for _, comment := range comments {
4✔
351
                if err = client.addPullRequestReviewComment(ctx, projectID, pullRequestID, comment, versions, mergeRequestChanges); err != nil {
3✔
352
                        return err
1✔
353
                }
1✔
354
        }
355

356
        return nil
1✔
357
}
358

359
func (client *GitLabClient) getMergeRequestDiffVersions(ctx context.Context, projectID string, pullRequestID int) ([]*gitlab.MergeRequestDiffVersion, error) {
2✔
360
        versions, _, err := client.glClient.MergeRequests.GetMergeRequestDiffVersions(projectID, pullRequestID, &gitlab.GetMergeRequestDiffVersionsOptions{}, gitlab.WithContext(ctx))
2✔
361
        return versions, err
2✔
362
}
2✔
363

364
func (client *GitLabClient) getMergeRequestDiff(ctx context.Context, projectID string, pullRequestID int) ([]*gitlab.MergeRequestDiff, error) {
2✔
365
        mergeRequestChanges, _, err := client.glClient.MergeRequests.ListMergeRequestDiffs(projectID, pullRequestID, nil, gitlab.WithContext(ctx))
2✔
366
        return mergeRequestChanges, err
2✔
367
}
2✔
368

369
func (client *GitLabClient) addPullRequestReviewComment(ctx context.Context, projectID string, pullRequestID int, comment PullRequestComment, versions []*gitlab.MergeRequestDiffVersion, mergeRequestChanges []*gitlab.MergeRequestDiff) error {
2✔
370
        // Find the corresponding change in merge request
2✔
371
        var newPath, oldPath string
2✔
372
        var newLine int
2✔
373
        var diffFound bool
2✔
374

2✔
375
        for _, diff := range mergeRequestChanges {
6✔
376
                if diff.NewPath != comment.NewFilePath {
7✔
377
                        continue
3✔
378
                }
379

380
                diffFound = true
1✔
381
                newLine = comment.NewStartLine
1✔
382
                newPath = diff.NewPath
1✔
383

1✔
384
                // New files don't have old data
1✔
385
                if !diff.NewFile {
2✔
386
                        oldPath = diff.OldPath
1✔
387
                }
1✔
388
                break
1✔
389
        }
390

391
        // If no matching change is found, return an error
392
        if !diffFound {
3✔
393
                return fmt.Errorf("could not find changes to %s in the current merge request", comment.NewFilePath)
1✔
394
        }
1✔
395

396
        // Create a NotePosition for the comment
397
        latestVersion := versions[0]
1✔
398
        diffPosition := &gitlab.PositionOptions{
1✔
399
                StartSHA:     &latestVersion.StartCommitSHA,
1✔
400
                HeadSHA:      &latestVersion.HeadCommitSHA,
1✔
401
                BaseSHA:      &latestVersion.BaseCommitSHA,
1✔
402
                PositionType: vcsutils.PointerOf("text"),
1✔
403
                NewLine:      &newLine,
1✔
404
                NewPath:      &newPath,
1✔
405
                OldLine:      &newLine,
1✔
406
                OldPath:      &oldPath,
1✔
407
        }
1✔
408

1✔
409
        // The GitLab REST API for creating a merge request discussion has strange behavior:
1✔
410
        // If the API call is not constructed precisely according to these rules, it may fail with an unclear error.
1✔
411
        // In all cases, 'new_path' and 'new_line' parameters are required.
1✔
412
        // - When commenting on a new file, do not include 'old_path' and 'old_line' parameters.
1✔
413
        // - When commenting on an existing file that has changed in the diff, omit 'old_path' and 'old_line' parameters.
1✔
414
        // - When commenting on an existing file that hasn't changed in the diff, include 'old_path' and 'old_line' parameters.
1✔
415

1✔
416
        client.logger.Debug(fmt.Sprintf("Create merge request discussion sent. newPath: %v newLine: %v oldPath: %v, oldLine: %v",
1✔
417
                newPath, newLine, oldPath, newLine))
1✔
418
        // Attempt to create a merge request discussion thread
1✔
419
        _, _, err := client.createMergeRequestDiscussion(ctx, projectID, comment.Content, pullRequestID, diffPosition)
1✔
420

1✔
421
        // Retry without oldLine and oldPath if the GitLab API call fails
1✔
422
        if err != nil {
2✔
423
                diffPosition.OldLine = nil
1✔
424
                diffPosition.OldPath = nil
1✔
425
                client.logger.Debug(fmt.Sprintf("Create merge request discussion second attempt sent. newPath: %v newLine: %v oldPath: %v, oldLine: %v",
1✔
426
                        newPath, newLine, oldPath, newLine))
1✔
427
                _, _, err = client.createMergeRequestDiscussion(ctx, projectID, comment.Content, pullRequestID, diffPosition)
1✔
428
        }
1✔
429

430
        // If the comment creation still fails, return an error
431
        if err != nil {
1✔
432
                return fmt.Errorf("could not create a merge request discussion thread: %w", err)
×
433
        }
×
434

435
        return nil
1✔
436
}
437

438
func (client *GitLabClient) createMergeRequestDiscussion(ctx context.Context, projectID, content string, pullRequestID int, position *gitlab.PositionOptions) (*gitlab.Discussion, *gitlab.Response, error) {
2✔
439
        return client.glClient.Discussions.CreateMergeRequestDiscussion(projectID, pullRequestID, &gitlab.CreateMergeRequestDiscussionOptions{
2✔
440
                Body:     &content,
2✔
441
                Position: position,
2✔
442
        }, gitlab.WithContext(ctx))
2✔
443
}
2✔
444

445
// ListPullRequestReviewComments on GitLab
446
func (client *GitLabClient) ListPullRequestReviewComments(ctx context.Context, owner, repository string, pullRequestID int) ([]CommentInfo, error) {
1✔
447
        // Validate parameters
1✔
448
        if err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository, "pullRequestID": strconv.Itoa(pullRequestID)}); err != nil {
1✔
449
                return nil, err
×
450
        }
×
451

452
        projectID := getProjectID(owner, repository)
1✔
453

1✔
454
        discussions, _, err := client.glClient.Discussions.ListMergeRequestDiscussions(projectID, pullRequestID, &gitlab.ListMergeRequestDiscussionsOptions{}, gitlab.WithContext(ctx))
1✔
455
        if err != nil {
1✔
456
                return nil, fmt.Errorf("failed fetching the list of merge requests discussions: %w", err)
×
457
        }
×
458

459
        var commentsInfo []CommentInfo
1✔
460
        for _, discussion := range discussions {
3✔
461
                commentsInfo = append(commentsInfo, mapGitLabNotesToCommentInfoList(discussion.Notes, discussion.ID)...)
2✔
462
        }
2✔
463

464
        return commentsInfo, nil
1✔
465
}
466

467
// ListPullRequestComments on GitLab
468
func (client *GitLabClient) ListPullRequestComments(ctx context.Context, owner, repository string, pullRequestID int) ([]CommentInfo, error) {
1✔
469
        if err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository, "pullRequestID": strconv.Itoa(pullRequestID)}); err != nil {
1✔
470
                return nil, err
×
471
        }
×
472
        commentsList, _, err := client.glClient.Notes.ListMergeRequestNotes(getProjectID(owner, repository), pullRequestID, &gitlab.ListMergeRequestNotesOptions{},
1✔
473
                gitlab.WithContext(ctx))
1✔
474
        if err != nil {
1✔
475
                return []CommentInfo{}, err
×
476
        }
×
477
        return mapGitLabNotesToCommentInfoList(commentsList, ""), nil
1✔
478
}
479

480
// DeletePullRequestReviewComment on GitLab
481
func (client *GitLabClient) DeletePullRequestReviewComments(ctx context.Context, owner, repository string, pullRequestID int, comments ...CommentInfo) error {
3✔
482
        if err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository, "pullRequestID": strconv.Itoa(pullRequestID)}); err != nil {
4✔
483
                return err
1✔
484
        }
1✔
485
        for _, comment := range comments {
5✔
486
                var commentID int64
3✔
487
                if err := validateParametersNotBlank(map[string]string{"commentID": strconv.FormatInt(commentID, 10), "discussionID": comment.ThreadID}); err != nil {
4✔
488
                        return err
1✔
489
                }
1✔
490
                if _, err := client.glClient.Discussions.DeleteMergeRequestDiscussionNote(getProjectID(owner, repository), pullRequestID, comment.ThreadID, int(commentID), gitlab.WithContext(ctx)); err != nil {
2✔
491
                        return fmt.Errorf("an error occurred while deleting pull request review comment: %w", err)
×
492
                }
×
493
        }
494
        return nil
1✔
495
}
496

497
// DeletePullRequestComment on GitLab
498
func (client *GitLabClient) DeletePullRequestComment(ctx context.Context, owner, repository string, pullRequestID, commentID int) error {
1✔
499
        if err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository}); err != nil {
1✔
500
                return err
×
501
        }
×
502
        if _, err := client.glClient.Notes.DeleteMergeRequestNote(getProjectID(owner, repository), pullRequestID, commentID, gitlab.WithContext(ctx)); err != nil {
1✔
503
                return fmt.Errorf("an error occurred while deleting pull request comment:\n%s", err.Error())
×
504
        }
×
505
        return nil
1✔
506
}
507

508
// GetLatestCommit on GitLab
509
func (client *GitLabClient) GetLatestCommit(ctx context.Context, owner, repository, branch string) (CommitInfo, error) {
7✔
510
        commits, err := client.GetCommits(ctx, owner, repository, branch)
7✔
511
        if err != nil {
12✔
512
                return CommitInfo{}, err
5✔
513
        }
5✔
514

515
        if len(commits) > 0 {
3✔
516
                return commits[0], nil
1✔
517
        }
1✔
518

519
        return CommitInfo{}, fmt.Errorf("no commits were returned for <%s/%s/%s>", owner, repository, branch)
1✔
520
}
521

522
// GetCommits on GitLab
523
func (client *GitLabClient) GetCommits(ctx context.Context, owner, repository, branch string) ([]CommitInfo, error) {
8✔
524
        err := validateParametersNotBlank(map[string]string{
8✔
525
                "owner":      owner,
8✔
526
                "repository": repository,
8✔
527
                "branch":     branch,
8✔
528
        })
8✔
529
        if err != nil {
12✔
530
                return nil, err
4✔
531
        }
4✔
532

533
        listOptions := &gitlab.ListCommitsOptions{
4✔
534
                RefName: &branch,
4✔
535
                ListOptions: gitlab.ListOptions{
4✔
536
                        Page:    1,
4✔
537
                        PerPage: vcsutils.NumberOfCommitsToFetch,
4✔
538
                },
4✔
539
        }
4✔
540
        return client.getCommitsWithQueryOptions(ctx, owner, repository, listOptions)
4✔
541
}
542

543
func (client *GitLabClient) GetCommitsWithQueryOptions(ctx context.Context, owner, repository string, listOptions GitCommitsQueryOptions) ([]CommitInfo, error) {
1✔
544
        err := validateParametersNotBlank(map[string]string{
1✔
545
                "owner":      owner,
1✔
546
                "repository": repository,
1✔
547
        })
1✔
548
        if err != nil {
1✔
549
                return nil, err
×
550
        }
×
551

552
        return client.getCommitsWithQueryOptions(ctx, owner, repository, convertToListCommitsOptions(listOptions))
1✔
553
}
554

555
func convertToListCommitsOptions(options GitCommitsQueryOptions) *gitlab.ListCommitsOptions {
1✔
556
        t := time.Now()
1✔
557
        return &gitlab.ListCommitsOptions{
1✔
558
                ListOptions: gitlab.ListOptions{
1✔
559
                        Page:    options.Page,
1✔
560
                        PerPage: options.PerPage,
1✔
561
                },
1✔
562
                Since: &options.Since,
1✔
563
                Until: &t,
1✔
564
        }
1✔
565
}
1✔
566

567
func (client *GitLabClient) getCommitsWithQueryOptions(ctx context.Context, owner, repository string, options *gitlab.ListCommitsOptions) ([]CommitInfo, error) {
5✔
568
        commits, _, err := client.glClient.Commits.ListCommits(getProjectID(owner, repository), options, gitlab.WithContext(ctx))
5✔
569
        if err != nil {
6✔
570
                return nil, err
1✔
571
        }
1✔
572

573
        var commitsInfo []CommitInfo
4✔
574
        for _, commit := range commits {
10✔
575
                commitInfo := mapGitLabCommitToCommitInfo(commit)
6✔
576
                commitsInfo = append(commitsInfo, commitInfo)
6✔
577
        }
6✔
578
        return commitsInfo, nil
4✔
579
}
580

581
// GetRepositoryInfo on GitLab
582
func (client *GitLabClient) GetRepositoryInfo(ctx context.Context, owner, repository string) (RepositoryInfo, error) {
5✔
583
        err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository})
5✔
584
        if err != nil {
8✔
585
                return RepositoryInfo{}, err
3✔
586
        }
3✔
587

588
        project, _, err := client.glClient.Projects.GetProject(getProjectID(owner, repository), nil, gitlab.WithContext(ctx))
2✔
589
        if err != nil {
2✔
590
                return RepositoryInfo{}, err
×
591
        }
×
592

593
        return RepositoryInfo{RepositoryVisibility: getGitLabProjectVisibility(project), CloneInfo: CloneInfo{HTTP: project.HTTPURLToRepo, SSH: project.SSHURLToRepo}}, nil
2✔
594
}
595

596
// GetCommitBySha on GitLab
597
func (client *GitLabClient) GetCommitBySha(ctx context.Context, owner, repository, sha string) (CommitInfo, error) {
6✔
598
        err := validateParametersNotBlank(map[string]string{
6✔
599
                "owner":      owner,
6✔
600
                "repository": repository,
6✔
601
                "sha":        sha,
6✔
602
        })
6✔
603
        if err != nil {
10✔
604
                return CommitInfo{}, err
4✔
605
        }
4✔
606

607
        commit, _, err := client.glClient.Commits.GetCommit(getProjectID(owner, repository), sha, nil, gitlab.WithContext(ctx))
2✔
608
        if err != nil {
3✔
609
                return CommitInfo{}, err
1✔
610
        }
1✔
611
        return mapGitLabCommitToCommitInfo(commit), nil
1✔
612
}
613

614
// CreateLabel on GitLab
615
func (client *GitLabClient) CreateLabel(ctx context.Context, owner, repository string, labelInfo LabelInfo) error {
5✔
616
        err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository, "LabelInfo.name": labelInfo.Name})
5✔
617
        if err != nil {
9✔
618
                return err
4✔
619
        }
4✔
620

621
        _, _, err = client.glClient.Labels.CreateLabel(getProjectID(owner, repository), &gitlab.CreateLabelOptions{
1✔
622
                Name:        &labelInfo.Name,
1✔
623
                Description: &labelInfo.Description,
1✔
624
                Color:       &labelInfo.Color,
1✔
625
        }, gitlab.WithContext(ctx))
1✔
626

1✔
627
        return err
1✔
628
}
629

630
// GetLabel on GitLub
631
func (client *GitLabClient) GetLabel(ctx context.Context, owner, repository, name string) (*LabelInfo, error) {
6✔
632
        err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository, "name": name})
6✔
633
        if err != nil {
10✔
634
                return nil, err
4✔
635
        }
4✔
636

637
        labels, _, err := client.glClient.Labels.ListLabels(getProjectID(owner, repository), &gitlab.ListLabelsOptions{}, gitlab.WithContext(ctx))
2✔
638
        if err != nil {
2✔
639
                return nil, err
×
640
        }
×
641

642
        for _, label := range labels {
4✔
643
                if label.Name == name {
3✔
644
                        return &LabelInfo{
1✔
645
                                Name:        label.Name,
1✔
646
                                Description: label.Description,
1✔
647
                                Color:       strings.TrimPrefix(label.Color, "#"),
1✔
648
                        }, err
1✔
649
                }
1✔
650
        }
651

652
        return nil, nil
1✔
653
}
654

655
// ListPullRequestLabels on GitLab
656
func (client *GitLabClient) ListPullRequestLabels(ctx context.Context, owner, repository string, pullRequestID int) ([]string, error) {
4✔
657
        err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository})
4✔
658
        if err != nil {
7✔
659
                return []string{}, err
3✔
660
        }
3✔
661
        mergeRequest, _, err := client.glClient.MergeRequests.GetMergeRequest(getProjectID(owner, repository), pullRequestID,
1✔
662
                &gitlab.GetMergeRequestsOptions{}, gitlab.WithContext(ctx))
1✔
663
        if err != nil {
1✔
664
                return []string{}, err
×
665
        }
×
666

667
        return mergeRequest.Labels, nil
1✔
668
}
669

670
// UnlabelPullRequest on GitLab
671
func (client *GitLabClient) UnlabelPullRequest(ctx context.Context, owner, repository, label string, pullRequestID int) error {
4✔
672
        err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository})
4✔
673
        if err != nil {
7✔
674
                return err
3✔
675
        }
3✔
676
        labels := gitlab.LabelOptions{label}
1✔
677
        _, _, err = client.glClient.MergeRequests.UpdateMergeRequest(getProjectID(owner, repository), pullRequestID, &gitlab.UpdateMergeRequestOptions{
1✔
678
                RemoveLabels: &labels,
1✔
679
        }, gitlab.WithContext(ctx))
1✔
680
        return err
1✔
681
}
682

683
// UploadCodeScanning on GitLab
684
func (client *GitLabClient) UploadCodeScanning(_ context.Context, _ string, _ string, _ string, _ string) (string, error) {
1✔
685
        return "", errGitLabCodeScanningNotSupported
1✔
686
}
1✔
687

688
// UploadCodeScanningWithRef on GitLab
NEW
689
func (client *GitLabClient) UploadCodeScanningWithRef(_ context.Context, _ string, _ string, _ string, _ string, _ string) (string, error) {
×
NEW
690
        return "", errGitLabCodeScanningNotSupported
×
NEW
691
}
×
692

693
// GetRepositoryEnvironmentInfo on GitLab
694
func (client *GitLabClient) GetRepositoryEnvironmentInfo(_ context.Context, _, _, _ string) (RepositoryEnvironmentInfo, error) {
1✔
695
        return RepositoryEnvironmentInfo{}, errGitLabGetRepoEnvironmentInfoNotSupported
1✔
696
}
1✔
697

698
// DownloadFileFromRepo on GitLab
699
func (client *GitLabClient) DownloadFileFromRepo(_ context.Context, owner, repository, branch, path string) ([]byte, int, error) {
1✔
700
        file, glResponse, err := client.glClient.RepositoryFiles.GetFile(getProjectID(owner, repository), path, &gitlab.GetFileOptions{Ref: &branch})
1✔
701
        var statusCode int
1✔
702
        if glResponse != nil && glResponse.Response != nil {
2✔
703
                statusCode = glResponse.StatusCode
1✔
704
        }
1✔
705
        if err != nil {
1✔
706
                return nil, statusCode, err
×
707
        }
×
708
        if statusCode != http.StatusOK {
1✔
709
                return nil, statusCode, fmt.Errorf("expected %d status code while received %d status code", http.StatusOK, glResponse.StatusCode)
×
710
        }
×
711
        var content []byte
1✔
712
        if file != nil {
2✔
713
                content, err = base64.StdEncoding.DecodeString(file.Content)
1✔
714
        }
1✔
715
        return content, statusCode, err
1✔
716
}
717

718
func (client *GitLabClient) GetModifiedFiles(_ context.Context, owner, repository, refBefore, refAfter string) ([]string, error) {
6✔
719
        if err := validateParametersNotBlank(map[string]string{
6✔
720
                "owner":      owner,
6✔
721
                "repository": repository,
6✔
722
                "refBefore":  refBefore,
6✔
723
                "refAfter":   refAfter,
6✔
724
        }); err != nil {
10✔
725
                return nil, err
4✔
726
        }
4✔
727

728
        // No pagination is needed according to the official documentation at
729
        // https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits
730
        compare, _, err := client.glClient.Repositories.Compare(
2✔
731
                getProjectID(owner, repository),
2✔
732
                &gitlab.CompareOptions{From: &refBefore, To: &refAfter},
2✔
733
        )
2✔
734
        if err != nil {
3✔
735
                return nil, err
1✔
736
        }
1✔
737

738
        fileNamesSet := datastructures.MakeSet[string]()
1✔
739
        for _, diff := range compare.Diffs {
4✔
740
                fileNamesSet.Add(diff.NewPath)
3✔
741
                fileNamesSet.Add(diff.OldPath)
3✔
742
        }
3✔
743
        _ = fileNamesSet.Remove("") // Make sure there are no blank filepath.
1✔
744
        fileNamesList := fileNamesSet.ToSlice()
1✔
745
        sort.Strings(fileNamesList)
1✔
746
        return fileNamesList, nil
1✔
747
}
748

749
func (client *GitLabClient) ListPullRequestReviews(ctx context.Context, owner, repository string, pullRequestID int) ([]PullRequestReviewDetails, error) {
1✔
750
        err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository})
1✔
751
        if err != nil {
1✔
752
                return nil, err
×
753
        }
×
754

755
        var prNotes []*gitlab.Note
1✔
756
        prNotes, _, err = client.glClient.Notes.ListMergeRequestNotes(owner+"/"+repository, pullRequestID, nil)
1✔
757
        if err != nil {
1✔
758
                return nil, err
×
759
        }
×
760

761
        var reviewInfos []PullRequestReviewDetails
1✔
762
        for _, review := range prNotes {
3✔
763
                reviewInfos = append(reviewInfos, PullRequestReviewDetails{
2✔
764
                        ID:          int64(review.ID),
2✔
765
                        Reviewer:    review.Author.Username,
2✔
766
                        Body:        review.Body,
2✔
767
                        SubmittedAt: review.CreatedAt.Format(time.RFC3339),
2✔
768
                        CommitID:    review.CommitID,
2✔
769
                })
2✔
770
        }
2✔
771

772
        return reviewInfos, nil
1✔
773
}
774

775
func (client *GitLabClient) ListPullRequestsAssociatedWithCommit(ctx context.Context, owner, repository string, commitSHA string) ([]PullRequestInfo, error) {
1✔
776
        err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository})
1✔
777
        if err != nil {
1✔
778
                return nil, err
×
779
        }
×
780

781
        var mergeRequests []*gitlab.MergeRequest
1✔
782
        mergeRequests, _, err = client.glClient.Commits.ListMergeRequestsByCommit(owner+"/"+repository, commitSHA, nil)
1✔
783
        if err != nil {
1✔
784
                return nil, err
×
785
        }
×
786
        return client.mapGitLabMergeRequestToPullRequestInfoList(mergeRequests, owner, repository, true)
1✔
787
}
788

789
func (client *GitLabClient) CreateBranch(ctx context.Context, owner, repository, sourceBranch, newBranch string) error {
×
790
        return errGitLabCreateBranchNotSupported
×
791
}
×
792

793
func (client *GitLabClient) AllowWorkflows(ctx context.Context, owner string) error {
×
794
        return errGitLabAllowWorkflowsNotSupported
×
795
}
×
796

797
func (client *GitLabClient) AddOrganizationSecret(ctx context.Context, owner, secretName, secretValue string) error {
×
798
        return errGitLLabAddOrganizationSecretNotSupported
×
799
}
×
800

801
func (client *GitLabClient) CreateOrgVariable(ctx context.Context, owner, variableName, variableValue string) error {
×
802
        return errGitLabCreateOrgVariableNotSupported
×
803
}
×
804

805
func (client *GitLabClient) CommitAndPushFiles(ctx context.Context, owner, repo, sourceBranch, commitMessage, authorName, authorEmail string, files []FileToCommit) error {
×
806
        return errGitLabCommitAndPushFilesNotSupported
×
807
}
×
808

809
func (client *GitLabClient) GetRepoCollaborators(ctx context.Context, owner, repo, affiliation, permission string) ([]string, error) {
×
810
        return nil, errGitLabGetCollaboratorsNotSupported
×
811
}
×
812

813
func (client *GitLabClient) GetRepoTeamsByPermissions(ctx context.Context, owner, repo string, permissions []string) ([]int64, error) {
×
814
        return nil, errGitLabGetRepoTeamsByPermissionsNotSupported
×
815
}
×
816

817
func (client *GitLabClient) CreateOrUpdateEnvironment(ctx context.Context, owner, repo, envName string, teams []int64, users []string) error {
×
818
        return errGitLabCreateOrUpdateEnvironmentNotSupported
×
819
}
×
820

821
func (client *GitLabClient) MergePullRequest(ctx context.Context, owner, repo string, prNumber int, commitMessage string) error {
×
822
        return errGitLabMergePullRequestNotSupported
×
823
}
×
824

825
func (client *GitLabClient) CreatePullRequestDetailed(ctx context.Context, owner, repository, sourceBranch, targetBranch, title, description string) (CreatedPullRequestInfo, error) {
×
826
        return CreatedPullRequestInfo{}, errGitlabCreatePullRequestDetailedNotSupported
×
827
}
×
828

829
func (client *GitLabClient) UploadSnapshotToDependencyGraph(ctx context.Context, owner, repo string, snapshot *SbomSnapshot) error {
×
830
        return errGitLabUploadSnapshotToDependencyGraphNotSupported
×
831
}
×
832

833
func getProjectID(owner, project string) string {
42✔
834
        return fmt.Sprintf("%s/%s", owner, project)
42✔
835
}
42✔
836

837
func createProjectHook(branch string, payloadURL string, webhookEvents ...vcsutils.WebhookEvent) *gitlab.ProjectHook {
2✔
838
        options := &gitlab.ProjectHook{URL: payloadURL}
2✔
839
        for _, webhookEvent := range webhookEvents {
11✔
840
                switch webhookEvent {
9✔
841
                case vcsutils.PrOpened, vcsutils.PrEdited, vcsutils.PrRejected, vcsutils.PrMerged:
6✔
842
                        options.MergeRequestsEvents = true
6✔
843
                case vcsutils.Push:
1✔
844
                        options.PushEvents = true
1✔
845
                        options.PushEventsBranchFilter = branch
1✔
846
                case vcsutils.TagPushed, vcsutils.TagRemoved:
2✔
847
                        options.TagPushEvents = true
2✔
848
                }
849
        }
850
        return options
2✔
851
}
852

853
func getGitLabProjectVisibility(project *gitlab.Project) RepositoryVisibility {
5✔
854
        switch project.Visibility {
5✔
855
        case gitlab.PublicVisibility:
1✔
856
                return Public
1✔
857
        case gitlab.InternalVisibility:
1✔
858
                return Internal
1✔
859
        default:
3✔
860
                return Private
3✔
861
        }
862
}
863

864
func getGitLabCommitState(commitState CommitStatus) string {
6✔
865
        switch commitState {
6✔
866
        case Pass:
1✔
867
                return "success"
1✔
868
        case Fail:
1✔
869
                return "failed"
1✔
870
        case Error:
1✔
871
                return "failed"
1✔
872
        case InProgress:
2✔
873
                return "running"
2✔
874
        }
875
        return ""
1✔
876
}
877

878
func mapGitLabCommitToCommitInfo(commit *gitlab.Commit) CommitInfo {
7✔
879
        return CommitInfo{
7✔
880
                Hash:          commit.ID,
7✔
881
                AuthorName:    commit.AuthorName,
7✔
882
                CommitterName: commit.CommitterName,
7✔
883
                Url:           commit.WebURL,
7✔
884
                Timestamp:     commit.CommittedDate.UTC().Unix(),
7✔
885
                Message:       commit.Message,
7✔
886
                ParentHashes:  commit.ParentIDs,
7✔
887
                AuthorEmail:   commit.AuthorEmail,
7✔
888
        }
7✔
889
}
7✔
890

891
func mapGitLabNotesToCommentInfoList(notes []*gitlab.Note, discussionId string) (res []CommentInfo) {
3✔
892
        for _, note := range notes {
8✔
893
                res = append(res, CommentInfo{
5✔
894
                        ID:       int64(note.ID),
5✔
895
                        ThreadID: discussionId,
5✔
896
                        Content:  note.Body,
5✔
897
                        Created:  *note.CreatedAt,
5✔
898
                })
5✔
899
        }
5✔
900
        return
3✔
901
}
902

903
func (client *GitLabClient) mapGitLabMergeRequestToPullRequestInfoList(mergeRequests []*gitlab.MergeRequest, owner, repository string, withBody bool) (res []PullRequestInfo, err error) {
3✔
904
        for _, mergeRequest := range mergeRequests {
6✔
905
                var mergeRequestInfo PullRequestInfo
3✔
906
                if mergeRequestInfo, err = client.mapGitLabMergeRequestToPullRequestInfo(mergeRequest, withBody, owner, repository); err != nil {
3✔
907
                        return
×
908
                }
×
909
                res = append(res, mergeRequestInfo)
3✔
910
        }
911
        return
3✔
912
}
913

914
func (client *GitLabClient) mapGitLabMergeRequestToPullRequestInfo(mergeRequest *gitlab.MergeRequest, withBody bool, owner, repository string) (PullRequestInfo, error) {
4✔
915
        var body string
4✔
916
        if withBody {
6✔
917
                body = mergeRequest.Description
2✔
918
        }
2✔
919
        sourceOwner := owner
4✔
920
        var err error
4✔
921
        if mergeRequest.SourceProjectID != mergeRequest.TargetProjectID {
4✔
922
                if sourceOwner, err = client.getProjectOwnerByID(mergeRequest.SourceProjectID); err != nil {
×
923
                        return PullRequestInfo{}, err
×
924
                }
×
925
        }
926

927
        return PullRequestInfo{
4✔
928
                ID:     int64(mergeRequest.IID),
4✔
929
                Title:  mergeRequest.Title,
4✔
930
                Body:   body,
4✔
931
                Author: mergeRequest.Author.Username,
4✔
932
                Source: BranchInfo{
4✔
933
                        Name:       mergeRequest.SourceBranch,
4✔
934
                        Repository: repository,
4✔
935
                        Owner:      sourceOwner,
4✔
936
                },
4✔
937
                URL: mergeRequest.WebURL,
4✔
938
                Target: BranchInfo{
4✔
939
                        Name:       mergeRequest.TargetBranch,
4✔
940
                        Repository: repository,
4✔
941
                        Owner:      owner,
4✔
942
                },
4✔
943
        }, nil
4✔
944
}
945

946
func (client *GitLabClient) getProjectOwnerByID(projectID int) (string, error) {
2✔
947
        project, glResponse, err := client.glClient.Projects.GetProject(projectID, &gitlab.GetProjectOptions{})
2✔
948
        if err != nil {
2✔
949
                return "", err
×
950
        }
×
951
        if glResponse != nil {
4✔
952
                if err = vcsutils.CheckResponseStatusWithBody(glResponse.Response, http.StatusOK); err != nil {
2✔
953
                        return "", err
×
954
                }
×
955
        }
956
        if project.Namespace == nil {
3✔
957
                return "", fmt.Errorf("could not fetch the name of the project owner. Project ID: %d", projectID)
1✔
958
        }
1✔
959
        return project.Namespace.Name, nil
1✔
960
}
961

962
func mapGitLabPullRequestState(state *vcsutils.PullRequestState) *string {
4✔
963
        var stateStringValue string
4✔
964
        switch *state {
4✔
965
        case vcsutils.Open:
2✔
966
                stateStringValue = "reopen"
2✔
967
        case vcsutils.Closed:
1✔
968
                stateStringValue = "close"
1✔
969
        default:
1✔
970
                return nil
1✔
971
        }
972
        return &stateStringValue
3✔
973
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc