There is no ability to apply merge request rule made through API

Summary

GitLab UI doesn't reflect changes made through GitLAb API for merge request approval rules. Looks like there is no ability to set desired merge request approval rule for MR if all of them were removed manually through UI and system one has been applied automatically

Main Idea is to change system rule for MR to custom one using API

Steps to reproduce

1. Have approval rule set for merge reuqest from project scope

UI: MR_initial

API:

API approval_rules output
azerg@tanos:/tmp$ curl -s -X GET -H "Content-Type: application/json" -H "PRIVATE-TOKEN: xxxxxx" https://mygitlab.com/api/v4/projects/17052/merge_requests/21/approval_rules | jq
[
  {
    "id": 104279,
    "name": "Default",
    "rule_type": "regular",
    "eligible_approvers": [
      {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      }
    ],
    "approvals_required": 1,
    "users": [
      {
        "id": 4063,
        "name": "Deny Test",
        "username": "TEST10435",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/3d48793cf012f8f5c1a5b89ffeaa96e5?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST10435"
      },
      {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      }
    ],
    "groups": [],
    "contains_hidden_groups": false,
    "source_rule": {
      "approvals_required": 1
    }
  }
]
azerg@tanos:/tmp$

API approvals output

{
"id": 355179,
"iid": 21,
"project_id": 17052,
"title": "TEST MR",
"description": "",
"state": "opened",
"created_at": "2020-02-23T14:10:09.470Z",
"updated_at": "2020-02-23T14:11:39.641Z",
"merge_status": "can_be_merged",
"approved": false,
"approvals_required": 1,
"approvals_left": 1,
"require_password_to_approve": null,
"approved_by": [],
"suggested_approvers": [
{
"id": 4866,
"name": "Ivan Test",
"username": "TEST13013",
"state": "active",
"avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
"web_url": "https://mygitlab.com/TEST13013"
}
],
"approvers": [
{
"user": {
"id": 4063,
"name": "Deny Test",
"username": "TEST10435",
"state": "active",
"avatar_url": "https://mygitlab.com/avatar/3d48793cf012f8f5c1a5b89ffeaa96e5?s=80&d=identicon",
"web_url": "https://mygitlab.com/TEST10435"
}
},
{
"user": {
"id": 4866,
"name": "Ivan Test",
"username": "TEST13013",
"state": "active",
"avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
"web_url": "https://mygitlab.com/TEST13013"
}
}
],
"approver_groups": [],
"user_has_approved": false,
"user_can_approve": false,
"approval_rules_left": [
{
"id": 104279,
"name": "Default",
"rule_type": "regular"
}
],
"has_approval_rules": true,
"merge_request_approvers_available": true,
"multiple_approval_rules_available": false
}

2. Remove this approval rule manually through UI (system rule has been set automatically):

UI: After_removed_appr

API:

API approval_rules ouptput

[
  {
    "id": 104280,
    "name": "All Members",
    "rule_type": "any_approver",
    "eligible_approvers": [],
    "approvals_required": 0,
    "users": [],
    "groups": [],
    "contains_hidden_groups": false,
    "source_rule": null
  }
]

API approvals output

{
  "id": 355179,
  "iid": 21,
  "project_id": 17052,
  "title": "TEST MR",
  "description": "",
  "state": "opened",
  "created_at": "2020-02-23T14:10:09.470Z",
  "updated_at": "2020-02-23T14:31:36.366Z",
  "merge_status": "can_be_merged",
  "approved": true,
  "approvals_required": 0,
  "approvals_left": 0,
  "require_password_to_approve": null,
  "approved_by": [],
  "suggested_approvers": [],
  "approvers": [],
  "approver_groups": [],
  "user_has_approved": false,
  "user_can_approve": false,
  "approval_rules_left": [],
  "has_approval_rules": true,
  "merge_request_approvers_available": true,
  "multiple_approval_rules_available": false
}

3. Try to set approval rule through API

API:

