Commit 1815ff4c authored by James Fargher's avatar James Fargher

Merge branch 'list-group-push-rules' into 'master'

API to retrieve group push rules

See merge request gitlab-org/gitlab!39642
parents 23d49064 41064baf
...@@ -1164,3 +1164,46 @@ DELETE /groups/:id/share/:group_id ...@@ -1164,3 +1164,46 @@ DELETE /groups/:id/share/:group_id
| --------- | -------------- | -------- | ----------- | | --------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `group_id` | integer | yes | The ID of the group to share with | | `group_id` | integer | yes | The ID of the group to share with |
## Push Rules **(STARTER)**
### Get group push rules
Get the [push rules](../user/group/index.md#group-push-rules-starter) of a group.
```plaintext
GET /groups/:id/push_rule
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID of the group or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
```json
{
"id": 2,
"created_at": "2020-08-17T19:09:19.580Z",
"commit_message_regex": "[a-zA-Z]",
"commit_message_negative_regex": "[x+]",
"branch_name_regex": "[a-z]",
"deny_delete_tag": true,
"member_check": true,
"prevent_secrets": true,
"author_email_regex": "^[A-Za-z0-9.]+@gitlab.com$",
"file_name_regex": "(exe)$",
"max_file_size": 100
}
```
Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) will also see
the `commit_committer_check` and `reject_unsigned_commits` parameters:
```json
{
"id": 2,
"created_at": "2020-08-17T19:09:19.580Z",
"commit_committer_check": true,
"reject_unsigned_commits": false,
...
}
```
...@@ -2124,7 +2124,7 @@ POST /projects/:id/housekeeping ...@@ -2124,7 +2124,7 @@ POST /projects/:id/housekeeping
### Get project push rules ### Get project push rules
Get the push rules of a project. Get the [push rules](../push_rules/push_rules.md#enabling-push-rules) of a project.
```plaintext ```plaintext
GET /projects/:id/push_rule GET /projects/:id/push_rule
......
---
title: API to retrieve group push rules
merge_request: 39642
author:
type: added
# frozen_string_literal: true
module API
class GroupPushRule < Grape::API::Instance
before { authenticate! }
before { authorize_admin_group }
before { check_feature_availability! }
params do
requires :id, type: String, desc: 'The ID of a group'
end
resource :groups do
helpers do
def check_feature_availability!
not_found! unless user_group.feature_available?(:push_rules)
end
end
desc 'Get group push rule' do
detail 'This feature was introduced in GitLab 13.4.'
success EE::API::Entities::GroupPushRule
end
get ":id/push_rule" do
push_rule = user_group.push_rule
not_found! unless push_rule
present push_rule, with: EE::API::Entities::GroupPushRule, user: current_user
end
end
end
end
...@@ -33,6 +33,7 @@ module EE ...@@ -33,6 +33,7 @@ module EE
mount ::API::PersonalAccessTokens mount ::API::PersonalAccessTokens
mount ::API::ProjectMirror mount ::API::ProjectMirror
mount ::API::ProjectPushRule mount ::API::ProjectPushRule
mount ::API::GroupPushRule
mount ::API::MergeTrains mount ::API::MergeTrains
mount ::API::GroupHooks mount ::API::GroupHooks
mount ::API::Scim mount ::API::Scim
......
# frozen_string_literal: true
module EE
module API
module Entities
class GroupPushRule < Grape::Entity
expose :id, :created_at
expose :commit_message_regex, :commit_message_negative_regex, :branch_name_regex, :deny_delete_tag
expose :member_check, :prevent_secrets, :author_email_regex
expose :file_name_regex, :max_file_size
expose :commit_committer_check, if: lambda { |push_rule| push_rule.available?(:commit_committer_check) }
expose :reject_unsigned_commits, if: lambda { |push_rule| push_rule.available?(:reject_unsigned_commits) }
end
end
end
end
{
"type": "object",
"properties" : {
"author_email_regex": { "type": ["string", null] },
"branch_name_regex": { "type": ["string", null] },
"commit_committer_check": { "type": "boolean" },
"commit_message_negative_regex": { "type": ["string", null] },
"commit_message_regex": { "type": ["string", null] },
"created_at": { "type": "date" },
"deny_delete_tag": { "type": ["boolean", null] },
"file_name_regex": { "type": ["string", null] },
"id": { "type": "integer" },
"max_file_size": { "type": "integer" },
"member_check": { "type": "boolean" },
"prevent_secrets": { "type": "boolean" },
"reject_unsigned_commits": { "type": "boolean" }
},
"required": [
"author_email_regex",
"branch_name_regex",
"commit_message_negative_regex",
"commit_message_regex",
"created_at",
"deny_delete_tag",
"file_name_regex",
"id",
"max_file_size",
"member_check",
"prevent_secrets"
],
"additionalProperties": false
}
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::GroupPushRule, 'GroupPushRule', api: true do
include ApiHelpers
include AccessMatchersForRequest
let_it_be(:admin) { create(:user, :admin) }
let_it_be(:user) { create(:user) }
shared_examples 'not found when feature is unavailable' do
before do
stub_licensed_features(push_rules: false)
end
it do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
shared_examples 'allow access to api based on role' do
it { expect { subject }.to be_allowed_for(:admin) }
it { expect { subject }.to be_allowed_for(:owner).of(group) }
it { expect { subject }.to be_denied_for(:developer).of(group) }
it { expect { subject }.to be_denied_for(:reporter).of(group) }
it { expect { subject }.to be_denied_for(:guest).of(group) }
it { expect { subject }.to be_denied_for(:anonymous) }
end
describe 'GET /groups/:id/push_rule' do
let_it_be(:group) { create(:group) }
let_it_be(:attributes) do
{
author_email_regex: '^[A-Za-z0-9.]+@gitlab.com$',
commit_committer_check: true,
commit_message_negative_regex: '[x+]',
commit_message_regex: '[a-zA-Z]',
deny_delete_tag: false,
max_file_size: 100,
member_check: false,
prevent_secrets: true,
reject_unsigned_commits: true
}
end
before_all do
push_rule = create(:push_rule, **attributes)
group.update!(push_rule: push_rule)
end
context 'when unlicensed' do
subject { get api("/groups/#{group.id}/push_rule", admin) }
it_behaves_like 'not found when feature is unavailable'
end
context 'authorized user' do
subject { get api("/groups/#{group.id}/push_rule", admin) }
context 'when licensed' do
before do
stub_licensed_features(push_rules: true,
commit_committer_check: true,
reject_unsigned_commits: true)
end
it 'returns attributes as expected' do
subject
expect(json_response).to eq(
{
"author_email_regex" => attributes[:author_email_regex],
"branch_name_regex" => nil,
"commit_committer_check" => true,
"commit_message_negative_regex" => attributes[:commit_message_negative_regex],
"commit_message_regex" => attributes[:commit_message_regex],
"created_at" => group.push_rule.created_at.iso8601(3),
"deny_delete_tag" => false,
"file_name_regex" => nil,
"id" => group.push_rule.id,
"max_file_size" => 100,
"member_check" => false,
"prevent_secrets" => true,
"reject_unsigned_commits" => true
}
)
end
it 'matches response schema' do
subject
expect(response).to match_response_schema('entities/group_push_rules')
end
end
context 'when reject_unsigned_commits is unavailable' do
before do
stub_licensed_features(reject_unsigned_commits: false)
end
it do
subject
expect(json_response).not_to have_key('reject_unsigned_commits')
end
end
context 'when commit_committer_check is unavailable' do
before do
stub_licensed_features(commit_committer_check: false)
end
it do
subject
expect(json_response).not_to have_key('commit_committer_check')
end
end
end
context 'permissions' do
subject(:get_push_rules) { get api("/groups/#{group.id}/push_rule", user) }
it_behaves_like 'allow access to api based on role'
end
context 'when push rule does not exist' do
let_it_be(:no_push_rule_group) { create(:group) }
it 'returns not found' do
get api("/groups/#{no_push_rule_group.id}/push_rule", admin)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment