0% прочитано

Jira + GitLab Merge Requests: How I Automated Issue Statuses Without Breaking the Workflow

In ICanUp, I wanted Jira issues to move automatically when a GitLab Merge Request was created and merged, but I did not want automation to own the entire issue lifecycle. I explain why I kept only two automatic transitions, how target branch and current status guards protect the workflow, and why repeated webhook events must remain idempotent.

11 вересня 2026 р. 9 хв читанняCI/CD

When I connected GitLab Merge Requests with Jira in ICanUp, the first idea looked simple: when a Merge Request is created, move the issue; when it is merged, move it again.

It quickly became clear that this kind of automation can cause problems if it reacts to every event without enough context.

I did not need automation to own the entire issue lifecycle. I only needed it at two points that GitLab could verify reliably.

In my workflow, GitLab automatically confirms only two things: a Merge Request was created and a Merge Request was successfully merged into development. Starting work, testing, and later decisions remain manual.
Jira issue status automation driven by GitLab Merge Request created and merged events
GitLab controls only two verified Jira issue transitions while the rest of the workflow remains manual.

I Did Not Want to Automate the Entire Issue Lifecycle

The simplest implementation would be to let GitLab move an issue from the beginning of work all the way to completion.

That was the wrong automation boundary for me.

GitLab knows that a Merge Request was created or merged. It does not know whether I actually started working, whether testing passed, or whether the issue is ready for production.

Automation should make decisions only where it has a reliable technical signal.

I Kept Only Two Automatic Transitions

Event

Current status

New status

Merge Request created for development

In Progress

Ready for Review

Merge Request merged into development

Ready for Review

Ready to Test

Everything else remains manual.

I move the issue to In Progress when work actually begins. After Ready to Test, automation stops controlling the issue as well.

Automation boundary
Manual:To Do  |  vIn Progress Automatic:In Progress  |  | Merge Request created  vReady for Review  |  | Merge Request merged  vReady to Test Manual after this point:TestingReady to DeployDone

The First Guard Is the Target Branch

A Merge Request being created is not enough by itself.

The same repository can have Merge Requests targeting development, main, or another branch.

An automatic transition should happen only when the target branch matches the workflow stage being automated.

Target branch guard
Event:Merge Request created Required:target branch = development If target branch = main:skip

This is especially important for production Merge Requests. A merge into main should not move a Jira issue again after it has already passed review and testing.

The Second Guard Is the Current Status

Even the correct GitLab event does not automatically mean that Jira should transition the issue.

A Merge Request event can be delivered again, or the issue may already have moved to another stage.

Before a transition, I check both the event and the current Jira status.

Status guard
MR created: if current status = In Progress    -> Ready for Reviewelse    -> skip  MR merged: if current status = Ready for Review    -> Ready to Testelse    -> skip
The current-status guard makes automation much safer: an event can be valid while the transition itself is no longer relevant.

Closed and Merged Are Not the Same Event

Another important boundary is that a closed Merge Request is not the same as a successfully merged Merge Request.

A Merge Request can be closed because the plan changed, the branch was wrong, or the work is no longer needed.

In that case, Jira should not move the issue to Ready to Test.

Merged and closed have different semantics
Merge Request merged-> transition may run Merge Request closed without merge-> no status change

The Jira Issue Key Needs a Reliable Source

The automation needs an issue key before a GitLab event can be connected to Jira.

In my workflow, the source branch is the strongest location. The Merge Request title is another source, while the commit message is only a fallback.

Where to resolve the issue key
Priority: 1. source branch2. Merge Request title3. commit message as fallback  Example branch: feature/PROJECT-123-fix-pagination

I do not bind the automation to one branch prefix.

feature/, fix/, chore/, or another convention can change. The issue key is the important part.

A Repeated Webhook Must Not Repeat the Transition

A webhook should not be treated as something that is guaranteed to arrive exactly once.

Repeated delivery, a repeated automation run, or another technical retry should not push the issue through another status.

The same event should leave the system in the same correct state.

Idempotent behavior
First event: Ready for Review+ MR merged= Ready to Test  Repeated event: Ready to Test+ same MR merged= skip

The current-status guard provides a simple protection here. After the first successful transition, the expected source status no longer matches, so the repeated event does nothing.

Two Small Automation Rules Were Better Than One Large Rule

At first, one large rule that understands the entire issue workflow can look convenient.

It quickly accumulates conditions for opened, merged, closed, target branch, current status, and multiple exceptions.

I preferred two rules with one responsibility each.