API create approval_rules output

curl  -s -X POST -H "Content-Type: application/json" -H "PRIVATE-TOKEN: xxxxxxxxxxxxxxxxxx" --data '{"name":"Test_Rule_1","approvals_required":"1", "user_ids": [4866,2314],"group_ids":[]}' https://mygitlab.com/api/v4/projects/17052/merge_requests/21/approval_rules | jq
{
  "id": 104281,
  "name": "Test_Rule_1",
  "rule_type": "regular",
  "eligible_approvers": [
    {
      "id": 4866,
      "name": "Ivan Test",
      "username": "TEST13013",
      "state": "active",
      "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
      "web_url": "https://mygitlab.com/TEST13013"
    },
    {
      "id": 2314,
      "name": "Alex Test",
      "username": "TEST04127",
      "state": "active",
      "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
      "web_url": "https://mygitlab.com/TEST04127"
    }
  ],
  "approvals_required": 1,
  "users": [
    {
      "id": 2314,
      "name": "Alex Test",
      "username": "TEST04127",
      "state": "active",
      "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
      "web_url": "https://mygitlab.com/TEST04127"
    },
    {
      "id": 4866,
      "name": "Ivan Test",
      "username": "TEST13013",
      "state": "active",
      "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
      "web_url": "https://mygitlab.com/TEST13013"
    }
  ],
  "groups": [],
  "contains_hidden_groups": false,
  "source_rule": null
}

Rule has been successfully created

API approval_rules output

[
  {
    "id": 104281,
    "name": "Test_Rule_1",
    "rule_type": "regular",
    "eligible_approvers": [
      {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      },
      {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST04127"
      }
    ],
    "approvals_required": 1,
    "users": [
      {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST04127"
      },
      {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      }
    ],
    "groups": [],
    "contains_hidden_groups": false,
    "source_rule": null
  },
  {
    "id": 104280,
    "name": "All Members",
    "rule_type": "any_approver",
    "eligible_approvers": [],
    "approvals_required": 0,
    "users": [],
    "groups": [],
    "contains_hidden_groups": false,
    "source_rule": null
  }
]

API approvals output

{
  "id": 355179,
  "iid": 21,
  "project_id": 17052,
  "title": "DEVOPS-389 TEST MR",
  "description": "",
  "state": "opened",
  "created_at": "2020-02-23T14:10:09.470Z",
  "updated_at": "2020-02-23T14:31:36.366Z",
  "merge_status": "can_be_merged",
  "approved": true,
  "approvals_required": 0,
  "approvals_left": 0,
  "require_password_to_approve": null,
  "approved_by": [],
  "suggested_approvers": [],
  "approvers": [],
  "approver_groups": [],
  "user_has_approved": false,
  "user_can_approve": false,
  "approval_rules_left": [],
  "has_approval_rules": true,
  "merge_request_approvers_available": true,
  "multiple_approval_rules_available": false
}

/approvals item is still showing nothing within approval_rules_left field

UI:

After_removed_appr

Gitlab UI don't reflect changes still and shows system rule

4. Try to set approvers through API for merge request and make Gitlab UI shows desired rule

API set approvers output


curl -X PUT -H "Content-Type: application/json" -H "PRIVATE-TOKEN: xxxxxxxxxxxxxxxx --data '{"approver_ids": [4866,2314],"approver_group_ids":[]}' https://mygitlab.com/api/v4/projects/17052/merge_requests/21/approvers | jq
{
  "id": 355179,
  "iid": 21,
  "project_id": 17052,
  "title": "TEST MR",
  "description": "",
  "state": "opened",
  "created_at": "2020-02-23T14:10:09.470Z",
  "updated_at": "2020-02-23T14:31:36.366Z",
  "merge_status": "can_be_merged",
  "approved": true,
  "approvals_required": 0,
  "approvals_left": 0,
  "require_password_to_approve": null,
  "approved_by": [],
  "suggested_approvers": [
    {
      "id": 4866,
      "name": "Ivan Test",
      "username": "TEST13013",
      "state": "active",
      "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
      "web_url": "https://mygitlab.com/TEST13013"
    },
    {
      "id": 2314,
      "name": "Alex Test",
      "username": "TEST04127",
      "state": "active",
      "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
      "web_url": "https://mygitlab.com/TEST04127"
    }
  ],
  "approvers": [
    {
      "user": {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST04127"
      }
    },
    {
      "user": {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      }
    }
  ],
  "approver_groups": [],
  "user_has_approved": false,
  "user_can_approve": false,
  "approval_rules_left": [],
  "has_approval_rules": true,
  "merge_request_approvers_available": true,
  "multiple_approval_rules_available": false
}

