Sign inSign up

neckarit/gitlab-auto-merge

By neckarit

Updated 10 days ago

Gitlab Auto Merge

Image
Networking
Developer tools
0

811

neckarit/gitlab-auto-merge repository overview

GitLab Auto Merge

Automated merge request management for GitLab. This service monitors your GitLab project and automatically handles merge requests.

Features

  • Automatic Merging - Merges approved MRs when pipeline succeeds
  • Auto Rebase - Rebases MRs that are behind the target branch
  • Pipeline Management - Cancels duplicate/obsolete pipelines to save CI resources (only merge_request_event source — see Pipeline Cancellation Scope)
  • Smart Labels - Automatically labels MRs with their current status
  • Queue Position Labels - Shows MR position in the merge queue (Merge::#1, Merge::#2, etc.)
  • Draft MR Handling - Cancels pipelines and removes labels from draft MRs to save CI resources
  • Job Retry - Retries failed jobs caused by transient errors (OOM, network issues)
  • Priority Support - Important MRs can be prioritized with a label
  • Conflict Detection - Identifies and labels MRs with merge conflicts
  • Web Dashboard - REST API for monitoring and integration

Quick Start

docker run -d \
  --name gitlab-auto-merge \
  -p 8711:8711 \
  -e EXECUTION_ENVIRONMENT=Docker \
  -e GITLAB_SERVER_URL=https://gitlab.example.com \
  -e GITLAB_PROJECT=group/project \
  -e GITLAB_ACCESS_TOKEN=glpat-xxxx \
  neckarit/gitlab-auto-merge:latest \
  --mode=Run

Docker Compose

services:
  gitlab-auto-merge:
    image: neckarit/gitlab-auto-merge:latest
    container_name: gitlab-auto-merge
    restart: unless-stopped
    ports:
      - "8711:8711"
    environment:
      - EXECUTION_ENVIRONMENT=Docker
      - DEPLOYMENT_STAGE=Production
      - GITLAB_SERVER_URL=https://gitlab.example.com
      - GITLAB_PROJECT=group/project
      - GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
    command:
      - "--mode=Run"

Create a .env file next to your docker-compose.yml:

GITLAB_ACCESS_TOKEN=glpat-xxxxxxxxxxxx

Then start with:

docker compose up -d
Production Example with All Options
services:
  gitlab-auto-merge:
    image: neckarit/gitlab-auto-merge:latest
    container_name: gitlab-auto-merge
    restart: unless-stopped
    ports:
      - "8711:8711"
    volumes:
      - /path/to/your/ca.crt:/certs/ca.crt:ro
    environment:
      - EXECUTION_ENVIRONMENT=Docker
      - DEPLOYMENT_STAGE=Production
      - GITLAB_SERVER_URL=https://gitlab.example.com
      - GITLAB_PROJECT=group/project
      - GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
      - CA_CERT_PATH=/certs/ca.crt
    command:
      - "--mode=Run"

Custom SSL Certificates

If your GitLab instance uses a self-signed certificate or a certificate signed by an internal CA, you can configure the service to trust it.

Pass the certificate directly as a Base64-encoded environment variable. No file mounts needed.

Generate Base64:

# Encode your PEM certificate to Base64
cat /path/to/your/ca.crt | base64 -w0

Docker Run:

docker run -d \
  --name gitlab-auto-merge \
  -p 8711:8711 \
  -e EXECUTION_ENVIRONMENT=Docker \
  -e GITLAB_SERVER_URL=https://gitlab.example.com \
  -e GITLAB_PROJECT=group/project \
  -e GITLAB_ACCESS_TOKEN=glpat-xxxx \
  -e CA_CERT_BASE64="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t..." \
  neckarit/gitlab-auto-merge:latest \
  --mode=Run

Docker Compose:

services:
  gitlab-auto-merge:
    image: neckarit/gitlab-auto-merge:latest
    container_name: gitlab-auto-merge
    restart: unless-stopped
    ports:
      - "8711:8711"
    environment:
      - EXECUTION_ENVIRONMENT=Docker
      - GITLAB_SERVER_URL=https://gitlab.example.com
      - GITLAB_PROJECT=group/project
      - GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
      - CA_CERT_BASE64=${CA_CERT_BASE64}
    command:
      - "--mode=Run"
Option 2: Certificate File Path

Mount the certificate file into the container.

Docker Run:

docker run -d \
  --name gitlab-auto-merge \
  -p 8711:8711 \
  -v /path/to/your/ca.crt:/certs/ca.crt:ro \
  -e EXECUTION_ENVIRONMENT=Docker \
  -e GITLAB_SERVER_URL=https://gitlab.example.com \
  -e GITLAB_PROJECT=group/project \
  -e GITLAB_ACCESS_TOKEN=glpat-xxxx \
  -e CA_CERT_PATH=/certs/ca.crt \
  neckarit/gitlab-auto-merge:latest \
  --mode=Run

Docker Compose:

services:
  gitlab-auto-merge:
    image: neckarit/gitlab-auto-merge:latest
    container_name: gitlab-auto-merge
    restart: unless-stopped
    ports:
      - "8711:8711"
    volumes:
      - /path/to/your/ca.crt:/certs/ca.crt:ro
    environment:
      - EXECUTION_ENVIRONMENT=Docker
      - GITLAB_SERVER_URL=https://gitlab.example.com
      - GITLAB_PROJECT=group/project
      - GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
      - CA_CERT_PATH=/certs/ca.crt
    command:
      - "--mode=Run"

Notes:

  • The certificate must be in PEM format
  • CA_CERT_BASE64 takes precedence over CA_CERT_PATH if both are set
  • The custom CA will be trusted in addition to system default CAs
  • Hostname verification remains enabled for security

Environment Variables

VariableDescriptionRequiredDefault
GITLAB_SERVER_URLGitLab instance URL (e.g., https://gitlab.com)Yes-
GITLAB_PROJECTProject path (e.g., mygroup/myproject)Yes-
GITLAB_ACCESS_TOKENGitLab personal access token with api scopeYes-
MERGE_REQUEST_BADGE_ENABLEDEmbed the SVG status badge image in MR descriptions. Set to false when the service host is not reachable from user browsers.Notrue
CA_CERT_BASE64Base64-encoded CA certificate (PEM format). Takes precedence over file pathNo-
CA_CERT_PATHPath to custom CA certificate (PEM format)No-
EXECUTION_ENVIRONMENTRuntime environment typeNoDocker
DEPLOYMENT_STAGEDeployment stageNo-
SERVICE_HOSTService host identifierNo-
OTEL_EXPORTER_OTLP_ENDPOINTOTLP collector URL. Setting this single variable enables OpenTelemetry export (Ktor server traces + JVM auto-instrumentation).No-
OTEL_EXPORTER_OTLP_PROTOCOLOTLP wire protocol: grpc (port 4317) or http/protobuf (port 4318). Match it to your collector's listener.Nogrpc
OTEL_RESOURCE_ATTRIBUTESComma-separated resource attributes tagged onto every signal, e.g. deployment.environment=production.No-
OTEL_SDK_DISABLEDForce telemetry off explicitly. Defaults to true in the image; the entrypoint clears it once OTEL_EXPORTER_OTLP_ENDPOINT is set.Notrue (image)
OpenTelemetry

Telemetry is off by default — the image exports nothing and never phones home. It only emits traces once you point it at your own OTLP collector by setting OTEL_EXPORTER_OTLP_ENDPOINT. That single variable both selects the destination and lifts the image's OTEL_SDK_DISABLED=true default.

The endpoint's port determines the protocol: 4317 is gRPC (the default), 4318 is HTTP/protobuf. If your collector only speaks HTTP, use port 4318 and set OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf.

Docker Run:

docker run -d \
  --name gitlab-auto-merge \
  -p 8711:8711 \
  -e EXECUTION_ENVIRONMENT=Docker \
  -e GITLAB_SERVER_URL=https://gitlab.example.com \
  -e GITLAB_PROJECT=group/project \
  -e GITLAB_ACCESS_TOKEN=glpat-xxxx \
  -e OTEL_EXPORTER_OTLP_ENDPOINT=https://your-collector.example.com:4317 \
  neckarit/gitlab-auto-merge:latest \
  --mode=Run

Docker Compose:

services:
  gitlab-auto-merge:
    image: neckarit/gitlab-auto-merge:latest
    container_name: gitlab-auto-merge
    restart: unless-stopped
    ports:
      - "8711:8711"
    environment:
      - EXECUTION_ENVIRONMENT=Docker
      - GITLAB_SERVER_URL=https://gitlab.example.com
      - GITLAB_PROJECT=group/project
      - GITLAB_ACCESS_TOKEN=${GITLAB_ACCESS_TOKEN}
      - OTEL_EXPORTER_OTLP_ENDPOINT=https://your-collector.example.com:4317
      - OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production
    command:
      - "--mode=Run"

The service emits Ktor server traces and the standard JVM auto-instrumentation. To force telemetry off explicitly — for example to silence the service in an environment where OTEL_EXPORTER_OTLP_ENDPOINT is set for other containers — set OTEL_SDK_DISABLED=true.

Execution Environment Values
ValueDescription
LocalDevLocal development (IDE, hot reload)
StandaloneJAR running directly on server/VM
DockerRunning inside a Docker container
CIContinuous Integration environment
Deployment Stage Values
ValueDescription
DevelopmentDevelopment environment (unstable, test data)
StagingPre-production environment
ProductionLive production environment

Modes

ModeDescription
DryRunOnly log what would be done (default). No changes to GitLab.
OnlyLabelsOnly update MR labels. No rebase, no merge, no pipeline cancellation.
RebaseOnlyRebase MRs and update labels, but don't cancel pipelines or merge.
NoMergeRebase MRs, update labels, cancel pipelines, but don't merge.
NoPipelineCancellationMerge, rebase, update labels, but don't cancel pipelines.
RunFull execution: merge, rebase, update labels, cancel pipelines.

Usage:

docker run ... neckarit/gitlab-auto-merge:latest --mode=Run

Use Cases:

  • DryRun - Test the service without making any changes
  • OnlyLabels - Visualize MR status without affecting CI/CD
  • RebaseOnly - Keep MRs up-to-date without interrupting running pipelines
  • NoMerge - Prepare MRs for merging, but let humans do the final merge
  • NoPipelineCancellation - Fully automated merging but let all pipelines run to completion
  • Run - Fully automated merge workflow with pipeline optimization

API Endpoints

EndpointDescription
GET /api/auto-merge/merge-requestsList categorized merge requests
GET /api/auto-merge/pipelinesPipeline status overview
GET /api/auto-merge/logExecution log
POST /api/auto-merge/events/from-gitlabGitLab webhook endpoint

GitLab Webhook Integration

Configure a webhook in your GitLab project:

  1. Go to Settings → Webhooks
  2. URL: https://your-auto-merge-host/api/auto-merge/events/from-gitlab
  3. Trigger: Merge request events, Pipeline events

Labels Applied

The service automatically applies these labels to merge requests:

Status Labels

All Auto-Merge labels use the Merge:: namespace prefix, consistent with other project label namespaces (Component::, Status::, Type::).

LabelMeaning
Merge::MergableReady to be merged (pipeline passed, approved)
Merge::Waiting for CIPipeline is running or pending
Merge::Waiting for CI (Last Failed)Pipeline running, but previous pipeline failed
Merge::Rebase RequiredNeeds rebase onto target branch
Merge::RebasingCurrently being rebased by Auto Merge
Merge::ConflictHas merge conflicts
Merge::TodoHas unresolved discussions or failed pipeline
Merge::Not ApprovedWaiting for approval
Merge::EmptyMR has no commits
Merge::MergedSuccessfully merged by Auto Merge

Note: MRs with running pipelines show the Waiting for CI status, while MRs with failed pipelines show Todo (user must take action). GitLab's native UI already displays pipeline status prominently (badge, header, widget).

User Labels

User labels are manually managed and never automatically added or removed by Auto Merge:

LabelMeaning
Merge::ImportantPrioritizes this MR — processed before others
Merge::Low PriorityOnly merged when no other MRs are in the queue
Merge::No CancelPipeline will not be cancelled by Auto Merge
Merge::IgnoreIgnored by Auto Merge — no rebase, merge, or pipeline management
Queue Position Labels

Approved MRs waiting to be merged receive queue position labels showing their place in the merge queue:

LabelMeaning
Merge::#1Next MR to be merged (bright green)
Merge::#2Second in queue
Merge::#3Third in queue
...Higher positions have muted colors

Queue labels are automatically updated as MRs move through the queue. When an MR is merged, positions shift automatically.

Pipeline Cancellation Scope

Auto Merge cancels duplicate pipelines on a strict positive allowlist:

Pipeline sourceCancelled by Auto Merge?
merge_request_eventyes — the only source Auto Merge ever replaces
apino
triggerno
scheduleno
webno
pushno
any other sourceno

Auto Merge starts its own MR pipeline as merge_request_event. It only ever competes with other merge_request_event pipelines on the same MR. API-triggered verify pipelines, scheduled jobs, manual web triggers, and external triggers all have their own purpose and are never cancelled — even if they share a SHA with an MR pipeline.

The allowlist is positive on purpose: any new GitLab pipeline source defaults to "do not cancel", which is the safe default for a destructive operation.

Draft MR Handling

Draft merge requests receive special handling to save CI resources:

  1. Pipeline Cancellation - Running pipelines for draft MRs are automatically cancelled
  2. Label Removal - All Auto Merge labels are removed from draft MRs
  3. Exclusion from Queue - Draft MRs are not considered for merging or rebasing

When you mark an MR as draft, its pipeline is cancelled. When you mark it ready, the next pipeline will run normally and the MR will be processed.

Job Retry Mechanism

The service automatically retries failed jobs when specific transient errors are detected in the job trace:

Error PatternCause
OOMErrorException: Not enough memory to run compilationKotlin compiler OOM
Insufficient permissions to pull from the repository of projectTemporary auth issue
Process 'Resolving NPM dependencies using yarn' returns 1Network/registry issue

Jobs are only retried automatically when these specific error messages are found in the job log. Other failures require manual intervention.

Priority Support

To prioritize an important merge request:

  1. Add the label Merge::Important to the MR
  2. The MR will be processed before other MRs of the same status
  3. Low-priority MR pipelines may be cancelled when high-priority MRs have running pipelines

This is useful for hotfixes or time-sensitive changes that need to be merged quickly.

Conflict Detection

Current Status: Conflict detection labels MRs that have merge conflicts, but automatic conflict resolution is not yet functional (returns 500 server error from GitLab API).

MRs with conflicts will:

  • Receive the Merge::Conflict label
  • Have their pipelines cancelled (since they cannot be merged anyway)
  • Require manual conflict resolution

API Endpoints

EndpointMethodDescription
/api/auto-merge/configurationGETService configuration
/api/auto-merge/merge-requestsGETList categorized merge requests
/api/auto-merge/merge-requests/asciiGETMRs as plain text
/api/auto-merge/pipelinesGETPipeline status overview
/api/auto-merge/pipelines/statusGETAggregated pipeline status
/api/auto-merge/pipelines/by-branch/mainGETMain branch pipelines
/api/auto-merge/pipelines/scheduledGETScheduled pipeline list
/api/auto-merge/runsGETAuto-merge run history
/api/auto-merge/runs/latestGETMost recent run details
/api/auto-merge/actionsGETActions timeline
/api/auto-merge/runnersGETRunner and job status
/api/auto-merge/logGETExecution log messages
/api/auto-merge/log/actionsGETExecuted actions log
/api/auto-merge/events/historyGETReceived GitLab events
/api/auto-merge/events/from-gitlabPOSTGitLab webhook endpoint

License

Proprietary - Neckar IT GmbH


Changelog — GitLab Auto-Merge

Format: Keep a Changelog 1.1.0.

[Unreleased]

Added
  • Opt-out for MR status badge: New CLI flag --merge-request-badge-enabled / --no-merge-request-badge-enabled (env MERGE_REQUEST_BADGE_ENABLED) controls whether the SVG status badge image is embedded in MR descriptions. Default stays enabled; disable in setups where the auto-merge host is not reachable from the user's browser, otherwise the embedded image renders as broken in GitLab (!14221)
  • SVG status badge in MR description: A dynamic SVG badge with branded header and Neckar IT footer logo is embedded at the top of the Auto-Merge status section (!13915, !12944)
  • Quick-Run for webhook events: When GitLab sends a webhook for a merge request, Auto-Merge refreshes that MR's status label within a couple of seconds instead of waiting up to 15 s for the next full-run tick. The full run still follows debounced (!13707)
  • Resource-aware pipeline starting: Auto-Merge now starts pipelines for MRs that need one when CI slots become free, instead of only cancelling. Unapproved and draft MRs participate in the global scheduling with their own priorities and no longer get stuck without a pipeline (!13208)
  • WaitingForCiLastFailed label: Specialized status label Waiting for CI (Last Failed) shown when the previous pipeline failed, signalling that a re-run may fail again (!12648)
  • Cleanup of merged MR labels: A new run phase scans the most recently merged MRs and removes stale auto-managed labels left behind by manual merges via the GitLab UI (!12641)
  • Retry limit: Failed jobs are no longer retried indefinitely. The default limit is 3; once reached, Auto-Merge posts a note instead of triggering another retry (!12459)
  • Retry counter on MR: Pipeline retries triggered by Auto-Merge are now visible in the MR description and as audit notes per retried job (!12438)
  • GitLab UI integration snippet: A pasteable JavaScript snippet (auto-merge-gitlab-integration/) injects an Auto-Merge status badge directly into GitLab MR pages with queue position, color-coded status and auto-refresh (!12416)
  • LowPriority user label: New Low Priority label processes labelled MRs only when no regular MRs are in the queue and deprioritizes their pipelines under resource scarcity (!12389)
Changed
  • OpenTelemetry service-port discovery: gitlab-auto-merge-service declares its HTTP port in the Jib container image so OTel's docker_observer finds and scrapes it without manual port configuration (!14127)
  • Run-detail response trichotomy: The useQueryRunDetail hook distinguishes good / bad / unknown response shapes so the run-detail UI can render each state explicitly (!13999)
  • Queue includes MRs with running CI: Approved MRs whose pipeline is still running receive a queue position label, so the visible merge order reflects their place even before the pipeline completes (!13265)
  • Scoped status labels with 🔀 prefix: Auto-Merge labels migrated to proper GitLab scoped labels (🔀 Status::… and 🔀 Important) with the merge-symbol prefix. Existing emoji-suffixed and Merge::-prefixed labels are migrated automatically on the next run (!13166, !13161)
  • Git hash display: Pipeline and commit hashes shown in the dashboard and notes use a consistent fixed-length abbreviation; full SHAs are kept in links (!13164)
  • Branding refresh: Bot avatar, badge logo and label prefix changed from the bus

Changelog truncated to fit Docker Hub's 25000-byte description limit. See the full CHANGELOG in the repository.

Tag summary

Content type

Image

Digest

sha256:d5f01a46e

Size

332.6 MB

Last updated

10 days ago

docker pull neckarit/gitlab-auto-merge