From befa7a9c170327ecc4ce698f416450dc3542942c Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 9 Mar 2016 13:25:39 -0500 Subject: Don't remove `ProjectSnippet#expires_at` from API See https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3103 This partially reverts commit 836d5930332797192094ce4a3c8083e96f7e8c53. --- doc/api/notes.md | 1 + doc/api/project_snippets.md | 1 + doc/web_hooks/web_hooks.md | 1 + lib/api/entities.rb | 3 +++ spec/requests/api/project_snippets_spec.rb | 18 ++++++++++++++++++ 5 files changed, 24 insertions(+) create mode 100644 spec/requests/api/project_snippets_spec.rb diff --git a/doc/api/notes.md b/doc/api/notes.md index 85d4f0bafa2..d4d63e825ab 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -145,6 +145,7 @@ Parameters: "state": "active", "created_at": "2013-09-30T13:46:01Z" }, + "expires_at": null, "updated_at": "2013-10-02T07:34:20Z", "created_at": "2013-10-02T07:34:20Z" } diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md index fb802102e3a..a7acf37b5bc 100644 --- a/doc/api/project_snippets.md +++ b/doc/api/project_snippets.md @@ -51,6 +51,7 @@ Parameters: "state": "active", "created_at": "2012-05-23T08:00:58Z" }, + "expires_at": null, "updated_at": "2012-06-28T10:52:04Z", "created_at": "2012-06-28T10:52:04Z" } diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md index e2b53c45ab1..b82306bd1da 100644 --- a/doc/web_hooks/web_hooks.md +++ b/doc/web_hooks/web_hooks.md @@ -582,6 +582,7 @@ X-Gitlab-Event: Note Hook "created_at": "2015-04-09 02:40:38 UTC", "updated_at": "2015-04-09 02:40:38 UTC", "file_name": "test.rb", + "expires_at": null, "type": "ProjectSnippet", "visibility_level": 0 } diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 5b5b8bd044b..b49af093a14 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -144,6 +144,9 @@ module API expose :id, :title, :file_name expose :author, using: Entities::UserBasic expose :updated_at, :created_at + + # TODO (rspeicher): Deprecated; remove in 9.0 + expose(:expires_at) { |snippet| nil } end class ProjectEntity < Grape::Entity diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb new file mode 100644 index 00000000000..3722ddf5a33 --- /dev/null +++ b/spec/requests/api/project_snippets_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +describe API::API, api: true do + include ApiHelpers + + describe 'GET /projects/:project_id/snippets/:id' do + # TODO (rspeicher): Deprecated; remove in 9.0 + it 'always exposes expires_at as nil' do + admin = create(:admin) + snippet = create(:project_snippet, author: admin) + + get api("/projects/#{snippet.project.id}/snippets/#{snippet.id}", admin) + + expect(json_response).to have_key('expires_at') + expect(json_response['expires_at']).to be_nil + end + end +end -- cgit v1.2.1 From 75ba7d5d4f13e4c4e4f53ff03a61a0f447ea0ce2 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 10 Mar 2016 20:32:08 -0500 Subject: Prepare docs for 8.6 RC1 [ci skip] --- doc/install/installation.md | 4 +- doc/update/8.5-to-8.6.md | 145 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 doc/update/8.5-to-8.6.md diff --git a/doc/install/installation.md b/doc/install/installation.md index 0fd54be58b0..4f011397269 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -233,9 +233,9 @@ sudo usermod -aG redis git ### Clone the Source # Clone GitLab repository - sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-5-stable gitlab + sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-6-stable gitlab -**Note:** You can change `8-5-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! +**Note:** You can change `8-6-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! ### Configure It diff --git a/doc/update/8.5-to-8.6.md b/doc/update/8.5-to-8.6.md new file mode 100644 index 00000000000..e42f691cd32 --- /dev/null +++ b/doc/update/8.5-to-8.6.md @@ -0,0 +1,145 @@ +# From 8.5 to 8.6 + +### 1. Stop server + + sudo service gitlab stop + +### 2. Backup + +```bash +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production +``` + +### 3. Get latest code + +```bash +sudo -u git -H git fetch --all +sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically +``` + +For GitLab Community Edition: + +```bash +sudo -u git -H git checkout 8-6-stable +``` + +OR + +For GitLab Enterprise Edition: + +```bash +sudo -u git -H git checkout 8-6-stable-ee +``` + +### 4. Update gitlab-shell + +```bash +cd /home/git/gitlab-shell +sudo -u git -H git fetch --all +sudo -u git -H git checkout v2.6.10 +``` + +### 5. Update gitlab-workhorse + +Install and compile gitlab-workhorse. This requires +[Go 1.5](https://golang.org/dl) which should already be on your system from +GitLab 8.1. + +```bash +cd /home/git/gitlab-workhorse +sudo -u git -H git fetch --all +sudo -u git -H git checkout 0.6.5 +sudo -u git -H make +``` + +### 6. Install libs, migrations, etc. + +```bash +cd /home/git/gitlab + +# MySQL installations (note: the line below states '--without postgres') +sudo -u git -H bundle install --without postgres development test --deployment + +# PostgreSQL installations (note: the line below states '--without mysql') +sudo -u git -H bundle install --without mysql development test --deployment + +# Optional: clean up old gems +sudo -u git -H bundle clean + +# Run database migrations +sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production + +# Clean up assets and cache +sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production + +``` + +### 7. Update configuration files + +#### New configuration options for `gitlab.yml` + +There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them manually to your current `gitlab.yml`: + +```sh +git diff origin/8-5-stable:config/gitlab.yml.example origin/8-6-stable:config/gitlab.yml.example +``` + +#### Nginx configuration + +Ensure you're still up-to-date with the latest NGINX configuration changes: + +```sh +# For HTTPS configurations +git diff origin/8-5-stable:lib/support/nginx/gitlab-ssl origin/8-6-stable:lib/support/nginx/gitlab-ssl + +# For HTTP configurations +git diff origin/8-5-stable:lib/support/nginx/gitlab origin/8-6-stable:lib/support/nginx/gitlab +``` + +If you are using Apache instead of NGINX please see the updated [Apache templates]. +Also note that because Apache does not support upstreams behind Unix sockets you +will need to let gitlab-workhorse listen on a TCP port. You can do this +via [/etc/default/gitlab]. + +[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache +[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-6-stable/lib/support/init.d/gitlab.default.example#L37 + +#### Init script + +Ensure you're still up-to-date with the latest init script changes: + + sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab + +### 8. Start application + + sudo service gitlab start + sudo service nginx restart + +### 9. Check application status + +Check if GitLab and its environment are configured correctly: + + sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production + +To make sure you didn't miss anything run a more thorough check: + + sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production + +If all items are green, then congratulations, the upgrade is complete! + +## Things went south? Revert to previous version (8.5) + +### 1. Revert the code to the previous version + +Follow the [upgrade guide from 8.4 to 8.5](8.4-to-8.5.md), except for the +database migration (the backup is already migrated to the previous version). + +### 2. Restore from the backup + +```bash +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production +``` + +If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above. -- cgit v1.2.1 From ea5f4cae53eb571b250fcbaa3649cefe3083a636 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 11 Mar 2016 17:47:05 +0100 Subject: Bring ProjectGroupLink model and migrations from EE Signed-off-by: Dmitriy Zaporozhets --- app/models/group.rb | 2 ++ app/models/project.rb | 2 ++ app/models/project_group_link.rb | 36 ++++++++++++++++++++++ .../20130711063759_create_project_group_links.rb | 10 ++++++ ...30820102832_add_access_to_project_group_link.rb | 5 +++ db/schema.rb | 14 +++++++-- spec/factories/project_group_links.rb | 6 ++++ spec/models/project_group_link_spec.rb | 17 ++++++++++ 8 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 app/models/project_group_link.rb create mode 100644 db/migrate/20130711063759_create_project_group_links.rb create mode 100644 db/migrate/20130820102832_add_access_to_project_group_link.rb create mode 100644 spec/factories/project_group_links.rb create mode 100644 spec/models/project_group_link_spec.rb diff --git a/app/models/group.rb b/app/models/group.rb index 76042b3e3fd..e307624e965 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -23,6 +23,8 @@ class Group < Namespace has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember' alias_method :members, :group_members has_many :users, through: :group_members + has_many :project_group_links, dependent: :destroy + has_many :shared_projects, through: :project_group_links, source: :project validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? } validates :avatar, file_size: { maximum: 200.kilobytes.to_i } diff --git a/app/models/project.rb b/app/models/project.rb index 65829bec77a..2232637f1f1 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -151,6 +151,8 @@ class Project < ActiveRecord::Base has_many :releases, dependent: :destroy has_many :lfs_objects_projects, dependent: :destroy has_many :lfs_objects, through: :lfs_objects_projects + has_many :project_group_links, dependent: :destroy + has_many :invited_groups, through: :project_group_links, source: :group has_many :todos, dependent: :destroy has_one :import_data, dependent: :destroy, class_name: "ProjectImportData" diff --git a/app/models/project_group_link.rb b/app/models/project_group_link.rb new file mode 100644 index 00000000000..e52a6bd7c84 --- /dev/null +++ b/app/models/project_group_link.rb @@ -0,0 +1,36 @@ +class ProjectGroupLink < ActiveRecord::Base + GUEST = 10 + REPORTER = 20 + DEVELOPER = 30 + MASTER = 40 + + belongs_to :project + belongs_to :group + + validates :project_id, presence: true + validates :group_id, presence: true + validates :group_id, uniqueness: { scope: [:project_id], message: "already shared with this group" } + validates :group_access, presence: true + validates :group_access, inclusion: { in: Gitlab::Access.values }, presence: true + validate :different_group + + def self.access_options + Gitlab::Access.options + end + + def self.default_access + DEVELOPER + end + + def human_access + self.class.access_options.key(self.group_access) + end + + private + + def different_group + if self.group && self.project && self.project.group == self.group + errors.add(:base, "Project cannot be shared with the project it is in.") + end + end +end diff --git a/db/migrate/20130711063759_create_project_group_links.rb b/db/migrate/20130711063759_create_project_group_links.rb new file mode 100644 index 00000000000..395083f2a03 --- /dev/null +++ b/db/migrate/20130711063759_create_project_group_links.rb @@ -0,0 +1,10 @@ +class CreateProjectGroupLinks < ActiveRecord::Migration + def change + create_table :project_group_links do |t| + t.integer :project_id, null: false + t.integer :group_id, null: false + + t.timestamps + end + end +end diff --git a/db/migrate/20130820102832_add_access_to_project_group_link.rb b/db/migrate/20130820102832_add_access_to_project_group_link.rb new file mode 100644 index 00000000000..00e3947a6bb --- /dev/null +++ b/db/migrate/20130820102832_add_access_to_project_group_link.rb @@ -0,0 +1,5 @@ +class AddAccessToProjectGroupLink < ActiveRecord::Migration + def change + add_column :project_group_links, :group_access, :integer, null: false, default: ProjectGroupLink.default_access + end +end diff --git a/db/schema.rb b/db/schema.rb index a74b86d8e2f..89e8c9e67b0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -656,6 +656,14 @@ ActiveRecord::Schema.define(version: 20160309140734) do add_index "oauth_applications", ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree add_index "oauth_applications", ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree + create_table "project_group_links", force: :cascade do |t| + t.integer "project_id", null: false + t.integer "group_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.integer "group_access", default: 30, null: false + end + create_table "project_import_data", force: :cascade do |t| t.integer "project_id" t.text "data" @@ -749,9 +757,9 @@ ActiveRecord::Schema.define(version: 20160309140734) do t.string "type" t.string "title" t.integer "project_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "active", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.boolean "active", default: false, null: false t.text "properties" t.boolean "template", default: false t.boolean "push_events", default: true diff --git a/spec/factories/project_group_links.rb b/spec/factories/project_group_links.rb new file mode 100644 index 00000000000..e73cc05f9d7 --- /dev/null +++ b/spec/factories/project_group_links.rb @@ -0,0 +1,6 @@ +FactoryGirl.define do + factory :project_group_link do + project + group + end +end diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb new file mode 100644 index 00000000000..2fa6715fcaf --- /dev/null +++ b/spec/models/project_group_link_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe ProjectGroupLink do + describe "Associations" do + it { should belong_to(:group) } + it { should belong_to(:project) } + end + + describe "Validation" do + let!(:project_group_link) { create(:project_group_link) } + + it { should validate_presence_of(:project_id) } + it { should validate_uniqueness_of(:group_id).scoped_to(:project_id).with_message(/already shared/) } + it { should validate_presence_of(:group_id) } + it { should validate_presence_of(:group_access) } + end +end -- cgit v1.2.1 From 25c2349200153db914ab498bb4b14099a79db01a Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 11 Mar 2016 17:59:51 +0100 Subject: Added 8.6 upgrade guide for PostgreSQL users --- doc/update/8.5-to-8.6.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/update/8.5-to-8.6.md b/doc/update/8.5-to-8.6.md index e42f691cd32..a8167b2cf0b 100644 --- a/doc/update/8.5-to-8.6.md +++ b/doc/update/8.5-to-8.6.md @@ -105,6 +105,23 @@ via [/etc/default/gitlab]. [Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache [/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-6-stable/lib/support/init.d/gitlab.default.example#L37 +### 8. Updates for PostgreSQL Users + +Starting with 8.6 users using GitLab in combination with PostgreSQL are required +to have the "pg_trgm" extension enabled for all GitLab databases. If you're +using GitLab's Omnibus packages there's nothing you'll need to do manually as +this extension is enabled automatically. Users who install GitLab without using +Omnibus (e.g. by building from source) have to enable this extension manually. +To enable this extension run the following SQL command as a PostgreSQL super +user for _every_ GitLab database: + + CREATE EXTENSION IF NOT EXISTS pg_trgm; + +Certain operating systems might require the installation of extra packages for +this extension to be available. For example, users using Ubuntu will have to +install the "postgresql-contrib" package in order for this extension to be +available. + #### Init script Ensure you're still up-to-date with the latest init script changes: -- cgit v1.2.1 From 746ac56b6f92991bc15d3cd787094b9555825ac3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 11 Mar 2016 18:37:46 +0100 Subject: Add functionality to setup share of project with group via project settings Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/dispatcher.js.coffee | 2 ++ app/controllers/projects/group_links_controller.rb | 23 ++++++++++++ app/models/project.rb | 5 +++ app/views/layouts/nav/_project_settings.html.haml | 6 ++++ app/views/projects/group_links/index.html.haml | 41 ++++++++++++++++++++++ config/routes.rb | 2 ++ 6 files changed, 79 insertions(+) create mode 100644 app/controllers/projects/group_links_controller.rb create mode 100644 app/views/projects/group_links/index.html.haml diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 54b28f2dd8d..e964bba1325 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -103,6 +103,8 @@ class Dispatcher new ProjectFork() when 'projects:artifacts:browse' new BuildArtifacts() + when 'projects:group_links:index' + new GroupsSelect() switch path.first() when 'admin' diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb new file mode 100644 index 00000000000..4159e53bfa9 --- /dev/null +++ b/app/controllers/projects/group_links_controller.rb @@ -0,0 +1,23 @@ +class Projects::GroupLinksController < Projects::ApplicationController + layout 'project_settings' + before_action :authorize_admin_project! + + def index + @group_links = project.project_group_links.all + end + + def create + link = project.project_group_links.new + link.group_id = params[:link_group_id] + link.group_access = params[:link_group_access] + link.save + + redirect_to namespace_project_group_links_path(project.namespace, project) + end + + def destroy + project.project_group_links.find(params[:id]).destroy + + redirect_to namespace_project_group_links_path(project.namespace, project) + end +end diff --git a/app/models/project.rb b/app/models/project.rb index 2232637f1f1..56865459724 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -880,6 +880,11 @@ class Project < ActiveRecord::Base jira_tracker? && jira_service.active end + def allowed_to_share_with_group? + # TODO: replace with logic + true + end + def ci_commit(sha) ci_commits.find_by(sha: sha) end diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml index 3359716202f..dc3050f02e5 100644 --- a/app/views/layouts/nav/_project_settings.html.haml +++ b/app/views/layouts/nav/_project_settings.html.haml @@ -13,6 +13,12 @@ = icon('pencil-square-o fw') %span Project Settings + - if @project.allowed_to_share_with_group? + = nav_link(controller: :group_links) do + = link_to namespace_project_group_links_path(@project.namespace, @project), title: "Groups" do + = icon('share-square-o fw') + %span + Groups = nav_link(controller: :deploy_keys) do = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do = icon('key fw') diff --git a/app/views/projects/group_links/index.html.haml b/app/views/projects/group_links/index.html.haml new file mode 100644 index 00000000000..13f5fc141fa --- /dev/null +++ b/app/views/projects/group_links/index.html.haml @@ -0,0 +1,41 @@ +- page_title "Groups" +%h3.page_title Share project with other groups +%p.light + Projects can be stored in only one group at once. However you can share a project with other groups here. +%hr +- if @group_links.present? + .enabled-groups.panel.panel-default + .panel-heading + Already shared with + %ul.well-list + - @group_links.each do |group_link| + - group = group_link.group + %li + .pull-right + = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), method: :delete, class: 'btn btn-sm' do + %i.icon-remove + disable sharing + = link_to group do + %strong + %i.icon-folder-open + = group.name + %br + .light up to #{group_link.human_access} + + +.available-groups + %h4 + Can be shared with + %div + = form_tag namespace_project_group_links_path(@project.namespace, @project), method: :post, class: 'form-horizontal' do + .form-group + = label_tag :link_group_id, 'Group', class: 'control-label' + .col-sm-10 + = groups_select_tag(:link_group_id, skip_group: @project.group.try(:path)) + .form-group + = label_tag :link_group_access, 'Max access level', class: 'control-label' + .col-sm-10 + = select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control" + .form-actions + = submit_tag "Share", class: "btn btn-create" + diff --git a/config/routes.rb b/config/routes.rb index a918b5bd3f0..a0e0cc87f51 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -701,6 +701,8 @@ Rails.application.routes.draw do end end + resources :group_links, only: [:index, :create, :destroy], constraints: { id: /\d+/ } + resources :notes, only: [:index, :create, :destroy, :update], constraints: { id: /\d+/ } do member do delete :delete_attachment -- cgit v1.2.1 From f8163c81e7c765ea654ea81818eb3f8a9da7648e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 11 Mar 2016 18:42:16 +0100 Subject: Show shared projects on group page Signed-off-by: Dmitriy Zaporozhets --- app/controllers/groups_controller.rb | 2 ++ app/views/groups/_shared_projects.html.haml | 18 ++++++++++++++++++ app/views/groups/show.html.haml | 7 +++++++ 3 files changed, 27 insertions(+) create mode 100644 app/views/groups/_shared_projects.html.haml diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index f05c29e9974..bd6b44bdbbc 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -46,6 +46,8 @@ class GroupsController < Groups::ApplicationController @projects = @projects.sort(@sort = params[:sort]) @projects = @projects.page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank? + @shared_projects = @group.shared_projects + respond_to do |format| format.html diff --git a/app/views/groups/_shared_projects.html.haml b/app/views/groups/_shared_projects.html.haml new file mode 100644 index 00000000000..d707ad4272d --- /dev/null +++ b/app/views/groups/_shared_projects.html.haml @@ -0,0 +1,18 @@ +- if projects.present? + .panel.panel-default + .panel-heading + Projects shared with + %strong #{@group.name} + (#{projects.count}) + %ul.well-list + - projects.each do |project| + %li.project-row + = link_to namespace_project_path(project.namespace, project), class: dom_class(project) do + %span.namespace-name + - if project.namespace + = project.namespace.human_name + \/ + %span.project-name + = truncate(project.name, length: 25) + %span.arrow + %i.icon-angle-right diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 6148d8cb3d2..c64c986b5a4 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -35,6 +35,10 @@ %li = link_to "#projects", 'data-toggle' => 'tab' do Projects + - if @shared_projects.present? + %li + = link_to "#shared", 'data-toggle' => 'tab' do + Shared Projects - if can?(current_user, :read_group, @group) %div{ class: container_class } @@ -52,6 +56,9 @@ .tab-pane#projects = render "projects", projects: @projects + .tab-pane#shared + = render "shared_projects", projects: @shared_projects + - else %p.nav-links.no-top No projects to show -- cgit v1.2.1 From 8901336c78a9075a6a64205500e6019c40fd632f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 11 Mar 2016 18:46:01 +0100 Subject: Allow users to access project shared with their group Signed-off-by: Dmitriy Zaporozhets --- app/models/project_team.rb | 52 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 9629c7e1bb9..70a8bbaba65 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -160,7 +160,27 @@ class ProjectTeam end end - access.max + if project.invited_groups.any? && project.allowed_to_share_with_group? + access << max_invited_level(user_id) + end + + access.compact.max + end + + + def max_invited_level(user_id) + project.project_group_links.map do |group_link| + invited_group = group_link.group + access = invited_group.group_members.find_by(user_id: user_id).try(:access_field) + + # If group member has higher access level we should restrict it + # to max allowed access level + if access && access > group_link.group_access + access = group_link.group_access + end + + access + end.compact.max end private @@ -168,6 +188,35 @@ class ProjectTeam def fetch_members(level = nil) project_members = project.project_members group_members = group ? group.group_members : [] + invited_members = [] + + if project.invited_groups.any? && project.allowed_to_share_with_group? + project.project_group_links.each do |group_link| + invited_group = group_link.group + im = invited_group.group_members + + if level + int_level = GroupMember.access_level_roles[level.to_s.singularize.titleize] + + # Skip group members if we ask for masters + # but max group access is developers + next if int_level > group_link.group_access + + # If we ask for developers and max + # group access is developers we need to provide + # both group master, developers as devs + if int_level == group_link.group_access + im.where("access_level >= ?)", group_link.group_access) + else + im.send(level) + end + end + + invited_members << im + end + + invited_members = invited_members.flatten.compact + end if level project_members = project_members.send(level) @@ -175,6 +224,7 @@ class ProjectTeam end user_ids = project_members.pluck(:user_id) + user_ids.push(*invited_members.map(&:user_id)) if invited_members.any? user_ids.push(*group_members.pluck(:user_id)) if group User.where(id: user_ids) -- cgit v1.2.1 From 068fd5de8a45ef0814c500df10d3b9d39496fcd9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 11 Mar 2016 18:55:17 +0100 Subject: Add finders logic and tests for shared projects feature Signed-off-by: Dmitriy Zaporozhets --- app/finders/projects_finder.rb | 3 +- app/models/user.rb | 3 +- app/views/admin/groups/show.html.haml | 16 +++++++++ features/project/group_links.feature | 16 +++++++++ features/steps/project/project_group_links.rb | 50 +++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 features/project/group_links.feature create mode 100644 features/steps/project/project_group_links.rb diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb index 3b4e0362e04..93fc7c4b01c 100644 --- a/app/finders/projects_finder.rb +++ b/app/finders/projects_finder.rb @@ -43,7 +43,8 @@ class ProjectsFinder if current_user [ group_projects_for_user(current_user, group), - group.projects.public_and_internal_only + group.projects.public_and_internal_only, + group.shared_projects.visible_to_user(current_user) ] else [group.projects.public_only] diff --git a/app/models/user.rb b/app/models/user.rb index 505a547d8ec..e9d1f479433 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -818,7 +818,8 @@ class User < ActiveRecord::Base def projects_union Gitlab::SQL::Union.new([personal_projects.select(:id), groups_projects.select(:id), - projects.select(:id)]) + projects.select(:id), + groups.joins(:shared_projects).select(:project_id)]) end def ci_projects_union diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index f7fd156b84a..264fa1bf0cd 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -50,6 +50,22 @@ .panel-footer = paginate @projects, param_name: 'projects_page', theme: 'gitlab' + - if @group.shared_projects.any? + .panel.panel-default + .panel-heading + Projects shared with #{@group.name} + %span.badge + #{@group.shared_projects.count} + %ul.well-list + - @group.shared_projects.sort_by(&:name).each do |project| + %li + %strong + = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project] + %span.label.label-gray + = repository_size(project) + %span.pull-right.light + %span.monospace= project.path_with_namespace + ".git" + .col-md-6 - if can?(current_user, :admin_group_member, @group) .panel.panel-default diff --git a/features/project/group_links.feature b/features/project/group_links.feature new file mode 100644 index 00000000000..2657c4487ad --- /dev/null +++ b/features/project/group_links.feature @@ -0,0 +1,16 @@ +Feature: Project Group Links + Background: + Given I sign in as a user + And I own project "Shop" + And project "Shop" is shared with group "Ops" + And project "Shop" is not shared with group "Market" + And I visit project group links page + + Scenario: I should see list of groups + Then I should see project already shared with group "Ops" + Then I should see project is not shared with group "Market" + + @javascript + Scenario: I share project with group + When I select group "Market" for share + Then I should see project is shared with group "Market" diff --git a/features/steps/project/project_group_links.rb b/features/steps/project/project_group_links.rb new file mode 100644 index 00000000000..739a85e5fa4 --- /dev/null +++ b/features/steps/project/project_group_links.rb @@ -0,0 +1,50 @@ +class Spinach::Features::ProjectGroupLinks < Spinach::FeatureSteps + include SharedAuthentication + include SharedProject + include SharedPaths + include Select2Helper + + step 'I should see project already shared with group "Ops"' do + page.within '.enabled-groups' do + expect(page).to have_content "Ops" + end + end + + step 'I should see project is not shared with group "Market"' do + page.within '.enabled-groups' do + expect(page).not_to have_content "Market" + end + end + + step 'I select group "Market" for share' do + group = Group.find_by(path: 'market') + select2(group.id, from: "#link_group_id") + select "Master", from: 'link_group_access' + click_button "Share" + end + + step 'I should see project is shared with group "Market"' do + page.within '.enabled-groups' do + expect(page).to have_content "Market" + end + end + + step 'project "Shop" is shared with group "Ops"' do + group = create(:group, name: 'Ops') + share_link = project.project_group_links.new(group_access: Gitlab::Access::MASTER) + share_link.group_id = group.id + share_link.save! + end + + step 'project "Shop" is not shared with group "Market"' do + create(:group, name: 'Market', path: 'market') + end + + step 'I visit project group links page' do + visit namespace_project_group_links_path(project.namespace, project) + end + + def project + @project ||= Project.find_by_name "Shop" + end +end -- cgit v1.2.1 From 9a95b15552fa8920800274324aa65900360e8038 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 11 Mar 2016 19:03:19 +0100 Subject: Add share project from group lock Signed-off-by: Dmitriy Zaporozhets --- app/controllers/groups_controller.rb | 2 +- app/models/project.rb | 3 +-- app/views/groups/edit.html.haml | 9 +++++++++ db/migrate/20150930110012_add_group_share_lock.rb | 5 +++++ db/schema.rb | 7 ++++--- 5 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20150930110012_add_group_share_lock.rb diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index bd6b44bdbbc..e8d9d9fb344 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -133,7 +133,7 @@ class GroupsController < Groups::ApplicationController end def group_params - params.require(:group).permit(:name, :description, :path, :avatar, :public) + params.require(:group).permit(:name, :description, :path, :avatar, :public, :share_with_group_lock) end def load_events diff --git a/app/models/project.rb b/app/models/project.rb index 56865459724..40f8c4c83da 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -881,8 +881,7 @@ class Project < ActiveRecord::Base end def allowed_to_share_with_group? - # TODO: replace with logic - true + !namespace.share_with_group_lock end def ci_commit(sha) diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 3430f56a9c9..83936d39b16 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -23,6 +23,15 @@ %hr = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar" + .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 = f.submit 'Save group', class: "btn btn-save" diff --git a/db/migrate/20150930110012_add_group_share_lock.rb b/db/migrate/20150930110012_add_group_share_lock.rb new file mode 100644 index 00000000000..78d1a4538f2 --- /dev/null +++ b/db/migrate/20150930110012_add_group_share_lock.rb @@ -0,0 +1,5 @@ +class AddGroupShareLock < ActiveRecord::Migration + def change + add_column :namespaces, :share_with_group_lock, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 89e8c9e67b0..20dbb4f5a3e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -568,14 +568,15 @@ ActiveRecord::Schema.define(version: 20160309140734) do add_index "milestones", ["title"], name: "index_milestones_on_title", using: :btree create_table "namespaces", force: :cascade do |t| - t.string "name", null: false - t.string "path", null: false + t.string "name", null: false + t.string "path", null: false t.integer "owner_id" t.datetime "created_at" t.datetime "updated_at" t.string "type" - t.string "description", default: "", null: false + t.string "description", default: "", null: false t.string "avatar" + t.boolean "share_with_group_lock", default: false end add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree -- cgit v1.2.1 From a63eba9a2bebd6e33c3d1051a0d2fd08e024f546 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 8 Mar 2016 20:04:13 -0500 Subject: Add unit specs for `Note#active?` --- app/models/note.rb | 33 ++++++++++++++++---------- spec/models/note_spec.rb | 62 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/app/models/note.rb b/app/models/note.rb index 8b0610ff77e..0ea61b24955 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -172,26 +172,29 @@ class Note < ActiveRecord::Base Note.where(noteable_id: noteable_id, noteable_type: noteable_type, line_code: line_code).last.try(:diff) end - # Check if such line of code exists in merge request diff - # If exists - its active discussion - # If not - its outdated diff + # Check if this note is part of an "active" discussion + # + # This will always return true for anything except MergeRequest noteables, + # which have special logic. + # + # If the note's current diff cannot be matched in the MergeRequest's current + # diff, it's considered inactive. def active? return true unless self.diff return false unless noteable return @active if defined?(@active) - diffs = noteable.diffs(Commit.max_diff_options) - notable_diff = diffs.find { |d| d.new_path == self.diff.new_path } + noteable_diff = find_noteable_diff - return @active = false if notable_diff.nil? + if noteable_diff + parsed_lines = Gitlab::Diff::Parser.new.parse(noteable_diff.diff.each_line) - parsed_lines = Gitlab::Diff::Parser.new.parse(notable_diff.diff.each_line) - # We cannot use ||= because @active may be false - @active = parsed_lines.any? { |line_obj| line_obj.text == diff_line } - end + @active = parsed_lines.any? { |line_obj| line_obj.text == diff_line } + else + @active = false + end - def outdated? - !active? + @active end def diff_file_index @@ -375,6 +378,12 @@ class Note < ActiveRecord::Base private + # Find the diff on noteable that matches our own + def find_noteable_diff + diffs = noteable.diffs(Commit.max_diff_options) + diffs.find { |d| d.new_path == self.diff.new_path } + end + def awards_supported? (for_issue? || for_merge_request?) && !for_diff_line? end diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index cd620ea5440..b3ed7d6f8bd 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -152,7 +152,7 @@ describe Note, models: true do end end - describe :grouped_awards do + describe '.grouped_awards' do before do create :note, note: "smile", is_award: true create :note, note: "smile", is_award: true @@ -169,6 +169,66 @@ describe Note, models: true do end end + describe '#active?' do + it 'is always true when the note has no associated diff' do + note = build(:note) + + expect(note).to receive(:diff).and_return(nil) + + expect(note).to be_active + end + + it 'is never true when the note has no noteable associated' do + note = build(:note) + + expect(note).to receive(:diff).and_return(double) + expect(note).to receive(:noteable).and_return(nil) + + expect(note).not_to be_active + end + + it 'returns the memoized value if defined' do + note = build(:note) + + expect(note).to receive(:diff).and_return(double) + expect(note).to receive(:noteable).and_return(double) + + note.instance_variable_set(:@active, 'foo') + expect(note).not_to receive(:find_noteable_diff) + + expect(note.active?).to eq 'foo' + end + + context 'for a merge request noteable' do + it 'is false when noteable has no matching diff' do + merge = build_stubbed(:merge_request, :simple) + note = build(:note, noteable: merge) + + allow(note).to receive(:diff).and_return(double) + expect(note).to receive(:find_noteable_diff).and_return(nil) + + expect(note).not_to be_active + end + + it 'is true when noteable has a matching diff' do + merge = create(:merge_request, :simple) + + # Generate a real line_code value so we know it will match. We use a + # random line from a random diff just for funsies. + diff = merge.diffs.to_a.sample + line = Gitlab::Diff::Parser.new.parse(diff.diff.each_line).to_a.sample + code = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) + + # We're persisting in order to trigger the set_diff callback + note = create(:note, noteable: merge, line_code: code) + + # Make sure we don't get a false positive from a guard clause + expect(note).to receive(:find_noteable_diff).and_call_original + expect(note).to be_active + end + end + end + describe "editable?" do it "returns true" do note = build(:note) -- cgit v1.2.1 From aff1058c61cb8bc2ffbec42babb935828aa766ec Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 11 Mar 2016 15:32:12 -0500 Subject: Fix ordering in 8.5-to-8.6 update guide [ci skip] --- doc/update/8.5-to-8.6.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/doc/update/8.5-to-8.6.md b/doc/update/8.5-to-8.6.md index a8167b2cf0b..9a1b94ab369 100644 --- a/doc/update/8.5-to-8.6.md +++ b/doc/update/8.5-to-8.6.md @@ -105,35 +105,37 @@ via [/etc/default/gitlab]. [Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache [/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-6-stable/lib/support/init.d/gitlab.default.example#L37 +#### Init script + +Ensure you're still up-to-date with the latest init script changes: + + sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab + ### 8. Updates for PostgreSQL Users Starting with 8.6 users using GitLab in combination with PostgreSQL are required -to have the "pg_trgm" extension enabled for all GitLab databases. If you're +to have the `pg_trgm` extension enabled for all GitLab databases. If you're using GitLab's Omnibus packages there's nothing you'll need to do manually as this extension is enabled automatically. Users who install GitLab without using Omnibus (e.g. by building from source) have to enable this extension manually. To enable this extension run the following SQL command as a PostgreSQL super user for _every_ GitLab database: - CREATE EXTENSION IF NOT EXISTS pg_trgm; +```sql +CREATE EXTENSION IF NOT EXISTS pg_trgm; +``` Certain operating systems might require the installation of extra packages for this extension to be available. For example, users using Ubuntu will have to -install the "postgresql-contrib" package in order for this extension to be +install the `postgresql-contrib` package in order for this extension to be available. -#### Init script - -Ensure you're still up-to-date with the latest init script changes: - - sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab - -### 8. Start application +### 9. Start application sudo service gitlab start sudo service nginx restart -### 9. Check application status +### 10. Check application status Check if GitLab and its environment are configured correctly: -- cgit v1.2.1 From 55ceda12045ffb59187b7104a3b28a34e28a8b87 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 12 Mar 2016 14:45:14 +0100 Subject: Bring shared project feature tests from EE Signed-off-by: Dmitriy Zaporozhets --- features/admin/groups.feature | 5 ++++ features/project/team_management.feature | 5 ++++ features/steps/admin/groups.rb | 19 +++++++++++++ features/steps/project/team_management.rb | 19 +++++++++++++ spec/finders/projects_finder_spec.rb | 34 +++++++++++++++++++++++- spec/models/project_team_spec.rb | 44 +++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 1 deletion(-) diff --git a/features/admin/groups.feature b/features/admin/groups.feature index 2edb3964f70..ab7de7ac315 100644 --- a/features/admin/groups.feature +++ b/features/admin/groups.feature @@ -21,6 +21,11 @@ Feature: Admin Groups When I select user "John Doe" from user list as "Reporter" Then I should see "John Doe" in team list in every project as "Reporter" + Scenario: Shared projects + Given group has shared projects + When I visit group page + Then I should see project shared with group + @javascript Scenario: Remove user from group Given we have user "John Doe" in group diff --git a/features/project/team_management.feature b/features/project/team_management.feature index 06fb45c8bde..5888662fc3f 100644 --- a/features/project/team_management.feature +++ b/features/project/team_management.feature @@ -39,3 +39,8 @@ Feature: Project Team Management And I click link "Import team from another project" And I submit "Website" project for import team Then I should see "Mike" in team list as "Reporter" + + Scenario: See all members of projects shared group + Given I share project with group "OpenSource" + And I visit project "Shop" team page + Then I should see "Opensource" group user listing diff --git a/features/steps/admin/groups.rb b/features/steps/admin/groups.rb index 43fd91d0d4c..e1f1db2872f 100644 --- a/features/steps/admin/groups.rb +++ b/features/steps/admin/groups.rb @@ -73,6 +73,21 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps end end + step 'group has shared projects' do + share_link = shared_project.project_group_links.new(group_access: Gitlab::Access::MASTER) + share_link.group_id = current_group.id + share_link.save! + end + + step 'I visit group page' do + visit admin_group_path(current_group) + end + + step 'I should see project shared with group' do + expect(page).to have_content(shared_project.name_with_namespace) + expect(page).to have_content "Projects shared with" + end + step 'we have user "John Doe" in group' do current_group.add_reporter(user_john) end @@ -123,6 +138,10 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps @group ||= Group.first end + def shared_project + @shared_project ||= create(:empty_project) + end + def user_john @user_john ||= User.find_by(name: "John Doe") end diff --git a/features/steps/project/team_management.rb b/features/steps/project/team_management.rb index caad52def79..3fbcf770b62 100644 --- a/features/steps/project/team_management.rb +++ b/features/steps/project/team_management.rb @@ -123,4 +123,23 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps click_link('Remove user from team') end end + + step 'I share project with group "OpenSource"' do + project = Project.find_by(name: 'Shop') + os_group = create(:group, name: 'OpenSource') + create(:project, group: os_group) + @os_user1 = create(:user) + @os_user2 = create(:user) + os_group.add_owner(@os_user1) + os_group.add_user(@os_user2, Gitlab::Access::DEVELOPER) + share_link = project.project_group_links.new(group_access: Gitlab::Access::MASTER) + share_link.group_id = os_group.id + share_link.save! + end + + step 'I should see "Opensource" group user listing' do + expect(page).to have_content("Shared with OpenSource group, members with Master role (2)") + expect(page).to have_content(@os_user1.name) + expect(page).to have_content(@os_user2.name) + end end diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb index f32641ef0f6..fae0da9d898 100644 --- a/spec/finders/projects_finder_spec.rb +++ b/spec/finders/projects_finder_spec.rb @@ -17,6 +17,10 @@ describe ProjectsFinder do create(:project, :public, group: group, name: 'C', path: 'C') end + let!(:shared_project) do + create(:project, :private, name: 'D', path: 'D') + end + let(:finder) { described_class.new } describe 'without a group' do @@ -56,7 +60,35 @@ describe ProjectsFinder do describe 'with a user' do subject { finder.execute(user, group: group) } - it { is_expected.to eq([public_project, internal_project]) } + describe 'without shared projects' do + it { is_expected.to eq([public_project, internal_project]) } + end + + describe 'with shared projects and group membership' do + before do + group.add_user(user, Gitlab::Access::DEVELOPER) + + shared_project.project_group_links. + create(group_access: Gitlab::Access::MASTER, group: group) + end + + it do + is_expected.to eq([shared_project, public_project, internal_project]) + end + end + + describe 'with shared projects and project membership' do + before do + shared_project.team.add_user(user, Gitlab::Access::DEVELOPER) + + shared_project.project_group_links. + create(group_access: Gitlab::Access::MASTER, group: group) + end + + it do + is_expected.to eq([shared_project, public_project, internal_project]) + end + end end end end diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 7b63da005f0..bacb17a8883 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -67,6 +67,50 @@ describe ProjectTeam, models: true do end end + describe :max_invited_level 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_invited_level(master.id)).to eq(Gitlab::Access::DEVELOPER) } + 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 } + 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 + describe "#human_max_access" do it 'returns Master role' do user = create(:user) -- cgit v1.2.1 From e12e937b943be2d9dce062cde10b02b6474e170b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 12 Mar 2016 15:05:52 +0100 Subject: Bring share with group feature documentation from EE Signed-off-by: Dmitriy Zaporozhets --- doc/workflow/README.md | 2 ++ doc/workflow/groups/max_access_level.png | Bin 0 -> 135354 bytes .../groups/other_group_sees_shared_project.png | Bin 0 -> 118382 bytes doc/workflow/groups/share_project_with_groups.png | Bin 0 -> 118868 bytes doc/workflow/share_projects_with_other_groups.md | 30 +++++++++++++++++++++ doc/workflow/share_with_group.md | 13 +++++++++ doc/workflow/share_with_group.png | Bin 0 -> 53784 bytes 7 files changed, 45 insertions(+) create mode 100644 doc/workflow/groups/max_access_level.png create mode 100644 doc/workflow/groups/other_group_sees_shared_project.png create mode 100644 doc/workflow/groups/share_project_with_groups.png create mode 100644 doc/workflow/share_projects_with_other_groups.md create mode 100644 doc/workflow/share_with_group.md create mode 100644 doc/workflow/share_with_group.png diff --git a/doc/workflow/README.md b/doc/workflow/README.md index 2ac32373ce9..25893f948ea 100644 --- a/doc/workflow/README.md +++ b/doc/workflow/README.md @@ -13,6 +13,8 @@ - [Project forking workflow](forking_workflow.md) - [Project users](add-user/add-user.md) - [Protected branches](protected_branches.md) +- [Sharing a project with a group](share_with_group.md) +- [Share projects with other groups](share_projects_with_other_groups.md) - [Web Editor](web_editor.md) - [Releases](releases.md) - [Milestones](milestones.md) diff --git a/doc/workflow/groups/max_access_level.png b/doc/workflow/groups/max_access_level.png new file mode 100644 index 00000000000..71106a8a5a0 Binary files /dev/null and b/doc/workflow/groups/max_access_level.png differ diff --git a/doc/workflow/groups/other_group_sees_shared_project.png b/doc/workflow/groups/other_group_sees_shared_project.png new file mode 100644 index 00000000000..cbf2c3c1fdc Binary files /dev/null and b/doc/workflow/groups/other_group_sees_shared_project.png differ diff --git a/doc/workflow/groups/share_project_with_groups.png b/doc/workflow/groups/share_project_with_groups.png new file mode 100644 index 00000000000..a5dbc89fe90 Binary files /dev/null and b/doc/workflow/groups/share_project_with_groups.png differ diff --git a/doc/workflow/share_projects_with_other_groups.md b/doc/workflow/share_projects_with_other_groups.md new file mode 100644 index 00000000000..4c59f59c587 --- /dev/null +++ b/doc/workflow/share_projects_with_other_groups.md @@ -0,0 +1,30 @@ +# Share Projects with other Groups + +In GitLab Enterprise Edition you can share projects with other groups. +This makes it possible to add a group of users to a project with a single action. + +## Groups as collections of users + +In GitLab Community Edition groups are used primarily to [create collections of projects](groups.md). +In GitLab Enterprise Edition you can also take advantage of the fact that groups define collections of _users_, namely the group members. + +## Sharing a project with a group of users + +The primary mechanism to give a group of users, say 'Engineering', access to a project, say 'Project Acme', in GitLab is to make the 'Engineering' group the owner of 'Project Acme'. +But what if 'Project Acme' already belongs to another group, say 'Open Source'? +This is where the (Enterprise Edition only) group sharing feature can be of use. + +To share 'Project Acme' with the 'Engineering' group, go to the project settings page for 'Project Acme' and use the left navigation menu to go to the 'Groups' section. + +![The 'Groups' section in the project settings screen (Enterprise Edition only)](groups/share_project_with_groups.png) + +Now you can add the 'Engineering' group with the maximum access level of your choice. +After sharing 'Project Acme' with 'Engineering', the project is listed on the group dashboard. + +!['Project Acme' is listed as a shared project for 'Engineering'](groups/other_group_sees_shared_project.png) + +## Maximum access level + +!['Project Acme' is shared with 'Engineering' with a maximum access level of 'Developer'](groups/max_access_level.png) + +In the screenshot above, the maximum access level of 'Developer' for members from 'Engineering' means that users with higher access levels in 'Engineering' ('Master' or 'Owner') will only have 'Developer' access to 'Project Acme'. diff --git a/doc/workflow/share_with_group.md b/doc/workflow/share_with_group.md new file mode 100644 index 00000000000..3b7690973cb --- /dev/null +++ b/doc/workflow/share_with_group.md @@ -0,0 +1,13 @@ +# Sharing a project with a group + +If you want to share a single project in a group with another group, +you can do so easily. By setting the permission you can quickly +give a select group of users access to a project in a restricted manner. + +In a project go to the project settings -> groups. + +Now you can select a group that you want to share this project with and with +which maximum access level. Users in that group are able to access this project +with their set group access level, up to the maximum level that you've set. + +![Share a project with a group](share_with_group.png) diff --git a/doc/workflow/share_with_group.png b/doc/workflow/share_with_group.png new file mode 100644 index 00000000000..a0ca6f14552 Binary files /dev/null and b/doc/workflow/share_with_group.png differ -- cgit v1.2.1 From e1dffa32db3d2ac877c0fc6f1728566d46c9e93f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 12 Mar 2016 18:01:55 +0100 Subject: Render project members from shared group Signed-off-by: Dmitriy Zaporozhets --- .../projects/project_members_controller.rb | 1 + .../project_members/_shared_group_members.html.haml | 21 +++++++++++++++++++++ app/views/projects/project_members/index.html.haml | 3 +++ 3 files changed, 25 insertions(+) create mode 100644 app/views/projects/project_members/_shared_group_members.html.haml diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 8364fc293b7..e7bddc4a6f1 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -27,6 +27,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController end @project_member = @project.project_members.new + @project_group_links = @project.project_group_links end def create diff --git a/app/views/projects/project_members/_shared_group_members.html.haml b/app/views/projects/project_members/_shared_group_members.html.haml new file mode 100644 index 00000000000..62888e41935 --- /dev/null +++ b/app/views/projects/project_members/_shared_group_members.html.haml @@ -0,0 +1,21 @@ +- @project_group_links.each do |group_links| + - shared_group = group_links.group + - shared_group_users_count = group_links.group.group_members.count + .panel.panel-default + .panel-heading + Shared with + %strong #{shared_group.name} + group, members with + %strong #{group_links.human_access} + role (#{shared_group_users_count}) + - if current_user.can?(:admin_group, shared_group) + .panel-head-actions + = link_to group_group_members_path(shared_group), class: 'btn btn-sm' do + %i.fa.fa-pencil-square-o + Edit group members + %ul.content-list + - shared_group.group_members.order('access_level DESC').limit(20).each do |member| + = render 'groups/group_members/group_member', member: member, show_controls: false, show_roles: false + - if shared_group_users_count > 20 + %li + and #{shared_group_users_count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(shared_group)} diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 0f8848a5cbe..ebcfc907ebb 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -18,3 +18,6 @@ - if @group = render "group_members", members: @group_members + + - if @project_group_links.any? && @project.allowed_to_share_with_group? + = render "shared_group_members" -- cgit v1.2.1 From b9d13c11dee8f555b0d80fd5b9b6a42be7721461 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 10 Mar 2016 01:49:13 +0000 Subject: implements upcoming filter in milstones --- app/finders/issuable_finder.rb | 8 ++++++++ app/helpers/milestones_helper.rb | 1 + app/models/milestone.rb | 1 + 3 files changed, 10 insertions(+) diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index c88a420b412..410e6f6456c 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -94,6 +94,10 @@ class IssuableFinder params[:milestone_title].present? end + def upcoming? + params[:milestone_title] == 'Upcoming' + end + def filter_by_no_milestone? milestones? && params[:milestone_title] == Milestone::None.title end @@ -248,6 +252,10 @@ class IssuableFinder if milestones? if filter_by_no_milestone? items = items.where(milestone_id: [-1, nil]) + elsif upcoming? + upcoming = Milestone.where(project_id: projects) + .where('due_date > ?', Time.now).order(due_date: :asc).first + items = items.joins(:milestone).where(milestone: { title: upcoming.title }) else items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] }) diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb index e3e7daa49c5..e8ac8788d9d 100644 --- a/app/helpers/milestones_helper.rb +++ b/app/helpers/milestones_helper.rb @@ -59,6 +59,7 @@ module MilestonesHelper grouped_milestones = grouped_milestones.sort_by { |x| x.due_date.nil? ? epoch : x.due_date } grouped_milestones.unshift(Milestone::None) grouped_milestones.unshift(Milestone::Any) + grouped_milestones.unshift(Milestone::Upcoming) options_from_collection_for_select(grouped_milestones, 'name', 'title', params[:milestone_title]) end diff --git a/app/models/milestone.rb b/app/models/milestone.rb index e3b6c552f92..85f7d8a7754 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -19,6 +19,7 @@ class Milestone < ActiveRecord::Base MilestoneStruct = Struct.new(:title, :name, :id) None = MilestoneStruct.new('No Milestone', 'No Milestone', 0) Any = MilestoneStruct.new('Any Milestone', '', -1) + Upcoming = MilestoneStruct.new('Upcoming', '', -2) include InternalId include Sortable -- cgit v1.2.1 From 7530827ecae0596616623d1c4f7775b08d5ada3c Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 11 Mar 2016 17:46:14 +0000 Subject: fixes issues for mr acceptance --- app/finders/issuable_finder.rb | 13 ++++++------- app/models/milestone.rb | 7 ++++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 410e6f6456c..d592bdd0eb5 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -94,10 +94,6 @@ class IssuableFinder params[:milestone_title].present? end - def upcoming? - params[:milestone_title] == 'Upcoming' - end - def filter_by_no_milestone? milestones? && params[:milestone_title] == Milestone::None.title end @@ -248,14 +244,17 @@ class IssuableFinder items end + def upcoming? + params[:milestone_title] == '#upcoming' && projects + end + def by_milestone(items) if milestones? if filter_by_no_milestone? items = items.where(milestone_id: [-1, nil]) elsif upcoming? - upcoming = Milestone.where(project_id: projects) - .where('due_date > ?', Time.now).order(due_date: :asc).first - items = items.joins(:milestone).where(milestone: { title: upcoming.title }) + upcoming = Milestone.upcoming(projects) + items = items.joins(:milestone).where(milestones: { title: upcoming.title }) else items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] }) diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 85f7d8a7754..7697072d231 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -19,7 +19,7 @@ class Milestone < ActiveRecord::Base MilestoneStruct = Struct.new(:title, :name, :id) None = MilestoneStruct.new('No Milestone', 'No Milestone', 0) Any = MilestoneStruct.new('Any Milestone', '', -1) - Upcoming = MilestoneStruct.new('Upcoming', '', -2) + Upcoming = MilestoneStruct.new('Upcoming', '#upcoming', -2) include InternalId include Sortable @@ -82,6 +82,11 @@ class Milestone < ActiveRecord::Base super("milestones", /(?\d+)/) end + def self.upcoming(projects) + self.where(project_id: projects) + .where('due_date > ?', Time.now). order(due_date: :asc).first + end + def to_reference(from_project = nil) escaped_title = self.title.gsub("]", "\\]") -- cgit v1.2.1 From 0291473b98b457e85657aac29520b5f2b5b631ec Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Sat, 12 Mar 2016 16:54:05 +0000 Subject: fixes issues --- app/finders/issuable_finder.rb | 4 ++-- app/models/milestone.rb | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index d592bdd0eb5..5e22aca45f7 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -245,7 +245,7 @@ class IssuableFinder end def upcoming? - params[:milestone_title] == '#upcoming' && projects + params[:milestone_title] == '#upcoming' end def by_milestone(items) @@ -253,7 +253,7 @@ class IssuableFinder if filter_by_no_milestone? items = items.where(milestone_id: [-1, nil]) elsif upcoming? - upcoming = Milestone.upcoming(projects) + upcoming = Milestone.where(project_id: projects).upcoming items = items.joins(:milestone).where(milestones: { title: upcoming.title }) else items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] }) diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 7697072d231..374590ba0c5 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -82,9 +82,8 @@ class Milestone < ActiveRecord::Base super("milestones", /(?\d+)/) end - def self.upcoming(projects) - self.where(project_id: projects) - .where('due_date > ?', Time.now). order(due_date: :asc).first + def self.upcoming + self.where('due_date > ?', Time.now).order(due_date: :asc).first end def to_reference(from_project = nil) -- cgit v1.2.1 From 8e6bd86cf26dd6e659fc7ccaf7361029b256891a Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Sat, 12 Mar 2016 17:24:33 +0000 Subject: adds my name to changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index d4554b96190..afef4b578c4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -35,6 +35,7 @@ v 8.5.5 - Prevent a 500 error in Todos when author was removed - Fix pagination for filtered dashboard and explore pages - Fix "Show all" link behavior + - Add #upcoming filter to Milestone filter (Tiago Botelho) v 8.5.4 - Do not cache requests for badges (including builds badge) -- cgit v1.2.1 From b94bdb698dedb519a8478440a3dc8a763856b6a0 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Sat, 12 Mar 2016 17:44:29 +0000 Subject: removes tab and replaces with space in changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index afef4b578c4..2535a78af48 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -36,6 +36,7 @@ v 8.5.5 - Fix pagination for filtered dashboard and explore pages - Fix "Show all" link behavior - Add #upcoming filter to Milestone filter (Tiago Botelho) + - Add #upcoming filter to Milestone filter (Tiago Botelho) v 8.5.4 - Do not cache requests for badges (including builds badge) -- cgit v1.2.1 From e8b3b92ddebc47595fe4b69dc5b5a3a6dd1365ab Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 13 Mar 2016 11:46:16 +0100 Subject: Bring share project with group API from EE Signed-off-by: Dmitriy Zaporozhets --- doc/api/projects.md | 14 ++++++++++++++ lib/api/entities.rb | 4 ++++ lib/api/projects.rb | 27 +++++++++++++++++++++++++++ spec/requests/api/projects_spec.rb | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index 9e9486cd87a..3703f4b327a 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -619,6 +619,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 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 Also called Project Hooks and Webhooks. diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 5b5b8bd044b..d96eaef7c0a 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -243,6 +243,10 @@ module API end end + class ProjectGroupLink < Grape::Entity + expose :id, :project_id, :group_id, :group_access + end + class Namespace < Grape::Entity expose :id, :path, :kind end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 6067c8b4a5e..6fcb5261e40 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -290,6 +290,33 @@ module API end end + # Share project with group + # + # Parameters: + # id (required) - The ID of a project + # group_id (required) - The ID of a group + # group_access (required) - Level of permissions for sharing + # + # Example Request: + # POST /projects/:id/share + post ":id/share" do + authorize! :admin_project, user_project + 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.group_id = params[:group_id] + link.group_access = params[:group_access] + if link.save + present link, with: Entities::ProjectGroupLink + else + render_api_error!(link.errors.full_messages.first, 409) + end + end + # Upload a file # # Parameters: diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 9f2365a4832..a6699cdc81c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -747,6 +747,42 @@ describe API::API, api: true do end end + describe "POST /projects/:id/share" do + let(:group) { create(:group) } + + it "should share project with group" do + expect do + post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER + end.to change { ProjectGroupLink.count }.by(1) + + expect(response.status).to eq 201 + expect(json_response['group_id']).to eq group.id + expect(json_response['group_access']).to eq Gitlab::Access::DEVELOPER + end + + it "should return a 400 error when group id is not given" do + post api("/projects/#{project.id}/share", user), group_access: Gitlab::Access::DEVELOPER + expect(response.status).to eq 400 + end + + it "should return a 400 error when access level is not given" do + post api("/projects/#{project.id}/share", user), group_id: group.id + expect(response.status).to eq 400 + 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 + post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: 1234 + expect(response.status).to eq 409 + expect(json_response['message']).to eq 'Group access is not included in the list' + end + end + describe 'GET /projects/search/:query' do let!(:query) { 'query'} let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) } -- cgit v1.2.1 From 1cefb73a9c067b1e2367a28b5c6852cf52d6b886 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 7 Mar 2016 10:06:54 +0100 Subject: Check redirect path in the continue_params Fixes https://dev.gitlab.org/gitlab/gitlabhq/issues/2649 https://gitlab.com/gitlab-org/gitlab-ce/issues/13956 --- app/controllers/concerns/continue_to_params.rb | 13 +++++++++++++ app/controllers/projects/forks_controller.rb | 13 ++----------- app/controllers/projects/imports_controller.rb | 12 ++---------- 3 files changed, 17 insertions(+), 21 deletions(-) create mode 100644 app/controllers/concerns/continue_to_params.rb diff --git a/app/controllers/concerns/continue_to_params.rb b/app/controllers/concerns/continue_to_params.rb new file mode 100644 index 00000000000..8b6c7051968 --- /dev/null +++ b/app/controllers/concerns/continue_to_params.rb @@ -0,0 +1,13 @@ +module ContinueToParams + extend ActiveSupport::Concern + + def continue_params + continue_params = params[:continue] + return nil unless continue_params + + continue_params = continue_params.permit(:to, :notice, :notice_now) + continue_params[:to] = root_url unless continue_params[:to].start_with?('/') + + continue_params + end +end diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index 7b202f3862f..c4884c13b12 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -1,4 +1,6 @@ class Projects::ForksController < Projects::ApplicationController + include ContinueToParams + # Authorize before_action :require_non_empty_project before_action :authorize_download_code! @@ -53,15 +55,4 @@ class Projects::ForksController < Projects::ApplicationController render :error end end - - private - - def continue_params - continue_params = params[:continue] - if continue_params - continue_params.permit(:to, :notice, :notice_now) - else - nil - end - end end diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb index 196996f1752..3756fc9139c 100644 --- a/app/controllers/projects/imports_controller.rb +++ b/app/controllers/projects/imports_controller.rb @@ -1,4 +1,6 @@ class Projects::ImportsController < Projects::ApplicationController + include ContinueToParams + # Authorize before_action :authorize_admin_project! before_action :require_no_repo, only: [:new, :create] @@ -44,16 +46,6 @@ class Projects::ImportsController < Projects::ApplicationController private - def continue_params - continue_params = params[:continue] - - if continue_params - continue_params.permit(:to, :notice, :notice_now) - else - nil - end - end - def finished_notice if @project.forked? 'The project was successfully forked.' -- cgit v1.2.1 From dfb96ed84bd7533abc411b148f0b27bf65321b3e Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 7 Mar 2016 10:36:16 +0100 Subject: ContinueToParams -> ContinueParams --- CHANGELOG | 1 + app/controllers/concerns/continue_params.rb | 13 +++++++++++++ app/controllers/concerns/continue_to_params.rb | 13 ------------- app/controllers/projects/forks_controller.rb | 2 +- app/controllers/projects/imports_controller.rb | 2 +- 5 files changed, 16 insertions(+), 15 deletions(-) create mode 100644 app/controllers/concerns/continue_params.rb delete mode 100644 app/controllers/concerns/continue_to_params.rb diff --git a/CHANGELOG b/CHANGELOG index d4554b96190..1929b6306db 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -45,6 +45,7 @@ v 8.5.3 - Show commit message in JIRA mention comment - Makes issue page and merge request page usable on mobile browsers. - Improved UI for profile settings + - Continue parameters are checked to ensure redirection goes to the same instance v 8.5.2 - Fix sidebar overlapping content when screen width was below 1200px diff --git a/app/controllers/concerns/continue_params.rb b/app/controllers/concerns/continue_params.rb new file mode 100644 index 00000000000..2ff7250922d --- /dev/null +++ b/app/controllers/concerns/continue_params.rb @@ -0,0 +1,13 @@ +module ContinueParams + extend ActiveSupport::Concern + + def continue_params + continue_params = params[:continue] + return nil unless continue_params + + continue_params = continue_params.permit(:to, :notice, :notice_now) + return unless continue_params[:to] && continue_params[:to].start_with?('/') + + continue_params + end +end diff --git a/app/controllers/concerns/continue_to_params.rb b/app/controllers/concerns/continue_to_params.rb deleted file mode 100644 index 8b6c7051968..00000000000 --- a/app/controllers/concerns/continue_to_params.rb +++ /dev/null @@ -1,13 +0,0 @@ -module ContinueToParams - extend ActiveSupport::Concern - - def continue_params - continue_params = params[:continue] - return nil unless continue_params - - continue_params = continue_params.permit(:to, :notice, :notice_now) - continue_params[:to] = root_url unless continue_params[:to].start_with?('/') - - continue_params - end -end diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index c4884c13b12..a1b8632df98 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -1,5 +1,5 @@ class Projects::ForksController < Projects::ApplicationController - include ContinueToParams + include ContinueParams # Authorize before_action :require_non_empty_project diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb index 3756fc9139c..7756f0f0ed3 100644 --- a/app/controllers/projects/imports_controller.rb +++ b/app/controllers/projects/imports_controller.rb @@ -1,5 +1,5 @@ class Projects::ImportsController < Projects::ApplicationController - include ContinueToParams + include ContinueParams # Authorize before_action :authorize_admin_project! -- cgit v1.2.1 From d3b7633da4a3964eb4609c7591763aa8e43fd0eb Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Sun, 13 Mar 2016 12:19:27 +0000 Subject: fixes small issues --- CHANGELOG | 1 - app/finders/issuable_finder.rb | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2535a78af48..b7bc48802d3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -35,7 +35,6 @@ v 8.5.5 - Prevent a 500 error in Todos when author was removed - Fix pagination for filtered dashboard and explore pages - Fix "Show all" link behavior - - Add #upcoming filter to Milestone filter (Tiago Botelho) - Add #upcoming filter to Milestone filter (Tiago Botelho) v 8.5.4 diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 5e22aca45f7..19e8c7a92be 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -244,7 +244,7 @@ class IssuableFinder items end - def upcoming? + def filter_by_upcoming_milestone? params[:milestone_title] == '#upcoming' end @@ -252,7 +252,7 @@ class IssuableFinder if milestones? if filter_by_no_milestone? items = items.where(milestone_id: [-1, nil]) - elsif upcoming? + elsif filter_by_upcoming_milestone? upcoming = Milestone.where(project_id: projects).upcoming items = items.joins(:milestone).where(milestones: { title: upcoming.title }) else -- cgit v1.2.1 From 5352ec2e21ba72d77a542b158ce1a98a1a3a9389 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 7 Mar 2016 11:45:14 +0100 Subject: Fix denting and spec --- CHANGELOG | 2 +- app/controllers/concerns/continue_params.rb | 2 +- spec/controllers/projects/imports_controller_spec.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1929b6306db..7c63414e580 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -29,6 +29,7 @@ v 8.6.0 (unreleased) - Add main language of a project in the list of projects (Tiago Botelho) - Add ability to show archived projects on dashboard, explore and group pages - Move group activity to separate page + - Continue parameters are checked to ensure redirection goes to the same instance v 8.5.5 - Ensure removing a project removes associated Todo entries @@ -45,7 +46,6 @@ v 8.5.3 - Show commit message in JIRA mention comment - Makes issue page and merge request page usable on mobile browsers. - Improved UI for profile settings - - Continue parameters are checked to ensure redirection goes to the same instance v 8.5.2 - Fix sidebar overlapping content when screen width was below 1200px diff --git a/app/controllers/concerns/continue_params.rb b/app/controllers/concerns/continue_params.rb index 2ff7250922d..0a995c45bdf 100644 --- a/app/controllers/concerns/continue_params.rb +++ b/app/controllers/concerns/continue_params.rb @@ -5,7 +5,7 @@ module ContinueParams continue_params = params[:continue] return nil unless continue_params - continue_params = continue_params.permit(:to, :notice, :notice_now) + continue_params = continue_params.permit(:to, :notice, :notice_now) return unless continue_params[:to] && continue_params[:to].start_with?('/') continue_params diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb index 0147bd2b953..2acbba469e3 100644 --- a/spec/controllers/projects/imports_controller_spec.rb +++ b/spec/controllers/projects/imports_controller_spec.rb @@ -19,7 +19,7 @@ describe Projects::ImportsController do end it 'sets flash.now if params is present' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: { notice_now: 'Started' } + get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: { to: '/', notice_now: 'Started' } expect(flash.now[:notice]).to eq 'Started' end @@ -45,7 +45,7 @@ describe Projects::ImportsController do end it 'sets flash.now if params is present' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: { notice_now: 'In progress' } + get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: { to: '/', notice_now: 'In progress' } expect(flash.now[:notice]).to eq 'In progress' end -- cgit v1.2.1 From ab0af56201413fea81cf42367671ec9a845315c7 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 13 Mar 2016 17:22:10 -0700 Subject: Use Capybara find methods and remove sleeps in feature specs in "All Issues" filter --- app/views/shared/issuable/_filter.html.haml | 2 +- features/steps/dashboard/issues.rb | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index c3fbba2ba54..e62d80aeb2c 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -15,7 +15,7 @@ .filter-item.inline - if params[:assignee_id] = hidden_field_tag(:assignee_id, params[:assignee_id]) - = dropdown_tag("Assignee", options: { toggle_class: "js-user-search js-filter-submit", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable", + = dropdown_tag("Assignee", options: { toggle_class: "js-user-search js-filter-submit js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable", placeholder: "Search assignee", data: { any_user: "Any Author", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id" } }) .filter-item.inline.milestone-filter diff --git a/features/steps/dashboard/issues.rb b/features/steps/dashboard/issues.rb index d723300f485..3072c790a4a 100644 --- a/features/steps/dashboard/issues.rb +++ b/features/steps/dashboard/issues.rb @@ -44,14 +44,11 @@ class Spinach::Features::DashboardIssues < Spinach::FeatureSteps end step 'I click "All" link' do - execute_script('$(".js-user-search").first().click()') - sleep 1 - execute_script('$(".js-user-search").first().parent().find("li a").first().click()') - sleep 1 - execute_script('$(".js-user-search").eq(1).click()') - sleep 1 - execute_script('$(".js-user-search").eq(1).parent().find("li a").first().click()') - sleep 1 + find('.js-author-search').click + find('.dropdown-menu-user-full-name', match: :first).click + + find('.js-assignee-search').click + find('.dropdown-menu-user-full-name', match: :first).click end def should_see(issue) -- cgit v1.2.1 From f0c73a5bdbbf07c6668b9ee50f38ba4f4813eabd Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 13 Mar 2016 22:09:42 -0700 Subject: Remove sleeps from network graph feature spec --- features/project/network_graph.feature | 3 ++- features/steps/project/network_graph.rb | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/features/project/network_graph.feature b/features/project/network_graph.feature index 6cc89a15a78..89a02706bd2 100644 --- a/features/project/network_graph.feature +++ b/features/project/network_graph.feature @@ -34,9 +34,10 @@ Feature: Project Network Graph @javascript Scenario: I should filter selected tag When I switch ref to "v1.0.0" + Then page should have "v1.0.0" in title Then page should have content not containing "v1.0.0" When click "Show only selected branch" checkbox - Then page should not have content not containing "v1.0.0" + Then page should only have content from "v1.0.0" When click "Show only selected branch" checkbox Then page should have content not containing "v1.0.0" diff --git a/features/steps/project/network_graph.rb b/features/steps/project/network_graph.rb index 7a83d32a240..9b59b682676 100644 --- a/features/steps/project/network_graph.rb +++ b/features/steps/project/network_graph.rb @@ -41,17 +41,14 @@ class Spinach::Features::ProjectNetworkGraph < Spinach::FeatureSteps When 'I switch ref to "feature"' do select 'feature', from: 'ref' - sleep 2 end When 'I switch ref to "v1.0.0"' do select 'v1.0.0', from: 'ref' - sleep 2 end When 'click "Show only selected branch" checkbox' do find('#filter_ref').click - sleep 2 end step 'page should have content not containing "v1.0.0"' do @@ -60,7 +57,11 @@ class Spinach::Features::ProjectNetworkGraph < Spinach::FeatureSteps end end - step 'page should not have content not containing "v1.0.0"' do + step 'page should have "v1.0.0" in title' do + expect(page).to have_css 'title', text: 'Network ยท v1.0.0', visible: false + end + + step 'page should only have content from "v1.0.0"' do page.within '.network-graph' do expect(page).not_to have_content 'Change some files' end -- cgit v1.2.1 From 35aca2d5fdd8d59e2e8ed4e6ce28838ea5bc7f86 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 14 Mar 2016 13:49:53 +0000 Subject: Fixed tests for MR & issue filters --- app/assets/javascripts/gl_dropdown.js.coffee | 4 +++- app/views/shared/issuable/_filter.html.haml | 2 +- features/steps/dashboard/issues.rb | 8 +++----- features/steps/dashboard/merge_requests.rb | 20 +++++++------------- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 8e1449bc59c..b94de4c7b5e 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -238,13 +238,15 @@ class GitLabDropdown selectedObject = @renderedData[selectedIndex] value = if @options.id then @options.id(selectedObject, el) else selectedObject.id + if !value? + field.remove() + if @options.multiSelect oldValue = field.val() if oldValue value = "#{oldValue},#{value}" else @dropdown.find(ACTIVE_CLASS).removeClass ACTIVE_CLASS - field.remove() # Toggle active class for the tick mark el.toggleClass "is-active" diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index e62d80aeb2c..4df96a06dbe 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -15,7 +15,7 @@ .filter-item.inline - if params[:assignee_id] = hidden_field_tag(:assignee_id, params[:assignee_id]) - = dropdown_tag("Assignee", options: { toggle_class: "js-user-search js-filter-submit js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable", + = dropdown_tag("Assignee", options: { toggle_class: "js-user-search js-filter-submit js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee", placeholder: "Search assignee", data: { any_user: "Any Author", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id" } }) .filter-item.inline.milestone-filter diff --git a/features/steps/dashboard/issues.rb b/features/steps/dashboard/issues.rb index 3072c790a4a..f4a56865532 100644 --- a/features/steps/dashboard/issues.rb +++ b/features/steps/dashboard/issues.rb @@ -36,11 +36,9 @@ class Spinach::Features::DashboardIssues < Spinach::FeatureSteps end step 'I click "Authored by me" link' do - execute_script('$("#assignee_id").val("")') - execute_script('$(".js-user-search").first().click()') - sleep 1 - execute_script("$('.dropdown-content li:contains(\"#{current_user.to_reference}\") a').click()") - sleep 1 + find("#assignee_id").set("") + find(".js-author-search", match: :first).click + find(".dropdown-menu-author li a", match: :first, text: current_user.to_reference).click end step 'I click "All" link' do diff --git a/features/steps/dashboard/merge_requests.rb b/features/steps/dashboard/merge_requests.rb index 7fc0e444e86..a2adc87f8ef 100644 --- a/features/steps/dashboard/merge_requests.rb +++ b/features/steps/dashboard/merge_requests.rb @@ -40,22 +40,16 @@ class Spinach::Features::DashboardMergeRequests < Spinach::FeatureSteps end step 'I click "Authored by me" link' do - execute_script('$("#assignee_id").val("")') - execute_script('$(".js-user-search").first().click()') - sleep 0.5 - execute_script("$('.dropdown-content li:contains(\"#{current_user.to_reference}\") a').click()") - sleep 2 + find("#assignee_id").set("") + find(".js-author-search", match: :first).click + find(".dropdown-menu-author li a", match: :first, text: current_user.to_reference).click end step 'I click "All" link' do - execute_script('$(".js-user-search").first().click()') - sleep 0.5 - execute_script('$(".js-user-search").first().parent().find("li a").first().click()') - sleep 2 - execute_script('$(".js-user-search").eq(1).click()') - sleep 0.5 - execute_script('$(".js-user-search").eq(1).parent().find("li a").first().click()') - sleep 2 + find(".js-author-search").click + find(".dropdown-menu-author li a", match: :first).click + find(".js-assignee-search").click + find(".dropdown-menu-assignee li a", match: :first).click end def should_see(merge_request) -- cgit v1.2.1 From d26bd026d92d9b06e207cc7ecf2d9e899151c155 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 14 Mar 2016 11:53:42 -0400 Subject: Update GITLAB_SHELL_VERSION to match EE [ci skip] --- GITLAB_SHELL_VERSION | 2 +- doc/update/8.5-to-8.6.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index a04abec9149..bc02b8685c1 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -2.6.10 +2.6.11 diff --git a/doc/update/8.5-to-8.6.md b/doc/update/8.5-to-8.6.md index 9a1b94ab369..024f6e8a433 100644 --- a/doc/update/8.5-to-8.6.md +++ b/doc/update/8.5-to-8.6.md @@ -37,7 +37,7 @@ sudo -u git -H git checkout 8-6-stable-ee ```bash cd /home/git/gitlab-shell sudo -u git -H git fetch --all -sudo -u git -H git checkout v2.6.10 +sudo -u git -H git checkout v2.6.11 ``` ### 5. Update gitlab-workhorse -- cgit v1.2.1 From 09d3cdfd9eed89023a6dc0244df7165a1b3dc52a Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 14 Mar 2016 16:03:17 +0000 Subject: Changed project home icon Closes #14196 --- app/views/layouts/nav/_project.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 319974e12c5..0ae83ee01eb 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -16,7 +16,7 @@ = nav_link(path: 'projects#show', html_options: {class: 'home'}) do = link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do - = icon('home fw') + = icon('bookmark fw') %span Project = nav_link(path: 'projects#activity') do -- cgit v1.2.1