Check \approvals after previous step

API approvals output



{
  "id": 355179,
  "iid": 21,
  "project_id": 17052,
  "title": "TEST MR",
  "description": "",
  "state": "opened",
  "created_at": "2020-02-23T14:10:09.470Z",
  "updated_at": "2020-02-23T14:31:36.366Z",
  "merge_status": "can_be_merged",
  "approved": true,
  "approvals_required": 0,
  "approvals_left": 0,
  "require_password_to_approve": null,
  "approved_by": [],
  "suggested_approvers": [
    {
      "id": 4866,
      "name": "Ivan Test",
      "username": "TEST13013",
      "state": "active",
      "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
      "web_url": "https://mygitlab.com/TEST13013"
    },
    {
      "id": 2314,
      "name": "Alex Test",
      "username": "TEST04127",
      "state": "active",
      "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
      "web_url": "https://mygitlab.com/TEST04127"
    }
  ],
  "approvers": [
    {
      "user": {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST04127"
      }
    },
    {
      "user": {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      }
    }
  ],
  "approver_groups": [],
  "user_has_approved": false,
  "user_can_approve": false,
  "approval_rules_left": [],
  "has_approval_rules": true,
  "merge_request_approvers_available": true,
  "multiple_approval_rules_available": false
}

approval_rules_left is still empty

Check approval_state for MR:

API approval_state output

curl  -s -X GET -H "Content-Type: application/json" -H "PRIVATE-TOKEN: xxxxxxxx" https://mygitlab.com/api/v4/projects/17052/merge_requests/21/approval_state | jq
{
  "approval_rules_overwritten": true,
  "rules": [
    {
      "id": 104280,
      "name": "All Members",
      "rule_type": "any_approver",
      "eligible_approvers": [
        {
          "id": 4866,
          "name": "Ivan Test",
          "username": "TEST13013",
          "state": "active",
          "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
          "web_url": "https://mygitlab.com/TEST13013"
        },
        {
          "id": 2314,
          "name": "Alex Test",
          "username": "TEST04127",
          "state": "active",
          "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
          "web_url": "https://mygitlab.com/TEST04127"
        }
      ],
      "approvals_required": 0,
      "users": [
        {
          "id": 2314,
          "name": "Alex Test",
          "username": "TEST04127",
          "state": "active",
          "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
          "web_url": "https://mygitlab.com/TEST04127"
        },
        {
          "id": 4866,
          "name": "Ivan Test",
          "username": "TEST13013",
          "state": "active",
          "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
          "web_url": "https://mygitlab.com/BH13013"
        }
      ],
      "groups": [],
      "contains_hidden_groups": false,
      "source_rule": {
        "approvals_required": 1
      },
      "code_owner": false,
      "approved_by": [],
      "approved": true
    }
  ]
}

