Protected Tags backend review changes
Added changelog
This commit is contained in:
parent
18506d4b8b
commit
f16377e7dc
25 changed files with 125 additions and 74 deletions
|
@ -1,32 +1,20 @@
|
|||
class Projects::ProtectedBranchesController < Projects::ProtectedRefsController
|
||||
protected
|
||||
|
||||
def protected_ref
|
||||
@protected_branch
|
||||
end
|
||||
|
||||
def protected_ref=(val)
|
||||
@protected_branch = val
|
||||
end
|
||||
|
||||
def matching_refs=(val)
|
||||
@matching_branches = val
|
||||
end
|
||||
|
||||
def project_refs
|
||||
@project.repository.branches
|
||||
end
|
||||
|
||||
def create_service
|
||||
def create_service_class
|
||||
::ProtectedBranches::CreateService
|
||||
end
|
||||
|
||||
def update_service
|
||||
def update_service_class
|
||||
::ProtectedBranches::UpdateService
|
||||
end
|
||||
|
||||
def load_protected_ref
|
||||
self.protected_ref = @project.protected_branches.find(params[:id])
|
||||
@protected_ref = @project.protected_branches.find(params[:id])
|
||||
end
|
||||
|
||||
def protected_ref_params
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class Projects::ProtectedRefsController < Projects::ApplicationController
|
||||
include RepositorySettingsRedirect
|
||||
|
||||
# Authorize
|
||||
before_action :require_non_empty_project
|
||||
before_action :authorize_admin_project!
|
||||
|
@ -12,33 +13,31 @@ class Projects::ProtectedRefsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
self.protected_ref = create_service.new(@project, current_user, protected_ref_params).execute
|
||||
protected_ref = create_service_class.new(@project, current_user, protected_ref_params).execute
|
||||
|
||||
unless protected_ref.persisted?
|
||||
flash[:alert] = protected_ref.errors.full_messages.join(', ').html_safe
|
||||
end
|
||||
|
||||
redirect_to_repository_settings(@project)
|
||||
end
|
||||
|
||||
def show
|
||||
self.matching_refs = protected_ref.matching(project_refs)
|
||||
@matching_refs = @protected_ref.matching(project_refs)
|
||||
end
|
||||
|
||||
def update
|
||||
self.protected_ref = update_service.new(@project, current_user, protected_ref_params).execute(protected_ref)
|
||||
@protected_ref = update_service_class.new(@project, current_user, protected_ref_params).execute(@protected_ref)
|
||||
|
||||
if protected_ref.valid?
|
||||
respond_to do |format|
|
||||
format.json { render json: protected_ref, status: :ok }
|
||||
end
|
||||
if @protected_ref.valid?
|
||||
render json: @protected_ref, status: :ok
|
||||
else
|
||||
respond_to do |format|
|
||||
format.json { render json: protected_ref.errors, status: :unprocessable_entity }
|
||||
end
|
||||
render json: @protected_ref.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
protected_ref.destroy
|
||||
@protected_ref.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_repository_settings(@project) }
|
||||
|
|
|
@ -1,32 +1,20 @@
|
|||
class Projects::ProtectedTagsController < Projects::ProtectedRefsController
|
||||
protected
|
||||
|
||||
def protected_ref
|
||||
@protected_tag
|
||||
end
|
||||
|
||||
def protected_ref=(val)
|
||||
@protected_tag = val
|
||||
end
|
||||
|
||||
def matching_refs=(val)
|
||||
@matching_tags = val
|
||||
end
|
||||
|
||||
def project_refs
|
||||
@project.repository.tags
|
||||
end
|
||||
|
||||
def create_service
|
||||
def create_service_class
|
||||
::ProtectedTags::CreateService
|
||||
end
|
||||
|
||||
def update_service
|
||||
def update_service_class
|
||||
::ProtectedTags::UpdateService
|
||||
end
|
||||
|
||||
def load_protected_ref
|
||||
self.protected_ref = @project.protected_tags.find(params[:id])
|
||||
@protected_ref = @project.protected_tags.find(params[:id])
|
||||
end
|
||||
|
||||
def protected_ref_params
|
||||
|
|
|
@ -29,4 +29,8 @@ module BranchesHelper
|
|||
def project_branches
|
||||
options_for_select(@project.repository.branch_names, @project.default_branch)
|
||||
end
|
||||
|
||||
def protected_branch?(project, branch)
|
||||
ProtectedBranch.protected?(project, branch.name)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,7 @@ module ProtectedBranchAccess
|
|||
include ProtectedRefAccess
|
||||
|
||||
belongs_to :protected_branch
|
||||
|
||||
delegate :project, to: :protected_branch
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ module ProtectedRef
|
|||
|
||||
included do
|
||||
belongs_to :project
|
||||
|
||||
validates :name, presence: true
|
||||
validates :project, presence: true
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ module ProtectedTagAccess
|
|||
include ProtectedRefAccess
|
||||
|
||||
belongs_to :protected_tag
|
||||
|
||||
delegate :project, to: :protected_tag
|
||||
end
|
||||
end
|
||||
|
|
|
@ -134,7 +134,7 @@ class Project < ActiveRecord::Base
|
|||
has_many :snippets, dependent: :destroy, class_name: 'ProjectSnippet'
|
||||
has_many :hooks, dependent: :destroy, class_name: 'ProjectHook'
|
||||
has_many :protected_branches, dependent: :destroy
|
||||
has_many :protected_tags, dependent: :destroy
|
||||
has_many :protected_tags, dependent: :destroy
|
||||
|
||||
has_many :project_authorizations
|
||||
has_many :authorized_users, through: :project_authorizations, source: :user, class_name: 'User'
|
||||
|
|
|
@ -6,8 +6,7 @@ class ProtectableDropdown
|
|||
|
||||
# Tags/branches which are yet to be individually protected
|
||||
def protectable_ref_names
|
||||
non_wildcard_protections = protections.reject(&:wildcard?)
|
||||
refs.map(&:name) - non_wildcard_protections.map(&:name)
|
||||
@protectable_ref_names ||= ref_names - non_wildcard_protected_ref_names
|
||||
end
|
||||
|
||||
def hash
|
||||
|
@ -20,7 +19,15 @@ class ProtectableDropdown
|
|||
@project.repository.public_send(@ref_type)
|
||||
end
|
||||
|
||||
def ref_names
|
||||
refs.map(&:name)
|
||||
end
|
||||
|
||||
def protections
|
||||
@project.public_send("protected_#{@ref_type}")
|
||||
end
|
||||
|
||||
def non_wildcard_protected_ref_names
|
||||
protections.reject(&:wildcard?).map(&:name)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
module ProtectedBranches
|
||||
class UpdateService < BaseService
|
||||
attr_reader :protected_branch
|
||||
|
||||
def execute(protected_branch)
|
||||
raise Gitlab::Access::AccessDeniedError unless can?(current_user, :admin_project, project)
|
||||
|
||||
@protected_branch = protected_branch
|
||||
@protected_branch.update(params)
|
||||
@protected_branch
|
||||
protected_branch.update(params)
|
||||
protected_branch
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
module ProtectedTags
|
||||
class UpdateService < BaseService
|
||||
attr_reader :protected_tag
|
||||
|
||||
def execute(protected_tag)
|
||||
raise Gitlab::Access::AccessDeniedError unless can?(current_user, :admin_project, project)
|
||||
|
||||
@protected_tag = protected_tag
|
||||
@protected_tag.update(params)
|
||||
@protected_tag
|
||||
protected_tag.update(params)
|
||||
protected_tag
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
%span.label.label-info.has-tooltip{ title: "Merged into #{@repository.root_ref}" }
|
||||
merged
|
||||
|
||||
- if ProtectedBranch.protected?(@project, branch.name)
|
||||
- if protected_branch?(@project, branch)
|
||||
%span.label.label-success
|
||||
protected
|
||||
.controls.hidden-xs<
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
- page_title @protected_branch.name, "Protected Branches"
|
||||
- page_title @protected_ref.name, "Protected Branches"
|
||||
|
||||
.row.prepend-top-default.append-bottom-default
|
||||
.col-lg-3
|
||||
%h4.prepend-top-0
|
||||
= @protected_branch.name
|
||||
= @protected_ref.name
|
||||
|
||||
.col-lg-9
|
||||
%h5 Matching Branches
|
||||
- if @matching_branches.present?
|
||||
- if @matching_refs.present?
|
||||
.table-responsive
|
||||
%table.table.protected-branches-list
|
||||
%colgroup
|
||||
|
@ -18,7 +18,7 @@
|
|||
%th Branch
|
||||
%th Last commit
|
||||
%tbody
|
||||
- @matching_branches.each do |matching_branch|
|
||||
- @matching_refs.each do |matching_branch|
|
||||
= render partial: "matching_branch", object: matching_branch
|
||||
- else
|
||||
%p.settings-message.text-center
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
- page_title @protected_tag.name, "Protected Tags"
|
||||
- page_title @protected_ref.name, "Protected Tags"
|
||||
|
||||
.row.prepend-top-default.append-bottom-default
|
||||
.col-lg-3
|
||||
%h4.prepend-top-0
|
||||
= @protected_tag.name
|
||||
= @protected_ref.name
|
||||
|
||||
.col-lg-9
|
||||
%h5 Matching Tags
|
||||
- if @matching_tags.present?
|
||||
- if @matching_refs.present?
|
||||
.table-responsive
|
||||
%table.table.protected-tags-list
|
||||
%colgroup
|
||||
|
@ -18,7 +18,7 @@
|
|||
%th Tag
|
||||
%th Last commit
|
||||
%tbody
|
||||
- @matching_tags.each do |matching_tag|
|
||||
- @matching_refs.each do |matching_tag|
|
||||
= render partial: "matching_tag", object: matching_tag
|
||||
- else
|
||||
%p.settings-message.text-center
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Protected Tags feature
|
||||
merge_request: 10356
|
||||
author:
|
|
@ -1,7 +1,6 @@
|
|||
class CreateProtectedTags < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
# Set this constant to true if this migration requires downtime.
|
||||
DOWNTIME = false
|
||||
|
||||
GITLAB_ACCESS_MASTER = 40
|
||||
|
|
|
@ -70,14 +70,8 @@ module Gitlab
|
|||
|
||||
def protected_tag_checks
|
||||
return unless tag_protected?
|
||||
|
||||
if update?
|
||||
return "Protected tags cannot be updated."
|
||||
end
|
||||
|
||||
if deletion?
|
||||
return "Protected tags cannot be deleted."
|
||||
end
|
||||
return "Protected tags cannot be updated." if update?
|
||||
return "Protected tags cannot be deleted." if deletion?
|
||||
|
||||
unless user_access.can_create_tag?(@tag_name)
|
||||
return "You are not allowed to create this tag as it is protected."
|
||||
|
|
|
@ -3,6 +3,7 @@ require('spec_helper')
|
|||
describe Projects::ProtectedBranchesController do
|
||||
describe "GET #index" do
|
||||
let(:project) { create(:project_empty_repo, :public) }
|
||||
|
||||
it "redirects empty repo to projects page" do
|
||||
get(:index, namespace_id: project.namespace.to_param, project_id: project)
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ require('spec_helper')
|
|||
describe Projects::ProtectedTagsController do
|
||||
describe "GET #index" do
|
||||
let(:project) { create(:project_empty_repo, :public) }
|
||||
|
||||
it "redirects empty repo to projects page" do
|
||||
get(:index, namespace_id: project.namespace.to_param, project_id: project)
|
||||
end
|
||||
|
|
|
@ -2,7 +2,9 @@ RSpec.shared_examples "protected branches > access control > CE" do
|
|||
ProtectedBranch::PushAccessLevel.human_access_levels.each do |(access_type_id, access_type_name)|
|
||||
it "allows creating protected branches that #{access_type_name} can push to" do
|
||||
visit namespace_project_protected_branches_path(project.namespace, project)
|
||||
|
||||
set_protected_branch_name('master')
|
||||
|
||||
within('.new_protected_branch') do
|
||||
allowed_to_push_button = find(".js-allowed-to-push")
|
||||
|
||||
|
@ -11,6 +13,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
|
|||
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
|
||||
end
|
||||
end
|
||||
|
||||
click_on "Protect"
|
||||
|
||||
expect(ProtectedBranch.count).to eq(1)
|
||||
|
@ -19,7 +22,9 @@ RSpec.shared_examples "protected branches > access control > CE" do
|
|||
|
||||
it "allows updating protected branches so that #{access_type_name} can push to them" do
|
||||
visit namespace_project_protected_branches_path(project.namespace, project)
|
||||
|
||||
set_protected_branch_name('master')
|
||||
|
||||
click_on "Protect"
|
||||
|
||||
expect(ProtectedBranch.count).to eq(1)
|
||||
|
@ -34,6 +39,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
|
|||
end
|
||||
|
||||
wait_for_ajax
|
||||
|
||||
expect(ProtectedBranch.last.push_access_levels.map(&:access_level)).to include(access_type_id)
|
||||
end
|
||||
end
|
||||
|
@ -41,7 +47,9 @@ RSpec.shared_examples "protected branches > access control > CE" do
|
|||
ProtectedBranch::MergeAccessLevel.human_access_levels.each do |(access_type_id, access_type_name)|
|
||||
it "allows creating protected branches that #{access_type_name} can merge to" do
|
||||
visit namespace_project_protected_branches_path(project.namespace, project)
|
||||
|
||||
set_protected_branch_name('master')
|
||||
|
||||
within('.new_protected_branch') do
|
||||
allowed_to_merge_button = find(".js-allowed-to-merge")
|
||||
|
||||
|
@ -50,6 +58,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
|
|||
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
|
||||
end
|
||||
end
|
||||
|
||||
click_on "Protect"
|
||||
|
||||
expect(ProtectedBranch.count).to eq(1)
|
||||
|
@ -58,7 +67,9 @@ RSpec.shared_examples "protected branches > access control > CE" do
|
|||
|
||||
it "allows updating protected branches so that #{access_type_name} can merge to them" do
|
||||
visit namespace_project_protected_branches_path(project.namespace, project)
|
||||
|
||||
set_protected_branch_name('master')
|
||||
|
||||
click_on "Protect"
|
||||
|
||||
expect(ProtectedBranch.count).to eq(1)
|
||||
|
@ -73,6 +84,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
|
|||
end
|
||||
|
||||
wait_for_ajax
|
||||
|
||||
expect(ProtectedBranch.last.merge_access_levels.map(&:access_level)).to include(access_type_id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,9 @@ RSpec.shared_examples "protected tags > access control > CE" do
|
|||
ProtectedTag::CreateAccessLevel.human_access_levels.each do |(access_type_id, access_type_name)|
|
||||
it "allows creating protected tags that #{access_type_name} can create" do
|
||||
visit namespace_project_protected_tags_path(project.namespace, project)
|
||||
|
||||
set_protected_tag_name('master')
|
||||
|
||||
within('.new_protected_tag') do
|
||||
allowed_to_create_button = find(".js-allowed-to-create")
|
||||
|
||||
|
@ -11,6 +13,7 @@ RSpec.shared_examples "protected tags > access control > CE" do
|
|||
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
|
||||
end
|
||||
end
|
||||
|
||||
click_on "Protect"
|
||||
|
||||
expect(ProtectedTag.count).to eq(1)
|
||||
|
@ -19,7 +22,9 @@ RSpec.shared_examples "protected tags > access control > CE" do
|
|||
|
||||
it "allows updating protected tags so that #{access_type_name} can create them" do
|
||||
visit namespace_project_protected_tags_path(project.namespace, project)
|
||||
|
||||
set_protected_tag_name('master')
|
||||
|
||||
click_on "Protect"
|
||||
|
||||
expect(ProtectedTag.count).to eq(1)
|
||||
|
@ -34,6 +39,7 @@ RSpec.shared_examples "protected tags > access control > CE" do
|
|||
end
|
||||
|
||||
wait_for_ajax
|
||||
|
||||
expect(ProtectedTag.last.create_access_levels.map(&:access_level)).to include(access_type_id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,6 +18,7 @@ describe ProtectableDropdown, models: true do
|
|||
create(:protected_branch, name: 'feat*', project: project)
|
||||
|
||||
subject = described_class.new(project.reload, :branches)
|
||||
|
||||
expect(subject.protectable_ref_names).to include('feature')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ProtectedTag, models: true do
|
||||
subject { build_stubbed(:protected_branch) }
|
||||
|
||||
describe 'Associations' do
|
||||
it { is_expected.to belong_to(:project) }
|
||||
end
|
||||
|
|
26
spec/services/protected_branches/update_service_spec.rb
Normal file
26
spec/services/protected_branches/update_service_spec.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ProtectedBranches::UpdateService, services: true do
|
||||
let(:protected_branch) { create(:protected_branch) }
|
||||
let(:project) { protected_branch.project }
|
||||
let(:user) { project.owner }
|
||||
let(:params) { { name: 'new protected branch name' } }
|
||||
|
||||
describe '#execute' do
|
||||
subject(:service) { described_class.new(project, user, params) }
|
||||
|
||||
it 'updates a protected branch' do
|
||||
result = service.execute(protected_branch)
|
||||
|
||||
expect(result.reload.name).to eq(params[:name])
|
||||
end
|
||||
|
||||
context 'without admin_project permissions' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it "raises error" do
|
||||
expect{ service.execute(protected_branch) }.to raise_error(Gitlab::Access::AccessDeniedError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
26
spec/services/protected_tags/update_service_spec.rb
Normal file
26
spec/services/protected_tags/update_service_spec.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ProtectedTags::UpdateService, services: true do
|
||||
let(:protected_tag) { create(:protected_tag) }
|
||||
let(:project) { protected_tag.project }
|
||||
let(:user) { project.owner }
|
||||
let(:params) { { name: 'new protected tag name' } }
|
||||
|
||||
describe '#execute' do
|
||||
subject(:service) { described_class.new(project, user, params) }
|
||||
|
||||
it 'updates a protected tag' do
|
||||
result = service.execute(protected_tag)
|
||||
|
||||
expect(result.reload.name).to eq(params[:name])
|
||||
end
|
||||
|
||||
context 'without admin_project permissions' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it "raises error" do
|
||||
expect{ service.execute(protected_tag) }.to raise_error(Gitlab::Access::AccessDeniedError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue