Commit 1c542e28 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'master' of dev.gitlab.org:gitlab/gitlab-ee

parents ace64666 8bcebf17
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.1.0
- Fix: LDAP group links API is not working as expected.
v 8.0.1 v 8.0.1
- Improve CI migration procedure and documentation - Improve CI migration procedure and documentation
......
v 8.1.0 (unreleased) v 8.1.0 (unreleased)
- added an issues template (Hannes Rosenögger) - added an issues template (Hannes Rosenögger)
v 8.1.0
- Add documentation for "Share project with group" API call
- Abiliy to disable 'Share with Group' feature (via UI and API)
v 8.0.1 v 8.0.1
- Correct gem dependency versions - Correct gem dependency versions
......
...@@ -135,7 +135,7 @@ class GroupsController < Groups::ApplicationController ...@@ -135,7 +135,7 @@ class GroupsController < Groups::ApplicationController
end end
def group_params def group_params
params.require(:group).permit(:name, :description, :path, :avatar, :membership_lock) params.require(:group).permit(:name, :description, :path, :avatar, :membership_lock, :share_with_group_lock)
end end
def load_events def load_events
......
...@@ -5,6 +5,7 @@ class LdapGroupLink < ActiveRecord::Base ...@@ -5,6 +5,7 @@ class LdapGroupLink < ActiveRecord::Base
validates :cn, :group_access, :group_id, presence: true validates :cn, :group_access, :group_id, presence: true
validates :cn, uniqueness: { scope: [:group_id, :provider] } validates :cn, uniqueness: { scope: [:group_id, :provider] }
validates :group_access, inclusion: { in: Gitlab::Access.all_values } validates :group_access, inclusion: { in: Gitlab::Access.all_values }
validates :provider, presence: true
scope :with_provider, ->(provider) { where(provider: provider) } scope :with_provider, ->(provider) { where(provider: provider) }
......
...@@ -777,4 +777,8 @@ class Project < ActiveRecord::Base ...@@ -777,4 +777,8 @@ class Project < ActiveRecord::Base
approvers.find_or_create_by(user_id: user_id, target_id: id) approvers.find_or_create_by(user_id: user_id, target_id: id)
end end
end end
def allowed_to_share_with_group?
!namespace.share_with_group_lock
end
end end
...@@ -145,7 +145,7 @@ class ProjectTeam ...@@ -145,7 +145,7 @@ class ProjectTeam
access << group.group_members.find_by(user_id: user_id).try(:access_field) access << group.group_members.find_by(user_id: user_id).try(:access_field)
end end
if project.invited_groups.any? if project.invited_groups.any? && project.allowed_to_share_with_group?
access << max_invited_level(user_id) access << max_invited_level(user_id)
end end
...@@ -175,7 +175,7 @@ class ProjectTeam ...@@ -175,7 +175,7 @@ class ProjectTeam
group_members = group ? group.group_members : [] group_members = group ? group.group_members : []
invited_members = [] invited_members = []
if project.invited_groups.any? if project.invited_groups.any? && project.allowed_to_share_with_group?
project.project_group_links.each do |group_link| project.project_group_links.each do |group_link|
invited_group = group_link.group invited_group = group_link.group
im = invited_group.group_members im = invited_group.group_members
......
...@@ -27,13 +27,22 @@ ...@@ -27,13 +27,22 @@
.form-group .form-group
%hr %hr
= f.label :name, class: 'control-label' do = f.label :membership_lock, class: 'control-label' do
Member lock Member lock
.col-sm-10 .col-sm-10
.checkbox .checkbox
= f.check_box :membership_lock = f.check_box :membership_lock
%span.descr Prevent adding new members to project membership within this group %span.descr Prevent adding new members to project membership within this group
.form-group
%hr
= f.label :share_with_group_lock, class: 'control-label' do
Share with group lock
.col-sm-10
.checkbox
= f.check_box :share_with_group_lock
%span.descr Prevent sharing a project with another group within this group
.form-actions .form-actions
= f.submit 'Save group', class: "btn btn-save" = f.submit 'Save group', class: "btn btn-save"
......
...@@ -13,11 +13,12 @@ ...@@ -13,11 +13,12 @@
= icon('pencil-square-o fw') = icon('pencil-square-o fw')
%span %span
Project Settings Project Settings
= nav_link(controller: :group_links) do - if @project.allowed_to_share_with_group?
= link_to namespace_project_group_links_path(@project.namespace, @project) do = nav_link(controller: :group_links) do
= icon('share-square-o fw') = link_to namespace_project_group_links_path(@project.namespace, @project) do
%span = icon('share-square-o fw')
Groups %span
Groups
= nav_link(controller: :deploy_keys) do = nav_link(controller: :deploy_keys) do
= link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys', data: {placement: 'right'} do = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys', data: {placement: 'right'} do
= icon('key fw') = icon('key fw')
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
- if @group - if @group
= render "group_members", members: @group_members = render "group_members", members: @group_members
- if @project_group_links.any? - if @project_group_links.any? && @project.allowed_to_share_with_group?
= render "shared_group_members" = render "shared_group_members"
:coffeescript :coffeescript
......
class AddGroupShareLock < ActiveRecord::Migration
def change
add_column :namespaces, :share_with_group_lock, :boolean, default: false
end
end
class UpdateGroupLinks < ActiveRecord::Migration
def change
provider = quote_string(Gitlab::LDAP::Config.providers.first)
execute("UPDATE ldap_group_links SET provider = '#{provider}' WHERE provider IS NULL")
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150929160851) do ActiveRecord::Schema.define(version: 20151008130321) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -58,7 +58,6 @@ ActiveRecord::Schema.define(version: 20150929160851) do ...@@ -58,7 +58,6 @@ ActiveRecord::Schema.define(version: 20150929160851) do
t.integer "session_expire_delay", default: 10080, null: false t.integer "session_expire_delay", default: 10080, null: false
t.text "import_sources" t.text "import_sources"
t.text "help_page_text" t.text "help_page_text"
t.boolean "ci_enabled", default: true, null: false
end end
create_table "approvals", force: true do |t| create_table "approvals", force: true do |t|
...@@ -130,8 +129,18 @@ ActiveRecord::Schema.define(version: 20150929160851) do ...@@ -130,8 +129,18 @@ ActiveRecord::Schema.define(version: 20150929160851) do
t.boolean "allow_failure", default: false, null: false t.boolean "allow_failure", default: false, null: false
t.string "stage" t.string "stage"
t.integer "trigger_request_id" t.integer "trigger_request_id"
t.integer "stage_idx"
t.boolean "tag"
t.string "ref"
t.integer "user_id"
t.string "type"
t.string "target_url"
t.string "description"
end end
add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree
add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree
add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree
add_index "ci_builds", ["commit_id"], name: "index_ci_builds_on_commit_id", using: :btree add_index "ci_builds", ["commit_id"], name: "index_ci_builds_on_commit_id", using: :btree
add_index "ci_builds", ["project_id", "commit_id"], name: "index_ci_builds_on_project_id_and_commit_id", using: :btree add_index "ci_builds", ["project_id", "commit_id"], name: "index_ci_builds_on_project_id_and_commit_id", using: :btree
add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree
...@@ -145,9 +154,10 @@ ActiveRecord::Schema.define(version: 20150929160851) do ...@@ -145,9 +154,10 @@ ActiveRecord::Schema.define(version: 20150929160851) do
t.text "push_data" t.text "push_data"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.boolean "tag", default: false t.boolean "tag", default: false
t.text "yaml_errors" t.text "yaml_errors"
t.datetime "committed_at" t.datetime "committed_at"
t.integer "gl_project_id"
end end
add_index "ci_commits", ["project_id", "committed_at", "id"], name: "index_ci_commits_on_project_id_and_committed_at_and_id", using: :btree add_index "ci_commits", ["project_id", "committed_at", "id"], name: "index_ci_commits_on_project_id_and_committed_at_and_id", using: :btree
...@@ -187,7 +197,7 @@ ActiveRecord::Schema.define(version: 20150929160851) do ...@@ -187,7 +197,7 @@ ActiveRecord::Schema.define(version: 20150929160851) do
add_index "ci_jobs", ["project_id"], name: "index_ci_jobs_on_project_id", using: :btree add_index "ci_jobs", ["project_id"], name: "index_ci_jobs_on_project_id", using: :btree
create_table "ci_projects", force: true do |t| create_table "ci_projects", force: true do |t|
t.string "name", null: false t.string "name"
t.integer "timeout", default: 3600, null: false t.integer "timeout", default: 3600, null: false
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
...@@ -519,6 +529,7 @@ ActiveRecord::Schema.define(version: 20150929160851) do ...@@ -519,6 +529,7 @@ ActiveRecord::Schema.define(version: 20150929160851) do
t.integer "position", default: 0 t.integer "position", default: 0
t.datetime "locked_at" t.datetime "locked_at"
t.integer "updated_by_id" t.integer "updated_by_id"
t.string "merge_error"
end end
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
...@@ -549,15 +560,16 @@ ActiveRecord::Schema.define(version: 20150929160851) do ...@@ -549,15 +560,16 @@ ActiveRecord::Schema.define(version: 20150929160851) do
add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree
create_table "namespaces", force: true do |t| create_table "namespaces", force: true do |t|
t.string "name", null: false t.string "name", null: false
t.string "path", null: false t.string "path", null: false
t.integer "owner_id" t.integer "owner_id"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "type" t.string "type"
t.string "description", default: "", null: false t.string "description", default: "", null: false
t.string "avatar" t.string "avatar"
t.boolean "membership_lock", default: false t.boolean "membership_lock", default: false
t.boolean "share_with_group_lock", default: false
end end
add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree
...@@ -834,6 +846,7 @@ ActiveRecord::Schema.define(version: 20150929160851) do ...@@ -834,6 +846,7 @@ ActiveRecord::Schema.define(version: 20150929160851) do
t.integer "dashboard", default: 0 t.integer "dashboard", default: 0
t.integer "project_view", default: 0 t.integer "project_view", default: 0
t.integer "consumed_timestep" t.integer "consumed_timestep"
t.integer "layout", default: 0
end end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
......
...@@ -46,6 +46,24 @@ Parameters: ...@@ -46,6 +46,24 @@ Parameters:
- `name` (required) - The name of the group - `name` (required) - The name of the group
- `path` (required) - The path of the group - `path` (required) - The path of the group
- `description` (optional) - The group's description - `description` (optional) - The group's description
- `membership_lock` (optional, boolean) - Prevent adding new members to project membership within this group
- `share_with_group_lock` (optional, boolean) - Prevent sharing a project with another group within this group
## Update group
Updates a project group. Available only for users who can manage this group.
```
PUT /groups/:id
```
Parameters:
- `name` (required) - The name of the group
- `path` (required) - The path of the group
- `description` (optional) - The group's description
- `membership_lock` (optional, boolean) - Prevent adding new members to project membership within this group
- `share_with_group_lock` (optional, boolean) - Prevent sharing a project with another group within this group
## Transfer project to group ## Transfer project to group
......
...@@ -477,6 +477,20 @@ Revoking team membership for a user who is not currently a team member is consid ...@@ -477,6 +477,20 @@ Revoking team membership for a user who is not currently a team member is consid
Please note that the returned JSON currently differs slightly. Thus you should not Please note that the returned JSON currently differs slightly. Thus you should not
rely on the returned JSON structure. rely on the returned JSON structure.
### Share project with group
Allow to share project with group.
```
POST /projects/:id/share
```
Parameters:
- `id` (required) - The ID of a project
- `group_id` (required) - The ID of a group
- `group_access` (required) - Level of permissions for sharing
## Hooks ## Hooks
Also called Project Hooks and Webhooks. Also called Project Hooks and Webhooks.
......
...@@ -23,15 +23,18 @@ module API ...@@ -23,15 +23,18 @@ module API
# Create group. Available only for users who can create groups. # Create group. Available only for users who can create groups.
# #
# Parameters: # Parameters:
# name (required) - The name of the group # name (required) - The name of the group
# path (required) - The path of the group # path (required) - The path of the group
# description (optional) - The details of the group
# membership_lock (optional, boolean) - Prevent adding new members to project membership within this group
# share_with_group_lock (optional, boolean) - Prevent sharing a project with another group within this group
# Example Request: # Example Request:
# POST /groups # POST /groups
post do post do
authorize! :create_group, current_user authorize! :create_group, current_user
required_attributes! [:name, :path] required_attributes! [:name, :path]
attrs = attributes_for_keys [:name, :path, :description] attrs = attributes_for_keys [:name, :path, :description, :membership_lock, :share_with_group_lock]
@group = Group.new(attrs) @group = Group.new(attrs)
if @group.save if @group.save
...@@ -51,6 +54,29 @@ module API ...@@ -51,6 +54,29 @@ module API
end end
end end
# Update group. Available only for users who can manage this group.
#
# Parameters:
# id (required) - The ID of a group
# name (required) - The name of the group
# path (required) - The path of the group
# description (optional) - The details of the group
# membership_lock (optional, boolean) - Prevent adding new members to project membership within this group
# share_with_group_lock (optional, boolean) - Prevent sharing a project with another group within this group
# Example Request:
# PUT /groups/:id
put ":id" do
attrs = attributes_for_keys [:name, :path, :description, :membership_lock, :share_with_group_lock]
@group = find_group(params[:id])
authorize! :admin_group, @group
if @group.update_attributes(attrs)
present @group, with: Entities::Group
else
render_api_error!("Failed to update group #{@group.errors.messages}", 400)
end
end
# Get a single group, with containing projects # Get a single group, with containing projects
# #
# Parameters: # Parameters:
......
...@@ -265,6 +265,10 @@ module API ...@@ -265,6 +265,10 @@ module API
authorize! :admin_project, user_project authorize! :admin_project, user_project
required_attributes! [:group_id, :group_access] required_attributes! [:group_id, :group_access]
unless user_project.allowed_to_share_with_group?
return render_api_error!("The project sharing with group is disabled", 400)
end
link = user_project.project_group_links.new link = user_project.project_group_links.new
link.group_id = params[:group_id] link.group_id = params[:group_id]
link.group_access = params[:group_access] link.group_access = params[:group_access]
......
...@@ -418,4 +418,17 @@ describe Project do ...@@ -418,4 +418,17 @@ describe Project do
it { should eq "http://localhost#{avatar_path}" } it { should eq "http://localhost#{avatar_path}" }
end end
end end
describe :allowed_to_share_with_group? do
let(:project) { create(:project) }
it "returns true" do
expect(project.allowed_to_share_with_group?).to be_truthy
end
it "returns false" do
project.namespace.update(share_with_group_lock: true)
expect(project.allowed_to_share_with_group?).to be_falsey
end
end
end end
...@@ -85,4 +85,29 @@ describe ProjectTeam do ...@@ -85,4 +85,29 @@ describe ProjectTeam do
it { expect(project.team.max_invited_level(reporter.id)).to eq(Gitlab::Access::REPORTER) } it { expect(project.team.max_invited_level(reporter.id)).to eq(Gitlab::Access::REPORTER) }
it { expect(project.team.max_invited_level(nonmember.id)).to be_nil } it { expect(project.team.max_invited_level(nonmember.id)).to be_nil }
end end
describe :max_member_access do
let(:group) { create(:group) }
let(:project) { create(:empty_project) }
before do
project.project_group_links.create(
group: group,
group_access: Gitlab::Access::DEVELOPER
)
group.add_user(master, Gitlab::Access::MASTER)
group.add_user(reporter, Gitlab::Access::REPORTER)
end
it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::DEVELOPER) }
it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) }
it { expect(project.team.max_member_access(nonmember.id)).to be_nil }
it "does not have an access" do
project.namespace.update(share_with_group_lock: true)
expect(project.team.max_member_access(master.id)).to be_nil
expect(project.team.max_member_access(reporter.id)).to be_nil
end
end
end end
...@@ -142,6 +142,24 @@ describe API::API, api: true do ...@@ -142,6 +142,24 @@ describe API::API, api: true do
end end
end end
describe "PUT /groups" do
context "when authenticated as user without group permissions" do
it "should not create group" do
put api("/groups/#{group2.id}", user1), attributes_for(:group)
expect(response.status).to eq(403)
end
end
context "when authenticated as user with group permissions" do
it "should update group" do
group2.update(owner: user2)
put api("/groups/#{group2.id}", user2), { name: 'Renamed' }
expect(response.status).to eq(200)
expect(group2.reload.name).to eq('Renamed')
end
end
end
describe "DELETE /groups/:id" do describe "DELETE /groups/:id" do
context "when authenticated as user" do context "when authenticated as user" do
it "should remove group" do it "should remove group" do
......
...@@ -655,6 +655,12 @@ describe API::API, api: true do ...@@ -655,6 +655,12 @@ describe API::API, api: true do
expect(response.status).to eq 400 expect(response.status).to eq 400
end end
it "should return a 400 error when sharing is disabled" do
project.namespace.update(share_with_group_lock: true)
post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER
expect(response.status).to eq 400
end
it "should return a 409 error when wrong params passed" do it "should return a 409 error when wrong params passed" do
post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: 1234 post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: 1234
expect(response.status).to eq 409 expect(response.status).to eq 409
......
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