I see 2 approval rules and system one has been overwritten somehow (thought that system one can't be overwritten.)

Check \approval_rules for that MR

API approval_rules output

[
  {
    "id": 104281,
    "name": "Test_Rule_1",
    "rule_type": "regular",
    "eligible_approvers": [
      {
        "id": 4866,
        "name": "Ivan Test",
        "username": "Test13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      },
      {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST04127"
      }
    ],
    "approvals_required": 1,
    "users": [
      {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST04127"
      },
      {
        "id": 4866,
        "name": "Iva Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      }
    ],
    "groups": [],
    "contains_hidden_groups": false,
    "source_rule": null
  },
  {
    "id": 104280,
    "name": "All Members",
    "rule_type": "any_approver",
    "eligible_approvers": [
      {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      },
      {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST04127"
      }
    ],
    "approvals_required": 0,
    "users": [
      {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST04127"
      },
      {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.fds.com/TEST13013"
      }
    ],
    "groups": [],
    "contains_hidden_groups": false,
    "source_rule": {
      "approvals_required": 1
    }
  }
]

2 approval rules is here but there is no ability to set desired rule for MR (custom one created through API Test_Rule_1)

UI:

UI_after_set_approvers_1

Only one thing is that Gitlab UI started showing users which were set trough API PUT call to \approvers for MR

However If you click on View eligible approvers option you'll get the same as previously:

UI_after_set_approvers_2

What is the current bug behavior?

Gitlab UI don't show changes for merge request approval rules made though API There is no ability to set desired merge request approval rule through API

What is the expected correct behavior?

Custom merge request approval rule should replace system rule after creation or there should be an ability to set it instead of system one through API.

Using UI everything works as expected:

  • system rule (any approver) is deleted
  • new rule is set

UI_manually_1png UI_manually_added_2

API should show:

API approval_rules expected output

[
  {
    "id": 104282,
    "name": "Test_Rule_1",
    "rule_type": "regular",
    "eligible_approvers": [
      {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      },
      {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST04127"
      }
    ],
    "approvals_required": 1,
    "users": [
      {
        "id": 2314,
        "name": "Alex Test",
        "username": "TEST04127",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/1247ef7f00348c58766a76f91ac30c83?s=80&d=identicon",
        "web_url": "https://mygitlab.com/YH04127"
      },
      {
        "id": 4866,
        "name": "Ivan Test",
        "username": "TEST13013",
        "state": "active",
        "avatar_url": "https://mygitlab.com/avatar/0d0498eef6c4d936591c1bee00c3222c?s=80&d=identicon",
        "web_url": "https://mygitlab.com/TEST13013"
      }
    ],
    "groups": [],
    "contains_hidden_groups": false,
    "source_rule": null
  }
]

So I expect the same behavior using API

Relevant logs and/or screenshots

Provided in the Steps to reproduce step.

Output of checks

Occurred on Gitlab 12.6.4-ee self managed (Starter)

Results of GitLab environment info

gitlab-rake gitlab:env:info


System information
System:		CentOS 7.3.1611
Proxy:		no
Current User:	git
Using RVM:	no
Ruby Version:	2.6.3p62
Gem Version:	2.7.9
Bundler Version:1.17.3
Rake Version:	12.3.3
Redis Version:	3.2.12
Git Version:	2.24.1
Sidekiq Version:5.2.7
Go Version:	unknown

GitLab information
Version:	12.6.4-ee
Revision:	cc6b787e7b0
Directory:	/opt/gitlab/embedded/service/gitlab-rails
DB Adapter:	PostgreSQL
DB Version:	10.9
URL:		https://mygitlab
HTTP Clone URL:	https://mygitlab/some-group/some-project.git
SSH Clone URL:	git@mygitlab:some-group/some-project.git
Elasticsearch:	yes
Geo:		no
Using LDAP:	yes
Using Omniauth:	yes
Omniauth Providers: 

GitLab Shell
Version:	10.3.0
Repository storage paths:
- default: 	/var/opt/gitlab/git-data/repositories
GitLab Shell path:		/opt/gitlab/embedded/service/gitlab-shell
Git:		/opt/gitlab/embedded/bin/git

Results of GitLab application Check

gitlab_sanityze.log

Edited Feb 24, 2020 by Tony Voz
Assignee Loading
Time tracking Loading