Skip to content

feat: Add GitLab event support for automation triggers#66

Open
malhotra5 wants to merge 4 commits into
mainfrom
feat/gitlab-event-support
Open

feat: Add GitLab event support for automation triggers#66
malhotra5 wants to merge 4 commits into
mainfrom
feat/gitlab-event-support

Conversation

@malhotra5
Copy link
Copy Markdown
Member

Summary

Add GitLab webhook event handling to the automation service, mirroring the existing GitHub support. This enables event-triggered automations for GitLab repositories.

Changes

New Files

  • automation/event_schemas/gitlab.py - GitLab event schema definitions with Pydantic models

Modified Files

  • automation/event_schemas/__init__.py - Register GitLab parser
  • automation/utils/webhook.py - Add 'gitlab' to builtin sources
  • automation/schemas.py - Add 'gitlab' to reserved sources
  • tests/test_event_schemas.py - Add GitLab event parsing, detection, and trigger matching tests
  • tests/test_event_router.py - Add GitLab event forwarding tests

GitLab Event Types Supported

GitLab Event Event Key Pattern GitHub Equivalent
merge_request merge_request.{action} pull_request.{action}
push push push
tag_push tag_push (tag portion of push)
issue issue.{action} issues.{action}
note note issue_comment.created
pipeline pipeline.{status} (no direct equivalent)

Implementation Details

  • GitLab events are forwarded from the OpenHands server using the same AUTOMATION_WEBHOOK_SECRET and X-Hub-Signature-256 header pattern as GitHub
  • Detection uses GitLab's object_kind field for reliable event type identification
  • Action extraction uses object_attributes.action (for MRs, issues) or object_attributes.status (for pipelines)
  • JMESPath filtering works against the raw payload, enabling filters like:
    • project.path_with_namespace == 'org/repo'
    • glob(project.path_with_namespace, 'org/*')
    • icontains(object_attributes.note, '@openhands')

Example Automation Trigger

{
  "type": "event",
  "source": "gitlab",
  "on": "merge_request.open",
  "filter": "glob(project.path_with_namespace, 'myorg/*')"
}

Testing

  • 23 new GitLab-specific tests added to test_event_schemas.py
  • 6 new GitLab event router tests added to test_event_router.py
  • All linting passes (ruff check/format)

Related

This complements the OpenHands server-side GitLab event forwarding implementation in OpenHands/OpenHands#14118


This PR was created by an AI assistant (OpenHands) on behalf of the user.

@malhotra5 can click here to continue refining the PR

Add GitLab webhook event handling to the automation service, mirroring
the existing GitHub support. This enables event-triggered automations
for GitLab repositories.

Changes:
- Add GitLab event schemas (merge_request, push, tag_push, issue, note, pipeline)
- Register GitLab parser in event_schemas/__init__.py
- Add 'gitlab' to builtin webhook sources in utils/webhook.py
- Add 'gitlab' to reserved sources in schemas.py
- Add comprehensive tests for GitLab event parsing, detection, and trigger matching

GitLab events are forwarded from the OpenHands server using the same
AUTOMATION_WEBHOOK_SECRET and X-Hub-Signature-256 header pattern as GitHub.

Event type mapping (GitLab -> GitHub equivalent):
- merge_request -> pull_request
- push -> push
- tag_push -> (tag portion of push)
- issue -> issues
- note -> issue_comment
- pipeline -> (no direct equivalent)

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 24, 2026

Coverage

Coverage Report
FileStmtsMissCoverMissing
__init__.py10100% 
app.py1185950%36, 39, 42, 48, 50, 53, 56–59, 62–63, 66, 73–74, 77–78, 82, 90–91, 94, 101–102, 104, 107–108, 111, 116–124, 126–128, 214–216, 221–222, 224–225, 227, 230–232, 234–235, 237–238, 243–244, 248, 251, 253
auth.py116595%80, 122, 286, 294–295
config.py1460100% 
constants.py160100% 
db.py442640%37–39, 48–49, 51–52, 54, 62, 69, 79, 82–83, 87–88, 96, 104, 109, 114, 117–123
dispatcher.py1393574%53, 65, 67–68, 137, 141, 163, 171, 190–192, 220–222, 225–227, 280–281, 305–312, 328, 341–342, 355–356, 363–364, 366
event_router.py591967%83, 88, 119–121, 137–138, 156, 158, 160–161, 163, 173, 179–181, 184, 186, 188
exceptions.py40100% 
execution.py24414739%36–38, 73–76, 84–88, 90, 98–100, 105–109, 111, 125–128, 130, 132, 134–137, 139–144, 146, 148–155, 157–158, 160, 196–198, 204–206, 217–220, 226–228, 268–272, 281, 289, 293, 295–296, 301–302, 307, 359, 361, 379, 382–385, 405–408, 410, 418–419, 422, 428, 491–493, 495–501, 504–505, 507, 509–511, 514, 517, 520–523, 525, 528–529, 532–534, 538–539, 543–546, 548, 556–557, 561–563, 565–571, 575, 577, 586–588, 590–592
filter_eval.py50296%161–162
logger.py551769%37, 50–51, 53–59, 74, 77, 101, 103–106
models.py800100% 
preset_router.py1825669%124–126, 234–235, 240–247, 252, 255, 257–258, 269–272, 274–278, 283, 292, 353–355, 466–467, 472–479, 484, 487, 489–490, 501–504, 506–510, 515, 525
router.py1136443%74–75, 95, 97, 100, 102, 116, 129, 131–132, 134–135, 138–140, 151–153, 171–174, 193, 196, 199, 206, 208, 237, 242–244, 247–249, 253–254, 259, 263–266, 268, 276, 278–279, 284–285, 288, 290, 292–294, 297–300, 305, 307–308, 317, 338–340, 344
scheduler.py57984%124–125, 162–163, 178–179, 189–190, 192
schemas.py2651793%31, 165, 171–173, 232–234, 236, 319–320, 323, 328, 333, 477, 485, 492
trigger_matcher.py28389%72–74
uploads.py1075944%138–141, 149–151, 157–158, 161, 170–171, 174–175, 183–184, 186–189, 192–195, 197, 199–201, 203–206, 208–209, 211, 226, 232–233, 236, 239, 242, 245, 247, 260–261, 275, 278–280, 282–283, 285, 291–292, 305, 313–315, 319
watchdog.py1004753%50–51, 63–64, 69–71, 83–84, 228–229, 231, 233, 242, 244–246, 248, 255–257, 259–261, 263–264, 266, 281, 283, 288–291, 293–298, 300–306, 308
webhook_router.py804840%57, 82–83, 107–108, 110, 113–114, 116, 126, 128–132, 137, 139, 151, 154, 157, 164–165, 167, 180, 182–183, 188, 204, 206–207, 213–215, 217–218, 220, 235, 237–238, 243–244, 261, 263–264, 270–271, 273, 275
event_schemas
   __init__.py31196%53
   custom.py33584%52–53, 64–66
   detection.py320100% 
   github.py125496%306, 311, 456, 483
   gitlab.py146397%212, 469, 496
