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

Helvethink / gitlab-ci-exporter / 18286274506

06 Oct 2025 03:36PM UTC coverage: 11.405% (+1.6%) from 9.811%
18286274506

push

github

web-flow
Release - RC1 (#74)

* Improve unit tests

* Implementer beter management for redis

* Fix test unit

* Bump docker/login-action from 3.4.0 to 3.5.0 (#80)

Bumps [docker/login-action](https://github.com/docker/login-action) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/74a5d1423...184bdaa07)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump step-security/harden-runner from 2.12.1 to 2.13.0 (#78)

Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.12.1 to 2.13.0.
- [Release notes](https://github.com/step-security/harden-runner/releases)
- [Commits](https://github.com/step-security/harden-runner/compare/v2.12.1...ec9f2d574)

---
updated-dependencies:
- dependency-name: step-security/harden-runner
  dependency-version: 2.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github/codeql-action from 3.29.0 to 3.29.9 (#77)

Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.0 to 3.29.9.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/ce28f5bb4...df559355d)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-ve... (continued)

20 of 208 new or added lines in 9 files covered. (9.62%)

3 existing lines in 2 files now uncovered.

818 of 7172 relevant lines covered (11.41%)

0.32 hits per line

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

0.0
/pkg/controller/webhooks.go
1
package controller
2

3
import (
4
        "context"
5
        "fmt"
6
        "regexp"
7
        "strconv"
8
        "strings"
9

10
        log "github.com/sirupsen/logrus"
11
        goGitlab "gitlab.com/gitlab-org/api/client-go"
12

13
        "github.com/helvethink/gitlab-ci-exporter/pkg/config"
14
        "github.com/helvethink/gitlab-ci-exporter/pkg/schemas"
15
)
16

17
// processPipelineEvent processes a GitLab pipeline event and triggers a metrics pull
18
// for the associated Git reference (branch, tag, or merge request).
19
//
20
// It determines the kind of ref involved in the pipeline event based on the event details:
21
//   - If the event is related to a merge request (indicated by a non-zero IID), it treats
22
//     the ref as a merge request and uses the merge request IID as the ref name.
23
//   - If the event is related to a tag pipeline, it treats the ref as a tag.
24
//   - Otherwise, it treats the ref as a branch.
25
//
26
// Finally, it constructs a new Ref object representing the pipeline's project and ref,
27
// and calls triggerRefMetricsPull to update metrics related to that ref.
28
//
29
// Parameters:
30
// - ctx: the context for tracing and cancellation
31
// - e: the GitLab pipeline event to process
32
func (c *Controller) processPipelineEvent(ctx context.Context, e goGitlab.PipelineEvent) {
×
33
        var (
×
34
                refKind schemas.RefKind          // Type of Git ref (branch, tag, or merge request)
×
35
                refName = e.ObjectAttributes.Ref // The ref name from the pipeline event (branch or tag name)
×
36
        )
×
37

×
38
        // TODO: Consider validating if the ref matches the expected pattern for a merge request ref
×
39

×
40
        // If the pipeline event is related to a merge request (non-zero IID),
×
41
        // treat the ref as a Merge Request kind and use the IID as the ref name
×
42
        if e.MergeRequest.IID != 0 {
×
43
                refKind = schemas.RefKindMergeRequest
×
44
                refName = strconv.Itoa(e.MergeRequest.IID)
×
45
        } else if e.ObjectAttributes.Tag {
×
46
                // If the pipeline event is for a tag, set ref kind to Tag
×
47
                refKind = schemas.RefKindTag
×
48
        } else {
×
49
                // Otherwise, treat the ref as a branch
×
50
                refKind = schemas.RefKindBranch
×
51
        }
×
52

53
        // Trigger a metrics pull for the detected ref by creating a new Ref object
54
        // and calling the triggerRefMetricsPull method
55
        c.triggerRefMetricsPull(ctx, schemas.NewRef(
×
56
                schemas.NewProject(e.Project.PathWithNamespace),
×
57
                refKind,
×
58
                refName,
×
59
        ))
×
60
}
61

62
// processJobEvent handles a GitLab job event by identifying the reference type (branch or tag)
63
// and triggers a metrics update for the corresponding Git reference.
64
//
65
// The function performs the following steps:
66
// 1. Determines if the job event's ref is a tag or a branch.
67
// 2. Retrieves the full project details from GitLab based on the project ID from the event.
68
// 3. If project retrieval fails, logs the error and stops further processing.
69
// 4. Creates a new Ref object representing the project and ref information.
70
// 5. Initiates a metrics pull for the identified Ref.
71
//
72
// Parameters:
73
// - ctx: Context to support cancellation, deadlines, and tracing.
74
// - e: The GitLab job event containing job metadata.
75
func (c *Controller) processJobEvent(ctx context.Context, e goGitlab.JobEvent) {
×
76
        var (
×
77
                // Initialize the reference kind and name from the event's ref field
×
78
                refKind schemas.RefKind
×
79
                refName = e.Ref
×
80
        )
×
81

×
82
        // Determine the type of ref: tag or branch
×
83
        if e.Tag {
×
84
                refKind = schemas.RefKindTag
×
85
        } else {
×
86
                refKind = schemas.RefKindBranch
×
87
        }
×
88

89
        // Fetch the full project metadata from GitLab using the project ID from the event
90
        project, _, err := c.Gitlab.Projects.GetProject(e.ProjectID, nil)
×
91
        if err != nil {
×
92
                // Log the error if project retrieval fails and stop processing
×
93
                log.WithContext(ctx).
×
94
                        WithError(err).
×
95
                        Error("reading project from GitLab")
×
96

×
97
                return
×
98
        }
×
99

100
        // Create a new Ref object combining the project path, ref kind, and ref name
101
        ref := schemas.NewRef(
×
102
                schemas.NewProject(project.PathWithNamespace),
×
103
                refKind,
×
104
                refName,
×
105
        )
×
106

×
107
        // Trigger the process to pull metrics for the identified ref
×
108
        c.triggerRefMetricsPull(ctx, ref)
×
109
}
110

111
// processPushEvent handles GitLab push events, specifically focusing on branch deletion events.
112
//
113
// When a branch is deleted in GitLab, the push event’s CheckoutSHA is empty ("").
114
// This function detects such deletions, extracts the branch name from the ref,
115
// and triggers the removal of the corresponding ref from the internal store.
116
//
117
// Parameters:
118
// - ctx: Context for cancellation, deadlines, and tracing.
119
// - e: The GitLab push event containing information about the pushed ref and project.
120
func (c *Controller) processPushEvent(ctx context.Context, e goGitlab.PushEvent) {
×
121
        // Only proceed if CheckoutSHA is empty, which indicates a branch deletion event
×
122
        if e.CheckoutSHA == "" {
×
123
                // The ref kind is a branch for deletion events
×
124
                var (
×
125
                        refKind = schemas.RefKindBranch
×
126
                        refName string
×
127
                )
×
128

×
129
                // GitLab branch refs have a "refs/heads/" prefix.
×
130
                // Extract the branch name by removing this prefix.
×
131
                if branch, found := strings.CutPrefix(e.Ref, "refs/heads/"); found {
×
132
                        refName = branch
×
133
                } else {
×
134
                        // If the prefix is missing, log an error and return early.
×
135
                        // This indicates unexpected ref format.
×
136
                        log.WithContext(ctx).
×
137
                                WithFields(log.Fields{
×
138
                                        "project-name": e.Project.Name,
×
139
                                        "ref":          e.Ref,
×
140
                                }).
×
141
                                Error("extracting branch name from ref")
×
142

×
143
                        return
×
144
                }
×
145

146
                // Create a new Ref object representing the project and branch to be deleted.
147
                // Call deleteRef to remove this ref from the store, indicating it was deleted upstream.
148
                _ = deleteRef(ctx, c.Store, schemas.NewRef(
×
149
                        schemas.NewProject(e.Project.PathWithNamespace),
×
150
                        refKind,
×
151
                        refName,
×
152
                ), "received branch deletion push event from webhook")
×
153
        }
154
}
155

156
// processTagEvent handles GitLab tag events, specifically focusing on tag deletion events.
157
//
158
// When a tag is deleted in GitLab, the push event’s CheckoutSHA is empty ("").
159
// This function detects such deletions, extracts the tag name from the ref,
160
// and triggers the removal of the corresponding tag ref from the internal store.
161
//
162
// Parameters:
163
// - ctx: Context for cancellation, deadlines, and tracing.
164
// - e: The GitLab tag event containing information about the tag ref and project.
165
func (c *Controller) processTagEvent(ctx context.Context, e goGitlab.TagEvent) {
×
166
        // Only proceed if CheckoutSHA is empty, indicating a tag deletion event
×
167
        if e.CheckoutSHA == "" {
×
168
                // The ref kind is a tag for deletion events
×
169
                var (
×
170
                        refKind = schemas.RefKindTag
×
171
                        refName string
×
172
                )
×
173

×
174
                // GitLab tag refs have a "refs/tags/" prefix.
×
175
                // Extract the tag name by removing this prefix.
×
176
                if tag, found := strings.CutPrefix(e.Ref, "refs/tags/"); found {
×
177
                        refName = tag
×
178
                } else {
×
179
                        // If the prefix is missing, log an error and return early.
×
180
                        // This indicates an unexpected ref format.
×
181
                        log.WithContext(ctx).
×
182
                                WithFields(log.Fields{
×
183
                                        "project-name": e.Project.Name,
×
184
                                        "ref":          e.Ref,
×
185
                                }).
×
186
                                Error("extracting tag name from ref")
×
187

×
188
                        return
×
189
                }
×
190

191
                // Create a new Ref object representing the project and tag to be deleted.
192
                // Call deleteRef to remove this ref from the store, indicating it was deleted upstream.
193
                _ = deleteRef(ctx, c.Store, schemas.NewRef(
×
194
                        schemas.NewProject(e.Project.PathWithNamespace),
×
195
                        refKind,
×
196
                        refName,
×
197
                ), "received tag deletion tag event from webhook")
×
198
        }
199
}
200

201
// processMergeEvent handles GitLab merge request events.
202
//
203
// It processes specific merge request actions such as "close" and "merge".
204
// For these events, it deletes the corresponding merge request reference from the internal store,
205
// as the merge request is no longer active or relevant.
206
//
207
// Parameters:
208
// - ctx: Context for cancellation, deadlines, and tracing.
209
// - e: The GitLab merge event containing information about the merge request and project.
210
func (c *Controller) processMergeEvent(ctx context.Context, e goGitlab.MergeEvent) {
×
211
        // Create a Ref representing the merge request using the project namespace and merge request IID.
×
212
        ref := schemas.NewRef(
×
213
                schemas.NewProject(e.Project.PathWithNamespace),
×
214
                schemas.RefKindMergeRequest,
×
215
                strconv.Itoa(e.ObjectAttributes.IID),
×
216
        )
×
217

×
218
        // Handle the merge request action
×
219
        switch e.ObjectAttributes.Action {
×
220
        // On "close" event, delete the merge request ref from the store
221
        case "close":
×
NEW
222
                //_ = deleteRef(ctx, c.Store, ref, "received merge request close event from webhook")
×
NEW
223
                c.triggerRefDeletion(ctx, ref)
×
224
        // On "merge" event, delete the merge request ref from the store
225
        case "merge":
×
NEW
226
                //_ = deleteRef(ctx, c.Store, ref, "received merge request merge event from webhook")
×
NEW
227
                c.triggerRefDeletion(ctx, ref)
×
228
        // For other actions, log that they are unsupported (e.g. "open", "update")
229
        default:
×
230
                log.
×
231
                        WithField("merge-request-event-type", e.ObjectAttributes.Action).
×
232
                        Debug("received a non supported merge-request event type as a webhook")
×
233
        }
234
}
235

NEW
236
func (c *Controller) triggerRefDeletion(ctx context.Context, ref schemas.Ref) {
×
NEW
237
        err := c.Store.DelRef(ctx, ref.Key())
×
NEW
238
        if err != nil {
×
NEW
239
                log.WithContext(ctx).WithFields(log.Fields{
×
NEW
240
                        "project-name": ref.Project.Name,
×
NEW
241
                        "ref":          ref.Name,
×
NEW
242
                }).Error("failed deleting ref")
×
NEW
243
        }
×
244
}
245

246
// triggerRefMetricsPull processes a reference (branch, tag, or merge request ref) and triggers
247
// a metrics pull if the ref is configured or matches configured wildcards.
248
//
249
// It first checks if the ref already exists in the store. If it does not exist,
250
// it tries to determine whether the project exists or can be matched by configured wildcards.
251
// If the project is found or matches a wildcard and the ref matches the project configuration,
252
// it stores the ref and then schedules a task to pull metrics for this ref.
253
//
254
// If the ref already exists, it immediately schedules a task to pull metrics.
255
//
256
// Parameters:
257
// - ctx: Context for cancellation, deadlines, and tracing.
258
// - ref: The reference (branch/tag/merge request) to check and possibly pull metrics for.
259
func (c *Controller) triggerRefMetricsPull(ctx context.Context, ref schemas.Ref) {
×
260
        logFields := log.Fields{
×
261
                "project-name": ref.Project.Name,
×
262
                "ref":          ref.Name,
×
263
                "ref-kind":     ref.Kind,
×
264
        }
×
265

×
266
        // Check if the ref already exists in the internal store
×
267
        refExists, err := c.Store.RefExists(ctx, ref.Key())
×
268
        if err != nil {
×
269
                log.WithContext(ctx).
×
270
                        WithFields(logFields).
×
271
                        WithError(err).
×
272
                        Error("reading ref from the store")
×
273
                return
×
274
        }
×
275

276
        // If the ref does not exist, try to see if the project is known or can be matched by wildcards
277
        if !refExists {
×
278
                p := schemas.NewProject(ref.Project.Name)
×
279

×
280
                projectExists, err := c.Store.ProjectExists(ctx, p.Key())
×
281
                if err != nil {
×
282
                        log.WithContext(ctx).
×
283
                                WithFields(logFields).
×
284
                                WithError(err).
×
285
                                Error("reading project from the store")
×
286
                        return
×
287
                }
×
288

289
                // If project does not exist, try to match wildcards configured to discover projects
290
                if !projectExists && len(c.Config.Wildcards) > 0 {
×
291
                        for _, w := range c.Config.Wildcards {
×
292
                                matches, err := isRefMatchingWilcard(w, ref)
×
293
                                if err != nil {
×
294
                                        log.WithContext(ctx).
×
295
                                                WithError(err).
×
296
                                                Warn("checking if the ref matches the wildcard config")
×
297
                                        continue
×
298
                                }
299

300
                                if matches {
×
301
                                        // If matched, schedule a task to pull the entire project based on the wildcard config
×
302
                                        c.ScheduleTask(context.TODO(), schemas.TaskTypePullProject, ref.Project.Name, ref.Project.Name, w.Pull)
×
303
                                        log.WithFields(logFields).Info("project ref not currently exported but its configuration matches a wildcard, triggering a pull of the project")
×
304
                                } else {
×
305
                                        log.WithFields(logFields).Debug("project ref not matching wildcard, skipping..")
×
306
                                }
×
307
                        }
308

309
                        log.WithFields(logFields).Info("done looking up for wildcards matching the project ref")
×
310
                        return
×
311
                }
312

313
                // If project exists, verify if the ref matches the project's pull refs configuration
314
                if projectExists {
×
315
                        if err := c.Store.GetProject(ctx, &p); err != nil {
×
316
                                log.WithContext(ctx).
×
317
                                        WithFields(logFields).
×
318
                                        WithError(err).
×
319
                                        Error("reading project from the store")
×
320
                                return
×
321
                        }
×
322

323
                        matches, err := isRefMatchingProjectPullRefs(p.Pull.Refs, ref)
×
324
                        if err != nil {
×
325
                                log.WithContext(ctx).
×
326
                                        WithError(err).
×
327
                                        Error("checking if the ref matches the project config")
×
328
                                return
×
329
                        }
×
330

331
                        if matches {
×
332
                                ref.Project = p
×
333

×
334
                                // Store the ref as it's now confirmed to be of interest
×
335
                                if err = c.Store.SetRef(ctx, ref); err != nil {
×
336
                                        log.WithContext(ctx).
×
337
                                                WithFields(logFields).
×
338
                                                WithError(err).
×
339
                                                Error("writing ref in the store")
×
340
                                        return
×
341
                                }
×
342

343
                                // Jump to scheduling the pull task after storing the ref
344
                                goto schedulePull
×
345
                        }
346
                }
347

348
                log.WithFields(logFields).Info("ref not configured in the exporter, ignoring pipeline webhook")
×
349
                return
×
350
        }
351

352
schedulePull:
353
        // If ref exists or has just been stored, schedule a pull metrics task for this ref
354
        log.WithFields(logFields).Info("received a pipeline webhook from GitLab for a ref, triggering metrics pull")
×
355

×
356
        // TODO: When all metrics are sent in the webhook, this pull might be avoidable
×
357
        c.ScheduleTask(context.TODO(), schemas.TaskTypePullRefMetrics, string(ref.Key()), ref)
×
358
}
359

360
// processDeploymentEvent handles a GitLab deployment event by triggering a metrics pull
361
// for the specific environment related to the deployment.
362
//
363
// Parameters:
364
// - ctx: Context for cancellation, deadlines, and tracing.
365
// - e: The GitLab deployment event containing deployment details.
366
func (c *Controller) processDeploymentEvent(ctx context.Context, e goGitlab.DeploymentEvent) {
×
367
        // Construct an Environment object from the event data
×
368
        env := schemas.Environment{
×
369
                ProjectName: e.Project.PathWithNamespace, // Full project namespace (e.g. "group/project")
×
370
                Name:        e.Environment,               // Name of the environment deployed to (e.g. "production")
×
371
        }
×
372

×
373
        // Trigger a metrics pull for the specified environment
×
374
        c.triggerEnvironmentMetricsPull(ctx, env)
×
375
}
×
376

377
// triggerEnvironmentMetricsPull triggers a metrics pull for a given environment.
378
// It checks if the environment exists in the store or matches configured wildcards or project settings,
379
// and schedules a pull task if appropriate.
380
//
381
// Parameters:
382
// - ctx: context for tracing, cancellation, and deadlines.
383
// - env: the environment to trigger metrics pull for.
384
func (c *Controller) triggerEnvironmentMetricsPull(ctx context.Context, env schemas.Environment) {
×
385
        // Prepare common log fields for consistent logging
×
386
        logFields := log.Fields{
×
387
                "project-name":     env.ProjectName,
×
388
                "environment-name": env.Name,
×
389
        }
×
390

×
391
        // Check if the environment exists in the store
×
392
        envExists, err := c.Store.EnvironmentExists(ctx, env.Key())
×
393
        if err != nil {
×
394
                log.WithContext(ctx).
×
395
                        WithFields(logFields).
×
396
                        WithError(err).
×
397
                        Error("reading environment from the store")
×
398
                return
×
399
        }
×
400

401
        if !envExists {
×
402
                // If environment is not found, check if the project exists
×
403
                p := schemas.NewProject(env.ProjectName)
×
404

×
405
                projectExists, err := c.Store.ProjectExists(ctx, p.Key())
×
406
                if err != nil {
×
407
                        log.WithContext(ctx).
×
408
                                WithFields(logFields).
×
409
                                WithError(err).
×
410
                                Error("reading project from the store")
×
411
                        return
×
412
                }
×
413

414
                // If project does not exist, check if it matches any configured wildcards
415
                if !projectExists && len(c.Config.Wildcards) > 0 {
×
416
                        for _, w := range c.Config.Wildcards {
×
417
                                // Check if the environment matches the wildcard pattern
×
418
                                matches, err := isEnvMatchingWilcard(w, env)
×
419
                                if err != nil {
×
420
                                        log.WithContext(ctx).
×
421
                                                WithError(err).
×
422
                                                Warn("checking if the env matches the wildcard config")
×
423
                                        continue
×
424
                                }
425

426
                                if matches {
×
427
                                        // Schedule a project pull task for matching wildcard configuration
×
428
                                        c.ScheduleTask(context.TODO(), schemas.TaskTypePullProject, env.ProjectName, env.ProjectName, w.Pull)
×
429
                                        log.WithFields(logFields).Info("project environment not currently exported but its configuration matches a wildcard, triggering a pull of the project")
×
430
                                } else {
×
431
                                        log.WithFields(logFields).Debug("project ref not matching wildcard, skipping..")
×
432
                                }
×
433
                        }
434

435
                        log.WithFields(logFields).Info("done looking up for wildcards matching the project ref")
×
436
                        return
×
437
                }
438

439
                // If the project exists, verify if environment matches the project's pull configuration
440
                if projectExists {
×
441
                        if err := c.Store.GetProject(ctx, &p); err != nil {
×
442
                                log.WithContext(ctx).
×
443
                                        WithFields(logFields).
×
444
                                        WithError(err).
×
445
                                        Error("reading project from the store")
×
446
                        }
×
447

448
                        matches, err := isEnvMatchingProjectPullEnvironments(p.Pull.Environments, env)
×
449
                        if err != nil {
×
450
                                log.WithContext(ctx).
×
451
                                        WithError(err).
×
452
                                        Error("checking if the env matches the project config")
×
453
                                return
×
454
                        }
×
455

456
                        if matches {
×
457
                                // Since environment ID might be missing, update environment details by querying GitLab API
×
458
                                if err = c.UpdateEnvironment(ctx, &env); err != nil {
×
459
                                        log.WithContext(ctx).
×
460
                                                WithFields(logFields).
×
461
                                                WithError(err).
×
462
                                                Error("updating event from GitLab API")
×
463
                                        return
×
464
                                }
×
465
                                // Proceed to schedule metrics pull after update
466
                                goto schedulePull
×
467
                        }
468
                }
469

470
                // Environment is neither configured nor matched by any project or wildcard - ignore the event
471
                log.WithFields(logFields).
×
472
                        Info("environment not configured in the exporter, ignoring deployment webhook")
×
473
                return
×
474
        }
475

476
        // If the environment ID is not set, refresh it from the store to ensure we have a valid ID
477
        if env.ID == 0 {
×
478
                if err = c.Store.GetEnvironment(ctx, &env); err != nil {
×
479
                        log.WithContext(ctx).
×
480
                                WithFields(logFields).
×
481
                                WithError(err).
×
482
                                Error("reading environment from the store")
×
483
                }
×
484
        }
485

486
schedulePull:
487
        // Log and schedule the metrics pull task for the environment
488
        log.WithFields(logFields).Info("received a deployment webhook from GitLab for an environment, triggering metrics pull")
×
489
        c.ScheduleTask(ctx, schemas.TaskTypePullEnvironmentMetrics, string(env.Key()), env)
×
490
}
491

492
// isRefMatchingProjectPullRefs checks if a given ref matches the pull refs configuration for a project.
493
//
494
// Parameters:
495
// - pprs: the ProjectPullRefs configuration specifying which refs are enabled and their regex patterns.
496
// - ref: the Ref object representing the reference to check.
497
//
498
// Returns:
499
// - matches: true if the ref matches the configuration and regex pattern, false otherwise.
500
// - err: error if an invalid ref kind is provided or regex compilation fails.
501
func isRefMatchingProjectPullRefs(pprs config.ProjectPullRefs, ref schemas.Ref) (matches bool, err error) {
×
502
        // First, check if the kind of ref is enabled in the project's pull refs config
×
503
        switch ref.Kind {
×
504
        case schemas.RefKindBranch:
×
505
                if !pprs.Branches.Enabled {
×
506
                        // Branch refs not enabled, return no match
×
507
                        return
×
508
                }
×
509
        case schemas.RefKindTag:
×
510
                if !pprs.Tags.Enabled {
×
511
                        // Tag refs not enabled, return no match
×
512
                        return
×
513
                }
×
514
        case schemas.RefKindMergeRequest:
×
515
                if !pprs.MergeRequests.Enabled {
×
516
                        // Merge request refs not enabled, return no match
×
517
                        return
×
518
                }
×
519
        default:
×
520
                // Invalid ref kind, return an error
×
521
                return false, fmt.Errorf("invalid ref kind %v", ref.Kind)
×
522
        }
523

524
        // Compile the regex pattern for the ref kind from the project's pull refs config
525
        var re *regexp.Regexp
×
526
        if re, err = schemas.GetRefRegexp(pprs, ref.Kind); err != nil {
×
527
                return
×
528
        }
×
529

530
        // Check if the ref name matches the regex pattern and return the result
531
        return re.MatchString(ref.Name), nil
×
532
}
533

534
// isEnvMatchingProjectPullEnvironments checks if a given environment matches
535
// the project's pull environments configuration.
536
//
537
// Parameters:
538
// - ppe: the ProjectPullEnvironments configuration, including enabled flag and regexp pattern.
539
// - env: the Environment object to check.
540
//
541
// Returns:
542
// - matches: true if the environment is enabled and matches the regexp pattern, false otherwise.
543
// - err: error if regexp compilation fails.
544
func isEnvMatchingProjectPullEnvironments(ppe config.ProjectPullEnvironments, env schemas.Environment) (matches bool, err error) {
×
545
        // Check if environment pulling is enabled in the config
×
546
        if !ppe.Enabled {
×
547
                // Pulling not enabled, so no match
×
548
                return
×
549
        }
×
550

551
        // Compile the regular expression for matching environment names
552
        var re *regexp.Regexp
×
553
        if re, err = regexp.Compile(ppe.Regexp); err != nil {
×
554
                // Return error if regexp compilation fails
×
555
                return
×
556
        }
×
557

558
        // Return whether the environment's name matches the compiled regexp
559
        return re.MatchString(env.Name), nil
×
560
}
561

562
// isRefMatchingWilcard checks if a given ref matches a wildcard configuration.
563
//
564
// It first verifies if the wildcard owner matches the ref's project name
565
// or if the owner is global (empty Kind means global).
566
// Then it checks if the ref matches the pull refs configuration of the wildcard.
567
//
568
// Returns true if all checks pass, false otherwise.
569
func isRefMatchingWilcard(w config.Wildcard, ref schemas.Ref) (matches bool, err error) {
×
570
        // Check if wildcard owner is specified and matches the ref's project name
×
571
        if w.Owner.Kind != "" && !strings.Contains(ref.Project.Name, w.Owner.Name) {
×
572
                return
×
573
        }
×
574

575
        // Check if the ref matches the pull refs pattern/configuration of the wildcard
576
        return isRefMatchingProjectPullRefs(w.Pull.Refs, ref)
×
577
}
578

579
// isEnvMatchingWilcard checks if a given environment matches a wildcard configuration.
580
//
581
// It first verifies if the wildcard owner matches the environment's project name
582
// or if the owner is global (empty Kind means global).
583
// Then it checks if the environment matches the pull environments configuration of the wildcard.
584
//
585
// Returns true if all checks pass, false otherwise.
586
func isEnvMatchingWilcard(w config.Wildcard, env schemas.Environment) (matches bool, err error) {
×
587
        // Check if wildcard owner is specified and matches the environment's project name
×
588
        if w.Owner.Kind != "" && !strings.Contains(env.ProjectName, w.Owner.Name) {
×
589
                return
×
590
        }
×
591

592
        // Check if the environment matches the pull environments pattern/configuration of the wildcard
593
        return isEnvMatchingProjectPullEnvironments(w.Pull.Environments, env)
×
594
}
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