Rule

Trigger

Single action

Merge Request created

MR created for development

In Progress -> Ready for Review

Merge Request merged

MR merged into development

Ready for Review -> Ready to Test

Rule 1 - Merge Request Created

First rule logic
Trigger:GitLab Merge Request created Conditions:- target branch is development- Jira key can be resolved- current Jira status is In Progress- Merge Request is not closed- Merge Request is not already merged Action:Ready for Review

Rule 2 - Merge Request Merged

Second rule logic
Trigger:GitLab Merge Request merged Conditions:- target branch is development- Jira key can be resolved- current Jira status is Ready for Review Action:Ready to Test

Why a Production Merge Does Not Move the Issue

After testing, I may create another Merge Request targeting main.

That is a different delivery stage.

If automation reacted to every merge, a production Merge Request could unexpectedly change the Jira status again.

The target branch is part of the workflow rule, not just a technical webhook detail.

After Ready to Test, a Person Decides Again

Automation stops exactly where GitLab no longer knows enough.

A merge into development confirms that the code entered the shared branch. It does not confirm that testing passed or that the issue is ready for production.

The following transitions therefore remain manual.

After the automatic part
Ready to Test  |  | manual  vTesting  |  | manual decision  +--> Ready to Deploy  |  +--> Waiting

The Audit Log Became Part of Verification

For automation like this, seeing the final Jira status is not enough.

I also need to understand why a rule ran or why it skipped an event.

The Audit Log therefore became part of troubleshooting rather than a secondary screen.

  • Which GitLab event triggered the rule.
  • Which Jira issue key was resolved.
  • Which target branch the Merge Request used.
  • Which Jira status existed before evaluation.
  • Whether a transition was executed.
  • Why the event was skipped when no transition occurred.

The Scenarios I Verify

Scenario

Expected result

MR created for development, status In Progress

Ready for Review

MR merged into development, status Ready for Review

Ready to Test

MR closed without merge

No change

MR created or merged for main

No change

Repeated merged event

No repeated transition

Unexpected current status

No forced change

This automation does not live separately from the broader CI/CD process in ICanUp.

I previously described how my real Laravel CI/CD pipeline is structured.

The difference here is that the pipeline verifies and delivers code, while Jira automation only synchronizes workflow stages that GitLab has already confirmed.

The Branch Name Became Part of the Contract

Once an issue key is resolved from the source branch, the branch name is no longer only a convenient label.

It becomes part of the integration contract between Git and Jira.

That is why I keep the issue key in the branch name even though Git itself allows almost any naming convention.

I saw the value of careful Git history management in another real case as well, when I needed to move an already pushed commit to the correct branch without losing history.

What Could Go Wrong

  • Reacting to a Merge Request for main as if it targeted development.
  • Treating a closed Merge Request as successfully merged.
  • Skipping the current Jira status check.
  • Repeating a transition after a duplicated webhook event.
  • Looking for the issue key only in a commit message.
  • Automatically moving To Do to In Progress without actual work starting.
  • Automatically moving issues after Ready to Test without a testing result.
  • Hiding every condition inside one large automation rule.
The most dangerous automation is not always the one that fails. It can be the one that successfully performs the wrong transition and creates a false picture of the issue state.

Automation Should Be Conservative

This case led me to a simple rule: if one required condition cannot be confirmed, doing nothing is safer.

No Jira key - skip. Wrong target branch - skip. Unexpected status - skip. Merge Request only closed - skip.

For automatic transitions, skipping an uncertain event is safer than forcing an issue into another state.

What I Kept for Next Time

  • Automate only transitions that an external system can verify unambiguously.
  • Check the target branch before every transition.
  • Check the current Jira status.
  • Treat merged and closed Merge Requests differently.
  • Design rules so repeated events remain safe.
  • Use the source branch as the primary issue-key source.
  • Prefer small automation rules with one responsibility.
  • Keep testing and production decisions under manual control.
  • Check the Audit Log after automation changes.

Good automation does not try to make every decision for me. It removes only the manual steps for which it already has a reliable signal.

Conclusion

The Jira and GitLab integration became more stable when I stopped treating it as a way to automate the entire issue lifecycle.

In ICanUp, GitLab owns only two transitions it can confirm without assumptions: a Merge Request was created for development, and a Merge Request was successfully merged into development.

The target branch, current status, event type, and repeated webhook delivery are checked before Jira changes. After Ready to Test, control returns to the manual workflow.

The automation does not own the workflow. It only synchronizes two facts that already happened in GitLab.