Protected Tags backend review changes

Added changelog
This commit is contained in:
James Edwards-Jones 2017-04-05 18:59:46 +01:00
parent 18506d4b8b
commit f16377e7dc
25 changed files with 125 additions and 74 deletions

View file

@ -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

View file

@ -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) }

View file

@ -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

View file

@ -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

View file

@ -5,6 +5,7 @@ module ProtectedBranchAccess
include ProtectedRefAccess
belongs_to :protected_branch
delegate :project, to: :protected_branch
end
end

View file

@ -3,6 +3,7 @@ module ProtectedRef
included do
belongs_to :project
validates :name, presence: true
validates :project, presence: true

View file

@ -5,6 +5,7 @@ module ProtectedTagAccess
include ProtectedRefAccess
belongs_to :protected_tag
delegate :project, to: :protected_tag
end
end

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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<

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,4 @@
---
title: Protected Tags feature
merge_request: 10356
author:

View file

@ -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

View file

@ -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."

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View 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