Commit 979ed6c4 authored by Kerri Miller's avatar Kerri Miller

Merge branch '885-api-for-default-description-template-for-issues-and-merge-requests' into 'master'

Allow updating default description templates for projects via API

See merge request gitlab-org/gitlab!55718
parents 0cd13aad 65bfdbfa
......@@ -1005,6 +1005,20 @@ If the project is a fork, and you provide a valid token to authenticate, the
}
```
Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/)
can also see the `issues_template` and `merge_requests_template` parameters:
[introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55718)
in GitLab 13.10.
```json
{
"id": 3,
"issues_template": null,
"merge_requests_template": null,
...
}
```
## Get project users
Get the users list of a project.
......@@ -1303,6 +1317,8 @@ PUT /projects/:id
| `visibility` | string | **{dotted-circle}** No | See [project visibility level](#project-visibility-level). |
| `wiki_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
| `wiki_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable wiki for this project. Use `wiki_access_level` instead. |
| `issues_template` **(PREMIUM)** | string | **{dotted-circle}** No | Default description for Issues. Description is parsed with GitLab Flavored Markdown. |
| `merge_requests_template` **(PREMIUM)** | string | **{dotted-circle}** No | Default description for Merge Requests. Description is parsed with GitLab Flavored Markdown. |
## Fork project
......
---
title: Add support for updating default description templates for issues and merge
requests via API
merge_request: 55718
author:
type: added
......@@ -37,6 +37,8 @@ module EE
expose :compliance_frameworks do |project, _|
[project.compliance_framework_setting&.compliance_management_framework&.name].compact
end
expose :issues_template, if: ->(project, _) { project.feature_available?(:issuable_default_templates) }
expose :merge_requests_template, if: ->(project, _) { project.feature_available?(:issuable_default_templates) }
end
end
end
......
......@@ -33,6 +33,8 @@ module EE
optional :mirror_overwrites_diverged_branches, type: Grape::API::Boolean, desc: 'Pull mirror overwrites diverged branches'
optional :import_url, type: String, desc: 'URL from which the project is imported'
optional :fallback_approvals_required, type: Integer, desc: 'Overall approvals required when no rule is present'
optional :issues_template, type: String, desc: 'Default description for Issues. Description is parsed with GitLab Flavored Markdown.'
optional :merge_requests_template, type: String, desc: 'Default description for Merge Requests. Description is parsed with GitLab Flavored Markdown.'
end
end
......@@ -48,8 +50,10 @@ module EE
super.concat [
:approvals_before_merge,
:external_authorization_classification_label,
:fallback_approvals_required,
:import_url,
:fallback_approvals_required
:issues_template,
:merge_requests_template
]
end
end
......
......@@ -82,6 +82,7 @@ module EE
super
verify_mirror_attrs!(project, attrs)
verify_issuable_default_templates_attrs!(project, attrs)
end
def verify_mirror_attrs!(project, attrs)
......@@ -92,6 +93,13 @@ module EE
end
end
def verify_issuable_default_templates_attrs!(project, attrs)
unless project.feature_available?(:issuable_default_templates)
attrs.delete(:issues_template)
attrs.delete(:merge_requests_template)
end
end
def check_audit_events_available!(project)
forbidden! unless project.feature_available?(:audit_events)
end
......
......@@ -93,6 +93,8 @@ RSpec.describe API::Projects do
end
describe 'GET /projects/:id' do
subject { get api("/projects/#{project.id}", user) }
context 'with external authorization' do
let(:project) do
create(:project,
......@@ -209,8 +211,6 @@ RSpec.describe API::Projects do
end
context 'project soft-deletion' do
subject { get api("/projects/#{project.id}", user) }
let(:project) do
create(:project, :public, archived: true, marked_for_deletion_at: 1.day.ago, deleting_user: user)
end
......@@ -253,6 +253,34 @@ RSpec.describe API::Projects do
end
end
end
context 'issuable default templates feature is available' do
before do
stub_licensed_features(issuable_default_templates: true)
end
it 'returns issuable default templates' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to have_key 'issues_template'
expect(json_response).to have_key 'merge_requests_template'
end
end
context 'issuable default templates feature not available' do
before do
stub_licensed_features(issuable_default_templates: false)
end
it 'does not return issuable default templates' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).not_to have_key 'issues_template'
expect(json_response).not_to have_key 'merge_requests_template'
end
end
end
# Assumes the following variables are defined:
......@@ -780,6 +808,65 @@ RSpec.describe API::Projects do
describe 'PUT /projects/:id' do
let(:project) { create(:project, namespace: user.namespace) }
let(:project_params) { {} }
subject { put api("/projects/#{project.id}", user), params: project_params }
context 'issuable default templates feature is available' do
before do
stub_licensed_features(issuable_default_templates: true)
end
context 'when updating issues_template' do
let(:project_params) { { issues_template: '## New Issue Template' } }
it 'updates the content' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['issues_template']).to eq(project_params[:issues_template])
end
end
context 'when updating merge_requests_template' do
let(:project_params) { { merge_requests_template: '## New Merge Request Template' } }
it 'updates the content' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['merge_requests_template']).to eq(project_params[:merge_requests_template])
end
end
end
context 'issuable default templates feature not available' do
before do
stub_licensed_features(issuable_default_templates: false)
end
context 'when updating issues_template' do
let(:project_params) { { issues_template: '## New Issue Template' } }
it 'does not update the content' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).not_to have_key 'issues_template'
end
end
context 'when updating merge_requests_template' do
let(:project_params) { { merge_requests_template: '## New Merge Request Template' } }
it 'does not update the content' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).not_to have_key 'merge_requests_template'
end
end
end
context 'when updating external classification' do
before do
......@@ -787,8 +874,10 @@ RSpec.describe API::Projects do
stub_licensed_features(external_authorization_service_api_management: true)
end
let(:project_params) { { external_authorization_classification_label: 'new label' } }
it 'updates the classification label' do
put(api("/projects/#{project.id}", user), params: { external_authorization_classification_label: 'new label' })
subject
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload.external_authorization_classification_label).to eq('new label')
......@@ -797,7 +886,7 @@ RSpec.describe API::Projects do
context 'when updating mirror related attributes' do
let(:import_url) { generate(:url) }
let(:mirror_params) do
let(:project_params) do
{
mirror: true,
import_url: import_url,
......@@ -813,7 +902,7 @@ RSpec.describe API::Projects do
end
it 'does not update mirror related attributes' do
put(api("/projects/#{project.id}", user), params: mirror_params)
subject
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload.mirror).to be false
......@@ -823,12 +912,12 @@ RSpec.describe API::Projects do
admin = create(:admin)
unrelated_user = create(:user)
mirror_params[:mirror_user_id] = unrelated_user.id
project_params[:mirror_user_id] = unrelated_user.id
project.add_maintainer(admin)
expect_any_instance_of(EE::ProjectImportState).to receive(:force_import_job!).once
put(api("/projects/#{project.id}", admin), params: mirror_params)
put(api("/projects/#{project.id}", admin), params: project_params)
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload).to have_attributes(
......@@ -845,7 +934,7 @@ RSpec.describe API::Projects do
it 'updates mirror related attributes' do
expect_any_instance_of(EE::ProjectImportState).to receive(:force_import_job!).once
put(api("/projects/#{project.id}", user), params: mirror_params)
subject
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload).to have_attributes(
......@@ -861,7 +950,7 @@ RSpec.describe API::Projects do
it 'updates project without mirror attributes when the project is unable to set up repository mirroring' do
stub_licensed_features(repository_mirrors: false)
put(api("/projects/#{project.id}", user), params: mirror_params)
subject
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload.mirror).to be false
......@@ -870,9 +959,9 @@ RSpec.describe API::Projects do
it 'renders an API error when mirror user is invalid' do
invalid_mirror_user = create(:user)
project.add_developer(invalid_mirror_user)
mirror_params[:mirror_user_id] = invalid_mirror_user.id
project_params[:mirror_user_id] = invalid_mirror_user.id
put(api("/projects/#{project.id}", user), params: mirror_params)
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response["message"]["mirror_user_id"].first).to eq("is invalid")
......@@ -882,7 +971,7 @@ RSpec.describe API::Projects do
developer = create(:user)
project.add_developer(developer)
put(api("/projects/#{project.id}", developer), params: mirror_params)
put(api("/projects/#{project.id}", developer), params: project_params)
expect(response).to have_gitlab_http_status(:forbidden)
end
......@@ -890,10 +979,10 @@ RSpec.describe API::Projects do
describe 'updating approvals_before_merge attribute' do
context 'when authenticated as project owner' do
it 'updates approvals_before_merge' do
project_param = { approvals_before_merge: 3 }
let(:project_params) { { approvals_before_merge: 3 } }
put api("/projects/#{project.id}", user), params: project_param
it 'updates approvals_before_merge' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['approvals_before_merge']).to eq(3)
......
......@@ -91,6 +91,8 @@ module API
end
params :optional_update_params_ee do
optional :issues_template, type: String, desc: 'Default description for Issues'
optional :merge_requests_template, type: String, desc: 'Default description for Merge Requests'
end
params :optional_update_params do
......@@ -128,8 +130,10 @@ module API
:emails_disabled,
:forking_access_level,
:issues_access_level,
:issues_template,
:lfs_enabled,
:merge_requests_access_level,
:merge_requests_template,
:merge_method,
:name,
:only_allow_merge_if_all_discussions_are_resolved,
......
......@@ -12,7 +12,6 @@ itself: # project
- import_source
- import_type
- import_url
- issues_template
- jobs_cache_index
- last_repository_check_at
- last_repository_check_failed
......@@ -24,7 +23,6 @@ itself: # project
- merge_requests_author_approval
- merge_requests_disable_committers_approval
- merge_requests_rebase_enabled
- merge_requests_template
- mirror_last_successful_update_at
- mirror_last_update_at
- mirror_overwrites_diverged_branches
......
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