presets
   __init__.py00100% 
storage
   __init__.py50100% 
   factory.py11190%29
   file_store.py22577%21, 30, 35, 40, 64
   google_cloud.py721184%49, 97–102, 136–137, 190, 192
   s3.py1121586%56, 100, 102–103, 107, 109, 190, 213–215, 269–270, 275, 337–338
utils
   __init__.py50100% 
   api_key.py322425%40–41, 46–48, 50, 55, 60, 62–65, 67–68, 70–71, 73, 79, 81–82, 89, 91–92, 98
   cron.py45686%39, 45, 74, 80, 123, 140
   log_context.py100100% 
   run.py771284%74–76, 175–177, 182–184, 231, 237–238
   sandbox.py1017624%40–41, 46–49, 51–53, 55–61, 73, 75, 85–86, 88–90, 92–93, 96–97, 103, 109–111, 121–122, 127–133, 156–157, 159–163, 165–169, 206–207, 209, 211–214, 219–220, 223, 225–226, 232–234, 239–241, 246–247, 255–257, 259
   tarball_validation.py480100% 
   time.py30100% 
   webhook.py511668%47, 52, 120, 130–132, 138, 175, 178–184, 190
TOTAL296579273% 

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 24, 2026

🚀 Deploy Preview PR Created/Updated

A deploy preview has been created/updated for this PR.

Deploy PR: https://github.com/OpenHands/deploy/pull/3917
Automation SHA: 45e2c2ecc6c9c6c03aae8db1fa63dbeb5e9043fc
Last updated: Apr 27, 2026, 12:44:45 PM ET

Once the deploy PR's CI passes, the automation service will be deployed to the feature environment.

Update test_only_github_reserved to test_builtin_providers_reserved
and add test_gitlab_is_reserved to properly test that both GitHub
and GitLab are in the RESERVED_SOURCES set.

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
@malhotra5 malhotra5 marked this pull request as ready for review April 27, 2026 16:34
Copy link
Copy Markdown

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Acceptable - Solid implementation that mirrors GitHub support well. Found minor issues with potentially dead code and missing test evidence.

Comment thread automation/event_schemas/gitlab.py
Comment thread automation/event_schemas/gitlab.py
Remove fallback detection rules that can never execute since GitLab
webhooks always include the object_kind field. The second comment about
action extraction duplication is acknowledged but kept as-is since it's
minor and doesn't warrant added complexity of a base class mixin.

Co-authored-by: openhands <openhands@all-hands.dev>
Copy link
Copy Markdown
Member Author

Addressed all review feedback in 45e2c2e:

Comment 1 (line 400): Removed dead fallback detection rules - GitLab webhooks always include object_kind
Comment 2 (line 162): Acknowledged but kept as-is - the action duplication is minimal and a mixin would add more complexity than it saves

Status:

  • All CI checks passing
  • All review threads resolved
  • Ready for final review

@malhotra5 malhotra5 requested a review from all-hands-bot April 27, 2026 16:50
Copy link
Copy Markdown

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Acceptable - Solid implementation that mirrors GitHub support well. Clean code with comprehensive test coverage.

[RISK ASSESSMENT]
🟢 LOW - Well-contained feature addition with good test coverage, no breaking changes, uses existing webhook validation infrastructure. Mirrors proven GitHub implementation pattern.

VERDICT: ✅ Worth merging

KEY INSIGHT: This follows the established pattern for event source integration, making it maintainable and predictable. The use of GitLab's built-in object_kind field for detection is simpler and more reliable than structural heuristics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants