From b6bd4856a33df3d144be66c4ed1f1396009bb08b Mon Sep 17 00:00:00 2001 From: devaroop Date: Wed, 2 Oct 2013 20:39:29 +0530 Subject: [PATCH 001/112] getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys --- app/controllers/profiles/keys_controller.rb | 18 ++++++++++++++++++ app/models/user.rb | 4 ++++ config/routes.rb | 3 +++ 3 files changed, 25 insertions(+) diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index c36dae2abd..2b991957b7 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -1,5 +1,6 @@ class Profiles::KeysController < ApplicationController layout "profile" + skip_before_filter :authenticate_user!, only: [:get_keys] def index @keys = current_user.keys.order('id DESC').all @@ -32,4 +33,21 @@ class Profiles::KeysController < ApplicationController format.js { render nothing: true } end end + + #get all keys of a user(params[:username]) in a text format + #helpful for sysadmins to put in respective servers + def get_keys + if params[:username].present? + begin + user = User.find_by_username(params[:username]) + user.present? ? (render :text => user.all_ssh_keys) : + (render_404 and return) + rescue => e + render text: e.message + end + else + render_404 and return + end + end + end diff --git a/app/models/user.rb b/app/models/user.rb index f1f93eadc1..225c97d35f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -391,4 +391,8 @@ class User < ActiveRecord::Base self end + + def all_ssh_keys + keys.collect{|x| x.key}.join("\n") + end end diff --git a/config/routes.rb b/config/routes.rb index 612a7327ec..1d2b4d7373 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,6 +11,9 @@ Gitlab::Application.routes.draw do API::API.logger Rails.logger mount API::API => '/api' + #get all keys of user + get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ } + constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? } constraints constraint do mount Sidekiq::Web, at: "/admin/sidekiq", as: :sidekiq From b9d58c4cecd06be74c3cc32ccfb522b31544ab2e Mon Sep 17 00:00:00 2001 From: devaroop Date: Wed, 2 Oct 2013 20:39:29 +0530 Subject: [PATCH 002/112] getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys changelog updated to include ssh key retrieval feature update --- CHANGELOG | 1 + app/controllers/profiles/keys_controller.rb | 18 ++++++++++++++++++ app/models/user.rb | 4 ++++ config/routes.rb | 3 +++ 4 files changed, 26 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index c1107717fc..1459ef84ae 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,5 @@ v 6.2.0 + - Retrieving user ssh keys publically(github style): http://__HOST__/__USERNAME__.keys - Public projects are visible from the outside - Add group access to permissions page - Require current password to change one diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index c36dae2abd..2b991957b7 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -1,5 +1,6 @@ class Profiles::KeysController < ApplicationController layout "profile" + skip_before_filter :authenticate_user!, only: [:get_keys] def index @keys = current_user.keys.order('id DESC').all @@ -32,4 +33,21 @@ class Profiles::KeysController < ApplicationController format.js { render nothing: true } end end + + #get all keys of a user(params[:username]) in a text format + #helpful for sysadmins to put in respective servers + def get_keys + if params[:username].present? + begin + user = User.find_by_username(params[:username]) + user.present? ? (render :text => user.all_ssh_keys) : + (render_404 and return) + rescue => e + render text: e.message + end + else + render_404 and return + end + end + end diff --git a/app/models/user.rb b/app/models/user.rb index f1f93eadc1..225c97d35f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -391,4 +391,8 @@ class User < ActiveRecord::Base self end + + def all_ssh_keys + keys.collect{|x| x.key}.join("\n") + end end diff --git a/config/routes.rb b/config/routes.rb index 612a7327ec..1d2b4d7373 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,6 +11,9 @@ Gitlab::Application.routes.draw do API::API.logger Rails.logger mount API::API => '/api' + #get all keys of user + get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ } + constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? } constraints constraint do mount Sidekiq::Web, at: "/admin/sidekiq", as: :sidekiq From 17105038caf237687ad0fc9f34bf5f368d0cc8a5 Mon Sep 17 00:00:00 2001 From: Gabe Martin-Dempesy Date: Sat, 2 Nov 2013 17:12:29 -0500 Subject: [PATCH 003/112] add rake gitlab:import: all_users_to_all_groups and user_to_groups I opted for admins to be added as "owners" instead of "masters" because project masters can managers members, but only group owners can manage members. --- doc/raketasks/user_management.md | 16 +++++++++++++++ lib/tasks/gitlab/bulk_add_permission.rake | 24 +++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md index 8fa2ed1311..345886f4ab 100644 --- a/doc/raketasks/user_management.md +++ b/doc/raketasks/user_management.md @@ -14,3 +14,19 @@ Notes: ``` bundle exec rake gitlab:import:all_users_to_all_projects ``` + +### Add user as a developer to all projects + +``` +bundle exec rake gitlab:import:user_to_groups[username@domain.tld] +``` + +### Add all users to all groups + +Notes: + +* admin users are added as owners so they can add additional users to the group + +``` +bundle exec rake gitlab:import:all_users_to_all_groups +``` diff --git a/lib/tasks/gitlab/bulk_add_permission.rake b/lib/tasks/gitlab/bulk_add_permission.rake index c270232edb..22f6a1544b 100644 --- a/lib/tasks/gitlab/bulk_add_permission.rake +++ b/lib/tasks/gitlab/bulk_add_permission.rake @@ -20,5 +20,29 @@ namespace :gitlab do puts "Importing #{user.email} users into #{project_ids.size} projects" UsersProject.add_users_into_projects(project_ids, Array.wrap(user.id), UsersProject::DEVELOPER) end + + desc "GITLAB | Add all users to all groups (admin users are added as owners)" + task all_users_to_all_groups: :environment do |t, args| + user_ids = User.where(admin: false).pluck(:id) + admin_ids = User.where(admin: true).pluck(:id) + groups = Group.all + + puts "Importing #{user_ids.size} users into #{groups.size} groups" + puts "Importing #{admin_ids.size} admins into #{groups.size} groups" + groups.each do |group| + group.add_users(user_ids, UsersGroup::DEVELOPER) + group.add_users(admin_ids, UsersGroup::OWNER) + end + end + + desc "GITLAB | Add a specific user to all groups (as a developer)" + task :user_to_groups, [:email] => :environment do |t, args| + user = User.find_by_email args.email + groups = Group.all + puts "Importing #{user.email} users into #{groups.size} groups" + groups.each do |group| + group.add_users(Array.wrap(user.id), UsersGroup::DEVELOPER) + end + end end end From 4105878ae7b6d84d81df8c2092d2292a105eff80 Mon Sep 17 00:00:00 2001 From: Terry Wang Date: Fri, 3 Jan 2014 16:46:39 +1100 Subject: [PATCH 004/112] Fix numbering in 6.3-to-6.4.md --- doc/update/6.3-to-6.4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/update/6.3-to-6.4.md b/doc/update/6.3-to-6.4.md index 69d184722c..7938330dc3 100644 --- a/doc/update/6.3-to-6.4.md +++ b/doc/update/6.3-to-6.4.md @@ -54,7 +54,7 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo service gitlab start sudo service nginx restart -### 8. Check application status +### 6. Check application status Check if GitLab and its environment are configured correctly: From 0fefbad6c9926f459aefa69ed0ff422cab3c4f93 Mon Sep 17 00:00:00 2001 From: Terry Wang Date: Fri, 3 Jan 2014 16:54:05 +1100 Subject: [PATCH 005/112] Unify markdown syntax for Bash commands --- doc/update/6.3-to-6.4.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/update/6.3-to-6.4.md b/doc/update/6.3-to-6.4.md index 7938330dc3..12f1a759ce 100644 --- a/doc/update/6.3-to-6.4.md +++ b/doc/update/6.3-to-6.4.md @@ -9,7 +9,9 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production ### 1. Stop server - sudo service gitlab stop +```bash +sudo service gitlab stop +```` ### 2. Get latest code @@ -51,18 +53,24 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab ### 5. Start application - sudo service gitlab start - sudo service nginx restart +```bash +sudo service gitlab start +sudo service nginx restart +``` ### 6. 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 +```bash +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 with: - sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production +```bash +sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production +``` If all items are green, then congratulations upgrade complete! From 427520ac537b1d34cc53eb0e8090f68600a21321 Mon Sep 17 00:00:00 2001 From: Peter Golm Date: Sat, 18 Jan 2014 19:11:42 +0100 Subject: [PATCH 006/112] use the iid to generate the link_to_merge_request_diff_line_note instead of id --- app/helpers/notes_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 695147cd6d..7ae104b8fd 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -17,7 +17,7 @@ module NotesHelper def link_to_merge_request_diff_line_note(note) if note.for_merge_request_diff_line? and note.diff - link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable_id, anchor: note.line_code) + link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable, anchor: note.line_code) end end From b057e58b6f32c9458fe212e8ef01ca4214860667 Mon Sep 17 00:00:00 2001 From: dosire Date: Thu, 23 Jan 2014 11:44:53 +0100 Subject: [PATCH 007/112] Reword upgrade -y comment, improve layout and allow just y. --- doc/update/upgrader.md | 4 +--- lib/gitlab/upgrader.rb | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md index 1f51005a8e..4ced635796 100644 --- a/doc/update/upgrader.md +++ b/doc/update/upgrader.md @@ -19,10 +19,8 @@ __GitLab Upgrader is available only for version 6.4.2 or higher__ cd /home/git/gitlab sudo -u git -H ruby script/upgrade.rb - - # it also supports -y option to avouid user input + # to perform a non-interactive install (no user input required) you can add -y # sudo -u git -H ruby script/upgrade.rb -y - ### 3. Start application diff --git a/lib/gitlab/upgrader.rb b/lib/gitlab/upgrader.rb index 859923cb56..d48fb8a40c 100644 --- a/lib/gitlab/upgrader.rb +++ b/lib/gitlab/upgrader.rb @@ -17,7 +17,7 @@ module Gitlab prompt("Do you want to upgrade (yes/no)? ", %w{yes no}) end - if answer == "yes" + if answer == "yes" || answer == "y" upgrade else exit 0 From e2e900a338894010e7ba4dac89fa7b926803a977 Mon Sep 17 00:00:00 2001 From: Jurnell Cockhren Date: Tue, 28 Jan 2014 15:10:36 -0600 Subject: [PATCH 008/112] In the case when a user can and has authenticated with ldap, however ldap is disabled in the gitlab config, this fixes the API still calling the ldap backend. --- lib/api/internal.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/api/internal.rb b/lib/api/internal.rb index ed6b50c3a6..ebc9fef07b 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -35,7 +35,9 @@ module API user = key.user return false if user.blocked? - return false if user.ldap_user? && Gitlab::LDAP::User.blocked?(user.extern_uid) + if Gitlab.config.ldap.enabled + return false if user.ldap_user? && Gitlab::LDAP::User.blocked?(user.extern_uid) + end action = case git_cmd when *DOWNLOAD_COMMANDS From 208ec627c323b86824dd5443c507a69e531d20b3 Mon Sep 17 00:00:00 2001 From: Takao Baba Date: Wed, 5 Feb 2014 14:43:20 +0900 Subject: [PATCH 009/112] Fix 500 error in Ruby 1.9. --- app/views/shared/_file_hljs.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_file_hljs.html.haml b/app/views/shared/_file_hljs.html.haml index 166a13bd76..338236c075 100644 --- a/app/views/shared/_file_hljs.html.haml +++ b/app/views/shared/_file_hljs.html.haml @@ -1,6 +1,6 @@ %div.highlighted-data{class: user_color_scheme_class} .line-numbers - - blob.data.lines.size.times do |index| + - blob.data.lines.to_a.size.times do |index| - offset = defined?(first_line_number) ? first_line_number : 1 - i = index + offset = link_to "#L#{i}", id: "L#{i}", rel: "#L#{i}" do From 1c9a41e0d5cac3ee937555ae4189ecd1ad597004 Mon Sep 17 00:00:00 2001 From: GitLab Date: Thu, 6 Feb 2014 14:42:59 +0530 Subject: [PATCH 010/112] adding tests for the ssh keys feature --- app/controllers/profiles/keys_controller.rb | 2 +- app/models/user.rb | 2 +- spec/models/user_spec.rb | 12 ++++++++++++ spec/routing/routing_spec.rb | 5 +++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index 2b991957b7..3bb1b0c2f2 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -40,7 +40,7 @@ class Profiles::KeysController < ApplicationController if params[:username].present? begin user = User.find_by_username(params[:username]) - user.present? ? (render :text => user.all_ssh_keys) : + user.present? ? (render :text => user.all_ssh_keys.join('\n')) : (render_404 and return) rescue => e render text: e.message diff --git a/app/models/user.rb b/app/models/user.rb index 225c97d35f..4c58effaf3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -393,6 +393,6 @@ class User < ActiveRecord::Base end def all_ssh_keys - keys.collect{|x| x.key}.join("\n") + keys.collect{|x| x.key} end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index f6c9f82c4e..f7e242af00 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -276,4 +276,16 @@ describe User do User.by_username_or_id('bar').should be_nil end end + + describe 'all_ssh_keys' do + it { should have_many(:keys).dependent(:destroy) } + + it "should have all ssh keys" do + user = create :user + key = create :key, key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD33bWLBxu48Sev9Fert1yzEO4WGcWglWF7K/AwblIUFselOt/QdOL9DSjpQGxLagO1s9wl53STIO8qGS4Ms0EJZyIXOEFMjFJ5xmjSy+S37By4sG7SsltQEHMxtbtFOaW5LV2wCrX+rUsRNqLMamZjgjcPO0/EgGCXIGMAYW4O7cwGZdXWYIhQ1Vwy+CsVMDdPkPgBXqK7nR/ey8KMs8ho5fMNgB5hBw/AL9fNGhRw3QTD6Q12Nkhl4VZES2EsZqlpNnJttnPdp847DUsT6yuLRlfiQfz5Cn9ysHFdXObMN5VYIiPFwHeYCZp1X2S4fDZooRE8uOLTfxWHPXwrhqSH", user_id: user.id + + user.all_ssh_keys.should include(key.key) + end + + end end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index 946ef7c28c..f5ffb21153 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -183,6 +183,11 @@ describe Profiles::KeysController, "routing" do it "to #destroy" do delete("/profile/keys/1").should route_to('profiles/keys#destroy', id: '1') end + + # get all the ssh-keys of a user + it "to #get_keys" do + get("/foo.keys").should route_to('profiles/keys#get_keys', username: 'foo') + end end # dashboard GET /dashboard(.:format) dashboard#show From 16d6eb3f9a6d97e17b501079c8770ba68ab999eb Mon Sep 17 00:00:00 2001 From: Devaroop Bhattacharya Date: Thu, 6 Feb 2014 19:51:31 +0530 Subject: [PATCH 011/112] Update Gemfile --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 6f4e1f4d4a..446ee73a4b 100644 --- a/Gemfile +++ b/Gemfile @@ -17,7 +17,7 @@ gem 'actionpack-action_caching' # Supported DBs gem "mysql2", group: :mysql -#gem "pg", group: :postgres +gem "pg", group: :postgres # Auth gem "devise", '3.0.4' From 5101ff7bec35704d844df8e608f604abd22df57a Mon Sep 17 00:00:00 2001 From: Devaroop Bhattacharya Date: Thu, 6 Feb 2014 19:53:29 +0530 Subject: [PATCH 012/112] Update Gemfile.lock --- Gemfile.lock | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gemfile.lock b/Gemfile.lock index 19d2fcf6b5..0428a9df48 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -311,6 +311,7 @@ GEM multi_json (~> 1.3) omniauth-oauth (~> 1.0) orm_adapter (0.5.0) + pg (0.15.1) phantomjs (1.9.2.0) poltergeist (1.4.1) capybara (~> 2.1.0) @@ -602,6 +603,7 @@ DEPENDENCIES omniauth-github omniauth-google-oauth2 omniauth-twitter + pg poltergeist (~> 1.4.1) protected_attributes pry From 42083b19aee3ee2bc3688ff1a31006a4b5e31b38 Mon Sep 17 00:00:00 2001 From: Devaroop Bhattacharya Date: Thu, 6 Feb 2014 20:31:27 +0530 Subject: [PATCH 013/112] update manual error in changelog while merging --- CHANGELOG | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index c152fead16..cf1b09a416 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -106,7 +106,6 @@ v 6.2.1 - Security: Fix issue with generated passwords for new users v 6.2.0 - - Public projects are visible from the outside - Public project pages are now visible to everyone (files, issues, wik, etc.) THIS MEANS YOUR ISSUES AND WIKI FOR PUBLIC PROJECTS ARE PUBLICLY VISIBLE AFTER THE UPGRADE - Add group access to permissions page From e139cc9e33810203fe3ac298ad6649cdbcd79f87 Mon Sep 17 00:00:00 2001 From: Andrew Kumanyaev Date: Thu, 6 Feb 2014 19:56:47 +0300 Subject: [PATCH 014/112] Add emoji images to asset load path. --- config/application.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/application.rb b/config/application.rb index 88759ce7cf..c53257090c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -62,7 +62,9 @@ module Gitlab # Enable the asset pipeline config.assets.enabled = true - + config.assets.paths << Emoji.images_path + config.assets.precompile << "emoji/*.png" + # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' From ff45c9755ff8195e2cfb30e408f39c75e576917b Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Thu, 6 Feb 2014 12:02:30 -0700 Subject: [PATCH 015/112] Update upgrade guide if you have more than one backup .tar file --- doc/update/6.4-to-6.5.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/update/6.4-to-6.5.md b/doc/update/6.4-to-6.5.md index 2b1fa2744f..d93ddc1162 100644 --- a/doc/update/6.4-to-6.5.md +++ b/doc/update/6.4-to-6.5.md @@ -65,7 +65,7 @@ To make sure you didn't miss anything run a more thorough check with: sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production -If all items are green, then congratulations upgrade complete! +If all items are green, then congratulations upgrade is complete! ## Things went south? Revert to previous version (6.4) @@ -79,3 +79,4 @@ Follow the [`upgrade guide from 6.3 to 6.4`](6.3-to-6.4.md), except for the data 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. \ No newline at end of file From 00ebfaa9425dda6dc60ddc98b69050c28bb19ec6 Mon Sep 17 00:00:00 2001 From: Matthew Trisoline Date: Mon, 10 Feb 2014 09:51:51 -0500 Subject: [PATCH 016/112] Updated script/{web,background_job} to use #!/usr/bin/env bash rather than #!/bin/bash to allow for transparency between OS namely Linux and FreeBSD and for source installs of bash where path is not exported by default for /usr/local/{bin,sbin} --- script/background_jobs | 2 +- script/web | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/background_jobs b/script/background_jobs index 623e26a283..06125c11ff 100755 --- a/script/background_jobs +++ b/script/background_jobs @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash cd $(dirname $0)/.. app_root=$(pwd) diff --git a/script/web b/script/web index 5464ed040a..1ad3b5d24b 100755 --- a/script/web +++ b/script/web @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash cd $(dirname $0)/.. app_root=$(pwd) From 41adbc0b944501501f7334691cd9d10b21a7fe27 Mon Sep 17 00:00:00 2001 From: dosire Date: Tue, 11 Feb 2014 09:53:07 +0100 Subject: [PATCH 017/112] We do not like configuration options. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a97faaf30..cf52808b74 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -84,7 +84,7 @@ We will accept a merge requests if it: * Fixes one specific issue or implements one specific feature (do not combine things, send separate merge requests if needed) * Keeps the GitLab code base clean and well structured * Contains functionality we think other users will benefit from too -* Doesn't add avoidable configuration options since these complicate future changes +* Doesn't add configuration options since these complicate future changes * Contains a single commit (please use `git rebase -i` to squash commits) For examples of feedback on merge requests please look at already [closed merge requests](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed). From 9d3d0a9e1804929618dc4ddb90267e11a45605c1 Mon Sep 17 00:00:00 2001 From: Pixelindustries Date: Tue, 11 Feb 2014 10:03:44 +0100 Subject: [PATCH 018/112] Fix spelling of plural project (projects and not project's). --- app/views/dashboard/issues.html.haml | 2 +- app/views/dashboard/merge_requests.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 app/views/dashboard/issues.html.haml mode change 100644 => 100755 app/views/dashboard/merge_requests.html.haml diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml old mode 100644 new mode 100755 index 19bd4e7bd5..af627588ad --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -3,7 +3,7 @@ %span.pull-right #{@issues.total_count} issues %p.light - List all issues from all project's you have access to. + List all issues from all projects you have access to. %hr .row diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml old mode 100644 new mode 100755 index b487a4d666..550a93e178 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -4,7 +4,7 @@ %p.light - List all merge requests from all project's you have access to. + List all merge requests from all projects you have access to. %hr .row .col-md-3 From f1da402be753a7cfff1fe7c8be96ce61a1ec3f58 Mon Sep 17 00:00:00 2001 From: dosire Date: Tue, 11 Feb 2014 10:06:25 +0100 Subject: [PATCH 019/112] Require a full yes. --- lib/gitlab/upgrader.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/upgrader.rb b/lib/gitlab/upgrader.rb index d48fb8a40c..859923cb56 100644 --- a/lib/gitlab/upgrader.rb +++ b/lib/gitlab/upgrader.rb @@ -17,7 +17,7 @@ module Gitlab prompt("Do you want to upgrade (yes/no)? ", %w{yes no}) end - if answer == "yes" || answer == "y" + if answer == "yes" upgrade else exit 0 From 9d61ea55d15aa5b201d9be6145d4c70db4fd0de8 Mon Sep 17 00:00:00 2001 From: Pixelindustries Date: Tue, 11 Feb 2014 10:39:13 +0100 Subject: [PATCH 020/112] Added margin between form and button in reset-password form. --- app/views/devise/passwords/new.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 app/views/devise/passwords/new.html.haml diff --git a/app/views/devise/passwords/new.html.haml b/app/views/devise/passwords/new.html.haml old mode 100644 new mode 100755 index a14ef2995c..040821ca32 --- a/app/views/devise/passwords/new.html.haml +++ b/app/views/devise/passwords/new.html.haml @@ -2,7 +2,8 @@ %h3.page-title Reset password .devise-errors = devise_error_messages! - = f.email_field :email, placeholder: "Email", class: "form-control", required: true + .clearfix.append-bottom-20 + = f.email_field :email, placeholder: "Email", class: "form-control", required: true .clearfix.append-bottom-10 = f.submit "Reset password", class: "btn-primary btn" %hr From 441e6dcf0d4d09a713ae6bc7bb47eddc76ad9f48 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Tue, 11 Feb 2014 11:44:08 +0100 Subject: [PATCH 021/112] Update api project documentation to include project name as attribute. --- doc/api/projects.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 559553a110..9f2945d070 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -162,7 +162,7 @@ GET /projects/:id/events Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project ```json @@ -290,7 +290,7 @@ GET /projects/:id/members Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `query` (optional) - Query string to search for members @@ -304,7 +304,7 @@ GET /projects/:id/members/:user_id Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `user_id` (required) - The ID of a user ```json @@ -332,7 +332,7 @@ POST /projects/:id/members Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `user_id` (required) - The ID of a user to add + `access_level` (required) - Project access level @@ -347,7 +347,7 @@ PUT /projects/:id/members/:user_id Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `user_id` (required) - The ID of a team member + `access_level` (required) - Project access level @@ -362,7 +362,7 @@ DELETE /projects/:id/members/:user_id Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `user_id` (required) - The ID of a team member This method is idempotent and can be called multiple times with the same parameters. @@ -383,7 +383,7 @@ GET /projects/:id/hooks Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project ### Get project hook @@ -396,7 +396,7 @@ GET /projects/:id/hooks/:hook_id Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `hook_id` (required) - The ID of a project hook ```json @@ -422,7 +422,7 @@ POST /projects/:id/hooks Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `url` (required) - The hook URL + `push_events` - Trigger hook on push events + `issues_events` - Trigger hook on issues events @@ -439,7 +439,7 @@ PUT /projects/:id/hooks/:hook_id Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `hook_id` (required) - The ID of a project hook + `url` (required) - The hook URL + `push_events` - Trigger hook on push events @@ -458,7 +458,7 @@ DELETE /projects/:id/hooks/:hook_id Parameters: -+ `id` (required) - The ID or NAME of a project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `hook_id` (required) - The ID of hook to delete Note the JSON response differs if the hook is available or not. If the project hook @@ -477,7 +477,7 @@ GET /projects/:id/repository/branches Parameters: -+ `id` (required) - The ID of the project ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project ```json [ @@ -539,7 +539,7 @@ GET /projects/:id/repository/branches/:branch Parameters: -+ `id` (required) - The ID of the project. ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `branch` (required) - The name of the branch. @@ -553,7 +553,7 @@ PUT /projects/:id/repository/branches/:branch/protect Parameters: -+ `id` (required) - The ID of the project. ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `branch` (required) - The name of the branch. @@ -567,7 +567,7 @@ PUT /projects/:id/repository/branches/:branch/unprotect Parameters: -+ `id` (required) - The ID of the project. ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project + `branch` (required) - The name of the branch. From 46ad09bf70400eeebab5495ee6a5ded4da86012e Mon Sep 17 00:00:00 2001 From: GitLab Date: Tue, 11 Feb 2014 19:04:47 +0530 Subject: [PATCH 022/112] code refactor as per standards --- app/controllers/profiles/keys_controller.rb | 11 +++++++---- app/models/user.rb | 2 +- config/routes.rb | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index 7c97987d00..e8237a1f22 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -34,14 +34,17 @@ class Profiles::KeysController < ApplicationController end end - #get all keys of a user(params[:username]) in a text format - #helpful for sysadmins to put in respective servers + # Get all keys of a user(params[:username]) in a text format + # Helpful for sysadmins to put in respective servers def get_keys if params[:username].present? begin user = User.find_by_username(params[:username]) - user.present? ? (render :text => user.all_ssh_keys.join('\n')) : - (render_404 and return) + if user.present? + render text: user.all_ssh_keys.join('\n') + else + render_404 and return + end rescue => e render text: e.message end diff --git a/app/models/user.rb b/app/models/user.rb index 2a58692375..10f21d2350 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -437,6 +437,6 @@ class User < ActiveRecord::Base end def all_ssh_keys - keys.collect{|x| x.key}.join("\n") + keys.map(&:key) end end diff --git a/config/routes.rb b/config/routes.rb index 1cc6242c62..8c66ad741f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -12,7 +12,7 @@ Gitlab::Application.routes.draw do API::API.logger Rails.logger mount API::API => '/api' - #get all keys of user + # Get all keys of user get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ } constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? } From 348e44ef06c3ebc89ada47c64d7bec5bf56dfd54 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 11 Feb 2014 15:49:39 +0200 Subject: [PATCH 023/112] Dont use avatars for user select if avatar is disabled Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/users_select.js.coffee | 4 +++- app/controllers/application_controller.rb | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 92cd3a9905..c1fa16ca89 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -2,10 +2,12 @@ $ -> userFormatResult = (user) -> if user.avatar avatar = user.avatar.url - else + else if gon.gravatar_enabled avatar = gon.gravatar_url avatar = avatar.replace('%{hash}', md5(user.email)) avatar = avatar.replace('%{size}', '24') + else + avatar = gon.relative_url_root + "/assets/no_avatar.png" "
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 442b1b65ce..5f6485e57c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -171,6 +171,7 @@ class ApplicationController < ActionController::Base gon.api_token = current_user.private_token if current_user gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url gon.relative_url_root = Gitlab.config.gitlab.relative_url_root + gon.gravatar_enabled = Gitlab.config.gravatar.enabled end def check_password_expiration From 3b8b396ccd30a65789c423c211de986cb757456d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 11 Feb 2014 16:05:36 +0200 Subject: [PATCH 024/112] Use rails image-url herlper Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/sections/header.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index f7241b017b..4f749bdd98 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -108,7 +108,7 @@ header { h1 { margin: 0; - background: url('logo-black.png') no-repeat center center; + background: image-url('logo-black.png') no-repeat center center; background-size: 32px; float: left; height: 46px; @@ -220,7 +220,7 @@ header { .app_logo { a { h1 { - background: url('logo-white.png') no-repeat center center; + background: image-url('logo-white.png') no-repeat center center; background-size: 32px; color: #fff; text-shadow: 0 1px 1px #444; From 91571c078dee6297a17afecb6dc071ce882c82be Mon Sep 17 00:00:00 2001 From: Ciro Santillli Date: Mon, 27 Jan 2014 15:53:59 +0100 Subject: [PATCH 025/112] User pages are visible to users without login ... if the user is authorized to at least one public project. --- CHANGELOG | 5 +- app/assets/stylesheets/sections/header.scss | 6 +- app/controllers/users_controller.rb | 20 ++++-- app/views/help/public_access.html.haml | 15 ++++ app/views/layouts/_head_panel.html.haml | 2 +- .../layouts/_public_head_panel.html.haml | 6 +- app/views/layouts/public.html.haml | 3 +- app/views/layouts/public_projects.html.haml | 4 +- app/views/layouts/public_users.html.haml | 7 ++ features/admin/groups.feature | 6 +- features/group/group.feature | 6 +- features/steps/admin/admin_groups.rb | 13 ++-- features/steps/group/group.rb | 13 ++-- features/steps/public/projects_feature.rb | 32 +-------- features/steps/shared/paths.rb | 8 +++ features/steps/shared/project.rb | 64 +++++++++++++++++ features/steps/shared/user.rb | 11 +++ features/steps/user.rb | 10 +++ features/user.feature | 69 +++++++++++++++++++ 19 files changed, 229 insertions(+), 71 deletions(-) create mode 100644 app/views/layouts/public_users.html.haml create mode 100644 features/steps/shared/user.rb create mode 100644 features/steps/user.rb create mode 100644 features/user.feature diff --git a/CHANGELOG b/CHANGELOG index 71547b387e..b40186b166 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ v 6.6.0 - Permissions: Developer now can manage issue tracker (modify any issue) - Improve Code Compare page performance - Group avatar - - Pygments.rb replaced with highlight.js + - Pygments.rb replaced with highlight.js - Improve Merge request diff store logic - Improve render performnace for MR show page - Fixed Assembla hardcoded project name @@ -12,6 +12,7 @@ v 6.6.0 - Mobile UI improvements (Drew Blessing) - Fix block/remove UI for admin::users#show page - Show users' group membership on users' activity page + - User pages are visible without login if user is authorized to a public project v 6.5.1 - Fix branch selectbox when create merge request from fork @@ -45,7 +46,7 @@ v6.4.3 v6.4.2 - Fixed wrong behaviour of script/upgrade.rb -v6.4.1 +v6.4.1 - Fixed bug with repository rename - Fixed bug with project transfer diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index f7241b017b..f268f2a984 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -56,7 +56,7 @@ header { font-size: 18px; .app_logo { margin-left: -15px; } - .project_name { + .title { display: inline-block; overflow: hidden; text-overflow: ellipsis; @@ -127,7 +127,7 @@ header { * Project / Area name * */ - .project_name { + .title { position: relative; float: left; margin: 0; @@ -227,7 +227,7 @@ header { } } } - .project_name { + .title { a { color: #BBB; &:hover { diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6a5ce62909..e86601a439 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,11 +1,23 @@ class UsersController < ApplicationController - layout 'navless' + + skip_before_filter :authenticate_user!, only: [:show] + layout :determine_layout def show - @user = User.find_by!(username: params[:username]) - @projects = @user.authorized_projects.where(id: current_user.authorized_projects.pluck(:id)).includes(:namespace) + @user = User.find_by_username!(params[:username]) + @projects = @user.authorized_projects.includes(:namespace).select {|project| can?(current_user, :read_project, project)} + if !current_user && @projects.empty? + return authenticate_user! + end @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20) - @title = @user.name end + + def determine_layout + if current_user + 'navless' + else + 'public_users' + end + end end diff --git a/app/views/help/public_access.html.haml b/app/views/help/public_access.html.haml index ba2df8c355..e1b2a2ce1f 100644 --- a/app/views/help/public_access.html.haml +++ b/app/views/help/public_access.html.haml @@ -44,3 +44,18 @@ %li Go to your project dashboard %li Click on the "Edit" tab %li Change "Visibility Level" + + %h4 Visibility of users + The public page of users, located at + = succeed "," do + %code u/username + is visible if either: + %ul + %li + You are logged in. + %li + %p + You are logged out, and the target user is authorized to (is Guest, Reporter, etc.) + at least one public project. + %p Otherwise, you will be redirected to the sign in page. + When visiting the public page of an user, you will only see listed projects which you can view yourself. diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 1d181d3519..5080a1b7ef 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -6,7 +6,7 @@ = link_to root_path, class: "home has_bottom_tooltip", title: "Dashboard" do %h1 GITLAB %span.separator - %h1.project_name= title + %h1.title= title %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"} %span.sr-only Toggle navigation diff --git a/app/views/layouts/_public_head_panel.html.haml b/app/views/layouts/_public_head_panel.html.haml index 65c806a915..99e11cd2b5 100644 --- a/app/views/layouts/_public_head_panel.html.haml +++ b/app/views/layouts/_public_head_panel.html.haml @@ -6,11 +6,7 @@ = link_to public_root_path, class: "home" do %h1 GITLAB %span.separator - %h1.project_name - - if @project - = project_title(@project) - - else - Public Projects + %h1.title= title .pull-right = link_to "Sign in", new_session_path(:user), class: 'btn btn-sign-in btn-new' diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml index 8f490f61a9..fda81b3cc8 100644 --- a/app/views/layouts/public.html.haml +++ b/app/views/layouts/public.html.haml @@ -5,7 +5,6 @@ - if current_user = render "layouts/head_panel", title: "Public Projects" - else - = render "layouts/public_head_panel" - + = render "layouts/public_head_panel", title: "Public Projects" .container.navless-container .content= yield diff --git a/app/views/layouts/public_projects.html.haml b/app/views/layouts/public_projects.html.haml index a8e3236d86..7de2347803 100644 --- a/app/views/layouts/public_projects.html.haml +++ b/app/views/layouts/public_projects.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: @project.name_with_namespace %body{class: "#{app_theme} application", :'data-page' => body_data_page} - = render "layouts/public_head_panel" - %nav.main-nav.navbar-collapse.collapse + = render "layouts/public_head_panel", title: @project.name_with_namespace + %nav.main-nav .container= render 'layouts/nav/project' .container .content= yield diff --git a/app/views/layouts/public_users.html.haml b/app/views/layouts/public_users.html.haml new file mode 100644 index 0000000000..80709d650d --- /dev/null +++ b/app/views/layouts/public_users.html.haml @@ -0,0 +1,7 @@ +!!! 5 +%html{ lang: "en"} + = render "layouts/head", title: @title + %body{class: "#{app_theme} application", :'data-page' => body_data_page} + = render "layouts/public_head_panel", title: @title + .container.navless-container + .content= yield diff --git a/features/admin/groups.feature b/features/admin/groups.feature index 6fed9a3486..7741307f17 100644 --- a/features/admin/groups.feature +++ b/features/admin/groups.feature @@ -2,7 +2,7 @@ Feature: Admin Groups Background: Given I sign in as an admin And I have group with projects - And Create gitlab user "John" + And Create user "John Doe" And I visit admin groups page Scenario: See group list @@ -17,5 +17,5 @@ Feature: Admin Groups @javascript Scenario: Add user into projects in group When I visit admin group page - When I select user "John" from user list as "Reporter" - Then I should see "John" in team list in every project as "Reporter" + 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" diff --git a/features/group/group.feature b/features/group/group.feature index ca3e67d2c1..6177263e47 100644 --- a/features/group/group.feature +++ b/features/group/group.feature @@ -21,10 +21,10 @@ Feature: Groups @javascript Scenario: I should add user to projects in Group - Given I have new user "John" + Given Create user "John Doe" When I visit group members page - And I select user "John" from list with role "Reporter" - Then I should see user "John" in team list + And I select user "John Doe" from list with role "Reporter" + Then I should see user "John Doe" in team list Scenario: I should see edit group page When I visit group settings page diff --git a/features/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb index 013fa6da8b..9c1bcfefb9 100644 --- a/features/steps/admin/admin_groups.rb +++ b/features/steps/admin/admin_groups.rb @@ -1,6 +1,7 @@ class AdminGroups < Spinach::FeatureSteps include SharedAuthentication include SharedPaths + include SharedUser include SharedActiveTab include Select2Helper @@ -20,10 +21,6 @@ class AdminGroups < Spinach::FeatureSteps @project.team << [current_user, :master] end - And 'Create gitlab user "John"' do - create(:user, name: "John") - end - And 'submit form with new group info' do fill_in 'group_name', with: 'gitlab' fill_in 'group_description', with: 'Group description' @@ -39,8 +36,8 @@ class AdminGroups < Spinach::FeatureSteps current_path.should == admin_group_path(Group.last) end - When 'I select user "John" from user list as "Reporter"' do - user = User.find_by(name: "John") + When 'I select user "John Doe" from user list as "Reporter"' do + user = User.find_by(name: "John Doe") select2(user.id, from: "#user_ids", multiple: true) within "#new_team_member" do select "Reporter", from: "group_access" @@ -48,9 +45,9 @@ class AdminGroups < Spinach::FeatureSteps click_button "Add users into group" end - Then 'I should see "John" in team list in every project as "Reporter"' do + Then 'I should see "John Doe" in team list in every project as "Reporter"' do within ".group-users-list" do - page.should have_content "John" + page.should have_content "John Doe" page.should have_content "Reporter" end end diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index 0b0f401c3b..686f683314 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -1,6 +1,7 @@ class Groups < Spinach::FeatureSteps include SharedAuthentication include SharedPaths + include SharedUser include Select2Helper Then 'I should see projects list' do @@ -34,12 +35,8 @@ class Groups < Spinach::FeatureSteps end end - Given 'I have new user "John"' do - create(:user, name: "John") - end - - And 'I select user "John" from list with role "Reporter"' do - user = User.find_by(name: "John") + And 'I select user "John Doe" from list with role "Reporter"' do + user = User.find_by(name: "John Doe") within ".users-group-form" do select2(user.id, from: "#user_ids", multiple: true) select "Reporter", from: "group_access" @@ -47,9 +44,9 @@ class Groups < Spinach::FeatureSteps click_button "Add users into group" end - Then 'I should see user "John" in team list' do + Then 'I should see user "John Doe" in team list' do projects_with_access = find(".ui-box .well-list") - projects_with_access.should have_content("John") + projects_with_access.should have_content("John Doe") end Given 'project from group has issues assigned to me' do diff --git a/features/steps/public/projects_feature.rb b/features/steps/public/projects_feature.rb index 84a5ebbf7a..eb1d235f43 100644 --- a/features/steps/public/projects_feature.rb +++ b/features/steps/public/projects_feature.rb @@ -3,12 +3,8 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps include SharedPaths include SharedProject - step 'I should see project "Community"' do - page.should have_content "Community" - end - - step 'I should not see project "Enterprise"' do - page.should_not have_content "Enterprise" + step 'public empty project "Empty Public Project"' do + create :empty_project, name: 'Empty Public Project', visibility_level: Gitlab::VisibilityLevel::PUBLIC end step 'I should see project "Empty Public Project"' do @@ -24,14 +20,6 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps page.should have_content 'README.md' end - step 'public project "Community"' do - create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC - end - - step 'public empty project "Empty Public Project"' do - create :empty_project, name: 'Empty Public Project', visibility_level: Gitlab::VisibilityLevel::PUBLIC - end - step 'I visit empty project page' do project = Project.find_by(name: 'Empty Public Project') visit project_path(project) @@ -60,10 +48,6 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end end - step 'private project "Enterprise"' do - create :project, name: 'Enterprise' - end - step 'I visit project "Enterprise" page' do project = Project.find_by(name: 'Enterprise') visit project_path(project) @@ -75,18 +59,6 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end end - step 'internal project "Internal"' do - create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL - end - - step 'I should see project "Internal"' do - page.should have_content "Internal" - end - - step 'I should not see project "Internal"' do - page.should_not have_content "Internal" - end - step 'I visit project "Internal" page' do project = Project.find_by(name: 'Internal') visit project_path(project) diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index d287121bb8..c1aafc183d 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -5,6 +5,14 @@ module SharedPaths visit new_project_path end + # ---------------------------------------- + # User + # ---------------------------------------- + + step 'I visit user "John Doe" page' do + visit user_path("john_doe") + end + # ---------------------------------------- # Group # ---------------------------------------- diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index 7360482d73..a6354aeaf8 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -65,4 +65,68 @@ module SharedProject def current_project @project ||= Project.first end + + # ---------------------------------------- + # Visibility level + # ---------------------------------------- + + step 'private project "Enterprise"' do + create :project, name: 'Enterprise' + end + + step 'I should see project "Enterprise"' do + page.should have_content "Enterprise" + end + + step 'I should not see project "Enterprise"' do + page.should_not have_content "Enterprise" + end + + step 'internal project "Internal"' do + create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL + end + + step 'I should see project "Internal"' do + page.should have_content "Internal" + end + + step 'I should not see project "Internal"' do + page.should_not have_content "Internal" + end + + step 'public project "Community"' do + create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC + end + + step 'I should see project "Community"' do + page.should have_content "Community" + end + + step 'I should not see project "Community"' do + page.should_not have_content "Community" + end + + step '"John Doe" is authorized to private project "Enterprise"' do + user = User.find_by(name: "John Doe") + user ||= create(:user, name: "John Doe", username: "john_doe") + project = Project.find_by(name: "Enterprise") + project ||= create(:project, name: "Enterprise", namespace: user.namespace) + project.team << [user, :master] + end + + step '"John Doe" is authorized to internal project "Internal"' do + user = User.find_by(name: "John Doe") + user ||= create(:user, name: "John Doe", username: "john_doe") + project = Project.find_by(name: "Internal") + project ||= create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL + project.team << [user, :master] + end + + step '"John Doe" is authorized to public project "Community"' do + user = User.find_by(name: "John Doe") + user ||= create(:user, name: "John Doe", username: "john_doe") + project = Project.find_by(name: "Community") + project ||= create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC + project.team << [user, :master] + end end diff --git a/features/steps/shared/user.rb b/features/steps/shared/user.rb new file mode 100644 index 0000000000..a2bf069a11 --- /dev/null +++ b/features/steps/shared/user.rb @@ -0,0 +1,11 @@ +module SharedUser + include Spinach::DSL + + step 'Create user "John Doe"' do + create(:user, name: "John Doe", username: "john_doe") + end + + step 'I sign in as "John Doe"' do + login_with(User.find_by(name: "John Doe")) + end +end diff --git a/features/steps/user.rb b/features/steps/user.rb new file mode 100644 index 0000000000..5fb248ffcb --- /dev/null +++ b/features/steps/user.rb @@ -0,0 +1,10 @@ +class Spinach::Features::User < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + include SharedUser + include SharedProject + + step 'I should see user "John Doe" page' do + expect(page.title).to match(/^\s*John Doe/) + end +end diff --git a/features/user.feature b/features/user.feature new file mode 100644 index 0000000000..c1c1ddda52 --- /dev/null +++ b/features/user.feature @@ -0,0 +1,69 @@ +Feature: User + Background: + Given Create user "John Doe" + And "John Doe" is authorized to private project "Enterprise" + + # Signed out + + Scenario: I visit user "John Doe" page while not signed in when he is authorized to a public project + Given "John Doe" is authorized to internal project "Internal" + And "John Doe" is authorized to public project "Community" + When I visit user "John Doe" page + Then I should see user "John Doe" page + And I should not see project "Enterprise" + And I should not see project "Internal" + And I should see project "Community" + + Scenario: I visit user "John Doe" page while not signed in when he is not authorized to a public project + Given "John Doe" is authorized to internal project "Internal" + When I visit user "John Doe" page + Then I should be redirected to sign in page + + # Signed in as someone else + + Scenario: I visit user "John Doe" page while signed in as someone else when he is authorized to a public project + Given "John Doe" is authorized to public project "Community" + And "John Doe" is authorized to internal project "Internal" + And I sign in as a user + When I visit user "John Doe" page + Then I should see user "John Doe" page + And I should not see project "Enterprise" + And I should see project "Internal" + And I should see project "Community" + + Scenario: I visit user "John Doe" page while signed in as someone else when he is not authorized to a public project + Given "John Doe" is authorized to internal project "Internal" + And I sign in as a user + When I visit user "John Doe" page + Then I should see user "John Doe" page + And I should not see project "Enterprise" + And I should see project "Internal" + And I should not see project "Community" + + Scenario: I visit user "John Doe" page while signed in as someone else when he is not authorized to a project I can see + Given I sign in as a user + When I visit user "John Doe" page + Then I should see user "John Doe" page + And I should not see project "Enterprise" + And I should not see project "Internal" + And I should not see project "Community" + + # Signed in as the user himself + + Scenario: I visit user "John Doe" page while signed in as "John Doe" when he has a public project + Given "John Doe" is authorized to internal project "Internal" + And "John Doe" is authorized to public project "Community" + And I sign in as "John Doe" + When I visit user "John Doe" page + Then I should see user "John Doe" page + And I should see project "Enterprise" + And I should see project "Internal" + And I should see project "Community" + + Scenario: I visit user "John Doe" page while signed in as "John Doe" when he has no public project + Given I sign in as "John Doe" + When I visit user "John Doe" page + Then I should see user "John Doe" page + And I should see project "Enterprise" + And I should not see project "Internal" + And I should not see project "Community" From 61748c993de8a38300c0c038cec5a07e6c324cd6 Mon Sep 17 00:00:00 2001 From: Ciro Santillli Date: Tue, 4 Feb 2014 08:48:33 +0100 Subject: [PATCH 026/112] Headers have ids and link to their own id. --- CHANGELOG | 1 + app/assets/images/icon-link.png | Bin 0 -> 1019 bytes app/assets/stylesheets/generic/files.scss | 1 - app/assets/stylesheets/generic/issue_box.scss | 5 +- .../stylesheets/generic/typography.scss | 21 +++ app/assets/stylesheets/main/mixins.scss | 4 + app/helpers/gitlab_markdown_helper.rb | 19 ++- app/views/help/_layout.html.haml | 3 +- app/views/projects/issues/show.html.haml | 7 +- .../merge_requests/show/_mr_box.html.haml | 7 +- app/views/projects/milestones/show.html.haml | 4 +- app/views/projects/notes/_note.html.haml | 2 +- doc/markdown/markdown.md | 160 ++++++++++-------- features/dashboard/help.feature | 8 + features/project/issues/issues.feature | 12 ++ features/project/issues/milestones.feature | 6 + features/project/merge_requests.feature | 12 ++ .../project/source/markdown_render.feature | 42 ++++- features/steps/help.rb | 21 +++ features/steps/project/project_issues.rb | 5 +- .../steps/project/project_markdown_render.rb | 32 ++-- .../steps/project/project_merge_requests.rb | 5 +- features/steps/project/project_milestones.rb | 8 +- features/steps/shared/markdown.rb | 12 ++ features/steps/shared/note.rb | 17 ++ lib/redcarpet/render/gitlab_html.rb | 11 ++ spec/helpers/gitlab_markdown_helper_spec.rb | 17 +- 27 files changed, 319 insertions(+), 123 deletions(-) create mode 100644 app/assets/images/icon-link.png create mode 100644 features/dashboard/help.feature create mode 100644 features/steps/help.rb create mode 100644 features/steps/shared/markdown.rb diff --git a/CHANGELOG b/CHANGELOG index 71547b387e..98276958ac 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ v 6.6.0 - Mobile UI improvements (Drew Blessing) - Fix block/remove UI for admin::users#show page - Show users' group membership on users' activity page + - Markdown rendered headers have id derived from their name and link to their id v 6.5.1 - Fix branch selectbox when create merge request from fork diff --git a/app/assets/images/icon-link.png b/app/assets/images/icon-link.png new file mode 100644 index 0000000000000000000000000000000000000000..32ade0fe9a37d114ff86789f34242a845f0c5294 GIT binary patch literal 1019 zcmeAS@N?(olHy`uVBq!ia0vp^4j{|{BpCXc^q7DYOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>W{q1T2-mH>T&A1Yu4-RqreFa^JXi zOekZ2@h>%dwG)f-b2bKB3Ey}hF505ra3Mc-t@R=M%=ZjQ@|PBu z{z^Wum)BwMIgUwk%mx13oA$Aus8aIyt)}qB{v@|$RYI=F(!H!9hY!6MS9f3W{pEK3 zlanvqV@h&5&v8cR7uyH6J@t>eYMDEnY;_oHFL`bHZNBb`a_&7j{f~=Tu2)|dVDWkI zafLgR+#oOZ#tdHQ9IP4%( zx_yfz&kXw?7yW!WPu#w56qKmG^uWt%Ypw$mIl0e%el9uV+@Ak?Zi+c9%grHnZ+mwXY{mQ*tuc`%&{@@cWO>Q-$uFmuK-{X}wpu zamlVXCs*rUjrHFfBQKr9Z*PB#K_mTA?T!UkjOz`wg5#{epO;+3U& zeuo>nzmRYiD9D=ieTob)!K;?IMwFx^mZVxG7o`Fz1|tJQ6I}yCU1P%#BLgb~Gb>XA zZ39Cq0|S94(U~Y3a`RI%(<*UmNZk4ODo}$Y$cEtjw370~qErUQl>DSr1<%~X^wgl# W#FWaylc}H_$>8bg=d#Wzp$P!{uByra literal 0 HcmV?d00001 diff --git a/app/assets/stylesheets/generic/files.scss b/app/assets/stylesheets/generic/files.scss index 20877507c9..85111a4591 100644 --- a/app/assets/stylesheets/generic/files.scss +++ b/app/assets/stylesheets/generic/files.scss @@ -50,7 +50,6 @@ } &.wiki { - padding: 20px; font-size: 14px; line-height: 1.6; diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss index afe9c5f818..c3a39f0251 100644 --- a/app/assets/stylesheets/generic/issue_box.scss +++ b/app/assets/stylesheets/generic/issue_box.scss @@ -23,11 +23,12 @@ line-height: 28px; margin: 0; color: #444; + border-bottom: 1px solid #eee; } .context { border: none; - border-top: 1px solid #eee; + border-bottom: 1px solid #eee; } .description { @@ -35,7 +36,7 @@ } .title, .context, .description { - padding: 15px; + padding: 15px 15px 15px 30px; .clearfix { margin: 0; diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss index 419a63d4d3..1a07fde53f 100644 --- a/app/assets/stylesheets/generic/typography.scss +++ b/app/assets/stylesheets/generic/typography.scss @@ -90,6 +90,27 @@ a:focus { font-size: 14px; line-height: 1.6; + + /* Link to current header. */ + h1, h2, h3, h4, h5, h6 { + position: relative; + &:hover > :last-child { + $size: 16px; + position: absolute; + right: 100%; + top: 50%; + margin-top: -$size/2; + margin-right: 0px; + padding-right: 20px; + display: inline-block; + width: $size; + height: $size; + background-image: url("icon-link.png"); + background-size: contain; + background-repeat: no-repeat; + } + } + ul { padding: 0; margin: 0 0 9px 25px !important; diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss index 4afe61d756..a7a5ed73ab 100644 --- a/app/assets/stylesheets/main/mixins.scss +++ b/app/assets/stylesheets/main/mixins.scss @@ -114,6 +114,10 @@ font-size: 1.2em; } + // Larger 30px left margin is required for the header link icon. + // Use on all markdown including those without header links for uniformity. + margin: 20px 20px 20px 30px; + blockquote p { color: #888; font-size: 14px; diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 315f1b805b..b25662e3ba 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -28,14 +28,16 @@ module GitlabMarkdownHelper link_to(gfm_body.html_safe, url, html_options) end - def markdown(text) - unless @markdown - gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, - # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch- - filter_html: true, - with_toc_data: true, - hard_wrap: true, - safe_links_only: true) + def markdown(text, options={}) + unless (@markdown and options == @options) + @options = options + gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, { + # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch- + filter_html: true, + with_toc_data: true, + hard_wrap: true, + safe_links_only: true + }.merge(options)) @markdown = Redcarpet::Markdown.new(gitlab_renderer, # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use no_intra_emphasis: true, @@ -47,7 +49,6 @@ module GitlabMarkdownHelper space_after_headers: true, superscript: true) end - @markdown.render(text).html_safe end diff --git a/app/views/help/_layout.html.haml b/app/views/help/_layout.html.haml index a413616bad..201d63ca24 100644 --- a/app/views/help/_layout.html.haml +++ b/app/views/help/_layout.html.haml @@ -8,4 +8,5 @@ = link_to title, path .col-md-9 - = yield + .wiki + = yield diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index cd4a158e42..5033dfefe2 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -46,10 +46,9 @@ = render partial: 'issue_context', locals: { issue: @issue } - if @issue.description.present? - .description - .wiki - = preserve do - = markdown @issue.description + .wiki + = preserve do + = markdown @issue.description - content_for :note_actions do - if can?(current_user, :modify_issue, @issue) diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml index b4f648ab19..9b95c09218 100644 --- a/app/views/projects/merge_requests/show/_mr_box.html.haml +++ b/app/views/projects/merge_requests/show/_mr_box.html.haml @@ -15,10 +15,9 @@ - if @merge_request.description.present? - .description - .wiki - = preserve do - = markdown @merge_request.description + .wiki + = preserve do + = markdown @merge_request.description - if @merge_request.closed? .description.alert-danger diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index e7c3785c05..283b4dfeac 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -42,13 +42,11 @@ .progress.progress-info .progress-bar{style: "width: #{@milestone.percent_complete}%;"} - - if @milestone.description.present? - .description + .wiki = preserve do = markdown @milestone.description - %ul.nav.nav-tabs.append-bottom-10 %li.active = link_to '#tab-issues', 'data-toggle' => 'tab' do diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index fd2a3f4367..217e36e38d 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -31,7 +31,7 @@ .note-body .note-text = preserve do - = markdown(note.note) + = markdown(note.note, {no_header_anchors: true}) .note-edit-form = form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f| diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md index bfb93a4701..008e37d11f 100644 --- a/doc/markdown/markdown.md +++ b/doc/markdown/markdown.md @@ -1,41 +1,37 @@ ---------------------------------------------- -Table of Contents +Table of Contents ================= ---------------------------------------------- -[GitLab Flavored Markdown](#toc_3) -------------------------------- -[Newlines](#toc_4) -[Multiple underscores in words](#toc_5) -[URL autolinking](#toc_6) -[Code and Syntax Highlighting](#toc_7) -[Emoji](#toc_8) -[Special GitLab references](#toc_9) +**[GitLab Flavored Markdown](#gitlab-flavored-markdown-gfm)** +[Newlines](#newlines) +[Multiple underscores in words](#multiple-underscores-in-words) +[URL autolinking](#url-autolinking) +[Code and Syntax Highlighting](#code-and-syntax-highlighting) +[Emoji](#emoji) +[Special GitLab references](#special-gitlab-references) +**[Standard Markdown](#standard-markdown)** -[Standard Markdown](#toc_10) ------------------------------- -[Headers](#toc_11) -[Emphasis](#toc_20) -[Lists](#toc_21) -[Links](#toc_22) -[Images](#toc_23) -[Blockquotes](#toc_24) -[Inline HTML](#toc_25) -[Horizontal Rule](#toc_26) -[Line Breaks](#toc_27) -[Tables](#toc_28) +[Headers](#headers) +[Emphasis](#emphasis) +[Lists](#lists) +[Links](#links) +[Images](#images) +[Blockquotes](#blockquotes) +[Inline HTML](#inline-html) +[Horizontal Rule](#horizontal-rule) +[Line Breaks](#line-breaks) +[Tables](#tables) -[References](#toc_29) ---------------------- +**[References](#references)** ---------------------------------------------- - -GitLab Flavored Markdown (GFM) +GitLab Flavored Markdown (GFM) ============================== For GitLab we developed something we call "GitLab Flavored Markdown" (GFM). It extends the standard Markdown in a few significant ways to add some useful functionality. @@ -49,7 +45,6 @@ You can use GFM in * milestones * wiki pages - Newlines -------- The biggest difference that GFM introduces is in the handling of linebreaks. With traditional Markdown you can hard wrap paragraphs of text and they will be combined into a single paragraph. We find this to be the cause of a huge number of unintentional formatting errors. GFM treats newlines in paragraph-like content as real line breaks, which is probably what you intended. @@ -61,8 +56,7 @@ The next paragraph contains two phrases separated by a single newline character: Roses are red Violets are blue - - + Multiple underscores in words ----------------------------- It is not reasonable to italicize just _part_ of a word, especially when you're dealing with code and names that often appear with multiple underscores. Therefore, GFM ignores multiple underscores in words. @@ -73,7 +67,6 @@ It is not reasonable to italicize just _part_ of a word, especially when you're perform_complicated_task do_this_and_do_that_and_another_thing - URL autolinking --------------- GFM will autolink standard URLs you copy and paste into your text. @@ -83,12 +76,10 @@ So if you want to link to a URL (instead of a textural link), you can simply put http://www.google.com - ## Code and Syntax Highlighting Blocks of code are either fenced by lines with three back-ticks ```, or are indented with four spaces. Only the fenced code blocks support syntax highlighting. - ```no-highlight Inline `code` has `back-ticks around` it. ``` @@ -101,14 +92,14 @@ Example: var s = "JavaScript syntax highlighting"; alert(s); ``` - + ```python def function(): #indenting works just fine in the fenced code block s = "Python syntax highlighting" print s ``` - + ```ruby require 'redcarpet' markdown = Redcarpet.new("Hello World!") @@ -116,7 +107,7 @@ Example: ``` ``` - No language indicated, so no syntax highlighting. + No language indicated, so no syntax highlighting. s = "There is no highlighting for this." But let's throw in a tag. ``` @@ -147,7 +138,6 @@ s = "There is no highlighting for this." But let's throw in a tag. ``` - Emoji ----- @@ -159,7 +149,7 @@ Emoji If you are :new: to this, don't be :fearful:. You can easily join the emoji :circus_tent:. All you need to do is to :book: up on the supported codes. - Consult the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) for a list of all supported emoji codes. :thumbsup: + Consult the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) for a list of all supported emoji codes. :thumbsup: Sometimes you want to be :cool: and add some :sparkles: to your :speech_balloon:. Well we have a :gift: for you: @@ -169,9 +159,8 @@ You can use it to point out a :bug: or warn about :monkey:patches. And if someon If you are :new: to this, don't be :fearful:. You can easily join the emoji :circus_tent:. All you need to do is to :book: up on the supported codes. -Consult the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) for a list of all supported emoji codes. :thumbsup: +Consult the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) for a list of all supported emoji codes. :thumbsup: - Special GitLab References ----- @@ -179,7 +168,6 @@ GFM recognized special references. You can easily reference e.g. a team member, an issue, or a commit within a project. GFM will turn that reference into a link so you can navigate between them easily. - GFM will recognize the following: * @foo : for team members @@ -189,13 +177,10 @@ GFM will recognize the following: * 1234567 : for commits * \[file\](path/to/file) : for file references - - ---------------------------------- # Standard Markdown ---------------------------------- - ## Headers ```no-highlight @@ -230,7 +215,54 @@ Alt-H1 Alt-H2 ------ - +### Header IDs and links + +All markdown rendered headers automatically get IDs, except for comments. + +On hover a link to those IDs becomes visible to make it easier to copy the link to the header to give it to someone else. + +The IDs are generated from the content of the header according to the following rules: + +1) remove the heading hashes `#` and process the rest of the line as it would be processed if it were not a header +2) from the result, remove all HTML tags, but keep their inner content +3) convert all characters to lowercase +4) convert all characters except `[a-z0-9_-]` into hyphens `-` +5) transform multiple adjacent hyphens into a single hyphen +6) remove trailing and heading hyphens + +For example: + +``` +###### ..Ab_c-d. e [anchor](url) ![alt text](url).. +``` + +which renders as: + +###### ..Ab_c-d. e [anchor](url) ![alt text](url).. + +will first be converted by step 1) into a string like: + +``` +..Ab_c-d. e <a href="url">anchor</a> <img src="url" alt="alt text"/>.. +``` + +After removing the tags in step 2) we get: + +``` +..Ab_c-d. e anchor .. +``` + +And applying all the other steps gives the id: + +``` +ab_c-d-e-anchor +``` + +Note in particular how: + +- for markdown anchors `[text](url)`, only the `text` is used +- markdown images `![alt](url)` are completely ignored + ## Emphasis ```no-highlight @@ -251,18 +283,16 @@ Combined emphasis with **asterisks and _underscores_**. Strikethrough uses two tildes. ~~Scratch this.~~ - - ## Lists ```no-highlight 1. First ordered list item 2. Another item - * Unordered sub-list. + * Unordered sub-list. 1. Actual numbers don't matter, just that it's a number 1. Ordered sub-list -4. And another item. - +4. And another item. + Some text that should be aligned with the above item. * Unordered list can use asterisks @@ -272,18 +302,17 @@ Strikethrough uses two tildes. ~~Scratch this.~~ 1. First ordered list item 2. Another item - * Unordered sub-list. + * Unordered sub-list. 1. Actual numbers don't matter, just that it's a number 1. Ordered sub-list -4. And another item. - +4. And another item. + Some text that should be aligned with the above item. * Unordered list can use asterisks - Or minuses + Or pluses - ## Links There are two ways to create links. @@ -320,30 +349,28 @@ Some text to show that the reference links can follow later. [1]: http://slashdot.org [link text itself]: http://www.reddit.com - ## Images Here's our logo (hover to see the title text): - Inline-style: + Inline-style: ![alt text](assets/logo-white.png) - Reference-style: + Reference-style: ![alt text1][logo] [logo]: assets/logo-white.png Here's our logo (hover to see the title text): -Inline-style: +Inline-style: ![alt text](/assets/logo-white.png "Logo Title Text 1") -Reference-style: +Reference-style: ![alt text][logo] [logo]: /assets/logo-white.png "Logo Title Text 2" - ## Blockquotes ```no-highlight @@ -352,7 +379,7 @@ Reference-style: Quote break. -> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote. +> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote. ``` > Blockquotes are very handy in email to emulate reply text. @@ -360,12 +387,11 @@ Quote break. Quote break. -> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote. +> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote. - ## Inline HTML -You can also use raw HTML in your Markdown, and it'll mostly work pretty well. +You can also use raw HTML in your Markdown, and it'll mostly work pretty well. ```no-highlight
@@ -385,7 +411,6 @@ You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
Does *not* work **very** well. Use HTML tags.
-
## Horizontal Rule ``` @@ -418,10 +443,9 @@ ___ Underscores - ## Line Breaks -My basic recommendation for learning how line breaks work is to experiment and discover -- hit <Enter> once (i.e., insert one newline), then hit it twice (i.e., insert two newlines), see what happens. You'll soon learn to get what you want. "Markdown Toggle" is your friend. +My basic recommendation for learning how line breaks work is to experiment and discover -- hit <Enter> once (i.e., insert one newline), then hit it twice (i.e., insert two newlines), see what happens. You'll soon learn to get what you want. "Markdown Toggle" is your friend. Here are some things to try out: @@ -438,11 +462,9 @@ Here's a line for us to start with. This line is separated from the one above by two newlines, so it will be a *separate paragraph*. -This line is also begins a separate paragraph, but... +This line is also begins a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the *same paragraph*. - - ## Tables Tables aren't part of the core Markdown spec, but they are part of GFM and Markdown Here supports them. @@ -461,10 +483,8 @@ Code above produces next output: | cell 1 | cell 2 | | cell 3 | cell 4 | - ------------ - ## References * This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). diff --git a/features/dashboard/help.feature b/features/dashboard/help.feature new file mode 100644 index 0000000000..02ec688f80 --- /dev/null +++ b/features/dashboard/help.feature @@ -0,0 +1,8 @@ +Feature: Help + Background: + Given I sign in as a user + And I visit the "Rake Tasks" help page + + Scenario: The markdown should be rendered correctly + Then I should see "Rake Tasks" page markdown rendered + And Header "Rebuild project satellites" should have correct ids and links diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature index 67986784bc..033051991e 100644 --- a/features/project/issues/issues.feature +++ b/features/project/issues/issues.feature @@ -55,3 +55,15 @@ Feature: Project Issues And I fill in issue search with ".3" Then I should see "Release 0.3" in issues And I should not see "Release 0.4" in issues + + # Markdown + + Scenario: Headers inside the description should have ids generated for them. + Given I visit issue page "Release 0.4" + Then Header "Description header" should have correct id and link + + @javascript + Scenario: Headers inside comments should not have ids generated for them. + Given I visit issue page "Release 0.4" + And I leave a comment with a header containing "Comment with a header" + Then The comment with the header should not have an ID diff --git a/features/project/issues/milestones.feature b/features/project/issues/milestones.feature index 2f38acf14d..e67b5d2d86 100644 --- a/features/project/issues/milestones.feature +++ b/features/project/issues/milestones.feature @@ -22,3 +22,9 @@ Feature: Project Milestones Given the milestone has open and closed issues And I click link "v2.2" Then I should see 3 issues + + # Markdown + + Scenario: Headers inside the description should have ids generated for them. + Given I click link "v2.2" + Then Header "Description header" should have correct id and link diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 946f676012..3ca099b957 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -77,3 +77,15 @@ Feature: Project Merge Requests Then I modify merge commit message And I accept this merge request Then I should see merged request + + # Markdown + + Scenario: Headers inside the description should have ids generated for them. + When I visit merge request page "Bug NS-04" + Then Header "Description header" should have correct id and link + + @javascript + Scenario: Headers inside comments should not have ids generated for them. + Given I visit merge request page "Bug NS-04" + And I leave a comment with a header containing "Comment with a header" + Then The comment with the header should not have an ID diff --git a/features/project/source/markdown_render.feature b/features/project/source/markdown_render.feature index 04467b6664..42d6ebcb1c 100644 --- a/features/project/source/markdown_render.feature +++ b/features/project/source/markdown_render.feature @@ -4,6 +4,15 @@ Feature: Project markdown render And I own project "Delta" Given I visit project source page + # ------------------------------------------- + # README + # ------------------------------------------- + + Scenario: Tree view should have correct links in README + Given I go directory which contains README file + And I click on a relative link in README + Then I should see the correct markdown + Scenario: I browse files from master branch Then I should see files from repository in master And I should see rendered README which contains correct links @@ -28,6 +37,14 @@ Feature: Project markdown render And I click on Maintenance in README Then I should see correct maintenance file rendered + Scenario: README headers should have header links + Then I should see rendered README which contains correct links + And Header "Application details" should have correct id and link + + # ------------------------------------------- + # File content + # ------------------------------------------- + Scenario: I navigate to doc directory to view documentation in master And I navigate to the doc/api/README And I see correct file rendered @@ -40,6 +57,14 @@ Feature: Project markdown render And I click on raketasks in doc/api/README Then I should see correct directory rendered + Scenario: I navigate to doc directory to view user doc in master + And I navigate to the doc/api/README + And Header "GitLab API" should have correct id and link + + # ------------------------------------------- + # Markdown branch README + # ------------------------------------------- + Scenario: I browse files from markdown branch When I visit markdown branch Then I should see files from repository in markdown branch @@ -68,6 +93,10 @@ Feature: Project markdown render And I click on raketasks in doc/api/README Then I should see correct directory rendered for markdown branch + # ------------------------------------------- + # Wiki + # ------------------------------------------- + Scenario: I create a wiki page with different links Given I go to wiki page And I add various links to the wiki page @@ -81,12 +110,7 @@ Feature: Project markdown render And I click on Rake tasks link Then I see Rake tasks directory - Scenario: I visit the help page with markdown - Given I visit to the help page - And I select a page with markdown - Then I should see a help page with markdown - - Scenario: Tree view should have correct links in README - Given I go directory which contains README file - And I click on a relative link in README - Then I should see the correct markdown + Scenario: Wiki headers should have should have ids generated for them. + Given I go to wiki page + And I add a header to the wiki page + Then Wiki header should have correct id and link diff --git a/features/steps/help.rb b/features/steps/help.rb new file mode 100644 index 0000000000..aa147fd65c --- /dev/null +++ b/features/steps/help.rb @@ -0,0 +1,21 @@ +class Spinach::Features::Help < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + include SharedMarkdown + + step 'I visit the help page' do + visit help_path + end + + step 'I visit the "Rake Tasks" help page' do + visit help_raketasks_path + end + + step 'I should see "Rake Tasks" page markdown rendered' do + page.should have_content "GitLab provides some specific rake tasks to enable special features or perform maintenance tasks" + end + + step 'Header "Rebuild project satellites" should have correct ids and links' do + header_should_have_correct_id_and_link(3, 'Rebuild project satellites', 'rebuild-project-satellites') + end +end diff --git a/features/steps/project/project_issues.rb b/features/steps/project/project_issues.rb index 4a503dfaf4..a92fd50584 100644 --- a/features/steps/project/project_issues.rb +++ b/features/steps/project/project_issues.rb @@ -3,6 +3,7 @@ class ProjectIssues < Spinach::FeatureSteps include SharedProject include SharedNote include SharedPaths + include SharedMarkdown Given 'I should see "Release 0.4" in issues' do page.should have_content "Release 0.4" @@ -121,7 +122,9 @@ class ProjectIssues < Spinach::FeatureSteps create(:issue, title: "Release 0.4", project: project, - author: project.users.first) + author: project.users.first, + description: "# Description header" + ) end And 'project "Shop" have "Tweet control" open issue' do diff --git a/features/steps/project/project_markdown_render.rb b/features/steps/project/project_markdown_render.rb index 1209aae643..89fbb7408c 100644 --- a/features/steps/project/project_markdown_render.rb +++ b/features/steps/project/project_markdown_render.rb @@ -1,6 +1,7 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps include SharedAuthentication include SharedPaths + include SharedMarkdown And 'I own project "Delta"' do @project = Project.find_by(name: "Delta") @@ -44,7 +45,6 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps page.should have_content "maintenance.md" end - And 'I click on GitLab API doc directory in README' do click_link "GitLab API doc directory" end @@ -140,6 +140,16 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps page.should have_content "test GitLab API doc Rake tasks" end + step 'I add a header to the wiki page' do + fill_in "wiki[content]", with: "# Wiki header\n" + fill_in "wiki[message]", with: "Add header to wiki" + click_button "Create page" + end + + step 'Wiki header should have correct id and link' do + header_should_have_correct_id_and_link(1, 'Wiki header', 'wiki-header') + end + And 'I click on test link' do click_link "test" end @@ -173,18 +183,6 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps page.should have_content "maintenance.md" end - Given 'I visit to the help page' do - visit help_path - end - - And 'I select a page with markdown' do - click_link "Rake Tasks" - end - - Then 'I should see a help page with markdown' do - page.should have_content "GitLab provides some specific rake tasks to enable special features or perform maintenance tasks" - end - Given 'I go directory which contains README file' do visit project_tree_path(@project, "master/doc/api") current_path.should == project_tree_path(@project, "master/doc/api") @@ -198,4 +196,12 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps current_path.should == project_blob_path(@project, "master/doc/api/users.md") page.should have_content "List users" end + + step 'Header "Application details" should have correct id and link' do + header_should_have_correct_id_and_link(2, 'Application details', 'application-details') + end + + step 'Header "GitLab API" should have correct id and link' do + header_should_have_correct_id_and_link(1, 'GitLab API', 'gitlab-api') + end end diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index 0c5f05a0a6..fcbae8b8fb 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -3,6 +3,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps include SharedProject include SharedNote include SharedPaths + include SharedMarkdown step 'I click link "New Merge Request"' do click_link "New Merge Request" @@ -83,7 +84,9 @@ class ProjectMergeRequests < Spinach::FeatureSteps target_project: project, source_branch: 'stable', target_branch: 'master', - author: project.users.first) + author: project.users.first, + description: "# Description header" + ) end step 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do diff --git a/features/steps/project/project_milestones.rb b/features/steps/project/project_milestones.rb index 85962221c0..9ce18fbaab 100644 --- a/features/steps/project/project_milestones.rb +++ b/features/steps/project/project_milestones.rb @@ -2,6 +2,7 @@ class ProjectMilestones < Spinach::FeatureSteps include SharedAuthentication include SharedProject include SharedPaths + include SharedMarkdown Then 'I should see milestone "v2.2"' do milestone = @project.milestones.find_by(title: "v2.2") @@ -32,8 +33,11 @@ class ProjectMilestones < Spinach::FeatureSteps And 'project "Shop" has milestone "v2.2"' do project = Project.find_by(name: "Shop") - milestone = create(:milestone, title: "v2.2", project: project) - + milestone = create(:milestone, + title: "v2.2", + project: project, + description: "# Description header" + ) 3.times { create(:issue, project: project, milestone: milestone) } end diff --git a/features/steps/shared/markdown.rb b/features/steps/shared/markdown.rb new file mode 100644 index 0000000000..782f3f0920 --- /dev/null +++ b/features/steps/shared/markdown.rb @@ -0,0 +1,12 @@ +module SharedMarkdown + include Spinach::DSL + + def header_should_have_correct_id_and_link(level, text, id, parent = ".wiki") + page.find(:css, "#{parent} h#{level}##{id}").text.should == text + page.find(:css, "#{parent} h#{level}##{id} > :last-child")[:href].should =~ /##{id}$/ + end + + step 'Header "Description header" should have correct id and link' do + header_should_have_correct_id_and_link(1, 'Description header', 'description-header') + end +end diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb index da08da9420..36b81b7418 100644 --- a/features/steps/shared/note.rb +++ b/features/steps/shared/note.rb @@ -102,4 +102,21 @@ module SharedNote page.should have_content("XML attached") end end + + # Markdown + + step 'I leave a comment with a header containing "Comment with a header"' do + within(".js-main-target-form") do + fill_in "note[note]", with: "# Comment with a header" + click_button "Add Comment" + sleep 0.05 + end + end + + step 'The comment with the header should not have an ID' do + within(".note-text") do + page.should have_content("Comment with a header") + page.should_not have_css("#comment-with-a-header") + end + end end diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb index 6da0c1d6f9..42f6316910 100644 --- a/lib/redcarpet/render/gitlab_html.rb +++ b/lib/redcarpet/render/gitlab_html.rb @@ -8,6 +8,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML @project = @template.instance_variable_get("@project") @ref = @template.instance_variable_get("@ref") @request_path = @template.instance_variable_get("@path") + @options = options.dup super options end @@ -34,6 +35,16 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML h.link_to_gfm(content, link, title: title) end + def header(text, level) + if @options[:no_header_anchors] + "#{text}" + else + id = ActionController::Base.helpers.strip_tags(h.gfm(text)).downcase() \ + .gsub(/[^a-z0-9_-]/, '-').gsub(/-+/, '-').gsub(/^-/, '').gsub(/-$/, '') + "#{text}" + end + end + def preprocess(full_document) if @project h.create_relative_links(full_document, @project, @ref, @request_path, is_wiki?) diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 59abfb38ec..a445c18f00 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -348,8 +348,21 @@ describe GitlabMarkdownHelper do it "should handle references in headers" do actual = "\n# Working around ##{issue.iid}\n## Apply !#{merge_request.iid}" - markdown(actual).should match(%r{Working around ##{issue.iid}}) - markdown(actual).should match(%r{Apply !#{merge_request.iid}}) + markdown(actual, {no_header_anchors:true}).should match(%r{Working around ##{issue.iid}}) + markdown(actual, {no_header_anchors:true}).should match(%r{Apply !#{merge_request.iid}}) + end + + it "should add ids and links to headers" do + # Test every rule except nested tags. + text = '..Ab_c-d. e..' + id = 'ab_c-d-e' + markdown("# #{text}").should match(%r{

#{text}

}) + markdown("# #{text}", {no_header_anchors:true}).should == "

#{text}

" + + id = 'link-text' + markdown("# [link text](url) ![img alt](url)").should match( + %r{

link text ]*>

} + ) end it "should handle references in lists" do From 4b9c28bccded2064fc95cf891b87a375d5bcdcf7 Mon Sep 17 00:00:00 2001 From: GitLab Date: Tue, 11 Feb 2014 21:12:27 +0530 Subject: [PATCH 027/112] remove unwanted spaces, reduce diff, clean before merge --- spec/models/user_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 3b09f7978b..fd8d7133ae 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -367,10 +367,8 @@ describe User do it 'does not begin with https if website url begins with https' do user.website_url = 'https://test.com' - + expect(user.short_website_url).to eq 'test.com' end end - end - From f10153818b51da7ee4e691cea308dd8964d908c9 Mon Sep 17 00:00:00 2001 From: Johannes Schleifenbaum Date: Tue, 11 Feb 2014 19:15:13 +0100 Subject: [PATCH 028/112] Split the user ssh keys by newline, not the characters "\n" before: GET /user.keys ssh-rsa ...\nssh-rsa ...\nssh-rsa ... after: GET /user.keys ssh-rsa ... ssh-rsa ... sha-rsa ... --- app/controllers/profiles/keys_controller.rb | 2 +- .../profile_keys_controller_spec.rb | 49 +++++++++++++++++++ spec/factories.rb | 6 +++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 spec/controllers/profile_keys_controller_spec.rb diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index e8237a1f22..b4f14e649e 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -41,7 +41,7 @@ class Profiles::KeysController < ApplicationController begin user = User.find_by_username(params[:username]) if user.present? - render text: user.all_ssh_keys.join('\n') + render text: user.all_ssh_keys.join("\n") else render_404 and return end diff --git a/spec/controllers/profile_keys_controller_spec.rb b/spec/controllers/profile_keys_controller_spec.rb new file mode 100644 index 0000000000..121012d5d4 --- /dev/null +++ b/spec/controllers/profile_keys_controller_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe Profiles::KeysController do + let(:user) { create(:user) } + + describe "#get_keys" do + describe "non existant user" do + it "should generally not work" do + get :get_keys, username: 'not-existent' + + expect(response).not_to be_success + end + end + + describe "user with no keys" do + it "should generally work" do + get :get_keys, username: user.username + + expect(response).to be_success + end + + it "should render all keys separated with a new line" do + get :get_keys, username: user.username + + expect(response.body).to eq("") + end + end + + describe "user with keys" do + before do + user.keys << create(:key) + user.keys << create(:another_key) + end + + it "should generally work" do + get :get_keys, username: user.username + + expect(response).to be_success + end + + it "should render all keys separated with a new line" do + get :get_keys, username: user.username + + expect(response.body).not_to eq("") + expect(response.body).to eq(user.all_ssh_keys.join("\n")) + end + end + end +end diff --git a/spec/factories.rb b/spec/factories.rb index 8c12c9b3e1..e5d05a4c2e 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -207,6 +207,12 @@ FactoryGirl.define do end end + factory :another_key do + key do + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmTillFzNTrrGgwaCKaSj+QCz81E6jBc/s9av0+3b1Hwfxgkqjl4nAK/OD2NjgyrONDTDfR8cRN4eAAy6nY8GLkOyYBDyuc5nTMqs5z3yVuTwf3koGm/YQQCmo91psZ2BgDFTor8SVEE5Mm1D1k3JDMhDFxzzrOtRYFPci9lskTJaBjpqWZ4E9rDTD2q/QZntCqbC3wE9uSemRQB5f8kik7vD/AD8VQXuzKladrZKkzkONCPWsXDspUitjM8HkQdOf0PsYn1CMUC1xKYbCxkg5TkEosIwGv6CoEArUrdu/4+10LVslq494mAvEItywzrluCLCnwELfW+h/m8UHoVhZ" + end + end + factory :invalid_key do key do "ssh-rsa this_is_invalid_key==" From d39948a8d000edaf84a74ea2a9a58b6e230e0041 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 11 Feb 2014 21:03:43 +0200 Subject: [PATCH 029/112] Restore old padding for wiki blocks Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/generic/files.scss | 1 + app/assets/stylesheets/generic/issue_box.scss | 11 +++++------ app/assets/stylesheets/main/mixins.scss | 4 ---- app/views/projects/issues/show.html.haml | 7 ++++--- .../projects/merge_requests/show/_mr_box.html.haml | 7 ++++--- app/views/projects/milestones/show.html.haml | 7 ++++--- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/app/assets/stylesheets/generic/files.scss b/app/assets/stylesheets/generic/files.scss index 85111a4591..12559f7605 100644 --- a/app/assets/stylesheets/generic/files.scss +++ b/app/assets/stylesheets/generic/files.scss @@ -52,6 +52,7 @@ &.wiki { font-size: 14px; line-height: 1.6; + padding: 25px; .highlight { margin-bottom: 9px; diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss index c3a39f0251..033b4b20f5 100644 --- a/app/assets/stylesheets/generic/issue_box.scss +++ b/app/assets/stylesheets/generic/issue_box.scss @@ -18,17 +18,16 @@ } .title { - font-size: 20px; + font-size: 22px; font-weight: 500; - line-height: 28px; + line-height: 1.5; margin: 0; - color: #444; - border-bottom: 1px solid #eee; + color: #333; } .context { border: none; - border-bottom: 1px solid #eee; + border-top: 1px solid #eee; } .description { @@ -36,7 +35,7 @@ } .title, .context, .description { - padding: 15px 15px 15px 30px; + padding: 15px 25px; .clearfix { margin: 0; diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss index a7a5ed73ab..4afe61d756 100644 --- a/app/assets/stylesheets/main/mixins.scss +++ b/app/assets/stylesheets/main/mixins.scss @@ -114,10 +114,6 @@ font-size: 1.2em; } - // Larger 30px left margin is required for the header link icon. - // Use on all markdown including those without header links for uniformity. - margin: 20px 20px 20px 30px; - blockquote p { color: #888; font-size: 14px; diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 5033dfefe2..cd4a158e42 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -46,9 +46,10 @@ = render partial: 'issue_context', locals: { issue: @issue } - if @issue.description.present? - .wiki - = preserve do - = markdown @issue.description + .description + .wiki + = preserve do + = markdown @issue.description - content_for :note_actions do - if can?(current_user, :modify_issue, @issue) diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml index 9b95c09218..b4f648ab19 100644 --- a/app/views/projects/merge_requests/show/_mr_box.html.haml +++ b/app/views/projects/merge_requests/show/_mr_box.html.haml @@ -15,9 +15,10 @@ - if @merge_request.description.present? - .wiki - = preserve do - = markdown @merge_request.description + .description + .wiki + = preserve do + = markdown @merge_request.description - if @merge_request.closed? .description.alert-danger diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 283b4dfeac..4d504380c9 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -43,9 +43,10 @@ .progress-bar{style: "width: #{@milestone.percent_complete}%;"} - if @milestone.description.present? - .wiki - = preserve do - = markdown @milestone.description + .description + .wiki + = preserve do + = markdown @milestone.description %ul.nav.nav-tabs.append-bottom-10 %li.active From a5c62585a966408542846029fa341bdced01798c Mon Sep 17 00:00:00 2001 From: "Samuel D. Leslie" Date: Wed, 12 Feb 2014 18:27:00 +1100 Subject: [PATCH 030/112] Fix spelling of "GitLab" in HipChat service Pedantic, but it frustrates OCD people like myself :) --- app/models/project_services/hipchat_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index c0ba9f1e7f..d4795867ba 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -40,7 +40,7 @@ class HipchatService < Service end def execute(push_data) - gate[room].send('Gitlab', create_message(push_data)) + gate[room].send('GitLab', create_message(push_data)) end private From abb6204de832e2b9398389b4de48dd6021da00f9 Mon Sep 17 00:00:00 2001 From: dosire Date: Wed, 12 Feb 2014 09:45:34 +0100 Subject: [PATCH 031/112] Add information about rich text format dependencies. --- doc/markdown/markdown.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md index 008e37d11f..f49f09756a 100644 --- a/doc/markdown/markdown.md +++ b/doc/markdown/markdown.md @@ -45,6 +45,10 @@ You can use GFM in * milestones * wiki pages +You can also use other rich text files in GitLab. +You might have to install a depency to do so. +Please see the [github-markup gem readme](https://github.com/gitlabhq/markup#markups) for more information. + Newlines -------- The biggest difference that GFM introduces is in the handling of linebreaks. With traditional Markdown you can hard wrap paragraphs of text and they will be combined into a single paragraph. We find this to be the cause of a huge number of unintentional formatting errors. GFM treats newlines in paragraph-like content as real line breaks, which is probably what you intended. From 0bcabdaf8330d0a260d95ee8435170fa7258eb98 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 12 Feb 2014 12:54:49 +0200 Subject: [PATCH 032/112] Use gitlab_git 5.4.0 without BROKEN_DIFF constant Signed-off-by: Dmitriy Zaporozhets --- Gemfile | 2 +- Gemfile.lock | 4 ++-- app/controllers/projects/compare_controller.rb | 6 +----- app/models/merge_request_diff.rb | 8 +++----- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index 5943dceb71..6a06df6fbe 100644 --- a/Gemfile +++ b/Gemfile @@ -29,7 +29,7 @@ gem 'omniauth-github' # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '~> 5.3.0' +gem "gitlab_git", '~> 5.4.0' # Ruby/Rack Git Smart-HTTP Server Handler gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack' diff --git a/Gemfile.lock b/Gemfile.lock index 59bdac20d9..2c99063726 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -177,7 +177,7 @@ GEM charlock_holmes (~> 0.6.6) escape_utils (~> 0.2.4) mime-types (~> 1.19) - gitlab_git (5.3.0) + gitlab_git (5.4.0) activesupport (~> 4.0.0) charlock_holmes (~> 0.6.9) gitlab-grit (~> 2.6.1) @@ -579,7 +579,7 @@ DEPENDENCIES gitlab-gollum-lib (~> 1.1.0) gitlab-grack (~> 2.0.0.pre) gitlab-linguist (~> 3.0.0) - gitlab_git (~> 5.3.0) + gitlab_git (~> 5.4.0) gitlab_meta (= 6.0) gitlab_omniauth-ldap (= 1.0.4) gon (~> 5.0.0) diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index 696cb7a4ba..234b6058ff 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -15,11 +15,7 @@ class Projects::CompareController < Projects::ApplicationController @diffs = compare.diffs @refs_are_same = compare.same @line_notes = [] - - if @diffs == [Gitlab::Git::Diff::BROKEN_DIFF] - @diffs = [] - @timeout = true - end + @timeout = compare.timeout diff_line_count = Commit::diff_line_count(@diffs) @suppress_diff = Commit::diff_suppress?(@diffs, diff_line_count) && !params[:force_show_diff] diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 3ea610197e..a226fef734 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -148,13 +148,11 @@ class MergeRequestDiff < ActiveRecord::Base Gitlab::Git::Diff.between(repository, source_branch, target_branch) end - if diffs == broken_diffs - self.state = :timeout - diffs = [] - end - diffs ||= [] diffs + rescue Gitlab::Git::Diff::TimeoutError => ex + self.state = :timeout + diffs = [] end def repository From 59769fdb940712737656a441ef43a1ad2dd47f4d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 12 Feb 2014 12:56:13 +0200 Subject: [PATCH 033/112] Improve compare logic for EmailOnPush service Signed-off-by: Dmitriy Zaporozhets --- app/mailers/emails/projects.rb | 1 + app/views/notify/repository_push_email.html.haml | 5 +++++ app/views/notify/repository_push_email.text.haml | 5 +++++ app/workers/emails_on_push_worker.rb | 4 ++-- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index df21d7b5b0..428d74d83c 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -17,6 +17,7 @@ module Emails def repository_push_email(project_id, recipient, author_id, branch, compare) @project = Project.find(project_id) @author = User.find(author_id) + @compare = compare @commits = Commit.decorate(compare.commits) @diffs = compare.diffs @branch = branch diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml index d0b30c0833..ab0d6c653b 100644 --- a/app/views/notify/repository_push_email.html.haml +++ b/app/views/notify/repository_push_email.html.haml @@ -21,3 +21,8 @@ %pre = diff.diff %br + +- if @compare.timeout + %h5 Huge diff. To prevent performance issues it was hidden +- elsif @compare.commits_over_limit? + %h5 Diff for big amount of commits is disabled diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml index 6718ca6835..93b344d2c8 100644 --- a/app/views/notify/repository_push_email.text.haml +++ b/app/views/notify/repository_push_email.text.haml @@ -18,3 +18,8 @@ Diff: = diff.new_path || diff.old_path \===================================== = diff.diff +\ +- if @compare.timeout + Huge diff. To prevent performance issues it was hidden +- elsif @compare.commits_over_limit? + Diff for big amount of commits is disabled diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb index 9982b362a1..5e81810cbd 100644 --- a/app/workers/emails_on_push_worker.rb +++ b/app/workers/emails_on_push_worker.rb @@ -13,13 +13,13 @@ class EmailsOnPushWorker return true end - compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha) + compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha, MergeRequestDiff::COMMITS_SAFE_SIZE) # Do not send emails if git compare failed return false unless compare && compare.commits.present? recipients.split(" ").each do |recipient| - Notify.delay.repository_push_email(project_id, recipient, author_id, branch, compare) + Notify.repository_push_email(project_id, recipient, author_id, branch, compare).deliver end end end From 70df6055356ccc1cc1d8c8199e9b23d171d045f4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 12 Feb 2014 13:03:32 +0200 Subject: [PATCH 034/112] Fix link for MR diff download Signed-off-by: Dmitriy Zaporozhets --- .../projects/merge_requests/show/_diffs.html.haml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml index 2c7507cfb8..2917accdb5 100644 --- a/app/views/projects/merge_requests/show/_diffs.html.haml +++ b/app/views/projects/merge_requests/show/_diffs.html.haml @@ -3,8 +3,10 @@ - elsif @merge_request_diff.empty? %h4.nothing_here_message Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} - else - %h4.nothing_here_message - Can't load diff. - You can - = link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request), format: :diff, class: "vlink" - instead. + .bs-callout.bs-callout-warning + %h4 + Diff for this comparison is extremely large. + %p + You can + = link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request, format: :diff), class: "vlink" + instead. From 0e90ff8018ff9e2fe8c6b238ebd5cdd6babd72e8 Mon Sep 17 00:00:00 2001 From: dosire Date: Wed, 12 Feb 2014 14:02:50 +0100 Subject: [PATCH 035/112] Gemnasium makes us red even though we are not exposed to a JRuby bug. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 7257dcdd2d..8280fbd2ca 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,6 @@ * [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) -* [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) this button can be yellow (small updates are available) but must not be red (a security fix or an important update is available), gems are updated in major releases of GitLab. - * [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq) ### Resources From 36462d77b56d2ed94c6dcd95ef3c529b6edf96d4 Mon Sep 17 00:00:00 2001 From: dosire Date: Wed, 12 Feb 2014 14:49:31 +0100 Subject: [PATCH 036/112] Markdown styles dependencies are optional. --- doc/install/installation.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index cc2641f6f3..8cee78b03d 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -56,9 +56,6 @@ Install the required packages: sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate - # For reStructuredText markup language support install required package: - sudo apt-get install -y python-docutils - Make sure you have the right version of Git installed # Install Git @@ -353,6 +350,15 @@ nobody can access your GitLab by using this login information later on. # Advanced Setup Tips +## Additional markup styles + +Apart from the always supported markdown style there are other rich text files that GitLab can display. +But you might have to install a depency to do so. +Please see the [github-markup gem readme](https://github.com/gitlabhq/markup#markups) for more information. +For example, reStructuredText markup language support requires python-docutils: + + sudo apt-get install -y python-docutils + ## Custom Redis Connection If you'd like Resque to connect to a Redis server on a non-standard port or on From a36f5730b04da9e745f9643908154b89b7249d5c Mon Sep 17 00:00:00 2001 From: dosire Date: Wed, 12 Feb 2014 15:45:36 +0100 Subject: [PATCH 037/112] Backticks are just confusing here. --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 8cee78b03d..dd391eeb4b 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -144,7 +144,7 @@ GitLab Shell is an ssh access and repository management software developed speci # 5. Database -To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md). +To setup the MySQL/PostgreSQL database and dependencies please see [doc/install/databases.md](./databases.md). # 6. GitLab From 439a61783d0b61bbcc8f3c9e5b828b2270a679aa Mon Sep 17 00:00:00 2001 From: Ciro Santillli Date: Fri, 7 Feb 2014 17:59:55 +0100 Subject: [PATCH 038/112] User can leave group from group page. --- app/controllers/application_controller.rb | 8 +- app/controllers/profiles/groups_controller.rb | 7 +- app/controllers/users_groups_controller.rb | 13 +- app/helpers/groups_helper.rb | 6 +- app/models/ability.rb | 15 +++ app/views/groups/members.html.haml | 5 +- app/views/help/permissions.html.haml | 1 + app/views/profiles/groups/index.html.haml | 7 +- app/views/users_groups/_users_group.html.haml | 17 ++- features/admin/groups.feature | 2 +- features/group.feature | 116 ++++++++++++++++++ features/group/create_group.feature | 11 -- features/group/group.feature | 47 ------- features/profile/group.feature | 47 +++++++ features/steps/group/group.rb | 111 ++++++++++------- features/steps/profile/group.rb | 44 +++++++ .../steps/project/project_network_graph.rb | 1 + features/steps/shared/authentication.rb | 8 ++ features/steps/shared/group.rb | 36 ++++++ features/steps/shared/paths.rb | 56 +++++++-- features/steps/shared/project.rb | 13 +- features/steps/shared/user.rb | 14 ++- features/user.feature | 2 +- 23 files changed, 433 insertions(+), 154 deletions(-) create mode 100644 features/group.feature delete mode 100644 features/group/create_group.feature delete mode 100644 features/group/group.feature create mode 100644 features/profile/group.feature create mode 100644 features/steps/profile/group.rb create mode 100644 features/steps/shared/group.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5f6485e57c..acb2f2c21d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base end end - def render_404 - render file: Rails.root.join("public", "404"), layout: false, status: "404" + def render_403 + head :forbidden end - def render_403 - render file: Rails.root.join("public", "403"), layout: false, status: "403" + def render_404 + render file: Rails.root.join("public", "404"), layout: false, status: "404" end def require_non_empty_project diff --git a/app/controllers/profiles/groups_controller.rb b/app/controllers/profiles/groups_controller.rb index bdd991bec0..9a4d088651 100644 --- a/app/controllers/profiles/groups_controller.rb +++ b/app/controllers/profiles/groups_controller.rb @@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController def leave @users_group = group.users_groups.where(user_id: current_user.id).first - - if group.last_owner?(current_user) - redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.") - else + if can?(current_user, :destroy, @users_group) @users_group.destroy redirect_to(profile_groups_path, info: "You left #{group.name} group.") + else + return render_403 end end diff --git a/app/controllers/users_groups_controller.rb b/app/controllers/users_groups_controller.rb index bc5db44552..b9bdc18952 100644 --- a/app/controllers/users_groups_controller.rb +++ b/app/controllers/users_groups_controller.rb @@ -19,11 +19,14 @@ class UsersGroupsController < ApplicationController def destroy @users_group = @group.users_groups.find(params[:id]) - @users_group.destroy - - respond_to do |format| - format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' } - format.js { render nothing: true } + if can?(current_user, :destroy, @users_group) # May fail if last owner. + @users_group.destroy + respond_to do |format| + format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' } + format.js { render nothing: true } + end + else + return render_403 end end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 7c09273d53..5865396b69 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -1,6 +1,10 @@ module GroupsHelper def remove_user_from_group_message(group, user) - "You are going to remove #{user.name} from #{group.name} Group. Are you sure?" + "Are you sure you want to remove \"#{user.name}\" from \"#{group.name}\"?" + end + + def leave_group_message(group) + "Are you sure you want to leave \"#{group}\" group?" end def group_head_title diff --git a/app/models/ability.rb b/app/models/ability.rb index 120af80744..ba0ce527f6 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -14,6 +14,7 @@ class Ability when "MergeRequest" then merge_request_abilities(user, subject) when "Group" then group_abilities(user, subject) when "Namespace" then namespace_abilities(user, subject) + when "UsersGroup" then users_group_abilities(user, subject) else [] end.concat(global_abilities(user)) end @@ -219,5 +220,19 @@ class Ability end end end + + def users_group_abilities(user, subject) + rules = [] + target_user = subject.user + group = subject.group + can_manage = group_abilities(user, group).include?(:manage_group) + if can_manage && (user != target_user) + rules << :modify + end + if !group.last_owner?(user) && (can_manage || (user == target_user)) + rules << :destroy + end + rules + end end end diff --git a/app/views/groups/members.html.haml b/app/views/groups/members.html.haml index 124560e478..3095a2c7b7 100644 --- a/app/views/groups/members.html.haml +++ b/app/views/groups/members.html.haml @@ -6,7 +6,6 @@ %strong= link_to "here", help_permissions_path, class: "vlink" %hr -- can_manage_group = current_user.can? :manage_group, @group .ui-box .title %strong #{@group.name} @@ -15,6 +14,6 @@ (#{@members.count}) %ul.well-list - @members.each do |member| - = render 'users_groups/users_group', member: member, show_controls: can_manage_group -- if can_manage_group + = render 'users_groups/users_group', member: member, show_controls: true +- if current_user.can? :manage_group, @group = render "new_group_member" diff --git a/app/views/help/permissions.html.haml b/app/views/help/permissions.html.haml index 6505609022..7fd0c74057 100644 --- a/app/views/help/permissions.html.haml +++ b/app/views/help/permissions.html.haml @@ -217,3 +217,4 @@ %td %td %td.permission-x ✓ + %p.light Any user can remove himself from a group, unless he is the last Owner of the group. diff --git a/app/views/profiles/groups/index.html.haml b/app/views/profiles/groups/index.html.haml index 1d24e636bf..eefebf98c5 100644 --- a/app/views/profiles/groups/index.html.haml +++ b/app/views/profiles/groups/index.html.haml @@ -22,9 +22,10 @@ %i.icon-cogs Settings - = link_to leave_profile_group_path(group), data: { confirm: "Are you sure you want to leave #{group.name} group?"}, method: :delete, class: "btn-small btn grouped", title: 'Remove user from group' do - %i.icon-signout - Leave + - if can?(current_user, :destroy, user_group) + = link_to leave_profile_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn grouped", title: 'Remove user from group' do + %i.icon-signout + Leave = link_to group, class: 'group-name' do %strong= group.name diff --git a/app/views/users_groups/_users_group.html.haml b/app/views/users_groups/_users_group.html.haml index 5f477f3c97..b66b486fbc 100644 --- a/app/views/users_groups/_users_group.html.haml +++ b/app/views/users_groups/_users_group.html.haml @@ -9,12 +9,17 @@ %span.pull-right %strong= member.human_access - - - if show_controls && can?(current_user, :manage_group, @group) && current_user != user - = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do - %i.icon-edit - = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do - %i.icon-minus.icon-white + - if show_controls + - if can?(current_user, :modify, member) + = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do + %i.icon-edit + - if can?(current_user, :destroy, member) + - if current_user == member.user + = link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do + %i.icon-minus.icon-white + - else + = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do + %i.icon-minus.icon-white .edit-member.hide.js-toggle-content = form_for [@group, member], remote: true do |f| diff --git a/features/admin/groups.feature b/features/admin/groups.feature index 7741307f17..352c1b3803 100644 --- a/features/admin/groups.feature +++ b/features/admin/groups.feature @@ -2,7 +2,7 @@ Feature: Admin Groups Background: Given I sign in as an admin And I have group with projects - And Create user "John Doe" + And User "John Doe" exists And I visit admin groups page Scenario: See group list diff --git a/features/group.feature b/features/group.feature new file mode 100644 index 0000000000..aa49056fee --- /dev/null +++ b/features/group.feature @@ -0,0 +1,116 @@ +Feature: Groups + Background: + Given I sign in as "John Doe" + And "John Doe" is owner of group "Owned" + And "John Doe" is guest of group "Guest" + + @javascript + Scenario: I should see group "Owned" dashboard list + When I visit group "Owned" page + Then I should see group "Owned" projects list + And I should see projects activity feed + + Scenario: Create a group from dasboard + When I visit group "Owned" page + And I visit dashboard page + And I click new group link + And submit form with new group "Samurai" info + Then I should be redirected to group "Samurai" page + And I should see newly created group "Samurai" + + Scenario: I should see group "Owned" issues list + Given project from group "Owned" has issues assigned to me + When I visit group "Owned" issues page + Then I should see issues from group "Owned" assigned to me + + Scenario: I should see group "Owned" merge requests list + Given project from group "Owned" has merge requests assigned to me + When I visit group "Owned" merge requests page + Then I should see merge requests from group "Owned" assigned to me + + @javascript + Scenario: I should add user to projects in group "Owned" + Given User "Mary Jane" exists + When I visit group "Owned" members page + And I select user "Mary Jane" from list with role "Reporter" + Then I should see user "Mary Jane" in team list + + Scenario: I should see edit group "Owned" page + When I visit group "Owned" settings page + And I change group "Owned" name to "new-name" + Then I should see new group "Owned" name + + Scenario: I edit group "Owned" avatar + When I visit group "Owned" settings page + And I change group "Owned" avatar + And I visit group "Owned" settings page + Then I should see new group "Owned" avatar + And I should see the "Remove avatar" button + + Scenario: I remove group "Owned" avatar + When I visit group "Owned" settings page + And I have group "Owned" avatar + And I visit group "Owned" settings page + And I remove group "Owned" avatar + Then I should not see group "Owned" avatar + And I should not see the "Remove avatar" button + + # Leave + + @javascript + Scenario: Owner should be able to remove himself from group if he is not the last owner + Given "Mary Jane" is owner of group "Owned" + When I visit group "Owned" members page + Then I should see user "John Doe" in team list + Then I should see user "Mary Jane" in team list + When I click on the "Remove User From Group" button for "John Doe" + And I visit group "Owned" members page + Then I should not see user "John Doe" in team list + Then I should see user "Mary Jane" in team list + + @javascript + Scenario: Owner should not be able to remove himself from group if he is the last owner + Given "Mary Jane" is guest of group "Owned" + When I visit group "Owned" members page + Then I should see user "John Doe" in team list + Then I should see user "Mary Jane" in team list + Then I should not see the "Remove User From Group" button for "Mary Jane" + + @javascript + Scenario: Guest should be able to remove himself from group + Given "Mary Jane" is guest of group "Guest" + When I visit group "Guest" members page + Then I should see user "John Doe" in team list + Then I should see user "Mary Jane" in team list + When I click on the "Remove User From Group" button for "John Doe" + When I visit group "Guest" members page + Then I should not see user "John Doe" in team list + Then I should see user "Mary Jane" in team list + + @javascript + Scenario: Guest should be able to remove himself from group even if he is the only user in the group + When I visit group "Guest" members page + Then I should see user "John Doe" in team list + When I click on the "Remove User From Group" button for "John Doe" + When I visit group "Guest" members page + Then I should not see user "John Doe" in team list + + # Remove others + + @javascript + Scenario: Owner should be able to remove other users from group + Given "Mary Jane" is owner of group "Owned" + When I visit group "Owned" members page + Then I should see user "John Doe" in team list + Then I should see user "Mary Jane" in team list + When I click on the "Remove User From Group" button for "Mary Jane" + When I visit group "Owned" members page + Then I should see user "John Doe" in team list + Then I should not see user "Mary Jane" in team list + + Scenario: Guest should not be able to remove other users from group + Given "Mary Jane" is guest of group "Guest" + When I visit group "Guest" members page + Then I should see user "John Doe" in team list + Then I should see user "Mary Jane" in team list + Then I should not see the "Remove User From Group" button for "Mary Jane" diff --git a/features/group/create_group.feature b/features/group/create_group.feature deleted file mode 100644 index b77f3599e6..0000000000 --- a/features/group/create_group.feature +++ /dev/null @@ -1,11 +0,0 @@ -Feature: Groups - Background: - Given I sign in as a user - - Scenario: Create a group from dasboard - Given I have group with projects - And I visit dashboard page - When I click new group link - And submit form with new group info - Then I should be redirected to group page - And I should see newly created group diff --git a/features/group/group.feature b/features/group/group.feature deleted file mode 100644 index 6177263e47..0000000000 --- a/features/group/group.feature +++ /dev/null @@ -1,47 +0,0 @@ -Feature: Groups - Background: - Given I sign in as a user - And I have group with projects - - @javascript - Scenario: I should see group dashboard list - When I visit group page - Then I should see projects list - And I should see projects activity feed - - Scenario: I should see group issues list - Given project from group has issues assigned to me - When I visit group issues page - Then I should see issues from this group assigned to me - - Scenario: I should see group merge requests list - Given project from group has merge requests assigned to me - When I visit group merge requests page - Then I should see merge requests from this group assigned to me - - @javascript - Scenario: I should add user to projects in Group - Given Create user "John Doe" - When I visit group members page - And I select user "John Doe" from list with role "Reporter" - Then I should see user "John Doe" in team list - - Scenario: I should see edit group page - When I visit group settings page - And I change group name - Then I should see new group name - - Scenario: I edit my group avatar - When I visit group settings page - And I change my group avatar - And I visit group settings page - Then I should see new group avatar - And I should see the "Remove avatar" button - - Scenario: I remove my group avatar - When I visit group settings page - And I have an group avatar - And I visit group settings page - And I remove my group avatar - Then I should not see my group avatar - And I should not see the "Remove avatar" button diff --git a/features/profile/group.feature b/features/profile/group.feature new file mode 100644 index 0000000000..70b682e291 --- /dev/null +++ b/features/profile/group.feature @@ -0,0 +1,47 @@ +Feature: Profile Group + Background: + Given I sign in as "John Doe" + And "John Doe" is owner of group "Owned" + And "John Doe" is guest of group "Guest" + + # Leave groups + + @javascript + Scenario: Owner should be able to leave from group if he is not the last owner + Given "Mary Jane" is owner of group "Owned" + When I visit profile groups page + Then I should see group "Owned" in group list + Then I should see group "Guest" in group list + When I click on the "Leave" button for group "Owned" + And I visit profile groups page + Then I should not see group "Owned" in group list + Then I should see group "Guest" in group list + + @javascript + Scenario: Owner should not be able to leave from group if he is the last owner + Given "Mary Jane" is guest of group "Owned" + When I visit profile groups page + Then I should see group "Owned" in group list + Then I should see group "Guest" in group list + Then I should not see the "Leave" button for group "Owned" + + @javascript + Scenario: Guest should be able to leave from group + Given "Mary Jane" is guest of group "Guest" + When I visit profile groups page + Then I should see group "Owned" in group list + Then I should see group "Guest" in group list + When I click on the "Leave" button for group "Guest" + When I visit profile groups page + Then I should see group "Owned" in group list + Then I should not see group "Guest" in group list + + @javascript + Scenario: Guest should be able to leave from group even if he is the only user in the group + When I visit profile groups page + Then I should see group "Owned" in group list + Then I should see group "Guest" in group list + When I click on the "Leave" button for group "Guest" + When I visit profile groups page + Then I should see group "Owned" in group list + Then I should not see group "Guest" in group list diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index 686f683314..bd59b7a12f 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -1,42 +1,34 @@ class Groups < Spinach::FeatureSteps include SharedAuthentication include SharedPaths + include SharedGroup include SharedUser include Select2Helper - Then 'I should see projects list' do - current_user.authorized_projects.each do |project| + Then 'I should see group "Owned" projects list' do + Group.find_by(name: "Owned").projects.each do |project| page.should have_link project.name end end - And 'I have group with projects' do - @group = create(:group) - @group.add_owner(current_user) - @project = create(:project, namespace: @group) - @event = create(:closed_issue_event, project: @project) - - @project.team << [current_user, :master] - end - And 'I should see projects activity feed' do page.should have_content 'closed issue' end - Then 'I should see issues from this group assigned to me' do + Then 'I should see issues from group "Owned" assigned to me' do assigned_to_me(:issues).each do |issue| page.should have_content issue.title end end - Then 'I should see merge requests from this group assigned to me' do + Then 'I should see merge requests from group "Owned" assigned to me' do assigned_to_me(:merge_requests).each do |issue| page.should have_content issue.title[0..80] end end - And 'I select user "John Doe" from list with role "Reporter"' do - user = User.find_by(name: "John Doe") + And 'I select user "Mary Jane" from list with role "Reporter"' do + user = User.find_by(name: "Mary Jane") || create(:user, name: "Mary Jane") within ".users-group-form" do select2(user.id, from: "#user_ids", multiple: true) select "Reporter", from: "group_access" @@ -49,14 +41,29 @@ class Groups < Spinach::FeatureSteps projects_with_access.should have_content("John Doe") end - Given 'project from group has issues assigned to me' do + Then 'I should not see user "John Doe" in team list' do + projects_with_access = find(".ui-box .well-list") + projects_with_access.should_not have_content("John Doe") + end + + Then 'I should see user "Mary Jane" in team list' do + projects_with_access = find(".ui-box .well-list") + projects_with_access.should have_content("Mary Jane") + end + + Then 'I should not see user "Mary Jane" in team list' do + projects_with_access = find(".ui-box .well-list") + projects_with_access.should_not have_content("Mary Jane") + end + + Given 'project from group "Owned" has issues assigned to me' do create :issue, project: project, assignee: current_user, author: current_user end - Given 'project from group has merge requests assigned to me' do + Given 'project from group "Owned" has merge requests assigned to me' do create :merge_request, source_project: project, target_project: project, @@ -68,78 +75,94 @@ class Groups < Spinach::FeatureSteps click_link "New group" end - And 'submit form with new group info' do + And 'submit form with new group "Samurai" info' do fill_in 'group_name', with: 'Samurai' fill_in 'group_description', with: 'Tokugawa Shogunate' click_button "Create group" end - Then 'I should see newly created group' do + Then 'I should be redirected to group "Samurai" page' do + current_path.should == group_path(Group.last) + end + + Then 'I should see newly created group "Samurai"' do page.should have_content "Samurai" page.should have_content "Tokugawa Shogunate" page.should have_content "You will only see events from projects in this group" end - Then 'I should be redirected to group page' do - current_path.should == group_path(Group.last) - end - - And 'I change group name' do + And 'I change group "Owned" name to "new-name"' do fill_in 'group_name', with: 'new-name' click_button "Save group" end - Then 'I should see new group name' do + Then 'I should see new group "Owned" name' do within ".navbar-gitlab" do page.should have_content "group: new-name" end end - step 'I change my group avatar' do + step 'I change group "Owned" avatar' do attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) click_button "Save group" - @group.reload + Group.find_by(name: "Owned").reload end - step 'I should see new group avatar' do - @group.avatar.should be_instance_of AttachmentUploader - @group.avatar.url.should == "/uploads/group/avatar/#{ @group.id }/gitlab_logo.png" + step 'I should see new group "Owned" avatar' do + Group.find_by(name: "Owned").avatar.should be_instance_of AttachmentUploader + Group.find_by(name: "Owned").avatar.url.should == "/uploads/group/avatar/#{ Group.find_by(name:"Owned").id }/gitlab_logo.png" end step 'I should see the "Remove avatar" button' do page.should have_link("Remove avatar") end - step 'I have an group avatar' do + step 'I have group "Owned" avatar' do attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) click_button "Save group" - @group.reload + Group.find_by(name: "Owned").reload end - step 'I remove my group avatar' do + step 'I remove group "Owned" avatar' do click_link "Remove avatar" - @group.reload + Group.find_by(name: "Owned").reload end - step 'I should not see my group avatar' do - @group.avatar?.should be_false + step 'I should not see group "Owned" avatar' do + Group.find_by(name: "Owned").avatar?.should be_false end step 'I should not see the "Remove avatar" button' do page.should_not have_link("Remove avatar") end + step 'I click on the "Remove User From Group" button for "John Doe"' do + find(:css, 'li', text: "John Doe").find(:css, 'a.btn-remove').click + # poltergeist always confirms popups. + end + + step 'I click on the "Remove User From Group" button for "Mary Jane"' do + find(:css, 'li', text: "Mary Jane").find(:css, 'a.btn-remove').click + # poltergeist always confirms popups. + end + + step 'I should not see the "Remove User From Group" button for "John Doe"' do + find(:css, 'li', text: "John Doe").should_not have_selector(:css, 'a.btn-remove') + # poltergeist always confirms popups. + end + + step 'I should not see the "Remove User From Group" button for "Mary Jane"' do + find(:css, 'li', text: "Mary Jane").should_not have_selector(:css, 'a.btn-remove') + # poltergeist always confirms popups. + end + protected - def current_group - @group ||= Group.first - end - - def project - current_group.projects.first - end - def assigned_to_me key project.send(key).where(assignee_id: current_user.id) end + + def project + Group.find_by(name: "Owned").projects.first + end end diff --git a/features/steps/profile/group.rb b/features/steps/profile/group.rb new file mode 100644 index 0000000000..03144104c7 --- /dev/null +++ b/features/steps/profile/group.rb @@ -0,0 +1,44 @@ +class ProfileGroup < Spinach::FeatureSteps + include SharedAuthentication + include SharedGroup + include SharedPaths + include SharedUser + + # Leave + + step 'I click on the "Leave" button for group "Owned"' do + find(:css, 'li', text: "Owner").find(:css, 'i.icon-signout').click + # poltergeist always confirms popups. + end + + step 'I click on the "Leave" button for group "Guest"' do + find(:css, 'li', text: "Guest").find(:css, 'i.icon-signout').click + # poltergeist always confirms popups. + end + + step 'I should not see the "Leave" button for group "Owned"' do + find(:css, 'li', text: "Owner").should_not have_selector(:css, 'i.icon-signout') + # poltergeist always confirms popups. + end + + step 'I should not see the "Leave" button for groupr "Guest"' do + find(:css, 'li', text: "Guest").should_not have_selector(:css, 'i.icon-signout') + # poltergeist always confirms popups. + end + + step 'I should see group "Owned" in group list' do + page.should have_content("Owned") + end + + step 'I should not see group "Owned" in group list' do + page.should_not have_content("Owned") + end + + step 'I should see group "Guest" in group list' do + page.should have_content("Guest") + end + + step 'I should not see group "Guest" in group list' do + page.should_not have_content("Guest") + end +end diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index c7d9ece6fe..1c5cfcc6c6 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -1,5 +1,6 @@ class ProjectNetworkGraph < Spinach::FeatureSteps include SharedAuthentication + include SharedPaths include SharedProject Then 'page should have network graph' do diff --git a/features/steps/shared/authentication.rb b/features/steps/shared/authentication.rb index df05754c28..b8c11ce0a2 100644 --- a/features/steps/shared/authentication.rb +++ b/features/steps/shared/authentication.rb @@ -12,6 +12,14 @@ module SharedAuthentication login_as :admin end + step 'I sign in as "John Doe"' do + login_with(user_exists("John Doe")) + end + + step 'I sign in as "Mary Jane"' do + login_with(user_exists("Mary Jane")) + end + step 'I should be redirected to sign in page' do current_path.should == new_user_session_path end diff --git a/features/steps/shared/group.rb b/features/steps/shared/group.rb new file mode 100644 index 0000000000..6b4c47312a --- /dev/null +++ b/features/steps/shared/group.rb @@ -0,0 +1,36 @@ +module SharedGroup + include Spinach::DSL + + step '"John Doe" is owner of group "Owned"' do + is_member_of("John Doe", "Owned", Gitlab::Access::OWNER) + end + + step '"John Doe" is guest of group "Guest"' do + is_member_of("John Doe", "Guest", Gitlab::Access::GUEST) + end + + step '"Mary Jane" is owner of group "Owned"' do + is_member_of("Mary Jane", "Owned", Gitlab::Access::OWNER) + end + + step '"Mary Jane" is guest of group "Owned"' do + is_member_of("Mary Jane", "Owned", Gitlab::Access::GUEST) + end + + step '"Mary Jane" is guest of group "Guest"' do + is_member_of("Mary Jane", "Guest", Gitlab::Access::GUEST) + end + + protected + + def is_member_of(username, groupname, role) + @project_count ||= 0 + user = User.find_by(name: username) || create(:user, name: username) + group = Group.find_by(name: groupname) || create(:group, name: groupname) + group.add_user(user, role) + project ||= create(:project, namespace: group, path: "project#{@project_count}") + event ||= create(:closed_issue_event, project: project) + project.team << [user, :master] + @project_count += 1 + end +end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index c1aafc183d..a0213815a7 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -17,24 +17,44 @@ module SharedPaths # Group # ---------------------------------------- - step 'I visit group page' do - visit group_path(current_group) + step 'I visit group "Owned" page' do + visit group_path(Group.find_by(name:"Owned")) end - step 'I visit group issues page' do - visit issues_group_path(current_group) + step 'I visit group "Owned" issues page' do + visit issues_group_path(Group.find_by(name:"Owned")) end - step 'I visit group merge requests page' do - visit merge_requests_group_path(current_group) + step 'I visit group "Owned" merge requests page' do + visit merge_requests_group_path(Group.find_by(name:"Owned")) end - step 'I visit group members page' do - visit members_group_path(current_group) + step 'I visit group "Owned" members page' do + visit members_group_path(Group.find_by(name:"Owned")) end - step 'I visit group settings page' do - visit edit_group_path(current_group) + step 'I visit group "Owned" settings page' do + visit edit_group_path(Group.find_by(name:"Owned")) + end + + step 'I visit group "Guest" page' do + visit group_path(Group.find_by(name:"Guest")) + end + + step 'I visit group "Guest" issues page' do + visit issues_group_path(Group.find_by(name:"Guest")) + end + + step 'I visit group "Guest" merge requests page' do + visit merge_requests_group_path(Group.find_by(name:"Guest")) + end + + step 'I visit group "Guest" members page' do + visit members_group_path(Group.find_by(name:"Guest")) + end + + step 'I visit group "Guest" settings page' do + visit edit_group_path(Group.find_by(name:"Guest")) end # ---------------------------------------- @@ -93,6 +113,14 @@ module SharedPaths visit history_profile_path end + step 'I visit profile groups page' do + visit profile_groups_path + end + + step 'I should be redirected to the profile groups page' do + current_path.should == profile_groups_path + end + # ---------------------------------------- # Admin # ---------------------------------------- @@ -326,4 +354,12 @@ module SharedPaths def project project = Project.find_by!(name: "Shop") end + + # ---------------------------------------- + # Errors + # ---------------------------------------- + + Then 'page status code should be 404' do + page.status_code.should == 404 + end end diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index a6354aeaf8..f35beab8af 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -58,10 +58,6 @@ module SharedProject page.should have_content("Features:") end - Then 'page status code should be 404' do - page.status_code.should == 404 - end - def current_project @project ||= Project.first end @@ -107,24 +103,21 @@ module SharedProject end step '"John Doe" is authorized to private project "Enterprise"' do - user = User.find_by(name: "John Doe") - user ||= create(:user, name: "John Doe", username: "john_doe") + user = user_exists("John Doe", username: "john_doe") project = Project.find_by(name: "Enterprise") project ||= create(:project, name: "Enterprise", namespace: user.namespace) project.team << [user, :master] end step '"John Doe" is authorized to internal project "Internal"' do - user = User.find_by(name: "John Doe") - user ||= create(:user, name: "John Doe", username: "john_doe") + user = user_exists("John Doe", username: "john_doe") project = Project.find_by(name: "Internal") project ||= create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL project.team << [user, :master] end step '"John Doe" is authorized to public project "Community"' do - user = User.find_by(name: "John Doe") - user ||= create(:user, name: "John Doe", username: "john_doe") + user = user_exists("John Doe", username: "john_doe") project = Project.find_by(name: "Community") project ||= create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC project.team << [user, :master] diff --git a/features/steps/shared/user.rb b/features/steps/shared/user.rb index a2bf069a11..209d77c7ac 100644 --- a/features/steps/shared/user.rb +++ b/features/steps/shared/user.rb @@ -1,11 +1,17 @@ module SharedUser include Spinach::DSL - step 'Create user "John Doe"' do - create(:user, name: "John Doe", username: "john_doe") + step 'User "John Doe" exists' do + user_exists("John Doe", {username: "john_doe"}) end - step 'I sign in as "John Doe"' do - login_with(User.find_by(name: "John Doe")) + step 'User "Mary Jane" exists' do + user_exists("Mary Jane", {username: "mary_jane"}) + end + + protected + + def user_exists(name, options = {}) + User.find_by(name: name) || create(:user, {name: name, admin: false}.merge(options)) end end diff --git a/features/user.feature b/features/user.feature index c1c1ddda52..d4198c08de 100644 --- a/features/user.feature +++ b/features/user.feature @@ -1,6 +1,6 @@ Feature: User Background: - Given Create user "John Doe" + Given User "John Doe" exists And "John Doe" is authorized to private project "Enterprise" # Signed out From bccc2729ef3bcebf344903e73cc8b3f7f03bd242 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 12 Feb 2014 17:42:56 +0100 Subject: [PATCH 039/112] Update minor version upgrade guide get latest code section. --- doc/update/6.4-to-6.5.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/doc/update/6.4-to-6.5.md b/doc/update/6.4-to-6.5.md index d93ddc1162..c88be3582c 100644 --- a/doc/update/6.4-to-6.5.md +++ b/doc/update/6.4-to-6.5.md @@ -16,8 +16,20 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production ```bash cd /home/git/gitlab sudo -u git -H git fetch --all +``` + +For Gitlab Community Edition: + +```bash sudo -u git -H git checkout 6-5-stable -# For GitLab Enterprise Edition: sudo -u git -H git checkout 6-5-stable-ee +``` + +OR + +For GitLab Enterprise Edition: + +```bash +sudo -u git -H git checkout 6-5-stable-ee ``` ### 3. Update gitlab-shell (and its config) @@ -79,4 +91,4 @@ Follow the [`upgrade guide from 6.3 to 6.4`](6.3-to-6.4.md), except for the data 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. \ No newline at end of file +If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above. From af9d7fafa9089e51db60f43b60a4fedebe053843 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 13 Feb 2014 11:00:44 +0200 Subject: [PATCH 040/112] Adopt Group#members page for large groups (> 100 users) Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/application.scss | 1 + app/assets/stylesheets/sections/groups.scss | 9 +++++++ app/controllers/groups_controller.rb | 9 ++++++- app/views/groups/_new_group_member.html.haml | 7 ----- app/views/groups/members.html.haml | 28 +++++++++++++++++--- 5 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 app/assets/stylesheets/sections/groups.scss diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index cc5fdf6140..d5522f00f5 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -65,6 +65,7 @@ @import "sections/wall.scss"; @import "sections/dashboard.scss"; @import "sections/stat_graph.scss"; +@import "sections/groups.scss"; /** * Code ighlight diff --git a/app/assets/stylesheets/sections/groups.scss b/app/assets/stylesheets/sections/groups.scss new file mode 100644 index 0000000000..60ec79acad --- /dev/null +++ b/app/assets/stylesheets/sections/groups.scss @@ -0,0 +1,9 @@ +.new-group-member-holder { + margin-top: 50px; + background: #f9f9f9; + padding-top: 20px; +} + +.member-search-form { + float: left; +} diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 7b418ec98f..b927dd2f20 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -63,7 +63,14 @@ class GroupsController < ApplicationController def members @project = group.projects.find(params[:project_id]) if params[:project_id] - @members = group.users_groups.order('group_access DESC') + @members = group.users_groups + + if params[:search].present? + users = group.users.search(params[:search]) + @members = @members.where(user_id: users) + end + + @members = @members.order('group_access DESC').page(params[:page]).per(50) @users_group = UsersGroup.new end diff --git a/app/views/groups/_new_group_member.html.haml b/app/views/groups/_new_group_member.html.haml index 5801139a9f..3ab9276c54 100644 --- a/app/views/groups/_new_group_member.html.haml +++ b/app/views/groups/_new_group_member.html.haml @@ -1,15 +1,8 @@ = form_for @users_group, url: group_users_groups_path(@group), html: { class: 'form-horizontal users-group-form' } do |f| - %h4.append-bottom-20 - New member(s) for - %strong #{@group.name} - group - - %p 1. Choose users you want in the group .form-group = f.label :user_ids, "People", class: 'control-label' .col-sm-10= users_select_tag(:user_ids, multiple: true, class: 'input-large') - %p 2. Set access level for them .form-group = f.label :group_access, "Group Access", class: 'control-label' .col-sm-10= select_tag :group_access, options_for_select(UsersGroup.group_access_roles, @users_group.group_access), class: "project-access-select select2" diff --git a/app/views/groups/members.html.haml b/app/views/groups/members.html.haml index 3095a2c7b7..38069feb37 100644 --- a/app/views/groups/members.html.haml +++ b/app/views/groups/members.html.haml @@ -6,14 +6,34 @@ %strong= link_to "here", help_permissions_path, class: "vlink" %hr -.ui-box + +.clearfix + = form_tag members_group_path(@group), method: :get, class: 'form-inline member-search-form' do + .form-group + = search_field_tag :search, params[:search], { placeholder: 'Find member by name', class: 'form-control search-text-input input-mn-300' } + = submit_tag 'Search', class: 'btn' + + - if current_user.can? :manage_group, @group + .pull-right + = link_to '#', class: 'btn btn-new js-toggle-visibility-link' do + Add members + %i.icon-chevron-down + + .js-toggle-visibility-container.hide.new-group-member-holder + = render "new_group_member" + +.ui-box.prepend-top-20 .title %strong #{@group.name} group members %small - (#{@members.count}) + (#{@members.total_count}) %ul.well-list - @members.each do |member| = render 'users_groups/users_group', member: member, show_controls: true -- if current_user.can? :manage_group, @group - = render "new_group_member" += paginate @members, theme: 'gitlab' + +:coffeescript + $('form.member-search-form').on 'submit', (event) -> + event.preventDefault() + Turbolinks.visit @.action + '?' + $(@).serialize() From 0f134e54dd4b6044deb3042787602fde938436e5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 13 Feb 2014 11:06:35 +0200 Subject: [PATCH 041/112] Fix group test for new member add procedure Signed-off-by: Dmitriy Zaporozhets --- features/steps/group/group.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index bd59b7a12f..81472d1ca3 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -29,6 +29,7 @@ class Groups < Spinach::FeatureSteps And 'I select user "Mary Jane" from list with role "Reporter"' do user = User.find_by(name: "Mary Jane") || create(:user, name: "Mary Jane") + click_link 'Add members' within ".users-group-form" do select2(user.id, from: "#user_ids", multiple: true) select "Reporter", from: "group_access" From 13ecbb04bc4deeddec49ccad6e9c1538bbc405d4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 13 Feb 2014 13:57:11 +0200 Subject: [PATCH 042/112] Show only people who have assigned issues in assignee dropdown Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/issues_controller.rb | 1 + app/views/projects/issues/_issues.html.haml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index ba5c52d510..3965569303 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -29,6 +29,7 @@ class Projects::IssuesController < Projects::ApplicationController sort_param = params[:sort] || 'newest' @sort = sort_param.humanize unless sort_param.empty? + @assignees = User.where(id: @project.issues.pluck(:assignee_id)) respond_to do |format| format.html diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index 87d30a4a16..fc4128a829 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -49,7 +49,7 @@ Any = link_to project_filter_path(assignee_id: 0) do Unassigned - - @project.team.members.sort_by(&:name).each do |user| + - @assignees.sort_by(&:name).each do |user| %li = link_to project_filter_path(assignee_id: user.id) do = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' From abb3121308d6317fdcc103ca463dc7c0cb9077dc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 13 Feb 2014 13:59:07 +0200 Subject: [PATCH 043/112] Show only people who have assigned merge requests in assignee dropdown Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/issues_controller.rb | 1 - app/controllers/projects/merge_requests_controller.rb | 1 + app/views/projects/merge_requests/index.html.haml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 3965569303..dd11948edd 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -28,7 +28,6 @@ class Projects::IssuesController < Projects::ApplicationController @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? sort_param = params[:sort] || 'newest' @sort = sort_param.humanize unless sort_param.empty? - @assignees = User.where(id: @project.issues.pluck(:assignee_id)) respond_to do |format| diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index de31ee12b6..d36b5b27e8 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -28,6 +28,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController assignee_id, milestone_id = params[:assignee_id], params[:milestone_id] @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero? @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? + @assignees = User.where(id: @project.merge_requests.pluck(:assignee_id)) end def show diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index a525a49015..dcc68a3030 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -31,7 +31,7 @@ Any = link_to project_filter_path(assignee_id: 0) do Unassigned - - @project.team.members.sort_by(&:name).each do |user| + - @assignees.sort_by(&:name).each do |user| %li = link_to project_filter_path(assignee_id: user.id) do = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' From 9d8c8275f8e7ef24263d9cbb9161a9487972581b Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Thu, 13 Feb 2014 13:30:06 +0100 Subject: [PATCH 044/112] Added gitter link --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8280fbd2ca..dcd303e08a 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,8 @@ or start each component separately * [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview. +* [Gitter](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help. + ### Getting in touch From cf9c8e7382254b7abc928ec5af093da736d1ec3f Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 13 Feb 2014 14:25:43 +0100 Subject: [PATCH 045/112] Explanation MR workflow and authorization --- app/views/help/workflow.html.haml | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/app/views/help/workflow.html.haml b/app/views/help/workflow.html.haml index 2b8950cd5c..2ac5cd3a65 100644 --- a/app/views/help/workflow.html.haml +++ b/app/views/help/workflow.html.haml @@ -1,6 +1,8 @@ = render layout: 'help/layout' do %h3.page-title Workflow + %h4 Summary + %ol.help %li %p Clone project @@ -35,3 +37,37 @@ %li %p Your team lead will review code & merge it to main branch + %h3 Authorization for Merge Requests + %p + There are two main ways to have a merge request flow with GitLab: working with protected branches in a single repository, or working with forks of an authoritative project. + + %h4 Protected branch flow + %p + With the protected branch flow everybody works within the same GitLab project. + The project maintainers get Master access and the regular developers get Developer access. + The maintainers mark the authoritative branches as 'Protected'. + The developers push feature branches to the project and create merge requests to have their feature branches reviewed and merged into one of the protected branches. + Only users with Master access can merge changes into a protected branch. + + %h5 Advantages + %ul + %li fewer projects means less clutter + %li developers need to consider only one remote repository + + %h5 Disadvantages + %ul + %li manual setup of protected branch required for each new project + + %h4 Forking workflow + %p + With the forking workflow the maintainers get Master access and the regular developers get Reporter access to the authoritative repository, which prohibits them from pushing any changes to it. + Developers create forks of the authoritative project and push their feature branches to their own forks. + To get their changes into master they need to create a merge request across forks. + + %h5 Advantages + %ul + %li in an appropriately configured GitLab group, new projects automatically get the required access restrictions for regular developers: fewer manual steps to configure authorization for new projects + + %h5 Disadvantages + %ul + %li all developers on the project need to keep their forks up to date, which requires more advanced Git skills (managing multiple remotes) From 1d48904ac807c6d382c8965329085b321381cc3d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 13 Feb 2014 15:45:24 +0200 Subject: [PATCH 046/112] Show avatars in ajax user selectbox Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/users_select.js.coffee | 4 ++-- app/assets/stylesheets/generic/selects.scss | 4 ++++ lib/api/entities.rb | 6 ++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index c1fa16ca89..ce9a505b1e 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -1,7 +1,7 @@ $ -> userFormatResult = (user) -> - if user.avatar - avatar = user.avatar.url + if user.avatar_url + avatar = user.avatar_url else if gon.gravatar_enabled avatar = gon.gravatar_url avatar = avatar.replace('%{hash}', md5(user.email)) diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss index c506bff8a7..a257049bac 100644 --- a/app/assets/stylesheets/generic/selects.scss +++ b/app/assets/stylesheets/generic/selects.scss @@ -78,3 +78,7 @@ select { .project-refs-form .select2-container { margin-right: 10px; } + +.ajax-users-dropdown .select2-search { + padding-top: 4px; +} diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 8f54d0d4d8..8557fa074d 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -6,6 +6,12 @@ module API expose :is_admin?, as: :is_admin expose :can_create_group?, as: :can_create_group expose :can_create_project?, as: :can_create_project + + expose :avatar_url do |user, options| + if user.avatar.present? + user.avatar.url + end + end end class UserSafe < Grape::Entity From f0f88390c1309b0d5a8cead701477e21c2174f05 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 13 Feb 2014 16:08:26 +0200 Subject: [PATCH 047/112] project_user selectbox with ajax autocomplete Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/api.js.coffee | 18 ++++++++ .../project_users_select.js.coffee | 43 +++++++++++++++++++ app/assets/stylesheets/generic/selects.scss | 6 ++- app/helpers/application_helper.rb | 9 ---- app/helpers/selects_helper.rb | 19 ++++++++ app/views/projects/issues/_issues.html.haml | 2 +- lib/api/projects.rb | 14 +++++- 7 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 app/assets/javascripts/project_users_select.js.coffee create mode 100644 app/helpers/selects_helper.rb diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee index 5f4a38ebbd..fafa5cdfaa 100644 --- a/app/assets/javascripts/api.js.coffee +++ b/app/assets/javascripts/api.js.coffee @@ -3,6 +3,7 @@ user_path: "/api/:version/users/:id.json" notes_path: "/api/:version/projects/:id/notes.json" namespaces_path: "/api/:version/namespaces.json" + project_users_path: "/api/:version/projects/:id/users.json" # Get 20 (depends on api) recent notes # and sort the ascending from oldest to newest @@ -50,6 +51,23 @@ ).done (users) -> callback(users) + # Return project users list. Filtered by query + # Only active users retrieved + projectUsers: (project_id, query, callback) -> + url = Api.buildUrl(Api.project_users_path) + url = url.replace(':id', project_id) + + $.ajax( + url: url + data: + private_token: gon.api_token + search: query + per_page: 20 + active: true + dataType: "json" + ).done (users) -> + callback(users) + # Return namespaces list. Filtered by query namespaces: (query, callback) -> url = Api.buildUrl(Api.namespaces_path) diff --git a/app/assets/javascripts/project_users_select.js.coffee b/app/assets/javascripts/project_users_select.js.coffee new file mode 100644 index 0000000000..fbb1293b28 --- /dev/null +++ b/app/assets/javascripts/project_users_select.js.coffee @@ -0,0 +1,43 @@ +$ -> + projectUserFormatResult = (user) -> + if user.avatar_url + avatar = user.avatar_url + else if gon.gravatar_enabled + avatar = gon.gravatar_url + avatar = avatar.replace('%{hash}', md5(user.email)) + avatar = avatar.replace('%{size}', '24') + else + avatar = gon.relative_url_root + "/assets/no_avatar.png" + + "
+
+
#{user.name}
+
#{user.username}
+
" + + projectUserFormatSelection = (user) -> + user.name + + $('.ajax-project-users-select').each (i, select) -> + project_id = $('body').data('project-id') + $(select).select2 + placeholder: "Search for a user" + multiple: $(select).hasClass('multiselect') + minimumInputLength: 0 + query: (query) -> + Api.projectUsers project_id, query.term, (users) -> + data = { results: users } + query.callback(data) + + initSelection: (element, callback) -> + id = $(element).val() + if id isnt "" + Api.user(id, callback) + + + formatResult: projectUserFormatResult + formatSelection: projectUserFormatSelection + dropdownCssClass: "ajax-project-users-dropdown" + dropdownAutoWidth: true + escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results + m diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss index a257049bac..0c7852925b 100644 --- a/app/assets/stylesheets/generic/selects.scss +++ b/app/assets/stylesheets/generic/selects.scss @@ -79,6 +79,8 @@ select { margin-right: 10px; } -.ajax-users-dropdown .select2-search { - padding-top: 4px; +.ajax-users-dropdown, .ajax-project-users-dropdown { + .select2-search { + padding-top: 4px; + } } diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 1550e8b7e0..4e7d01acd2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -162,15 +162,6 @@ module ApplicationHelper alias_method :url_to_image, :image_url - def users_select_tag(id, opts = {}) - css_class = "ajax-users-select " - css_class << "multiselect " if opts[:multiple] - css_class << (opts[:class] || '') - value = opts[:selected] || '' - - hidden_field_tag(id, value, class: css_class) - end - def body_data_page path = controller.controller_path.split('/') namespace = path.first if path.second diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb new file mode 100644 index 0000000000..0668a16480 --- /dev/null +++ b/app/helpers/selects_helper.rb @@ -0,0 +1,19 @@ +module SelectsHelper + def users_select_tag(id, opts = {}) + css_class = "ajax-users-select " + css_class << "multiselect " if opts[:multiple] + css_class << (opts[:class] || '') + value = opts[:selected] || '' + + hidden_field_tag(id, value, class: css_class) + end + + def project_users_select_tag(id, opts = {}) + css_class = "ajax-project-users-select " + css_class << "multiselect " if opts[:multiple] + css_class << (opts[:class] || '') + value = opts[:selected] || '' + + hidden_field_tag(id, value, class: css_class) + end +end diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index fc4128a829..66e8efb7df 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -6,7 +6,7 @@ = form_tag bulk_update_project_issues_path(@project), method: :post do %span Update selected issues with   = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") - = select_tag('update[assignee_id]', bulk_update_assignee_options, prompt: "Assignee") + = project_users_select_tag('update[assignee_id]') = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone") = hidden_field_tag 'update[issues_ids]', [] = hidden_field_tag :status, params[:status] diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 888aa7e77d..bcca69ff49 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -11,7 +11,7 @@ module API end not_found! end - + def map_public_to_visibility_level(attrs) publik = attrs.delete(:public) publik = [ true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON' ].include?(publik) @@ -308,6 +308,18 @@ module API projects = Project.where("(id in (?) OR visibility_level in (?)) AND (name LIKE (?))", ids, visibility_levels, "%#{params[:query]}%") present paginate(projects), with: Entities::Project end + + + # Get a users list + # + # Example Request: + # GET /users + get ':id/users' do + @users = User.where(id: user_project.team.users.map(&:id)) + @users = @users.search(params[:search]) if params[:search].present? + @users = paginate @users + present @users, with: Entities::User + end end end end From 67798492bc5409b5a596fa28022e1e6cdf5985e4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 13 Feb 2014 16:16:23 +0200 Subject: [PATCH 048/112] Add placeholder support for project_users_select_tag Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/project_users_select.js.coffee | 3 ++- app/helpers/selects_helper.rb | 3 ++- app/views/projects/issues/_issues.html.haml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/project_users_select.js.coffee b/app/assets/javascripts/project_users_select.js.coffee index fbb1293b28..59a53cb52b 100644 --- a/app/assets/javascripts/project_users_select.js.coffee +++ b/app/assets/javascripts/project_users_select.js.coffee @@ -20,8 +20,9 @@ $ -> $('.ajax-project-users-select').each (i, select) -> project_id = $('body').data('project-id') + $(select).select2 - placeholder: "Search for a user" + placeholder: $(select).data('placeholder') || "Search for a user" multiple: $(select).hasClass('multiselect') minimumInputLength: 0 query: (query) -> diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb index 0668a16480..a1fe4488ae 100644 --- a/app/helpers/selects_helper.rb +++ b/app/helpers/selects_helper.rb @@ -13,7 +13,8 @@ module SelectsHelper css_class << "multiselect " if opts[:multiple] css_class << (opts[:class] || '') value = opts[:selected] || '' + placeholder = opts[:placeholder] || 'Select user' - hidden_field_tag(id, value, class: css_class) + hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder) end end diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index 66e8efb7df..9cedcd453f 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -6,7 +6,7 @@ = form_tag bulk_update_project_issues_path(@project), method: :post do %span Update selected issues with   = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") - = project_users_select_tag('update[assignee_id]') + = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee') = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone") = hidden_field_tag 'update[issues_ids]', [] = hidden_field_tag :status, params[:status] From 9b5728057e1d0a47fd2923c3b2fa2248edebafac Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 13 Feb 2014 19:59:09 +0200 Subject: [PATCH 049/112] Restyle issue/mr top filters for list Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/generic/common.scss | 1 + app/assets/stylesheets/sections/issues.scss | 29 +++- app/helpers/issues_helper.rb | 4 +- app/views/projects/issues/_head.html.haml | 4 +- app/views/projects/issues/_issues.html.haml | 157 +++++++++--------- .../projects/merge_requests/index.html.haml | 102 ++++++------ app/views/shared/_sort_dropdown.html.haml | 2 +- 7 files changed, 156 insertions(+), 143 deletions(-) diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss index 4824194ec4..9161868808 100644 --- a/app/assets/stylesheets/generic/common.scss +++ b/app/assets/stylesheets/generic/common.scss @@ -112,6 +112,7 @@ pre.well-pre { .dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus { background: #29b; + color: #FFF } .breadcrumb > li + li:before { diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss index 5afb13a86b..a7fa900faf 100644 --- a/app/assets/stylesheets/sections/issues.scss +++ b/app/assets/stylesheets/sections/issues.scss @@ -14,8 +14,8 @@ .issue-check { float: left; - padding: 8px 0; padding-right: 8px; + margin-bottom: 10px; min-width: 15px; } @@ -38,13 +38,21 @@ } } -input.check_all_issues { +.check-all-holder { + height: 32px; float: left; - padding: 0; - margin: 0; - margin-right: 10px; - position: relative; - top: 13px; + margin-right: 12px; + padding: 6px 10px; + border: 1px solid #ccc; + @include border-radius(4px); + + + input.check_all_issues { + padding: 0; + margin: 0; + position: relative; + top: 3px; + } } .issues_content { @@ -91,6 +99,13 @@ input.check_all_issues { .update_selected_issues { margin-left: 4px; } + + .select2-container .select2-choice { + height: 32px; + line-height: 28px; + color: #444 !important; + font-weight: 500; + } } } diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index cdba6ce84d..16981edd98 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -70,11 +70,11 @@ module IssuesHelper end def bulk_update_milestone_options - options_for_select(["None (backlog)", nil]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id]) + options_for_select(["None (backlog)"]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id]) end def bulk_update_assignee_options - options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]) + options_for_select(["None (unassigned)"]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]) end def assignee_options object diff --git a/app/views/projects/issues/_head.html.haml b/app/views/projects/issues/_head.html.haml index 61213e752f..2f0aa33fe1 100644 --- a/app/views/projects/issues/_head.html.haml +++ b/app/views/projects/issues/_head.html.haml @@ -17,10 +17,10 @@ %li.pull-right .pull-right - = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'inline issue-search-form' do + = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do .append-right-10.hidden-xs.hidden-sm = search_field_tag :issue_search, nil, { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' } - if can? current_user, :write_issue, @project - = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new", title: "New Issue", id: "new_issue_link" do + = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do %i.icon-plus New Issue diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index 9cedcd453f..020bfa3697 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -1,87 +1,86 @@ -.ui-box - .title +.append-bottom-10 + .check-all-holder = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" - .clearfix - .issues_bulk_update.hide - = form_tag bulk_update_project_issues_path(@project), method: :post do - %span Update selected issues with   - = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") - = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee') - = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone") - = hidden_field_tag 'update[issues_ids]', [] - = hidden_field_tag :status, params[:status] - = button_tag "Save", class: "btn update_selected_issues btn-small btn-save" - .issues-filters - %span Filter by - .dropdown.inline.prepend-left-10 - %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"} - %i.icon-tags - %span.light labels: - - if params[:label_name].present? - %strong= params[:label_name] - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to project_filter_path(label_name: nil) do - Any - - issue_label_names.each do |label_name| - %li - = link_to project_filter_path(label_name: label_name) do - %span{class: "label #{label_css_class(label_name)}"} - %i.icon-tag - = label_name - .dropdown.inline.prepend-left-10 - %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"} - %i.icon-user - %span.light assignee: - - if @assignee.present? - %strong= @assignee.name - - elsif params[:assignee_id] == "0" - Unassigned - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to project_filter_path(assignee_id: nil) do - Any - = link_to project_filter_path(assignee_id: 0) do - Unassigned - - @assignees.sort_by(&:name).each do |user| - %li - = link_to project_filter_path(assignee_id: user.id) do - = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' - = user.name + .issues-filters + .dropdown.inline + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.icon-tags + %span.light labels: + - if params[:label_name].present? + %strong= params[:label_name] + - else + Any + %b.caret + %ul.dropdown-menu + %li + = link_to project_filter_path(label_name: nil) do + Any + - issue_label_names.each do |label_name| + %li + = link_to project_filter_path(label_name: label_name) do + %span{class: "label #{label_css_class(label_name)}"} + %i.icon-tag + = label_name + .dropdown.inline.prepend-left-10 + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.icon-user + %span.light assignee: + - if @assignee.present? + %strong= @assignee.name + - elsif params[:assignee_id] == "0" + Unassigned + - else + Any + %b.caret + %ul.dropdown-menu + %li + = link_to project_filter_path(assignee_id: nil) do + Any + = link_to project_filter_path(assignee_id: 0) do + Unassigned + - @assignees.sort_by(&:name).each do |user| + %li + = link_to project_filter_path(assignee_id: user.id) do + = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' + = user.name - .dropdown.inline.prepend-left-10 - %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"} - %i.icon-time - %span.light milestone: - - if @milestone.present? - %strong= @milestone.title - - elsif params[:milestone_id] == "0" - None (backlog) - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to project_filter_path(milestone_id: nil) do - Any - = link_to project_filter_path(milestone_id: 0) do - None (backlog) - - project_active_milestones.each do |milestone| - %li - = link_to project_filter_path(milestone_id: milestone.id) do - %strong= milestone.title - %small.light= milestone.expires_at + .dropdown.inline.prepend-left-10 + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.icon-time + %span.light milestone: + - if @milestone.present? + %strong= @milestone.title + - elsif params[:milestone_id] == "0" + None (backlog) + - else + Any + %b.caret + %ul.dropdown-menu + %li + = link_to project_filter_path(milestone_id: nil) do + Any + = link_to project_filter_path(milestone_id: 0) do + None (backlog) + - project_active_milestones.each do |milestone| + %li + = link_to project_filter_path(milestone_id: milestone.id) do + %strong= milestone.title + %small.light= milestone.expires_at - .pull-right - = render 'shared/sort_dropdown' + .pull-right + = render 'shared/sort_dropdown' + .clearfix + .issues_bulk_update.hide + = form_tag bulk_update_project_issues_path(@project), method: :post do + = select_tag('update[status]', options_for_select(['Open', 'Closed']), prompt: "Status") + = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee') + = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone") + = hidden_field_tag 'update[issues_ids]', [] + = hidden_field_tag :status, params[:status] + = button_tag "Update issues", class: "btn update_selected_issues btn-save" +.ui-box %ul.well-list.issues-list = render @issues - if @issues.blank? diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index dcc68a3030..d45bec3a23 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -10,59 +10,57 @@ .col-md-3 = render 'shared/project_filter', project_entities_path: project_merge_requests_path(@project) .col-md-9 + .mr-filters.append-bottom-10 + .dropdown.inline + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.icon-user + %span.light assignee: + - if @assignee.present? + %strong= @assignee.name + - elsif params[:assignee_id] == "0" + Unassigned + - else + Any + %b.caret + %ul.dropdown-menu + %li + = link_to project_filter_path(assignee_id: nil) do + Any + = link_to project_filter_path(assignee_id: 0) do + Unassigned + - @assignees.sort_by(&:name).each do |user| + %li + = link_to project_filter_path(assignee_id: user.id) do + = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' + = user.name + + .dropdown.inline.prepend-left-10 + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.icon-time + %span.light milestone: + - if @milestone.present? + %strong= @milestone.title + - elsif params[:milestone_id] == "0" + None (backlog) + - else + Any + %b.caret + %ul.dropdown-menu + %li + = link_to project_filter_path(milestone_id: nil) do + Any + = link_to project_filter_path(milestone_id: 0) do + None (backlog) + - project_active_milestones.each do |milestone| + %li + = link_to project_filter_path(milestone_id: milestone.id) do + %strong= milestone.title + %small.light= milestone.expires_at + + .pull-right + = render 'shared/sort_dropdown' + .ui-box - .title - .mr-filters - %span Filter by - .dropdown.inline.prepend-left-10 - %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"} - %i.icon-user - %span.light assignee: - - if @assignee.present? - %strong= @assignee.name - - elsif params[:assignee_id] == "0" - Unassigned - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to project_filter_path(assignee_id: nil) do - Any - = link_to project_filter_path(assignee_id: 0) do - Unassigned - - @assignees.sort_by(&:name).each do |user| - %li - = link_to project_filter_path(assignee_id: user.id) do - = image_tag avatar_icon(user.email), class: "avatar s16", alt: '' - = user.name - - .dropdown.inline.prepend-left-10 - %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"} - %i.icon-time - %span.light milestone: - - if @milestone.present? - %strong= @milestone.title - - elsif params[:milestone_id] == "0" - None (backlog) - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to project_filter_path(milestone_id: nil) do - Any - = link_to project_filter_path(milestone_id: 0) do - None (backlog) - - project_active_milestones.each do |milestone| - %li - = link_to project_filter_path(milestone_id: milestone.id) do - %strong= milestone.title - %small.light= milestone.expires_at - - .pull-right - = render 'shared/sort_dropdown' - %ul.well-list.mr-list = render @merge_requests - if @merge_requests.blank? diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml index 2e87566996..7b37b39780 100644 --- a/app/views/shared/_sort_dropdown.html.haml +++ b/app/views/shared/_sort_dropdown.html.haml @@ -1,5 +1,5 @@ .dropdown.inline.prepend-left-10 - %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"} + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %span.light sort: - if @sort.present? = @sort From aaad7fd973d88a49fe23f01cca6b2248ad7977d4 Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Thu, 13 Feb 2014 20:09:11 +0100 Subject: [PATCH 050/112] Fixes #6207 Allow raw download of *.msi files This PR also allows for download of [exe,rar,r0n,7z,7zip,zip] Fix was originaly proposed by @MensSana --- app/controllers/projects/raw_controller.rb | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index 18ace028b0..a6b7ae3f12 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -11,11 +11,7 @@ class Projects::RawController < Projects::ApplicationController @blob = @repository.blob_at(@commit.id, @path) if @blob - type = if @blob.mime_type =~ /html|javascript/ - 'text/plain; charset=utf-8' - else - @blob.mime_type - end + type = get_blob_type headers['X-Content-Type-Options'] = 'nosniff' @@ -29,5 +25,17 @@ class Projects::RawController < Projects::ApplicationController not_found! end end + + private + + def get_blob_type + if @blob.mime_type =~ /html|javascript/ + 'text/plain; charset=utf-8' + elsif @blob.name =~ /(?:msi|exe|rar|r0\d|7z|7zip|zip)$/ + 'application/octet-stream' + else + @blob.mime_type + end + end end From 009858bf4bd4b81c526aaccfe6847b1c8862aaa3 Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Thu, 13 Feb 2014 20:59:45 +0100 Subject: [PATCH 051/112] Update readme.md Changed `Gitter` to `Gitter chat room` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcd303e08a..6678f427e4 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ or start each component separately * [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview. -* [Gitter](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help. +* [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help. ### Getting in touch From 5ed87ab7ccc8e5cf92b068bb75542f05b28a947e Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Thu, 13 Feb 2014 21:14:20 +0100 Subject: [PATCH 052/112] Fixes #6311: cp the init.d file locally instead of remote --- doc/update/5.4-to-6.0.md | 2 +- doc/update/6.0-to-6.1.md | 2 +- doc/update/6.1-to-6.2.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/update/5.4-to-6.0.md b/doc/update/5.4-to-6.0.md index a1a406fe7e..312e9a4608 100644 --- a/doc/update/5.4-to-6.0.md +++ b/doc/update/5.4-to-6.0.md @@ -94,7 +94,7 @@ Note: We switched from Puma in GitLab 5.4 to unicorn in GitLab 6.0. ```bash sudo rm /etc/init.d/gitlab -sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/6-0-stable/lib/support/init.d/gitlab +sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo chmod +x /etc/init.d/gitlab ``` diff --git a/doc/update/6.0-to-6.1.md b/doc/update/6.0-to-6.1.md index ac8f0a77ef..b7fd763485 100644 --- a/doc/update/6.0-to-6.1.md +++ b/doc/update/6.0-to-6.1.md @@ -71,7 +71,7 @@ sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production ```bash sudo rm /etc/init.d/gitlab -sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/6-1-stable/lib/support/init.d/gitlab +sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo chmod +x /etc/init.d/gitlab ``` diff --git a/doc/update/6.1-to-6.2.md b/doc/update/6.1-to-6.2.md index 7342a9117c..3c453a5ab4 100644 --- a/doc/update/6.1-to-6.2.md +++ b/doc/update/6.1-to-6.2.md @@ -87,7 +87,7 @@ sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab ```bash sudo rm /etc/init.d/gitlab -sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/6-2-stable/lib/support/init.d/gitlab +sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo chmod +x /etc/init.d/gitlab ``` From c131c185acafeed355a255d90892145ae689781a Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Thu, 13 Feb 2014 21:50:02 -0700 Subject: [PATCH 053/112] Update upgrader.md ... safety first --- doc/update/upgrader.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md index 99c81a7877..305ef961be 100644 --- a/doc/update/upgrader.md +++ b/doc/update/upgrader.md @@ -28,3 +28,15 @@ __GitLab Upgrader is available only for GitLab version 6.4.2 or higher__ sudo service gitlab start sudo service nginx restart + +### 4. 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 with: + + sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production + +If all items are green, then congratulations upgrade is complete! From 29cfd33d949d21d67f3892473c24d4f0a127dfe6 Mon Sep 17 00:00:00 2001 From: Jason Hollingsworth Date: Sat, 8 Feb 2014 21:08:49 -0600 Subject: [PATCH 054/112] Add email aliases for users Emails are used to associate commits with users. The emails are not verified and don't have to be valid email addresses. They are assigned on a first come, first serve basis. Notifications are sent when an email is added. --- app/controllers/profiles/emails_controller.rb | 26 ++++++ app/helpers/commits_helper.rb | 15 ++-- app/mailers/emails/profile.rb | 6 ++ app/models/email.rb | 33 ++++++++ app/models/user.rb | 13 +++ app/observers/email_observer.rb | 5 ++ app/services/git_push_service.rb | 4 +- app/services/notification_service.rb | 7 ++ app/views/layouts/nav/_profile.html.haml | 4 + app/views/notify/new_email_email.html.haml | 10 +++ app/views/notify/new_email_email.text.erb | 7 ++ app/views/profiles/emails/index.html.haml | 29 +++++++ config/routes.rb | 1 + db/migrate/20140209025651_create_emails.rb | 13 +++ db/schema.rb | 84 +++++++++++-------- features/profile/emails.feature | 25 ++++++ .../commits/commits_user_lookup.feature | 14 ++++ features/steps/profile/profile_emails.rb | 48 +++++++++++ .../project_browse_commits_user_lookup.rb | 35 ++++++++ features/support/env.rb | 2 +- spec/factories.rb | 13 +++ spec/mailers/notify_spec.rb | 22 +++++ spec/observers/email_observer_spec.rb | 17 ++++ spec/routing/routing_spec.rb | 17 ++++ spec/services/notification_service_spec.rb | 13 +++ spec/support/valid_commit.rb | 1 + spec/support/valid_commit_with_alt_email.rb | 6 ++ 27 files changed, 424 insertions(+), 46 deletions(-) create mode 100644 app/controllers/profiles/emails_controller.rb create mode 100644 app/models/email.rb create mode 100644 app/observers/email_observer.rb create mode 100644 app/views/notify/new_email_email.html.haml create mode 100644 app/views/notify/new_email_email.text.erb create mode 100644 app/views/profiles/emails/index.html.haml create mode 100644 db/migrate/20140209025651_create_emails.rb create mode 100644 features/profile/emails.feature create mode 100644 features/project/commits/commits_user_lookup.feature create mode 100644 features/steps/profile/profile_emails.rb create mode 100644 features/steps/project/project_browse_commits_user_lookup.rb create mode 100644 spec/observers/email_observer_spec.rb create mode 100644 spec/support/valid_commit_with_alt_email.rb diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb new file mode 100644 index 0000000000..9996b67a8a --- /dev/null +++ b/app/controllers/profiles/emails_controller.rb @@ -0,0 +1,26 @@ +class Profiles::EmailsController < ApplicationController + layout "profile" + + def index + @primary = current_user.email + @emails = current_user.emails + end + + def create + @email = current_user.emails.new(params[:email]) + + flash[:alert] = @email.errors.full_messages.first unless @email.save + + redirect_to profile_emails_url + end + + def destroy + @email = current_user.emails.find(params[:id]) + @email.destroy + + respond_to do |format| + format.html { redirect_to profile_emails_url } + format.js { render nothing: true } + end + end +end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 663369e458..5e5f3f77a2 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -122,17 +122,18 @@ module CommitsHelper def commit_person_link(commit, options = {}) source_name = commit.send "#{options[:source]}_name".to_sym source_email = commit.send "#{options[:source]}_email".to_sym + + user = User.find_for_commit(source_email, source_name) + person_name = user.nil? ? source_name : user.name + person_email = user.nil? ? source_email : user.email + text = if options[:avatar] - avatar = image_tag(avatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") - %Q{#{avatar} #{source_name}} + avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") + %Q{#{avatar} #{person_name}} else - source_name + person_name end - # Prefer email match over name match - user = User.where(email: source_email).first - user ||= User.where(name: source_name).first - options = { class: "commit-#{options[:source]}-link has_tooltip", data: { :'original-title' => sanitize(source_email) } diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb index bcd44f9476..c91660a02b 100644 --- a/app/mailers/emails/profile.rb +++ b/app/mailers/emails/profile.rb @@ -6,6 +6,12 @@ module Emails mail(to: @user.email, subject: subject("Account was created for you")) end + def new_email_email(email_id) + @email = Email.find(email_id) + @user = @email.user + mail(to: @user.email, subject: subject("Email was added to your account")) + end + def new_ssh_key_email(key_id) @key = Key.find(key_id) @user = @key.user diff --git a/app/models/email.rb b/app/models/email.rb new file mode 100644 index 0000000000..22e71e4f10 --- /dev/null +++ b/app/models/email.rb @@ -0,0 +1,33 @@ +# == Schema Information +# +# Table name: emails +# +# id :integer not null, primary key +# user_id :integer not null +# email :string not null +# created_at :datetime not null +class Email < ActiveRecord::Base + attr_accessible :email, :user_id + + # + # Relations + # + belongs_to :user + + # + # Validations + # + validates :user_id, presence: true + validates :email, presence: true, email: { strict_mode: true }, uniqueness: true + validate :unique_email, if: ->(email) { email.email_changed? } + + before_validation :cleanup_email + + def cleanup_email + self.email = self.email.downcase.strip + end + + def unique_email + self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email) + end +end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index 10f21d2350..dd59f67ea3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -78,6 +78,7 @@ class User < ActiveRecord::Base # Profile has_many :keys, dependent: :destroy + has_many :emails, dependent: :destroy # Groups has_many :users_groups, dependent: :destroy @@ -116,6 +117,7 @@ class User < ActiveRecord::Base validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true validate :namespace_uniq, if: ->(user) { user.username_changed? } validate :avatar_type, if: ->(user) { user.avatar_changed? } + validate :unique_email, if: ->(user) { user.email_changed? } validates :avatar, file_size: { maximum: 100.kilobytes.to_i } before_validation :generate_password, on: :create @@ -183,6 +185,13 @@ class User < ActiveRecord::Base where(conditions).first end end + + def find_for_commit(email, name) + # Prefer email match over name match + User.where(email: email).first || + User.joins(:emails).where(emails: { email: email }).first || + User.where(name: name).first + end def filter filter_name case filter_name @@ -250,6 +259,10 @@ class User < ActiveRecord::Base end end + def unique_email + self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email) + end + # Groups user has access to def authorized_groups @authorized_groups ||= begin diff --git a/app/observers/email_observer.rb b/app/observers/email_observer.rb new file mode 100644 index 0000000000..026ad8b1d9 --- /dev/null +++ b/app/observers/email_observer.rb @@ -0,0 +1,5 @@ +class EmailObserver < BaseObserver + def after_create(email) + notification.new_email(email) + end +end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index e54f88e42d..fcc03c3e4b 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -188,8 +188,6 @@ class GitPushService end def commit_user commit - User.where(email: commit.author_email).first || - User.where(name: commit.author_name).first || - user + User.find_for_commit(commit.author_email, commit.author_name) || user end end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 7c02777e91..9d7bb9639a 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -17,6 +17,13 @@ class NotificationService end end + # Always notify user about email added to profile + def new_email(email) + if email.user + mailer.new_email_email(email.id) + end + end + # When create an issue we should send next emails: # # * issue assignee if their notification level is not Disabled diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml index d44cb975ea..35d0d41750 100644 --- a/app/views/layouts/nav/_profile.html.haml +++ b/app/views/layouts/nav/_profile.html.haml @@ -4,6 +4,10 @@ %i.icon-home = nav_link(controller: :accounts) do = link_to "Account", profile_account_path + = nav_link(controller: :emails) do + = link_to profile_emails_path do + Emails + %span.count= current_user.emails.count + 1 - unless current_user.ldap_user? = nav_link(controller: :passwords) do = link_to "Password", edit_profile_password_path diff --git a/app/views/notify/new_email_email.html.haml b/app/views/notify/new_email_email.html.haml new file mode 100644 index 0000000000..4a0448a573 --- /dev/null +++ b/app/views/notify/new_email_email.html.haml @@ -0,0 +1,10 @@ +%p + Hi #{@user.name}! +%p + A new email was added to your account: +%p + email: + %code= @email.email +%p + If this email was added in error, you can remove it here: + = link_to "Emails", profile_emails_url diff --git a/app/views/notify/new_email_email.text.erb b/app/views/notify/new_email_email.text.erb new file mode 100644 index 0000000000..51cba99ad0 --- /dev/null +++ b/app/views/notify/new_email_email.text.erb @@ -0,0 +1,7 @@ +Hi <%= @user.name %>! + +A new email was added to your account: + +email.................. <%= @email.email %> + +If this email was added in error, you can remove it here: <%= profile_emails_url %> diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml new file mode 100644 index 0000000000..dc45ab2de7 --- /dev/null +++ b/app/views/profiles/emails/index.html.haml @@ -0,0 +1,29 @@ +%h3.page-title + My Email Addresses +%p.light + Your + %b Primary Email + will be used for account notifications, avatar detection and web based operations, such as edits and merges. All email addresses will be used to identify your commits. + +.ui-box + .title + Emails (#{@emails.count + 1}) + %ul.well-list#emails-table + %li + %strong= @primary + %span.label.label-success Primary Email + - @emails.each do |email| + %li + %strong= email.email + %span.cgray + added #{time_ago_with_tooltip(email.created_at)} + = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-small btn-remove pull-right' + +%h3.page-title Add Email Address += form_for 'email', url: profile_emails_path, html: { class: 'form-horizontal' } do |f| + .form-group + = f.label :email, class: 'control-label' + .col-sm-10 + = f.text_field :email, class: 'form-control' + .form-actions + = f.submit 'Add', class: 'btn btn-create' \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 8c66ad741f..fdca1e6266 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -124,6 +124,7 @@ Gitlab::Application.routes.draw do end end resources :keys + resources :emails, only: [:index, :create, :destroy] resources :groups, only: [:index] do member do delete :leave diff --git a/db/migrate/20140209025651_create_emails.rb b/db/migrate/20140209025651_create_emails.rb new file mode 100644 index 0000000000..cb78c4af11 --- /dev/null +++ b/db/migrate/20140209025651_create_emails.rb @@ -0,0 +1,13 @@ +class CreateEmails < ActiveRecord::Migration + def change + create_table :emails do |t| + t.integer :user_id, null: false + t.string :email, null: false + + t.timestamps + end + + add_index :emails, :user_id + add_index :emails, :email, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index acbb793bbe..65f79fb7e0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140127170938) do +ActiveRecord::Schema.define(version: 20140209025651) do create_table "broadcast_messages", force: true do |t| t.text "message", null: false @@ -33,6 +33,16 @@ ActiveRecord::Schema.define(version: 20140127170938) do add_index "deploy_keys_projects", ["project_id"], name: "index_deploy_keys_projects_on_project_id", using: :btree + create_table "emails", force: true do |t| + t.integer "user_id", null: false + t.string "email", null: false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "emails", ["email"], name: "index_emails_on_email", unique: true, using: :btree + add_index "emails", ["user_id"], name: "index_emails_on_user_id", using: :btree + create_table "events", force: true do |t| t.string "target_type" t.integer "target_id" @@ -66,8 +76,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do t.integer "assignee_id" t.integer "author_id" t.integer "project_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "position", default: 0 t.string "branch_name" t.text "description" @@ -85,8 +95,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do create_table "keys", force: true do |t| t.integer "user_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.text "key" t.string "title" t.string "type" @@ -111,8 +121,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do t.integer "author_id" t.integer "assignee_id" t.string "title" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "milestone_id" t.string "state" t.string "merge_status" @@ -164,8 +174,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do t.text "note" t.string "noteable_type" t.integer "author_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "project_id" t.string "attachment" t.string "line_code" @@ -187,8 +197,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do t.string "name" t.string "path" t.text "description" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "creator_id" t.boolean "issues_enabled", default: true, null: false t.boolean "wall_enabled", default: true, null: false @@ -239,8 +249,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do t.text "content", limit: 2147483647 t.integer "author_id", null: false t.integer "project_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "file_name" t.datetime "expires_at" t.boolean "private", default: true, null: false @@ -262,42 +272,45 @@ ActiveRecord::Schema.define(version: 20140127170938) do t.datetime "created_at" end + add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree + add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree + create_table "tags", force: true do |t| t.string "name" end create_table "users", force: true do |t| - t.string "email", default: "", null: false - t.string "encrypted_password", limit: 128, default: "", null: false + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0 + t.integer "sign_in_count", default: 0 t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" t.string "last_sign_in_ip" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "name" - t.boolean "admin", default: false, null: false - t.integer "projects_limit", default: 10 - t.string "skype", default: "", null: false - t.string "linkedin", default: "", null: false - t.string "twitter", default: "", null: false + t.boolean "admin", default: false, null: false + t.integer "projects_limit", default: 10 + t.string "skype", default: "", null: false + t.string "linkedin", default: "", null: false + t.string "twitter", default: "", null: false t.string "authentication_token" - t.integer "theme_id", default: 1, null: false + t.integer "theme_id", default: 1, null: false t.string "bio" - t.integer "failed_attempts", default: 0 + t.integer "failed_attempts", default: 0 t.datetime "locked_at" t.string "extern_uid" t.string "provider" t.string "username" - t.boolean "can_create_group", default: true, null: false - t.boolean "can_create_team", default: true, null: false + t.boolean "can_create_group", default: true, null: false + t.boolean "can_create_team", default: true, null: false t.string "state" - t.integer "color_scheme_id", default: 1, null: false - t.integer "notification_level", default: 1, null: false + t.integer "color_scheme_id", default: 1, null: false + t.integer "notification_level", default: 1, null: false t.datetime "password_expires_at" t.integer "created_by_id" t.string "avatar" @@ -305,14 +318,15 @@ ActiveRecord::Schema.define(version: 20140127170938) do t.datetime "confirmed_at" t.datetime "confirmation_sent_at" t.string "unconfirmed_email" - t.boolean "hide_no_ssh_key", default: false - t.string "website_url", default: "", null: false + t.boolean "hide_no_ssh_key", default: false + t.string "website_url", default: "", null: false end add_index "users", ["admin"], name: "index_users_on_admin", using: :btree add_index "users", ["authentication_token"], name: "index_users_on_authentication_token", unique: true, using: :btree add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree + add_index "users", ["extern_uid", "provider"], name: "index_users_on_extern_uid_and_provider", unique: true, using: :btree add_index "users", ["name"], name: "index_users_on_name", using: :btree add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree add_index "users", ["username"], name: "index_users_on_username", using: :btree @@ -331,8 +345,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do create_table "users_projects", force: true do |t| t.integer "user_id", null: false t.integer "project_id", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "project_access", default: 0, null: false t.integer "notification_level", default: 3, null: false end @@ -344,8 +358,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do create_table "web_hooks", force: true do |t| t.string "url" t.integer "project_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "type", default: "ProjectHook" t.integer "service_id" t.boolean "push_events", default: true, null: false diff --git a/features/profile/emails.feature b/features/profile/emails.feature new file mode 100644 index 0000000000..148fc76608 --- /dev/null +++ b/features/profile/emails.feature @@ -0,0 +1,25 @@ +Feature: Profile Emails + Background: + Given I sign in as a user + And I visit profile emails page + + Scenario: I should see emails + Then I should see my emails + + Scenario: Add new email + Given I submit new email "my@email.com" + Then I should see new email "my@email.com" + And I should see my emails + + Scenario: Add duplicate email + Given I submit duplicate email @user.email + Then I should not have @user.email added + And I should see my emails + + Scenario: Remove email + Given I submit new email "my@email.com" + Then I should see new email "my@email.com" + And I should see my emails + Then I click link "Remove" for "my@email.com" + Then I should not see email "my@email.com" + And I should see my emails diff --git a/features/project/commits/commits_user_lookup.feature b/features/project/commits/commits_user_lookup.feature new file mode 100644 index 0000000000..f3864c0ab3 --- /dev/null +++ b/features/project/commits/commits_user_lookup.feature @@ -0,0 +1,14 @@ +Feature: Project Browse Commits User Lookup + Background: + Given I sign in as a user + And I own a project + And I have the user that authored the commits + And I visit my project's commits page + + Scenario: I browse commit from list + Given I click on commit link + Then I see commit info + + Scenario: I browse another commit from list + Given I click on another commit link + Then I see other commit info \ No newline at end of file diff --git a/features/steps/profile/profile_emails.rb b/features/steps/profile/profile_emails.rb new file mode 100644 index 0000000000..99588c8599 --- /dev/null +++ b/features/steps/profile/profile_emails.rb @@ -0,0 +1,48 @@ +class ProfileEmails < Spinach::FeatureSteps + include SharedAuthentication + + Then 'I visit profile emails page' do + visit profile_emails_path + end + + Then 'I should see my emails' do + page.should have_content(@user.email) + @user.emails.each do |email| + page.should have_content(email.email) + end + end + + And 'I submit new email "my@email.com"' do + fill_in "email_email", with: "my@email.com" + click_button "Add" + end + + Then 'I should see new email "my@email.com"' do + email = @user.emails.find_by(email: "my@email.com") + email.should_not be_nil + page.should have_content("my@email.com") + end + + Then 'I should not see email "my@email.com"' do + email = @user.emails.find_by(email: "my@email.com") + email.should be_nil + page.should_not have_content("my@email.com") + end + + Then 'I click link "Remove" for "my@email.com"' do + # there should only be one remove button at this time + click_link "Remove" + # force these to reload as they have been cached + @user.emails.reload + end + + And 'I submit duplicate email @user.email' do + fill_in "email_email", with: @user.email + click_button "Add" + end + + Then 'I should not have @user.email added' do + email = @user.emails.find_by(email: @user.email) + email.should be_nil + end +end diff --git a/features/steps/project/project_browse_commits_user_lookup.rb b/features/steps/project/project_browse_commits_user_lookup.rb new file mode 100644 index 0000000000..328be37355 --- /dev/null +++ b/features/steps/project/project_browse_commits_user_lookup.rb @@ -0,0 +1,35 @@ +class ProjectBrowseCommitsUserLookup < Spinach::FeatureSteps + include SharedAuthentication + include SharedProject + include SharedPaths + + Given 'I have the user that authored the commits' do + @user = create(:user, email: 'dmitriy.zaporozhets@gmail.com') + create(:email, { user: @user, email: 'dzaporozhets@sphereconsultinginc.com' }) + end + + Given 'I click on commit link' do + visit project_commit_path(@project, ValidCommit::ID) + end + + Given 'I click on another commit link' do + visit project_commit_path(@project, ValidCommitWithAltEmail::ID) + end + + Then 'I see commit info' do + page.should have_content ValidCommit::MESSAGE + check_author_link(ValidCommit::AUTHOR_EMAIL) + end + + Then 'I see other commit info' do + page.should have_content ValidCommitWithAltEmail::MESSAGE + check_author_link(ValidCommitWithAltEmail::AUTHOR_EMAIL) + end + + def check_author_link(email) + author_link = find('.commit-author-link') + author_link['href'].should == user_path(@user) + author_link['data-original-title'].should == email + find('.commit-author-name').text.should == @user.name + end +end diff --git a/features/support/env.rb b/features/support/env.rb index 0186002c55..7b11f5a7c6 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -15,7 +15,7 @@ require 'spinach/capybara' require 'sidekiq/testing/inline' -%w(valid_commit big_commits select2_helper test_env).each do |f| +%w(valid_commit valid_commit_with_alt_email big_commits select2_helper test_env).each do |f| require Rails.root.join('spec', 'support', f) end diff --git a/spec/factories.rb b/spec/factories.rb index e5d05a4c2e..37436e53b9 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -219,6 +219,19 @@ FactoryGirl.define do end end end + + factory :email do + user + email do + Faker::Internet.email('alias') + end + + factory :another_email do + email do + Faker::Internet.email('another.alias') + end + end + end factory :milestone do title diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index d53dc17d97..88cae0bb75 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -90,6 +90,28 @@ describe Notify do end end + describe 'user added email' do + let(:email) { create(:email) } + + subject { Notify.new_email_email(email.id) } + + it 'is sent to the new user' do + should deliver_to email.user.email + end + + it 'has the correct subject' do + should have_subject /^gitlab \| Email was added to your account$/i + end + + it 'contains the new email address' do + should have_body_text /#{email.email}/ + end + + it 'includes a link to emails page' do + should have_body_text /#{profile_emails_path}/ + end + end + context 'for a project' do describe 'items that are assignable, the email' do let(:assignee) { create(:user, email: 'assignee@example.com') } diff --git a/spec/observers/email_observer_spec.rb b/spec/observers/email_observer_spec.rb new file mode 100644 index 0000000000..599b9a6ffb --- /dev/null +++ b/spec/observers/email_observer_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe EmailObserver do + let(:email) { create(:email) } + + before { subject.stub(notification: double('NotificationService').as_null_object) } + + subject { EmailObserver.instance } + + describe '#after_create' do + it 'trigger notification to send emails' do + subject.should_receive(:notification) + + subject.after_create(email) + end + end +end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index 8929a48973..9b67cd432b 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -183,6 +183,23 @@ describe Profiles::KeysController, "routing" do end end +# emails GET /emails(.:format) emails#index +# POST /keys(.:format) emails#create +# DELETE /keys/:id(.:format) keys#destroy +describe Profiles::EmailsController, "routing" do + it "to #index" do + get("/profile/emails").should route_to('profiles/emails#index') + end + + it "to #create" do + post("/profile/emails").should route_to('profiles/emails#create') + end + + it "to #destroy" do + delete("/profile/emails/1").should route_to('profiles/emails#destroy', id: '1') + end +end + # profile_avatar DELETE /profile/avatar(.:format) profiles/avatars#destroy describe Profiles::AvatarsController, "routing" do it "to #destroy" do diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 09a5debe1d..e378be0425 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -16,6 +16,19 @@ describe NotificationService do end end + describe 'Email' do + describe :new_email do + let(:email) { create(:email) } + + it { notification.new_email(email).should be_true } + + it 'should send email to email owner' do + Notify.should_receive(:new_email_email).with(email.id) + notification.new_email(email) + end + end + end + describe 'Notes' do context 'issue note' do let(:issue) { create(:issue, assignee: create(:user)) } diff --git a/spec/support/valid_commit.rb b/spec/support/valid_commit.rb index 8094b679e9..98bc59b573 100644 --- a/spec/support/valid_commit.rb +++ b/spec/support/valid_commit.rb @@ -2,6 +2,7 @@ module ValidCommit ID = "8470d70da67355c9c009e4401746b1d5410af2e3" MESSAGE = "notes controller refactored" AUTHOR_FULL_NAME = "Dmitriy Zaporozhets" + AUTHOR_EMAIL = "dmitriy.zaporozhets@gmail.com" FILES = [".foreman", ".gitignore", ".rails_footnotes", ".rspec", ".travis.yml", "CHANGELOG", "Gemfile", "Gemfile.lock", "LICENSE", "Procfile", "Procfile.production", "README.md", "Rakefile", "VERSION", "app", "config.ru", "config", "db", "doc", "lib", "log", "public", "resque.sh", "script", "spec", "vendor"] FILES_COUNT = 26 diff --git a/spec/support/valid_commit_with_alt_email.rb b/spec/support/valid_commit_with_alt_email.rb new file mode 100644 index 0000000000..d6e364c41f --- /dev/null +++ b/spec/support/valid_commit_with_alt_email.rb @@ -0,0 +1,6 @@ +module ValidCommitWithAltEmail + ID = "1e689bfba39525ead225eaf611948cfbe8ac34cf" + MESSAGE = "fixed notes logic" + AUTHOR_FULL_NAME = "Dmitriy Zaporozhets" + AUTHOR_EMAIL = "dzaporozhets@sphereconsultinginc.com" +end \ No newline at end of file From dac0e2f17411e23f06ddfef7fb737716e82f0518 Mon Sep 17 00:00:00 2001 From: dosire Date: Fri, 14 Feb 2014 11:13:52 +0100 Subject: [PATCH 055/112] Add namespace for projects to docs. --- doc/api/projects.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index 9f2945d070..12e0c47ee6 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -231,6 +231,7 @@ POST /projects Parameters: + `name` (required) - new project name ++ `namespace_id` (optional) - namespace for the new project (defaults to user) + `description` (optional) - short project description + `issues_enabled` (optional) + `wall_enabled` (optional) @@ -254,6 +255,7 @@ Parameters: + `user_id` (required) - user_id of owner + `name` (required) - new project name ++ `namespace_id` (optional) - namespace for the new project (defaults to user) + `description` (optional) - short project description + `default_branch` (optional) - 'master' by default + `issues_enabled` (optional) From ea1e92a0b660ebf2bcc99015301a367fe947d84b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 14 Feb 2014 12:30:12 +0200 Subject: [PATCH 056/112] Use project_users_select_tag for Issue form and MR form Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/generic/forms.scss | 24 +++++++++++++++++++ app/assets/stylesheets/generic/selects.scss | 7 ++++-- app/views/projects/issues/_form.html.haml | 2 +- .../projects/merge_requests/_form.html.haml | 2 +- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/generic/forms.scss b/app/assets/stylesheets/generic/forms.scss index 931b75a323..19e3e7a953 100644 --- a/app/assets/stylesheets/generic/forms.scss +++ b/app/assets/stylesheets/generic/forms.scss @@ -51,3 +51,27 @@ label { .input-mn-300 { min-width: 300px; } + +.custom-form-control { + width: 150px; +} + +@media (min-width: $screen-sm-min) { + .custom-form-control { + width: 150px; + } +} + +/* Medium devices (desktops, 992px and up) */ +@media (min-width: $screen-md-min) { + .custom-form-control { + width: 170px; + } +} + +/* Large devices (large desktops, 1200px and up) */ +@media (min-width: $screen-lg-min) { + .custom-form-control { + width: 200px; + } +} diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss index 0c7852925b..7ee1fec4e0 100644 --- a/app/assets/stylesheets/generic/selects.scss +++ b/app/assets/stylesheets/generic/selects.scss @@ -1,5 +1,4 @@ /** Select2 selectbox style override **/ - .select2-container, .select2-container.select2-drop-above { .select2-choice { background: #FFF; @@ -12,9 +11,13 @@ } .select2-drop-active { - border: 1px solid #BBB; + border: 1px solid #BBB !important; margin-top: 4px; + &.select2-drop-above { + margin-bottom: 8px; + } + .select2-search input { background: #fafafa; border-color: #DDD; diff --git a/app/views/projects/issues/_form.html.haml b/app/views/projects/issues/_form.html.haml index c95e817859..2bf66eef6c 100644 --- a/app/views/projects/issues/_form.html.haml +++ b/app/views/projects/issues/_form.html.haml @@ -24,7 +24,7 @@ %i.icon-user Assign to .col-sm-10 - = f.select(:assignee_id, assignee_options(@issue), { include_blank: "Select a user" }, {class: 'select2'}) + = project_users_select_tag('issue[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control')   = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link' .form-group diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml index b4ba127da2..b9f80c3566 100644 --- a/app/views/projects/merge_requests/_form.html.haml +++ b/app/views/projects/merge_requests/_form.html.haml @@ -47,7 +47,7 @@ %i.icon-user Assign to .col-sm-10 - = f.select(:assignee_id, assignee_options(@merge_request), { include_blank: "Select a user" }, {class: 'select2'}) + = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control')   = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link' .form-group From fd12e5c604f63516bc09c53f7fde52bc3a5cd494 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 14 Feb 2014 12:42:08 +0200 Subject: [PATCH 057/112] Dont render more than 20 group members on Project#members page Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/team_members/_group_members.html.haml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/views/projects/team_members/_group_members.html.haml b/app/views/projects/team_members/_group_members.html.haml index 68f0800685..eceec6627b 100644 --- a/app/views/projects/team_members/_group_members.html.haml +++ b/app/views/projects/team_members/_group_members.html.haml @@ -1,10 +1,14 @@ +- group_users_count = @group.users_groups.count .ui-box .title %strong #{@group.name} - group members (#{@group.users_groups.count}) + group members (#{group_users_count}) .pull-right = link_to members_group_path(@group), class: 'btn btn-small' do %i.icon-edit %ul.well-list - - @group.users_groups.order('group_access DESC').each do |member| + - @group.users_groups.order('group_access DESC').limit(20).each do |member| = render 'users_groups/users_group', member: member, show_controls: false + - if group_users_count > 20 + %li + and #{group_users_count - 20} more. For full list visit #{link_to 'group members page', members_group_path(@group)} From aa618dd87df8943aaabdfa6122d40f3285681452 Mon Sep 17 00:00:00 2001 From: dosire Date: Fri, 14 Feb 2014 14:28:49 +0100 Subject: [PATCH 058/112] Prevent mixed content warnings. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcd303e08a..300dc05947 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ### Code status -* [![build status](http://ci.gitlab.org/projects/1/status.png?ref=master)](http://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch) +* [![build status](https://ci.gitlab.org/projects/1/status.png?ref=master)](https://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch) * [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) From 654d876c86a759bd026cf324fde874f34f5b9951 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 14 Feb 2014 13:42:17 +0000 Subject: [PATCH 059/112] More changelog entries --- CHANGELOG | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 9933f2f77d..22a01ddfaa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,9 @@ v 6.6.0 - Show users' group membership on users' activity page - User pages are visible without login if user is authorized to a public project - Markdown rendered headers have id derived from their name and link to their id + - Improve application to work faster with large groups (100+ members) + - Multiple emails per user + - Show last commit for file when view file source v 6.5.1 - Fix branch selectbox when create merge request from fork @@ -641,4 +644,4 @@ v 0.8.0 - stability - security fixes - increased test coverage - - email notification + - email notification \ No newline at end of file From 0331f36a2c97180b95355cc676b3c8238c763789 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 14 Feb 2014 15:58:15 +0200 Subject: [PATCH 060/112] Few responsive fixes Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/issues/_issue_context.html.haml | 2 +- app/views/projects/merge_requests/show/_mr_title.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml index 7ddf470b6a..35ea4f260f 100644 --- a/app/views/projects/issues/_issue_context.html.haml +++ b/app/views/projects/issues/_issue_context.html.haml @@ -11,7 +11,7 @@ = link_to_member(@project, @issue.assignee) - .pull-right.hidden-sm + .pull-right.hidden-sm.hidden-xs - if issue.milestone - milestone = issue.milestone %cite.cgray Attached to milestone diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index 08a3fdf869..7540c8a640 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -34,7 +34,7 @@ %i.icon-edit Edit -.votes-holder +.votes-holder.hidden-sm.hidden-xs #votes= render 'votes/votes_block', votable: @merge_request .back-link From c187d2795555e88f7e363399cad11f45cc778d19 Mon Sep 17 00:00:00 2001 From: Pixelindustries Date: Fri, 14 Feb 2014 15:45:41 +0100 Subject: [PATCH 061/112] Added margin between form and button in resend-confirmation form. --- app/views/devise/confirmations/new.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 app/views/devise/confirmations/new.html.haml diff --git a/app/views/devise/confirmations/new.html.haml b/app/views/devise/confirmations/new.html.haml old mode 100644 new mode 100755 index dd63a232fe..bf634d9de6 --- a/app/views/devise/confirmations/new.html.haml +++ b/app/views/devise/confirmations/new.html.haml @@ -3,7 +3,8 @@ = form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| .devise-errors = devise_error_messages! - = f.email_field :email, placeholder: 'Email', class: "form-control", required: true + .clearfix.append-bottom-20 + = f.email_field :email, placeholder: 'Email', class: "form-control", required: true .clearfix.append-bottom-10 = f.submit "Resend confirmation instructions", class: 'btn btn-success' %hr From b6a609edbc1e46c72980b577e482b76f85dd39fc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Feb 2014 13:35:20 +0200 Subject: [PATCH 062/112] Truncate long names for admin dashboard with css Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/sections/admin.scss | 6 +- app/views/admin/dashboard/index.html.haml | 251 +++++++++++---------- 2 files changed, 131 insertions(+), 126 deletions(-) diff --git a/app/assets/stylesheets/sections/admin.scss b/app/assets/stylesheets/sections/admin.scss index 8ad9bc732b..a558633d11 100644 --- a/app/assets/stylesheets/sections/admin.scss +++ b/app/assets/stylesheets/sections/admin.scss @@ -2,7 +2,7 @@ * Admin area * */ -.admin_dash { +.admin-dashboard { .data { a { h1 { @@ -14,6 +14,10 @@ } } } + + .str-truncated { + max-width: 60%; + } } .admin-filter form { diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index dd663945ea..bbd60bc622 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -3,136 +3,137 @@ %p.light You can manage projects, users and other GitLab data from here. %hr -.admin_dash.row - .col-sm-4 - .light-well - %h4 Projects - .data - = link_to admin_projects_path do - %h1= Project.count - %hr - = link_to 'New Project', new_project_path, class: "btn btn-new" - .col-sm-4 - .light-well - %h4 Users - .data - = link_to admin_users_path do - %h1= User.count - %hr - = link_to 'New User', new_admin_user_path, class: "btn btn-new" - .col-sm-4 - .light-well - %h4 Groups - .data - = link_to admin_groups_path do - %h1= Group.count - %hr - = link_to 'New Group', new_admin_group_path, class: "btn btn-new" +.admin-dashboard + .row + .col-sm-4 + .light-well + %h4 Projects + .data + = link_to admin_projects_path do + %h1= Project.count + %hr + = link_to 'New Project', new_project_path, class: "btn btn-new" + .col-sm-4 + .light-well + %h4 Users + .data + = link_to admin_users_path do + %h1= User.count + %hr + = link_to 'New User', new_admin_user_path, class: "btn btn-new" + .col-sm-4 + .light-well + %h4 Groups + .data + = link_to admin_groups_path do + %h1= Group.count + %hr + = link_to 'New Group', new_admin_group_path, class: "btn btn-new" -.row.prepend-top-10 - .col-md-4 - %h4 Latest projects - %hr - - @projects.each do |project| + .row.prepend-top-10 + .col-md-4 + %h4 Latest projects + %hr + - @projects.each do |project| + %p + = link_to project.name_with_namespace, [:admin, project], class: 'str-truncated' + %span.light.pull-right + #{time_ago_with_tooltip(project.created_at)} + + .col-md-4 + %h4 Latest users + %hr + - @users.each do |user| + %p + = link_to [:admin, user], class: 'str-truncated' do + = user.name + %span.light.pull-right + #{time_ago_with_tooltip(user.created_at)} + + .col-md-4 + %h4 Latest groups + %hr + - @groups.each do |group| + %p + = link_to [:admin, group], class: 'str-truncated' do + = group.name + %span.light.pull-right + #{time_ago_with_tooltip(group.created_at)} + + %br + .row + .col-md-4 + %h4 Stats + %hr %p - = link_to project.name_with_namespace, [:admin, project] + Forks %span.light.pull-right - #{time_ago_with_tooltip(project.created_at)} - - .col-md-4 - %h4 Latest users - %hr - - @users.each do |user| + = ForkedProjectLink.count %p - = link_to [:admin, user] do - = user.name + Issues %span.light.pull-right - #{time_ago_with_tooltip(user.created_at)} - - .col-md-4 - %h4 Latest groups - %hr - - @groups.each do |group| + = Issue.count %p - = link_to [:admin, group] do - = group.name + Merge Requests %span.light.pull-right - #{time_ago_with_tooltip(group.created_at)} + = MergeRequest.count + %p + Notes + %span.light.pull-right + = Note.count + %p + Snippets + %span.light.pull-right + = Snippet.count + %p + SSH Keys + %span.light.pull-right + = Key.count + %p + Milestones + %span.light.pull-right + = Milestone.count + .col-md-4 + %h4 + Features + %hr + %p + Sign up + %span.light.pull-right + = boolean_to_icon gitlab_config.signup_enabled + %p + LDAP + %span.light.pull-right + = boolean_to_icon Gitlab.config.ldap.enabled + %p + Gravatar + %span.light.pull-right + = boolean_to_icon Gitlab.config.gravatar.enabled + %p + OmniAuth + %span.light.pull-right + = boolean_to_icon Gitlab.config.omniauth.enabled + .col-md-4 + %h4 Components + %hr + %p + GitLab + %span.pull-right + = Gitlab::VERSION + %p + GitLab Shell + %span.pull-right + = Gitlab::Shell.new.version + %p + GitLab API + %span.pull-right + = API::API::version + %p + Ruby + %span.pull-right + #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} -%br -.row - .col-md-4 - %h4 Stats - %hr - %p - Forks - %span.light.pull-right - = ForkedProjectLink.count - %p - Issues - %span.light.pull-right - = Issue.count - %p - Merge Requests - %span.light.pull-right - = MergeRequest.count - %p - Notes - %span.light.pull-right - = Note.count - %p - Snippets - %span.light.pull-right - = Snippet.count - %p - SSH Keys - %span.light.pull-right - = Key.count - %p - Milestones - %span.light.pull-right - = Milestone.count - .col-md-4 - %h4 - Features - %hr - %p - Sign up - %span.light.pull-right - = boolean_to_icon gitlab_config.signup_enabled - %p - LDAP - %span.light.pull-right - = boolean_to_icon Gitlab.config.ldap.enabled - %p - Gravatar - %span.light.pull-right - = boolean_to_icon Gitlab.config.gravatar.enabled - %p - OmniAuth - %span.light.pull-right - = boolean_to_icon Gitlab.config.omniauth.enabled - .col-md-4 - %h4 Components - %hr - %p - GitLab - %span.pull-right - = Gitlab::VERSION - %p - GitLab Shell - %span.pull-right - = Gitlab::Shell.new.version - %p - GitLab API - %span.pull-right - = API::API::version - %p - Ruby - %span.pull-right - #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} - - %p - Rails - %span.pull-right - #{Rails::VERSION::STRING} + %p + Rails + %span.pull-right + #{Rails::VERSION::STRING} From 87415ab2a67495713be5da79a60c1ec26060be9b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Feb 2014 13:41:48 +0200 Subject: [PATCH 063/112] Add bottom margin to nav-tabs Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/gl_bootstrap.scss | 2 ++ app/assets/stylesheets/sections/dashboard.scss | 2 +- app/views/devise/sessions/new.html.haml | 2 +- app/views/projects/commits/_head.html.haml | 2 +- app/views/projects/issues/_head.html.haml | 2 +- app/views/projects/merge_requests/_show.html.haml | 2 +- app/views/projects/milestones/show.html.haml | 2 +- app/views/projects/wikis/_nav.html.haml | 2 +- app/views/search/_project_results.html.haml | 2 +- 9 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss index 7f45d64fb7..169f1268cd 100644 --- a/app/assets/stylesheets/gl_bootstrap.scss +++ b/app/assets/stylesheets/gl_bootstrap.scss @@ -108,6 +108,8 @@ $pagination-active-bg: $bg_style_color; // Nav tabs .nav.nav-tabs { + margin-bottom: 15px; + li { > a { padding: 8px 20px; diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss index 1fd82c84fc..6fc394e2e2 100644 --- a/app/assets/stylesheets/sections/dashboard.scss +++ b/app/assets/stylesheets/sections/dashboard.scss @@ -41,7 +41,7 @@ .dash-sidebar-tabs { margin-bottom: 2px; border: none; - margin: 0; + margin: 0 !important; li { &.active { diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 938f61d209..bb87d9ecb4 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -1,7 +1,7 @@ .login-box %h3.page-title Sign in - if ldap_enabled? - %ul.nav.nav-tabs.append-bottom-20 + %ul.nav.nav-tabs %li.active = link_to 'LDAP', '#tab-ldap', 'data-toggle' => 'tab' %li diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml index b9ab27d212..81e3374391 100644 --- a/app/views/projects/commits/_head.html.haml +++ b/app/views/projects/commits/_head.html.haml @@ -1,4 +1,4 @@ -%ul.nav.nav-tabs.append-bottom-15 +%ul.nav.nav-tabs %li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'} = nav_link(controller: [:commit, :commits]) do diff --git a/app/views/projects/issues/_head.html.haml b/app/views/projects/issues/_head.html.haml index 2f0aa33fe1..0b7697622b 100644 --- a/app/views/projects/issues/_head.html.haml +++ b/app/views/projects/issues/_head.html.haml @@ -1,4 +1,4 @@ -%ul.nav.nav-tabs.append-bottom-15 +%ul.nav.nav-tabs = nav_link(controller: :issues) do = link_to project_issues_path(@project), class: "tab" do Browse Issues diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 42641765c5..0b9e4df3fd 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -12,7 +12,7 @@ = render "projects/merge_requests/show/commits" - if @commits.present? - %ul.nav.nav-tabs.append-bottom-10 + %ul.nav.nav-tabs %li.notes-tab{data: {action: 'notes'}} = link_to project_merge_request_path(@project, @merge_request) do %i.icon-comment diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 4d504380c9..31eb5765fa 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -48,7 +48,7 @@ = preserve do = markdown @milestone.description -%ul.nav.nav-tabs.append-bottom-10 +%ul.nav.nav-tabs %li.active = link_to '#tab-issues', 'data-toggle' => 'tab' do Issues diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml index 5e5aa5170d..0a7e51e974 100644 --- a/app/views/projects/wikis/_nav.html.haml +++ b/app/views/projects/wikis/_nav.html.haml @@ -1,4 +1,4 @@ -%ul.nav.nav-tabs.append-bottom-20 +%ul.nav.nav-tabs = nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do = link_to 'Home', project_wiki_path(@project, :home) diff --git a/app/views/search/_project_results.html.haml b/app/views/search/_project_results.html.haml index ea324b3a9a..f285bda573 100644 --- a/app/views/search/_project_results.html.haml +++ b/app/views/search/_project_results.html.haml @@ -1,4 +1,4 @@ -%ul.nav.nav-tabs.append-bottom-10 +%ul.nav.nav-tabs %li{class: ("active" if params[:search_code].present?)} = link_to search_path(params.merge(search_code: true)) do Repository Code From d7310fe7a9fcfec4fa49e6f5cd64899604155633 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Feb 2014 14:01:08 +0200 Subject: [PATCH 064/112] Improve email page ui Signed-off-by: Dmitriy Zaporozhets --- app/views/profiles/emails/index.html.haml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml index dc45ab2de7..b5f1e438cc 100644 --- a/app/views/profiles/emails/index.html.haml +++ b/app/views/profiles/emails/index.html.haml @@ -1,9 +1,13 @@ %h3.page-title - My Email Addresses + My email addresses %p.light Your %b Primary Email - will be used for account notifications, avatar detection and web based operations, such as edits and merges. All email addresses will be used to identify your commits. + will be used for account notifications, avatar detection and web based operations, such as edits and merges. + %br + All email addresses will be used to identify your commits. + +%hr .ui-box .title @@ -19,11 +23,11 @@ added #{time_ago_with_tooltip(email.created_at)} = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-small btn-remove pull-right' -%h3.page-title Add Email Address +%h4 Add email address = form_for 'email', url: profile_emails_path, html: { class: 'form-horizontal' } do |f| .form-group = f.label :email, class: 'control-label' .col-sm-10 = f.text_field :email, class: 'form-control' .form-actions - = f.submit 'Add', class: 'btn btn-create' \ No newline at end of file + = f.submit 'Add', class: 'btn btn-create' From e702928fbacfee00e248f3ffe3382e5ea259f816 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Feb 2014 14:11:31 +0200 Subject: [PATCH 065/112] Dark header improvements Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/sections/header.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index c8091c8489..883c9a859e 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -229,9 +229,9 @@ header { } .title { a { - color: #BBB; + color: #FFF; &:hover { - color: #FFF; + text-decoration: underline; } } color: #fff; From 1701144b41b2a7507cec2fab4d8a045cf71f4c98 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Feb 2014 14:14:50 +0200 Subject: [PATCH 066/112] Style pills color for violet theme Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/themes/ui_color.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/themes/ui_color.scss b/app/assets/stylesheets/themes/ui_color.scss index 0fc72d4e0a..96070d9205 100644 --- a/app/assets/stylesheets/themes/ui_color.scss +++ b/app/assets/stylesheets/themes/ui_color.scss @@ -36,4 +36,8 @@ } } } + + .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus { + background: #658; + } } From db961b8b46497c4626a4d9479e3e20c308e83a57 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Feb 2014 14:31:01 +0200 Subject: [PATCH 067/112] Improve few admin pages Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/themes/ui_color.scss | 2 +- app/views/admin/groups/index.html.haml | 27 +++++++++------------ app/views/admin/users/index.html.haml | 12 ++++----- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/app/assets/stylesheets/themes/ui_color.scss b/app/assets/stylesheets/themes/ui_color.scss index 96070d9205..edac4290e7 100644 --- a/app/assets/stylesheets/themes/ui_color.scss +++ b/app/assets/stylesheets/themes/ui_color.scss @@ -38,6 +38,6 @@ } .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus { - background: #658; + background: #769; } } diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 7a373ee586..9a0d596792 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -1,11 +1,12 @@ %h3.page-title Groups (#{@groups.total_count}) - %small - allows you to keep projects organized. - Use groups for uniting related projects. - = link_to 'New Group', new_admin_group_path, class: "btn btn-new pull-right" -%br + +%p.light + Group allows you to keep projects organized. + Use groups for uniting related projects. + +%hr = form_tag admin_groups_path, method: :get, class: 'form-inline' do .form-group = text_field_tag :name, params[:name], class: "form-control input-mn-300" @@ -23,24 +24,18 @@ %h4 = link_to [:admin, group] do + %i.icon-folder-close = group.name → %span.monospace - %i.icon-folder-close %strong #{group.path}/ - - .clearfix.light.append-bottom-10 - %span - %b Members: - %span.badge= group.members.size - \| - %span - %b Projects: - %span.badge= group.projects.count - .clearfix %p = truncate group.description, length: 150 + .clearfix + %p.light + #{pluralize(group.members.size, 'member')}, #{pluralize(group.projects.count, 'project')} + = paginate @groups, theme: "gitlab" diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 1fa6fdfaff..0b3934a712 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,12 +1,6 @@ .row .col-md-3 .admin-filter - = form_tag admin_users_path, method: :get, class: 'form-inline' do - .append-bottom-10 - .form-group - = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control' - = button_tag type: 'submit', class: 'btn btn-primary' do - %i.icon-search %ul.nav.nav-pills.nav-stacked %li{class: "#{'active' unless params[:filter]}"} = link_to admin_users_path do @@ -25,6 +19,12 @@ Without projects %small.pull-right= User.without_projects.count %hr + = form_tag admin_users_path, method: :get, class: 'form-inline' do + .form-group + = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control' + = button_tag type: 'submit', class: 'btn btn-primary' do + %i.icon-search + %hr = link_to 'Reset', admin_users_path, class: "btn btn-cancel" .col-md-9 From 1e106756fa12d91e233adee740e338e3846939ac Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Feb 2014 14:36:58 +0200 Subject: [PATCH 068/112] For form MR render only namespace name Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 8 ++++++++ .../projects/merge_requests/_merge_request.html.haml | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index ca2644ec73..a3d786c213 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -219,6 +219,14 @@ class MergeRequest < ActiveRecord::Base end end + def source_project_namespace + if source_project && source_project.namespace + source_project.namespace.path + else + "(removed)" + end + end + def source_branch_exists? return false unless self.source_project diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index ff763bca30..980ac12674 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -10,14 +10,14 @@ %span.pull-right - if merge_request.for_fork? %span.light - = "#{merge_request.source_project_path}" - = "#{merge_request.source_branch}" + #{merge_request.source_project_namespace}: + = merge_request.source_branch %i.icon-angle-right.light - = "#{merge_request.target_branch}" + = merge_request.target_branch - else - = "#{merge_request.source_branch}" + = merge_request.source_branch %i.icon-angle-right.light - = "#{merge_request.target_branch}" + = merge_request.target_branch .merge-request-info - if merge_request.author authored by #{link_to_member(merge_request.source_project, merge_request.author)} From 99fd58ce4af0e18a6f4252597985269aa5e2b635 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Feb 2014 14:52:33 +0200 Subject: [PATCH 069/112] Show full commit info at MR form Signed-off-by: Dmitriy Zaporozhets --- .../stylesheets/sections/merge_requests.scss | 4 ++-- .../projects/merge_requests/_form.html.haml | 19 +++++++++++-------- .../merge_requests/branch_from.js.haml | 2 +- .../projects/merge_requests/branch_to.js.haml | 2 +- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index 4388da0073..6e21bf0b0a 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -31,10 +31,10 @@ .mr_source_commit, .mr_target_commit { + margin-top: 10px; .commit { margin: 0; - padding: 0; - padding: 5px 0; + padding: 2px 0; list-style: none; &:hover { background: none; diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml index b9f80c3566..7049e313cd 100644 --- a/app/views/projects/merge_requests/_form.html.haml +++ b/app/views/projects/merge_requests/_form.html.haml @@ -6,19 +6,22 @@ %li= msg .merge-request-branches - .row - .col-md-5 + .form-group + = label_tag nil, class: 'control-label' do + From + .col-sm-10 .clearfix .pull-left = f.select(:source_project_id, [[@merge_request.source_project_path,@merge_request.source_project.id]] , {}, { class: 'source_project select2 span3', disabled: @merge_request.persisted? }) .pull-left   = f.select(:source_branch, @merge_request.source_branches, { include_blank: "Select branch" }, {class: 'source_branch select2 span2'}) - .mr_source_commit.prepend-top-10 - .col-md-2 - .merge-request-angle - %i.icon-long-arrow-right - .col-md-5 + .mr_source_commit + %br + .form-group + = label_tag nil, class: 'control-label' do + To + .col-sm-10 .clearfix .pull-left - projects = @project.forked_from_project.nil? ? [@project] : [ @project,@project.forked_from_project] @@ -26,7 +29,7 @@ .pull-left   = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, {class: 'target_branch select2 span2'}) - .mr_target_commit.prepend-top-10 + .mr_target_commit %hr .merge-request-form-info diff --git a/app/views/projects/merge_requests/branch_from.js.haml b/app/views/projects/merge_requests/branch_from.js.haml index ec4d7f2121..d3147188d1 100644 --- a/app/views/projects/merge_requests/branch_from.js.haml +++ b/app/views/projects/merge_requests/branch_from.js.haml @@ -1,5 +1,5 @@ :plain - $(".mr_source_commit").html("#{commit_to_html(@commit, @source_project)}"); + $(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}"); var mrTitle = $('#merge_request_title'); if(mrTitle.val().length == 0) { diff --git a/app/views/projects/merge_requests/branch_to.js.haml b/app/views/projects/merge_requests/branch_to.js.haml index f4e2886ee4..f7ede0ded5 100644 --- a/app/views/projects/merge_requests/branch_to.js.haml +++ b/app/views/projects/merge_requests/branch_to.js.haml @@ -1,2 +1,2 @@ :plain - $(".mr_target_commit").html("#{commit_to_html(@commit, @target_project)}"); + $(".mr_target_commit").html("#{commit_to_html(@commit, @target_project, false)}"); From 5a68db91c8a2ae7d23b07a5c52b8b74d859a819f Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Sat, 15 Feb 2014 20:46:15 +0100 Subject: [PATCH 070/112] Added spring to the project --- Gemfile | 4 ++++ Gemfile.lock | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/Gemfile b/Gemfile index 6a06df6fbe..ba7f6a7f52 100644 --- a/Gemfile +++ b/Gemfile @@ -208,6 +208,10 @@ group :development, :test do gem 'spork', '~> 1.0rc' gem 'jasmine', '2.0.0.rc5' + + gem "spring", '1.1.1' + gem "spring-commands-rspec", '1.0.1' + gem "spring-commands-spinach", '1.0.0' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 2c99063726..91d04e2ec7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -470,6 +470,11 @@ GEM railties (>= 3) spinach (>= 0.4) spork (1.0.0rc4) + spring (1.1.1) + spring-commands-rspec (1.0.1) + spring (>= 0.9.1) + spring-commands-spinach (1.0.0) + spring (>= 0.9.1) sprockets (2.10.1) hike (~> 1.2) multi_json (~> 1.0) @@ -637,6 +642,9 @@ DEPENDENCIES slim spinach-rails spork (~> 1.0rc) + spring (= 1.1.1) + spring-commands-rspec (= 1.0.1) + spring-commands-spinach (= 1.0.0) stamp state_machine test_after_commit From c35036c091adf71dca557edb6ffc5cb07e361500 Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Sat, 15 Feb 2014 21:03:10 +0100 Subject: [PATCH 071/112] Rails uses bin folder we forgot to create it when upgrading --- bin/bundle | 3 +++ bin/rails | 4 ++++ bin/rake | 4 ++++ 3 files changed, 11 insertions(+) create mode 100644 bin/bundle create mode 100644 bin/rails create mode 100644 bin/rake diff --git a/bin/bundle b/bin/bundle new file mode 100644 index 0000000000..66e9889e8b --- /dev/null +++ b/bin/bundle @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +load Gem.bin_path('bundler', 'bundle') diff --git a/bin/rails b/bin/rails new file mode 100644 index 0000000000..728cd85aa5 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path('../../config/application', __FILE__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake new file mode 100644 index 0000000000..17240489f6 --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative '../config/boot' +require 'rake' +Rake.application.run From 0f834d117291e64e054b0226cc8e63ebaa517964 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Feb 2014 22:57:20 +0200 Subject: [PATCH 072/112] Improve navbar UX Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/sections/nav.scss | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss index 372fa9669c..88f16a2159 100644 --- a/app/assets/stylesheets/sections/nav.scss +++ b/app/assets/stylesheets/sections/nav.scss @@ -36,8 +36,7 @@ &.active { a { color: #333; - font-weight: bolder; - + font-weight: bold; &:after { content: ''; display: block; @@ -56,7 +55,20 @@ &:hover { a { - color: $style_color; + color: $link_color; + &:after { + content: ''; + display: block; + position: relative; + bottom: 8px; + left: 50%; + width: 0; + height: 0; + border-color: transparent transparent #29b transparent; + border-style: solid; + border-width: 6px; + margin-left: -6px; + } } } @@ -73,7 +85,7 @@ a { display: block; text-align: center; - font-weight: normal; + font-weight: 500; height: 38px; line-height: 34px; color: #777; From ee993dfc645bbe98431d3181e0d544d50b13c4de Mon Sep 17 00:00:00 2001 From: Timm Drevensek Date: Sat, 15 Feb 2014 22:46:02 +0100 Subject: [PATCH 073/112] Fix branches/compare butten to directly diff to default branch --- app/views/projects/branches/_branch.html.haml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index 40b6fc5d72..902dfcea31 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -11,9 +11,10 @@ .pull-right - if can?(current_user, :download_code, @project) = render 'projects/repositories/download_archive', ref: branch.name, btn_class: 'grouped btn-group-small' - = link_to project_compare_index_path(@project, from: branch.name, to: branch.name), class: 'btn grouped btn-small', title: "Compare" do - %i.icon-copy - Compare + - if branch.name != @repository.root_ref + = link_to project_compare_index_path(@project, from: @repository.root_ref, to: branch.name), class: 'btn grouped btn-small', method: :post, title: "Compare" do + %i.icon-copy + Compare - if can?(current_user, :admin_project, @project) && branch.name != @repository.root_ref = link_to project_branch_path(@project, branch.name), class: 'btn grouped btn-small remove-row', method: :delete, data: { confirm: 'Removed branch cannot be restored. Are you sure?'}, remote: true do From 99dc9c6fc9880519dddf2cb2557b984792843848 Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Sun, 16 Feb 2014 11:22:03 +0100 Subject: [PATCH 074/112] Inserted spring in the binstubs Now possible to run: `bin/rails` `bin/rspec` `bin/spinach` `bin/rake` --- bin/rails | 4 ++++ bin/rake | 4 ++++ bin/rspec | 7 +++++++ bin/spinach | 7 +++++++ bin/spring | 18 ++++++++++++++++++ 5 files changed, 40 insertions(+) create mode 100644 bin/rspec create mode 100644 bin/spinach create mode 100644 bin/spring diff --git a/bin/rails b/bin/rails index 728cd85aa5..7feb6a30e6 100644 --- a/bin/rails +++ b/bin/rails @@ -1,4 +1,8 @@ #!/usr/bin/env ruby +begin + load File.expand_path("../spring", __FILE__) +rescue LoadError +end APP_PATH = File.expand_path('../../config/application', __FILE__) require_relative '../config/boot' require 'rails/commands' diff --git a/bin/rake b/bin/rake index 17240489f6..8017a0271d 100644 --- a/bin/rake +++ b/bin/rake @@ -1,4 +1,8 @@ #!/usr/bin/env ruby +begin + load File.expand_path("../spring", __FILE__) +rescue LoadError +end require_relative '../config/boot' require 'rake' Rake.application.run diff --git a/bin/rspec b/bin/rspec new file mode 100644 index 0000000000..41e37089ac --- /dev/null +++ b/bin/rspec @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby +begin + load File.expand_path("../spring", __FILE__) +rescue LoadError +end +require 'bundler/setup' +load Gem.bin_path('rspec', 'rspec') diff --git a/bin/spinach b/bin/spinach new file mode 100644 index 0000000000..a080e286cf --- /dev/null +++ b/bin/spinach @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby +begin + load File.expand_path("../spring", __FILE__) +rescue LoadError +end +require 'bundler/setup' +load Gem.bin_path('spinach', 'spinach') diff --git a/bin/spring b/bin/spring new file mode 100644 index 0000000000..253ec37c34 --- /dev/null +++ b/bin/spring @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +# This file loads spring without using Bundler, in order to be fast +# It gets overwritten when you run the `spring binstub` command + +unless defined?(Spring) + require "rubygems" + require "bundler" + + if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ spring \((.*?)\)$.*?^$/m) + ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR) + ENV["GEM_HOME"] = "" + Gem.paths = ENV + + gem "spring", match[1] + require "spring/binstub" + end +end From 4f4a1b961d7896f7a71dd69defeaa9d3012ad42d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 16 Feb 2014 17:22:16 +0000 Subject: [PATCH 075/112] Version to beta --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c07edf251a..c74844b883 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.6.0.pre +6.6.0.beta1 \ No newline at end of file From e9cf2e140f9685e43a63ed6095874f8096de90c3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 16 Feb 2014 17:51:09 +0000 Subject: [PATCH 076/112] Fix version sample for release candidate in monthly.md --- doc/release/monthly.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/release/monthly.md b/doc/release/monthly.md index 62bb0f7b40..28fc260b33 100644 --- a/doc/release/monthly.md +++ b/doc/release/monthly.md @@ -61,7 +61,7 @@ After making the release branch new commits are cherry-picked from master. When * 17th: feature freeze (stop merging new features in master) * 18th: UI freeze (stop merging changes to the user interface) * 19th: code freeze (stop merging non-essential code improvements) -* 20th: release candidate 1 (VERSION x.x.0.pre, tag and tweet about x.x.0.rc1) +* 20th: release candidate 1 (VERSION x.x.0.rc1, tag and tweet about x.x.0.rc1) * 21st: optional release candidate 2 (x.x.0.rc2, only if rc1 had problems) * 22nd: release (VERSION x.x.0, create x-x-stable branch, tag, blog and tweet) * 23nd: optional patch releases (x.x.1, x.x.2, etc., only if there are serious problems) @@ -73,4 +73,4 @@ After making the release branch new commits are cherry-picked from master. When * Mention what GitLab is on the second line: GitLab is open source software to collaborate on code. * Select and thank the the Most Valuable Person (MVP) of this release. -* Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible. +* Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible. \ No newline at end of file From 10561f4c462b3068ad795a47b7f4e19c06ac2ffb Mon Sep 17 00:00:00 2001 From: PatrickJS Date: Sun, 16 Feb 2014 23:06:35 -0800 Subject: [PATCH 077/112] update copyright year to range --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 7cecc2485f..8ebd322ffc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011 Dmitriy Zaporozhets +Copyright (c) 2011-2014 Dmitriy Zaporozhets Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 8dc3dafe24fd481acdd8ebe87cad189fd8b861f4 Mon Sep 17 00:00:00 2001 From: Cynddl Date: Mon, 17 Feb 2014 11:26:33 +0100 Subject: [PATCH 078/112] Fix issue with robots constantly asking for projects archives --- .../repositories/_download_archive.html.haml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/projects/repositories/_download_archive.html.haml b/app/views/projects/repositories/_download_archive.html.haml index b03feded0a..88c1cfa28e 100644 --- a/app/views/projects/repositories/_download_archive.html.haml +++ b/app/views/projects/repositories/_download_archive.html.haml @@ -3,7 +3,7 @@ - split_button = split_button || false - if split_button == true %span.btn-group{class: btn_class} - = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn' do + = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do %i.icon-download-alt %span Download zip %a.btn.dropdown-toggle{ 'data-toggle' => 'dropdown' } @@ -12,26 +12,26 @@ Select Archive Format %ul.dropdown-menu{ role: 'menu' } %li - = link_to archive_project_repository_path(@project, ref: ref, format: 'zip') do + = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), rel: 'nofollow' do %i.icon-download-alt %span Download zip %li - = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz') do + = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do %i.icon-download-alt %span Download tar.gz %li - = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.bz2') do + = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do %i.icon-download-alt %span Download tar.bz2 %li - = link_to archive_project_repository_path(@project, ref: ref, format: 'tar') do + = link_to archive_project_repository_path(@project, ref: ref, format: 'tar'), rel: 'nofollow' do %i.icon-download-alt %span Download tar - else %span.btn-group{class: btn_class} - = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn' do + = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do %i.icon-download-alt %span zip - = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), class: 'btn' do + = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), class: 'btn', rel: 'nofollow' do %i.icon-download-alt %span tar.gz \ No newline at end of file From 97b47c735e74cdaf316002be8c00f6d06ae4a96e Mon Sep 17 00:00:00 2001 From: dosire Date: Mon, 17 Feb 2014 12:29:56 +0100 Subject: [PATCH 079/112] Add new installation methods to the readme. --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ca003f111a..40e33bd2e8 100644 --- a/README.md +++ b/README.md @@ -45,13 +45,17 @@ #### Official installation methods -* [Manual installation guide for a production server](doc/install/installation.md) +* [GitLab packages (beta)](https://www.gitlab.com/downloads/) These packages contain GitLab and all its depencies (PostgreSQL, Redis, Nginx, Unicorn, etc.). They are made with with [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md) that also contains the installation instructions. These packages currently support a reduced selection of GitLab's normal features. For instance, it is not yet possible to create/restore application backups or to use HTTPS. + +* [GitLab virtual machine images](https://www.gitlab.com/downloads/) contain an operating system and a preinstalled GitLab. They are made with [GitLab Packer](https://gitlab.com/gitlab-org/gitlab-packer/blob/master/README.md) that also contains the installation instructions. * [GitLab Chef Cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md) This cookbook can be used both for development installations and production installations. If you want to [contribute](CONTRIBUTE.md) to GitLab we suggest you follow the [development installation on a virtual machine with Vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) instructions to install all testing dependencies. +* [Manual installation guide](doc/install/installation.md) This guide to set up a production server offers detailed and complete step-by-step instructions. + #### Third party one-click installers -* [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/blog_posts/host-your-git-repositories-in-55-seconds-with-gitlab) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app such as GitLab. +* [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/blog_posts/host-your-git-repositories-in-55-seconds-with-gitlab) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app such as GitLab. We recommend selecting a droplet with [1GB of memory](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md). * [BitNami one-click installers](http://bitnami.com/stack/gitlab) This package contains both GitLab and GitLab CI. It is available as installer, virtual machine or for cloud hosting providers (Amazon Web Services/Azure/etc.). From c9b3767ff1d78207ccb44650715a33cc98c6bc72 Mon Sep 17 00:00:00 2001 From: dosire Date: Mon, 17 Feb 2014 14:11:21 +0100 Subject: [PATCH 080/112] Double word. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40e33bd2e8..90237268da 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ #### Official installation methods -* [GitLab packages (beta)](https://www.gitlab.com/downloads/) These packages contain GitLab and all its depencies (PostgreSQL, Redis, Nginx, Unicorn, etc.). They are made with with [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md) that also contains the installation instructions. These packages currently support a reduced selection of GitLab's normal features. For instance, it is not yet possible to create/restore application backups or to use HTTPS. +* [GitLab packages (beta)](https://www.gitlab.com/downloads/) These packages contain GitLab and all its depencies (PostgreSQL, Redis, Nginx, Unicorn, etc.). They are made with [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md) that also contains the installation instructions. These packages currently support a reduced selection of GitLab's normal features. For instance, it is not yet possible to create/restore application backups or to use HTTPS. * [GitLab virtual machine images](https://www.gitlab.com/downloads/) contain an operating system and a preinstalled GitLab. They are made with [GitLab Packer](https://gitlab.com/gitlab-org/gitlab-packer/blob/master/README.md) that also contains the installation instructions. From 936353edfdf00653b23f6837f29095dbc3a5f5dc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 17 Feb 2014 18:06:24 +0200 Subject: [PATCH 081/112] Improve notification settings page Signed-off-by: Dmitriy Zaporozhets --- .../stylesheets/sections/dashboard.scss | 1 + app/assets/stylesheets/sections/profile.scss | 11 +++ app/helpers/notifications_helper.rb | 6 +- app/models/notification.rb | 25 ++++-- .../notifications/_settings.html.haml | 44 ++++------ .../profiles/notifications/show.html.haml | 81 +++++++++---------- .../steps/profile/profile_notifications.rb | 1 - 7 files changed, 87 insertions(+), 82 deletions(-) diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss index 6fc394e2e2..7509f47367 100644 --- a/app/assets/stylesheets/sections/dashboard.scss +++ b/app/assets/stylesheets/sections/dashboard.scss @@ -67,6 +67,7 @@ a { display: block; + color: #333; } .project-name, .group-name { diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/sections/profile.scss index 0ee46b9a2f..7a696c21e4 100644 --- a/app/assets/stylesheets/sections/profile.scss +++ b/app/assets/stylesheets/sections/profile.scss @@ -114,3 +114,14 @@ height: 50px; } } + +.global-notifications-form .level-title { + font-size: 15px; + color: #333; + font-weight: bold; +} + +.notification-icon-holder { + width: 20px; + float: left; +} diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index ae3402b261..b2399bb6db 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -1,11 +1,11 @@ module NotificationsHelper def notification_icon(notification) if notification.disabled? - content_tag :i, nil, class: 'icon-circle cred' + content_tag :i, nil, class: 'icon-volume-off cred' elsif notification.participating? - content_tag :i, nil, class: 'icon-circle cblue' + content_tag :i, nil, class: 'icon-volume-down cblue' elsif notification.watch? - content_tag :i, nil, class: 'icon-circle cgreen' + content_tag :i, nil, class: 'icon-volume-up cgreen' else content_tag :i, nil, class: 'icon-circle-blank cblue' end diff --git a/app/models/notification.rb b/app/models/notification.rb index ff6a18d6a5..b0f8ed6a4e 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -9,12 +9,23 @@ class Notification attr_accessor :target - def self.notification_levels - [N_DISABLED, N_PARTICIPATING, N_WATCH] - end + class << self + def notification_levels + [N_DISABLED, N_PARTICIPATING, N_WATCH] + end - def self.project_notification_levels - [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL] + def options_with_labels + { + disabled: N_DISABLED, + participating: N_PARTICIPATING, + watch: N_WATCH, + global: N_GLOBAL + } + end + + def project_notification_levels + [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL] + end end def initialize(target) @@ -36,4 +47,8 @@ class Notification def global? target.notification_level == N_GLOBAL end + + def level + target.notification_level + end end diff --git a/app/views/profiles/notifications/_settings.html.haml b/app/views/profiles/notifications/_settings.html.haml index d123b8f940..218d51d31a 100644 --- a/app/views/profiles/notifications/_settings.html.haml +++ b/app/views/profiles/notifications/_settings.html.haml @@ -1,31 +1,17 @@ %li - .row - .col-sm-4 - %span - = notification_icon(notification) - - - if membership.kind_of? UsersGroup - = link_to membership.group.name, membership.group - - else - = link_to_project(membership.project) - .col-sm-8 - = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do - = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type') - = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id') - - = label_tag nil, class: 'radio-inline' do - = radio_button_tag :notification_level, Notification::N_GLOBAL, notification.global?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit' - %span Use global setting - - = label_tag nil, class: 'radio-inline' do - = radio_button_tag :notification_level, Notification::N_DISABLED, notification.disabled?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit' - %span Disabled - - = label_tag nil, class: 'radio-inline' do - = radio_button_tag :notification_level, Notification::N_PARTICIPATING, notification.participating?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit' - %span Participating - - = label_tag nil, class: 'radio-inline' do - = radio_button_tag :notification_level, Notification::N_WATCH, notification.watch?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit' - %span Watch + %span.notification-icon-holder + - if notification.global? + = notification_icon(@notification) + - else + = notification_icon(notification) + %span.str-truncated + - if membership.kind_of? UsersGroup + = link_to membership.group.name, membership.group + - else + = link_to_project(membership.project) + .pull-right + = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do + = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type') + = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id') + = select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'trigger-submit' diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index 878d7f7743..efe9c03219 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -3,56 +3,49 @@ %p.light GitLab uses the email specified in your profile for notifications %hr -.alert.alert-info - %p - %i.icon-circle.cred - %strong Disabled - – You will not get any notifications via email - %p - %i.icon-circle.cblue - %strong Participating - – You will only receive notifications from related resources (e.g. from your commits or assigned issues) - %p - %i.icon-circle.cgreen - %strong Watch - – You will receive all notifications from projects in which you participate += form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications form-horizontal global-notifications-form' do + = hidden_field_tag :notification_type, 'global' -.row - .col-sm-4 - %h4 - = notification_icon(@notification) - Global setting - .col-sm-8 - = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do - = hidden_field_tag :notification_type, 'global' - - = label_tag nil, class: 'radio-inline' do + = label_tag :notification_level, 'Notification level', class: 'control-label' + .col-sm-10 + .radio + = label_tag nil, class: '' do = radio_button_tag :notification_level, Notification::N_DISABLED, @notification.disabled?, class: 'trigger-submit' - %span Disabled + .level-title + Disabled + %p You will not get any notifications via email - = label_tag nil, class: 'radio-inline' do + .radio + = label_tag nil, class: '' do = radio_button_tag :notification_level, Notification::N_PARTICIPATING, @notification.participating?, class: 'trigger-submit' - %span Participating + .level-title + Participating + %p You will only receive notifications from related resources (e.g. from your commits or assigned issues) - = label_tag nil, class: 'radio-inline' do + .radio + = label_tag nil, class: '' do = radio_button_tag :notification_level, Notification::N_WATCH, @notification.watch?, class: 'trigger-submit' - %span Watch + .level-title + Watch + %p You will receive all notifications from projects in which you participate -%br -= link_to '#', class: 'js-toggle-visibility-link' do - %span.btn.btn-tiny - %i.icon-chevron-down - %span Advanced notifications settings -.js-toggle-visibility-container.hide +.clearfix %hr - %h4 Groups: - %ul.bordered-list - - @users_groups.each do |users_group| - - notification = Notification.new(users_group) - = render 'settings', type: 'group', membership: users_group, notification: notification + %p + You can also specify notification level per group or per project + %br + By default all projects and groups uses notification level set above +.row.all-notifications + .col-md-6 + %h4 Groups: + %ul.bordered-list + - @users_groups.each do |users_group| + - notification = Notification.new(users_group) + = render 'settings', type: 'group', membership: users_group, notification: notification - %h4 Projects: - %ul.bordered-list - - @users_projects.each do |users_project| - - notification = Notification.new(users_project) - = render 'settings', type: 'project', membership: users_project, notification: notification + .col-md-6 + %h4 Projects: + %ul.bordered-list + - @users_projects.each do |users_project| + - notification = Notification.new(users_project) + = render 'settings', type: 'project', membership: users_project, notification: notification diff --git a/features/steps/profile/profile_notifications.rb b/features/steps/profile/profile_notifications.rb index 7a41687dfd..e884df3098 100644 --- a/features/steps/profile/profile_notifications.rb +++ b/features/steps/profile/profile_notifications.rb @@ -8,6 +8,5 @@ class ProfileNotifications < Spinach::FeatureSteps step 'I should see global notifications settings' do page.should have_content "Notifications settings" - page.should have_content "Global setting" end end From 64dbcfe27f362ebbb3da840b0914c40dba814505 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 17 Feb 2014 18:09:49 +0200 Subject: [PATCH 082/112] Revert css change done by mistake Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/sections/dashboard.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss index 7509f47367..6fc394e2e2 100644 --- a/app/assets/stylesheets/sections/dashboard.scss +++ b/app/assets/stylesheets/sections/dashboard.scss @@ -67,7 +67,6 @@ a { display: block; - color: #333; } .project-name, .group-name { From 423dcb46eeba31461f02424c0afa1629b24f9652 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 17 Feb 2014 18:23:11 +0200 Subject: [PATCH 083/112] Set initial value to Issue/MR form -> assignee selectbox Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/issues/_form.html.haml | 2 +- app/views/projects/issues/_issue_context.html.haml | 3 ++- app/views/projects/merge_requests/_form.html.haml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/projects/issues/_form.html.haml b/app/views/projects/issues/_form.html.haml index 2bf66eef6c..f725db57ad 100644 --- a/app/views/projects/issues/_form.html.haml +++ b/app/views/projects/issues/_form.html.haml @@ -24,7 +24,7 @@ %i.icon-user Assign to .col-sm-10 - = project_users_select_tag('issue[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control') + = project_users_select_tag('issue[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @issue.assignee_id)   = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link' .form-group diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml index 35ea4f260f..029d7d6f0f 100644 --- a/app/views/projects/issues/_issue_context.html.haml +++ b/app/views/projects/issues/_issue_context.html.haml @@ -6,7 +6,8 @@ - if can?(current_user, :modify_issue, @issue) = link_to profile_path(issue.assignee) do = image_tag(avatar_icon(issue.assignee.email), class: 'avatar avatar-inline s16 assignee') if issue.assignee - = f.select(:assignee_id, assignee_options(@issue), { include_blank: "Assign to user (none):" }, {class: 'select2'}) + + = project_users_select_tag('issue[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @issue.assignee_id) - elsif issue.assignee = link_to_member(@project, @issue.assignee) diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml index 7049e313cd..9502ff95d8 100644 --- a/app/views/projects/merge_requests/_form.html.haml +++ b/app/views/projects/merge_requests/_form.html.haml @@ -50,7 +50,7 @@ %i.icon-user Assign to .col-sm-10 - = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control') + = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id)   = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link' .form-group From e0022912d77a40938c576d4b67a61d8322473210 Mon Sep 17 00:00:00 2001 From: dosire Date: Mon, 17 Feb 2014 17:30:50 +0100 Subject: [PATCH 084/112] Better English for the password reset screen. --- app/views/profiles/passwords/new.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml index c8c0368d00..b72232ee36 100644 --- a/app/views/profiles/passwords/new.html.haml +++ b/app/views/profiles/passwords/new.html.haml @@ -2,9 +2,9 @@ %hr = form_for @user, url: profile_password_path, method: :post, html: { class: 'form-horizontal '} do |f| %p.slead - Please set new password before proceed. + Please set a new password before proceeding. %br - After successful password update you will be redirected to login screen + After a successful password update you will be redirected to login screen. -if @user.errors.any? .alert.alert-danger %ul From 4d093f9f8df502f89bfdbff8e0db6848b4e8ab43 Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Mon, 17 Feb 2014 21:35:23 +0100 Subject: [PATCH 085/112] Added broadcast message on every layout file Fixes: #5674 --- app/views/layouts/admin.html.haml | 1 + app/views/layouts/navless.html.haml | 1 + app/views/layouts/public.html.haml | 1 + app/views/layouts/public_projects.html.haml | 1 + app/views/layouts/public_users.html.haml | 1 + app/views/layouts/search.html.haml | 1 + app/views/layouts/user_team.html.haml | 1 + 7 files changed, 7 insertions(+) diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index 439cb978a7..53e0dbaef9 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -2,6 +2,7 @@ %html{ lang: "en"} = render "layouts/head", title: "Admin area" %body{class: "#{app_theme} admin", :'data-page' => body_data_page} + = render "layouts/broadcast" = render "layouts/head_panel", title: "Admin area" = render "layouts/flash" %nav.main-nav.navbar-collapse.collapse diff --git a/app/views/layouts/navless.html.haml b/app/views/layouts/navless.html.haml index 7325664bc1..c43d688a2c 100644 --- a/app/views/layouts/navless.html.haml +++ b/app/views/layouts/navless.html.haml @@ -2,6 +2,7 @@ %html{ lang: "en"} = render "layouts/head", title: @title %body{class: "#{app_theme} application", :'data-page' => body_data_page} + = render "layouts/broadcast" = render "layouts/head_panel", title: @title = render "layouts/flash" diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml index fda81b3cc8..3c76bbb957 100644 --- a/app/views/layouts/public.html.haml +++ b/app/views/layouts/public.html.haml @@ -2,6 +2,7 @@ %html{ lang: "en"} = render "layouts/head", title: "Public Projects" %body{class: "#{app_theme} application", :'data-page' => body_data_page} + = render "layouts/broadcast" - if current_user = render "layouts/head_panel", title: "Public Projects" - else diff --git a/app/views/layouts/public_projects.html.haml b/app/views/layouts/public_projects.html.haml index 7de2347803..5fcf9f99e7 100644 --- a/app/views/layouts/public_projects.html.haml +++ b/app/views/layouts/public_projects.html.haml @@ -2,6 +2,7 @@ %html{ lang: "en"} = render "layouts/head", title: @project.name_with_namespace %body{class: "#{app_theme} application", :'data-page' => body_data_page} + = render "layouts/broadcast" = render "layouts/public_head_panel", title: @project.name_with_namespace %nav.main-nav .container= render 'layouts/nav/project' diff --git a/app/views/layouts/public_users.html.haml b/app/views/layouts/public_users.html.haml index 80709d650d..4aa258fea0 100644 --- a/app/views/layouts/public_users.html.haml +++ b/app/views/layouts/public_users.html.haml @@ -2,6 +2,7 @@ %html{ lang: "en"} = render "layouts/head", title: @title %body{class: "#{app_theme} application", :'data-page' => body_data_page} + = render "layouts/broadcast" = render "layouts/public_head_panel", title: @title .container.navless-container .content= yield diff --git a/app/views/layouts/search.html.haml b/app/views/layouts/search.html.haml index 177b3a4f8f..97ed8ba12d 100644 --- a/app/views/layouts/search.html.haml +++ b/app/views/layouts/search.html.haml @@ -2,6 +2,7 @@ %html{ lang: "en"} = render "layouts/head", title: "Search" %body{class: "#{app_theme} application", :'data-page' => body_data_page} + = render "layouts/broadcast" = render "layouts/head_panel", title: "Search" = render "layouts/flash" diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index 191ad406c3..ce13853ed7 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -2,6 +2,7 @@ %html{ lang: "en"} = render "layouts/head", title: "#{@team.name}" %body{class: "#{app_theme} application", :'data-page' => body_data_page} + = render "layouts/broadcast" = render "layouts/head_panel", title: "team: #{@team.name}" = render "layouts/flash" %nav.main-nav.navbar-collapse.collapse From 883c86a59e8ad7ec85891ad7a45340ea7caa2ca9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 09:04:30 +0200 Subject: [PATCH 086/112] Fix notification specs Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/show.html.haml | 2 +- spec/helpers/notifications_helper_spec.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 32a42916bd..8a1e1d3354 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -51,7 +51,7 @@ %p %span.light Owned by - if @project.group - #{link_to @project.group.name, @project.group} Group + #{link_to @project.group.name, @project.group} group - else #{link_to @project.owner_name, @project.owner} diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb index c1efc1fb2a..dce28525ca 100644 --- a/spec/helpers/notifications_helper_spec.rb +++ b/spec/helpers/notifications_helper_spec.rb @@ -8,7 +8,7 @@ describe NotificationsHelper do before { notification.stub(disabled?: true) } it "has a red icon" do - notification_icon(notification).should match('class="icon-circle cred"') + notification_icon(notification).should match('class="icon-volume-off cred"') end end @@ -16,7 +16,7 @@ describe NotificationsHelper do before { notification.stub(participating?: true) } it "has a blue icon" do - notification_icon(notification).should match('class="icon-circle cblue"') + notification_icon(notification).should match('class="icon-volume-down cblue"') end end @@ -24,7 +24,7 @@ describe NotificationsHelper do before { notification.stub(watch?: true) } it "has a green icon" do - notification_icon(notification).should match('class="icon-circle cgreen"') + notification_icon(notification).should match('class="icon-volume-up cgreen"') end end From 3c742dad27d298fae9aa8ee68cf1a83178fb8704 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 11:40:45 +0200 Subject: [PATCH 087/112] Fixed bug with json files content being escaped in api After update to recent grape env['api.format'] does not work any more. Use content_type for rendering raw json files content Signed-off-by: Dmitriy Zaporozhets --- lib/api/api.rb | 2 ++ lib/api/repositories.rb | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/api/api.rb b/lib/api/api.rb index 283f7642f6..9022cf7375 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -22,6 +22,8 @@ module API end format :json + content_type :txt, "text/plain" + helpers APIHelpers mount Groups diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index cad64760ab..c305c889fc 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -167,9 +167,7 @@ module API blob = Gitlab::Git::Blob.find(repo, commit.id, params[:filepath]) not_found! "File" unless blob - env['api.format'] = :txt - - content_type blob.mime_type + content_type 'text/plain' present blob.data end From ddbe978041753d7851780165f8c6c66865570862 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 12:27:02 +0200 Subject: [PATCH 088/112] Complete api files CRUD Signed-off-by: Dmitriy Zaporozhets --- app/models/repository.rb | 12 ++-- app/views/help/_api_layout.html.haml | 2 +- doc/api/README.md | 1 + doc/api/repositories.md | 41 ----------- doc/api/repository_files.md | 102 +++++++++++++++++++++++++++ lib/api/files.rb | 53 +++++++++++++- spec/requests/api/files_spec.rb | 30 ++++++++ 7 files changed, 192 insertions(+), 49 deletions(-) create mode 100644 doc/api/repository_files.md diff --git a/app/models/repository.rb b/app/models/repository.rb index 2c2bf242b9..99d908b5d8 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -180,13 +180,13 @@ class Repository end def blob_at_branch(branch_name, path) - last_commit = commit(branch_name) + last_commit = commit(branch_name) - if last_commit - blob_at(last_commit.sha, path) - else - nil - end + if last_commit + blob_at(last_commit.sha, path) + else + nil + end end # Returns url for submodule diff --git a/app/views/help/_api_layout.html.haml b/app/views/help/_api_layout.html.haml index c211b65841..9f7bc78355 100644 --- a/app/views/help/_api_layout.html.haml +++ b/app/views/help/_api_layout.html.haml @@ -5,7 +5,7 @@ %i.icon-angle-left Back to help %ul.nav.nav-pills.nav-stacked - - %w(README projects project_snippets repositories deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file| + - %w(README projects project_snippets repositories repository_files deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file| %li{class: file == @category ? 'active' : nil} = link_to file.titleize, help_api_file_path(file) diff --git a/doc/api/README.md b/doc/api/README.md index 517a9fae6f..f13f319a84 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -127,6 +127,7 @@ But when you want to create a link to web page - use `http:://host/project/issu + [Projects](projects.md) + [Project Snippets](project_snippets.md) + [Repositories](repositories.md) ++ [Repository Files](repository_files.md) + [Merge Requests](merge_requests.md) + [Issues](issues.md) + [Milestones](milestones.md) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 0160726300..70e297f1bc 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -388,44 +388,3 @@ GET /projects/:id/repository/archive Parameters: + `id` (required) - The ID of a project + `sha` (optional) - The commit sha to download defaults to the tip of the default branch - - -## Create new file in repository - -``` -POST /projects/:id/repository/files -``` - -Parameters: - -+ `file_path` (optional) - Full path to new file. Ex. lib/class.rb -+ `branch_name` (required) - The name of branch -+ `encoding` (optional) - 'text' or 'base64'. Text is default. -+ `content` (required) - File content -+ `commit_message` (required) - Commit message - -## Update existing file in repository - -``` -PUT /projects/:id/repository/files -``` - -Parameters: - -+ `file_path` (required) - Full path to file. Ex. lib/class.rb -+ `branch_name` (required) - The name of branch -+ `encoding` (optional) - 'text' or 'base64'. Text is default. -+ `content` (required) - New file content -+ `commit_message` (required) - Commit message - -## Delete existing file in repository - -``` -DELETE /projects/:id/repository/files -``` - -Parameters: - -+ `file_path` (required) - Full path to file. Ex. lib/class.rb -+ `branch_name` (required) - The name of branch -+ `commit_message` (required) - Commit message diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md new file mode 100644 index 0000000000..cafab8c828 --- /dev/null +++ b/doc/api/repository_files.md @@ -0,0 +1,102 @@ +# CRUD for repository files + +## Create, read, update and delete repository files using this API + +- - - + +## Get file from repository + +Allows you to receive information about file in repository like name, size, content. +Note that file content is Base64 encoded. + +``` +GET /projects/:id/repository/files +``` + +Example response: + +```json +{ + "file_name": "key.rb", + "file_path": "app/models/key.rb", + "size": 1476, + "encoding": "base64", + "content": "IyA9PSBTY2hlbWEgSW5mb3...", + "ref": "master", + "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83", + "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50" +} +``` + +Parameters: + ++ `file_path` (required) - Full path to new file. Ex. lib/class.rb ++ `ref` (required) - The name of branch, tag or commit + +## Create new file in repository + +``` +POST /projects/:id/repository/files +``` + +Example response: + +```json +{ + "file_name": "app/project.rb", + "branch_name": "master", +} +``` + +Parameters: + ++ `file_path` (required) - Full path to new file. Ex. lib/class.rb ++ `branch_name` (required) - The name of branch ++ `encoding` (optional) - 'text' or 'base64'. Text is default. ++ `content` (required) - File content ++ `commit_message` (required) - Commit message + +## Update existing file in repository + +``` +PUT /projects/:id/repository/files +``` + +Example response: + +```json +{ + "file_name": "app/project.rb", + "branch_name": "master", +} +``` + +Parameters: + ++ `file_path` (required) - Full path to file. Ex. lib/class.rb ++ `branch_name` (required) - The name of branch ++ `encoding` (optional) - 'text' or 'base64'. Text is default. ++ `content` (required) - New file content ++ `commit_message` (required) - Commit message + +## Delete existing file in repository + +``` +DELETE /projects/:id/repository/files +``` + +Example response: + +```json +{ + "file_name": "app/project.rb", + "branch_name": "master", +} +``` + +Parameters: + ++ `file_path` (required) - Full path to file. Ex. lib/class.rb ++ `branch_name` (required) - The name of branch ++ `commit_message` (required) - Commit message + diff --git a/lib/api/files.rb b/lib/api/files.rb index 213604915a..e0c46f92b8 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -5,10 +5,61 @@ module API before { authorize! :push_code, user_project } resource :projects do + # Get file from repository + # File content is Base64 encoded + # + # Parameters: + # file_path (required) - The path to the file. Ex. lib/class.rb + # ref (required) - The name of branch, tag or commit + # + # Example Request: + # GET /projects/:id/repository/files + # + # Example response: + # { + # "file_name": "key.rb", + # "file_path": "app/models/key.rb", + # "size": 1476, + # "encoding": "base64", + # "content": "IyA9PSBTY2hlbWEgSW5mb3...", + # "ref": "master", + # "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83", + # "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50" + # } + # + get ":id/repository/files" do + required_attributes! [:file_path, :ref] + attrs = attributes_for_keys [:file_path, :ref] + ref = attrs.delete(:ref) + file_path = attrs.delete(:file_path) + + commit = user_project.repository.commit(ref) + not_found! "Commit" unless commit + + blob = user_project.repository.blob_at(commit.sha, file_path) + + if blob + status(200) + + { + file_name: blob.name, + file_path: blob.path, + size: blob.size, + encoding: "base64", + content: Base64.encode64(blob.data), + ref: ref, + blob_id: blob.id, + commit_id: commit.id, + } + else + render_api_error!('File not found', 404) + end + end + # Create new file in repository # # Parameters: - # file_path (optional) - The path to new file. Ex. lib/class.rb + # file_path (required) - The path to new file. Ex. lib/class.rb # branch_name (required) - The name of branch # content (required) - File content # commit_message (required) - Commit message diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index acef7df877..fa25a4bec6 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -9,6 +9,36 @@ describe API::API do let!(:project) { create(:project, namespace: user.namespace ) } before { project.team << [user, :developer] } + describe "GET /projects/:id/repository/files" do + it "should return file info" do + params = { + file_path: 'app/models/key.rb', + ref: 'master', + } + + get api("/projects/#{project.id}/repository/files", user), params + response.status.should == 200 + json_response['file_path'].should == 'app/models/key.rb' + json_response['file_name'].should == 'key.rb' + Base64.decode64(json_response['content']).lines.first.should == "class Key < ActiveRecord::Base\n" + end + + it "should return a 400 bad request if no params given" do + get api("/projects/#{project.id}/repository/files", user) + response.status.should == 400 + end + + it "should return a 404 if such file does not exist" do + params = { + file_path: 'app/models/application.rb', + ref: 'master', + } + + get api("/projects/#{project.id}/repository/files", user), params + response.status.should == 404 + end + end + describe "POST /projects/:id/repository/files" do let(:valid_params) { { From 6cf39fe10ddf6f90a17d52ba6b50425f58215eeb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 12:41:21 +0200 Subject: [PATCH 089/112] Extract commits API to separate file Signed-off-by: Dmitriy Zaporozhets --- app/views/help/_api_layout.html.haml | 2 +- doc/api/README.md | 1 + doc/api/commits.md | 95 ++++++++++++++++++++++++++ doc/api/repositories.md | 93 ------------------------- lib/api/api.rb | 1 + lib/api/commits.rb | 64 +++++++++++++++++ lib/api/repositories.rb | 44 ------------ spec/requests/api/commits_spec.rb | 87 +++++++++++++++++++++++ spec/requests/api/repositories_spec.rb | 71 ------------------- 9 files changed, 249 insertions(+), 209 deletions(-) create mode 100644 doc/api/commits.md create mode 100644 lib/api/commits.rb create mode 100644 spec/requests/api/commits_spec.rb diff --git a/app/views/help/_api_layout.html.haml b/app/views/help/_api_layout.html.haml index 9f7bc78355..af723f906d 100644 --- a/app/views/help/_api_layout.html.haml +++ b/app/views/help/_api_layout.html.haml @@ -5,7 +5,7 @@ %i.icon-angle-left Back to help %ul.nav.nav-pills.nav-stacked - - %w(README projects project_snippets repositories repository_files deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file| + - %w(README projects project_snippets repositories repository_files commits deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file| %li{class: file == @category ? 'active' : nil} = link_to file.titleize, help_api_file_path(file) diff --git a/doc/api/README.md b/doc/api/README.md index f13f319a84..850666953a 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -128,6 +128,7 @@ But when you want to create a link to web page - use `http:://host/project/issu + [Project Snippets](project_snippets.md) + [Repositories](repositories.md) + [Repository Files](repository_files.md) ++ [Commits](commits.md) + [Merge Requests](merge_requests.md) + [Issues](issues.md) + [Milestones](milestones.md) diff --git a/doc/api/commits.md b/doc/api/commits.md new file mode 100644 index 0000000000..69b44a2e83 --- /dev/null +++ b/doc/api/commits.md @@ -0,0 +1,95 @@ +# Commits API + +## List repository commits + +Get a list of repository commits in a project. + +``` +GET /projects/:id/repository/commits +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch + +```json +[ + { + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "Replace sanitize with escape once", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dzaporozhets@sphereconsultinginc.com", + "created_at": "2012-09-20T11:50:22+03:00" + }, + { + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "dmitriy.zaporozhets@gmail.com", + "created_at": "2012-09-20T09:06:12+03:00" + } +] +``` + +## Get a single commit + +Get a specific commit identified by the commit hash or name of a branch or tag. + +``` +GET /projects/:id/repository/commits/:sha +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `sha` (required) - The commit hash or name of a repository branch or tag + +```json +{ + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "dmitriy.zaporozhets@gmail.com", + "created_at": "2012-09-20T09:06:12+03:00", + "committed_date": "2012-09-20T09:06:12+03:00", + "authored_date": "2012-09-20T09:06:12+03:00", + "parent_ids" : [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ] +} +``` + + +## Get the diff of a commit + +Get the diff of a commit in a project. + +``` +GET /projects/:id/repository/commits/:sha/diff +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `sha` (required) - The name of a repository branch or tag or if not given the default branch + +```json +[ + { + "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files", + "new_path": "doc/update/5.4-to-6.0.md", + "old_path": "doc/update/5.4-to-6.0.md", + "a_mode": null, + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false + } +] +``` + + diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 70e297f1bc..65ea361535 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -204,99 +204,6 @@ Parameters: ] ``` - -## List repository commits - -Get a list of repository commits in a project. - -``` -GET /projects/:id/repository/commits -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch - -```json -[ - { - "id": "ed899a2f4b50b4370feeea94676502b42383c746", - "short_id": "ed899a2f4b5", - "title": "Replace sanitize with escape once", - "author_name": "Dmitriy Zaporozhets", - "author_email": "dzaporozhets@sphereconsultinginc.com", - "created_at": "2012-09-20T11:50:22+03:00" - }, - { - "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", - "short_id": "6104942438c", - "title": "Sanitize for network graph", - "author_name": "randx", - "author_email": "dmitriy.zaporozhets@gmail.com", - "created_at": "2012-09-20T09:06:12+03:00" - } -] -``` - -## Get a single commit - -Get a specific commit identified by the commit hash or name of a branch or tag. - -``` -GET /projects/:id/repository/commits/:sha -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `sha` (required) - The commit hash or name of a repository branch or tag - -```json -{ - "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", - "short_id": "6104942438c", - "title": "Sanitize for network graph", - "author_name": "randx", - "author_email": "dmitriy.zaporozhets@gmail.com", - "created_at": "2012-09-20T09:06:12+03:00", - "committed_date": "2012-09-20T09:06:12+03:00", - "authored_date": "2012-09-20T09:06:12+03:00", - "parent_ids" : [ - "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" - ] -} -``` - - -## Get the diff of a commit - -Get the diff of a commit in a project. - -``` -GET /projects/:id/repository/commits/:sha/diff -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `sha` (required) - The name of a repository branch or tag or if not given the default branch - -```json -[ - { - "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files", - "new_path": "doc/update/5.4-to-6.0.md", - "old_path": "doc/update/5.4-to-6.0.md", - "a_mode": null, - "b_mode": "100644", - "new_file": false, - "renamed_file": false, - "deleted_file": false - } -] -``` - ## List repository tree Get a list of repository files and directories in a project. diff --git a/lib/api/api.rb b/lib/api/api.rb index 283f7642f6..4157397b5e 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -40,6 +40,7 @@ module API mount ProjectHooks mount Services mount Files + mount Commits mount Namespaces end end diff --git a/lib/api/commits.rb b/lib/api/commits.rb new file mode 100644 index 0000000000..33b8b3d224 --- /dev/null +++ b/lib/api/commits.rb @@ -0,0 +1,64 @@ +require 'mime/types' + +module API + # Projects API + class Commits < Grape::API + before { authenticate! } + before { authorize! :download_code, user_project } + + resource :projects do + helpers do + def handle_project_member_errors(errors) + if errors[:project_access].any? + error!(errors[:project_access], 422) + end + not_found! + end + end + + # Get a project repository commits + # + # Parameters: + # id (required) - The ID of a project + # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used + # Example Request: + # GET /projects/:id/repository/commits + get ":id/repository/commits" do + page = (params[:page] || 0).to_i + per_page = (params[:per_page] || 20).to_i + ref = params[:ref_name] || user_project.try(:default_branch) || 'master' + + commits = user_project.repository.commits(ref, nil, per_page, page * per_page) + present commits, with: Entities::RepoCommit + end + + # Get a specific commit of a project + # + # Parameters: + # id (required) - The ID of a project + # sha (required) - The commit hash or name of a repository branch or tag + # Example Request: + # GET /projects/:id/repository/commits/:sha + get ":id/repository/commits/:sha" do + sha = params[:sha] + commit = user_project.repository.commit(sha) + not_found! "Commit" unless commit + present commit, with: Entities::RepoCommitDetail + end + + # Get the diff for a specific commit of a project + # + # Parameters: + # id (required) - The ID of a project + # sha (required) - The commit or branch name + # Example Request: + # GET /projects/:id/repository/commits/:sha/diff + get ":id/repository/commits/:sha/diff" do + sha = params[:sha] + commit = user_project.repository.commit(sha) + not_found! "Commit" unless commit + commit.diffs + end + end + end +end diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index cad64760ab..00a0c919b4 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -85,50 +85,6 @@ module API present user_project.repo.tags.sort_by(&:name).reverse, with: Entities::RepoObject, project: user_project end - # Get a project repository commits - # - # Parameters: - # id (required) - The ID of a project - # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used - # Example Request: - # GET /projects/:id/repository/commits - get ":id/repository/commits" do - page = (params[:page] || 0).to_i - per_page = (params[:per_page] || 20).to_i - ref = params[:ref_name] || user_project.try(:default_branch) || 'master' - - commits = user_project.repository.commits(ref, nil, per_page, page * per_page) - present commits, with: Entities::RepoCommit - end - - # Get a specific commit of a project - # - # Parameters: - # id (required) - The ID of a project - # sha (required) - The commit hash or name of a repository branch or tag - # Example Request: - # GET /projects/:id/repository/commits/:sha - get ":id/repository/commits/:sha" do - sha = params[:sha] - commit = user_project.repository.commit(sha) - not_found! "Commit" unless commit - present commit, with: Entities::RepoCommitDetail - end - - # Get the diff for a specific commit of a project - # - # Parameters: - # id (required) - The ID of a project - # sha (required) - The commit or branch name - # Example Request: - # GET /projects/:id/repository/commits/:sha/diff - get ":id/repository/commits/:sha/diff" do - sha = params[:sha] - commit = user_project.repository.commit(sha) - not_found! "Commit" unless commit - commit.diffs - end - # Get a project repository tree # # Parameters: diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb new file mode 100644 index 0000000000..ea317e1137 --- /dev/null +++ b/spec/requests/api/commits_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' +require 'mime/types' + +describe API::API do + include ApiHelpers + before(:each) { enable_observers } + after(:each) {disable_observers} + + let(:user) { create(:user) } + let(:user2) { create(:user) } + let!(:project) { create(:project, creator_id: user.id) } + let!(:master) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } + let!(:guest) { create(:users_project, user: user2, project: project, project_access: UsersProject::GUEST) } + + before { project.team << [user, :reporter] } + + describe "GET /projects/:id/repository/commits" do + context "authorized user" do + before { project.team << [user2, :reporter] } + + it "should return project commits" do + get api("/projects/#{project.id}/repository/commits", user) + response.status.should == 200 + + json_response.should be_an Array + json_response.first['id'].should == project.repository.commit.id + end + end + + context "unauthorized user" do + it "should not return project commits" do + get api("/projects/#{project.id}/repository/commits") + response.status.should == 401 + end + end + end + + describe "GET /projects:id/repository/commits/:sha" do + context "authorized user" do + it "should return a commit by sha" do + get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) + response.status.should == 200 + json_response['id'].should == project.repository.commit.id + json_response['title'].should == project.repository.commit.title + end + + it "should return a 404 error if not found" do + get api("/projects/#{project.id}/repository/commits/invalid_sha", user) + response.status.should == 404 + end + end + + context "unauthorized user" do + it "should not return the selected commit" do + get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}") + response.status.should == 401 + end + end + end + + describe "GET /projects:id/repository/commits/:sha/diff" do + context "authorized user" do + before { project.team << [user2, :reporter] } + + it "should return the diff of the selected commit" do + get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user) + response.status.should == 200 + + json_response.should be_an Array + json_response.length.should >= 1 + json_response.first.keys.should include "diff" + end + + it "should return a 404 error if invalid commit" do + get api("/projects/#{project.id}/repository/commits/invalid_sha/diff", user) + response.status.should == 404 + end + end + + context "unauthorized user" do + it "should not return the diff of the selected commit" do + get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff") + response.status.should == 401 + end + end + end +end diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 4700872825..99d966edc3 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -103,77 +103,6 @@ describe API::API do end end - describe "GET /projects/:id/repository/commits" do - context "authorized user" do - before { project.team << [user2, :reporter] } - - it "should return project commits" do - get api("/projects/#{project.id}/repository/commits", user) - response.status.should == 200 - - json_response.should be_an Array - json_response.first['id'].should == project.repository.commit.id - end - end - - context "unauthorized user" do - it "should not return project commits" do - get api("/projects/#{project.id}/repository/commits") - response.status.should == 401 - end - end - end - - describe "GET /projects:id/repository/commits/:sha" do - context "authorized user" do - it "should return a commit by sha" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) - response.status.should == 200 - json_response['id'].should == project.repository.commit.id - json_response['title'].should == project.repository.commit.title - end - - it "should return a 404 error if not found" do - get api("/projects/#{project.id}/repository/commits/invalid_sha", user) - response.status.should == 404 - end - end - - context "unauthorized user" do - it "should not return the selected commit" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}") - response.status.should == 401 - end - end - end - - describe "GET /projects:id/repository/commits/:sha/diff" do - context "authorized user" do - before { project.team << [user2, :reporter] } - - it "should return the diff of the selected commit" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user) - response.status.should == 200 - - json_response.should be_an Array - json_response.length.should >= 1 - json_response.first.keys.should include "diff" - end - - it "should return a 404 error if invalid commit" do - get api("/projects/#{project.id}/repository/commits/invalid_sha/diff", user) - response.status.should == 404 - end - end - - context "unauthorized user" do - it "should not return the diff of the selected commit" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff") - response.status.should == 401 - end - end - end - describe "GET /projects/:id/repository/tree" do context "authorized user" do before { project.team << [user2, :reporter] } From 8a55636f8974d73c097a52721e2208cea727bc17 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 13:15:43 +0200 Subject: [PATCH 090/112] Dont replace all issue context when change assignee/milestone Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/dispatcher.js.coffee | 2 + app/assets/javascripts/issue.js.coffee | 9 +++ app/assets/javascripts/issues.js.coffee | 6 -- .../project_users_select.js.coffee | 58 ++++++++++--------- .../projects/issues/_issue_context.html.haml | 3 - app/views/projects/issues/update.js.haml | 3 - 6 files changed, 42 insertions(+), 39 deletions(-) create mode 100644 app/assets/javascripts/issue.js.coffee diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 9afb597485..46d6db0f05 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -19,6 +19,8 @@ class Dispatcher switch page when 'projects:issues:index' Issues.init() + when 'projects:issues:show' + new Issue() when 'projects:issues:new', 'projects:merge_requests:new' GitLab.GfmAutoComplete.setup() when 'dashboard:show' diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee new file mode 100644 index 0000000000..36935a0a15 --- /dev/null +++ b/app/assets/javascripts/issue.js.coffee @@ -0,0 +1,9 @@ +class Issue + constructor: -> + $('.edit-issue.inline-update input[type="submit"]').hide() + $(".issue-box .inline-update").on "change", "select", -> + $(this).submit() + $(".issue-box .inline-update").on "change", "#issue_assignee_id", -> + $(this).submit() + +@Issue = Issue diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee index 6c239c66c0..e2f1bc743f 100644 --- a/app/assets/javascripts/issues.js.coffee +++ b/app/assets/javascripts/issues.js.coffee @@ -77,9 +77,3 @@ $("#update_issues_ids").val [] $(".issues_bulk_update").hide() $(".issues-filters").show() - -$ -> - $('.edit-issue.inline-update input[type="submit"]').hide(); - $("body").on "change", ".edit-issue.inline-update select", -> - $(this).submit() - diff --git a/app/assets/javascripts/project_users_select.js.coffee b/app/assets/javascripts/project_users_select.js.coffee index 59a53cb52b..aa8b70d9b8 100644 --- a/app/assets/javascripts/project_users_select.js.coffee +++ b/app/assets/javascripts/project_users_select.js.coffee @@ -1,5 +1,31 @@ -$ -> - projectUserFormatResult = (user) -> +@projectUsersSelect = + init: -> + $('.ajax-project-users-select').each (i, select) -> + project_id = $('body').data('project-id') + + $(select).select2 + placeholder: $(select).data('placeholder') || "Search for a user" + multiple: $(select).hasClass('multiselect') + minimumInputLength: 0 + query: (query) -> + Api.projectUsers project_id, query.term, (users) -> + data = { results: users } + query.callback(data) + + initSelection: (element, callback) -> + id = $(element).val() + if id isnt "" + Api.user(id, callback) + + + formatResult: projectUsersSelect.projectUserFormatResult + formatSelection: projectUsersSelect.projectUserFormatSelection + dropdownCssClass: "ajax-project-users-dropdown" + dropdownAutoWidth: true + escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results + m + + projectUserFormatResult: (user) -> if user.avatar_url avatar = user.avatar_url else if gon.gravatar_enabled @@ -15,30 +41,8 @@ $ ->
#{user.username}
" - projectUserFormatSelection = (user) -> + projectUserFormatSelection: (user) -> user.name - $('.ajax-project-users-select').each (i, select) -> - project_id = $('body').data('project-id') - - $(select).select2 - placeholder: $(select).data('placeholder') || "Search for a user" - multiple: $(select).hasClass('multiselect') - minimumInputLength: 0 - query: (query) -> - Api.projectUsers project_id, query.term, (users) -> - data = { results: users } - query.callback(data) - - initSelection: (element, callback) -> - id = $(element).val() - if id isnt "" - Api.user(id, callback) - - - formatResult: projectUserFormatResult - formatSelection: projectUserFormatSelection - dropdownCssClass: "ajax-project-users-dropdown" - dropdownAutoWidth: true - escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results - m +$ -> + projectUsersSelect.init() diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml index 029d7d6f0f..fb124a8ab4 100644 --- a/app/views/projects/issues/_issue_context.html.haml +++ b/app/views/projects/issues/_issue_context.html.haml @@ -4,9 +4,6 @@ \ and currently assigned to - if can?(current_user, :modify_issue, @issue) - = link_to profile_path(issue.assignee) do - = image_tag(avatar_icon(issue.assignee.email), class: 'avatar avatar-inline s16 assignee') if issue.assignee - = project_users_select_tag('issue[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @issue.assignee_id) - elsif issue.assignee = link_to_member(@project, @issue.assignee) diff --git a/app/views/projects/issues/update.js.haml b/app/views/projects/issues/update.js.haml index 59524e0f22..5199e9fc61 100644 --- a/app/views/projects/issues/update.js.haml +++ b/app/views/projects/issues/update.js.haml @@ -3,10 +3,7 @@ :plain $("##{dom_id(@issue)}").fadeOut(); - elsif params[:issue_context] - $('.issue-box .context').html("#{escape_javascript(render partial: 'issue_context', locals: { issue: @issue })}"); $('.issue-box .context').effect('highlight'); - $('.select2').select2(); - $('.edit-issue.inline-update input[type="submit"]').hide(); - if @issue.milestone $('.milestone-nav-link').replaceWith("| Milestone #{escape_javascript(link_to @issue.milestone.title, project_milestone_path(@issue.project, @issue.milestone))}") - else From 4f6b570fbe6e87befd9242f19acee1f14a28574e Mon Sep 17 00:00:00 2001 From: Tudor Pavel Date: Mon, 17 Feb 2014 16:54:19 +0200 Subject: [PATCH 091/112] Filter issues by multiple labels with Spinach feature spec --- app/assets/stylesheets/main/variables.scss | 1 + app/helpers/projects_helper.rb | 25 +++++++ app/views/projects/issues/_issues.html.haml | 19 ----- app/views/shared/_project_filter.html.haml | 12 ++++ features/project/issues/filter_labels.feature | 26 +++++++ .../steps/project/project_filter_labels.rb | 70 +++++++++++++++++++ 6 files changed, 134 insertions(+), 19 deletions(-) create mode 100644 features/project/issues/filter_labels.feature create mode 100644 features/steps/project/project_filter_labels.rb diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss index decc5f5046..4b5fa0979b 100644 --- a/app/assets/stylesheets/main/variables.scss +++ b/app/assets/stylesheets/main/variables.scss @@ -5,6 +5,7 @@ $primary_color: #2FA0BB; $link_color: #3A89A3; $style_color: #474D57; $bg_style_color: #2299BB; +$list-group-active-bg: $bg_style_color; $hover: #D9EDF7; /** diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index a6a507360b..204950a04b 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -64,6 +64,31 @@ module ProjectsHelper project_nav_tabs.include? name end + def selected_label?(label_name) + params[:label_name].to_s.split(',').include?(label_name) + end + + def labels_filter_path(label_name) + label_name = + if selected_label?(label_name) + params[:label_name].split(',').reject { |l| l == label_name }.join(',') + elsif params[:label_name].present? + "#{params[:label_name]},#{label_name}" + else + label_name + end + + project_filter_path(label_name: label_name) + end + + def label_filter_class(label_name) + if selected_label?(label_name) + 'list-group-item active' + else + 'list-group-item' + end + end + def project_filter_path(options={}) exist_opts = { state: params[:state], diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index 020bfa3697..676bf4a02e 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -2,25 +2,6 @@ .check-all-holder = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" .issues-filters - .dropdown.inline - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %i.icon-tags - %span.light labels: - - if params[:label_name].present? - %strong= params[:label_name] - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to project_filter_path(label_name: nil) do - Any - - issue_label_names.each do |label_name| - %li - = link_to project_filter_path(label_name: label_name) do - %span{class: "label #{label_css_class(label_name)}"} - %i.icon-tag - = label_name .dropdown.inline.prepend-left-10 %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %i.icon-user diff --git a/app/views/shared/_project_filter.html.haml b/app/views/shared/_project_filter.html.haml index 9b89c5c800..0d4023bbd7 100644 --- a/app/views/shared/_project_filter.html.haml +++ b/app/views/shared/_project_filter.html.haml @@ -26,6 +26,18 @@ = link_to project_filter_path(state: 'all') do All + %fieldset + %legend Labels + %ul.list-group + - issue_label_names.each do |label_name| + = link_to labels_filter_path(label_name), class: label_filter_class(label_name) do + %span{class: "label #{label_css_class(label_name)}"} + %i.icon-tag + = label_name + - if selected_label?(label_name) + .pull-right + %i.icon-remove + %fieldset - if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any? = link_to project_entities_path, class: 'cgray pull-right' do diff --git a/features/project/issues/filter_labels.feature b/features/project/issues/filter_labels.feature new file mode 100644 index 0000000000..8df7a119e8 --- /dev/null +++ b/features/project/issues/filter_labels.feature @@ -0,0 +1,26 @@ +Feature: Project Filter Labels + Background: + Given I sign in as a user + And I own project "Shop" + And project "Shop" has issue "Bugfix1" with tags: "bug", "feature" + And project "Shop" has issue "Bugfix2" with tags: "bug", "enhancement" + And project "Shop" has issue "Feature1" with tags: "feature" + Given I visit project "Shop" issues page + + Scenario: I should see project issues + Then I should see "bug" in labels filter + And I should see "feature" in labels filter + And I should see "enhancement" in labels filter + + Scenario: I filter by one label + Given I click link "bug" + Then I should see "Bugfix1" in issues list + And I should see "Bugfix2" in issues list + And I should not see "Feature1" in issues list + + Scenario: I filter by two labels + Given I click link "bug" + And I click link "feature" + Then I should see "Bugfix1" in issues list + And I should not see "Bugfix2" in issues list + And I should not see "Feature1" in issues list diff --git a/features/steps/project/project_filter_labels.rb b/features/steps/project/project_filter_labels.rb new file mode 100644 index 0000000000..d507d3417e --- /dev/null +++ b/features/steps/project/project_filter_labels.rb @@ -0,0 +1,70 @@ +class ProjectFilterLabels < Spinach::FeatureSteps + include SharedAuthentication + include SharedProject + include SharedPaths + + Then 'I should see "bug" in labels filter' do + within ".list-group" do + page.should have_content "bug" + end + end + + And 'I should see "feature" in labels filter' do + within ".list-group" do + page.should have_content "feature" + end + end + + And 'I should see "enhancement" in labels filter' do + within ".list-group" do + page.should have_content "enhancement" + end + end + + Then 'I should see "Bugfix1" in issues list' do + within ".issues-list" do + page.should have_content "Bugfix1" + end + end + + And 'I should see "Bugfix2" in issues list' do + within ".issues-list" do + page.should have_content "Bugfix2" + end + end + + And 'I should not see "Bugfix2" in issues list' do + within ".issues-list" do + page.should_not have_content "Bugfix2" + end + end + + And 'I should not see "Feature1" in issues list' do + within ".issues-list" do + page.should_not have_content "Feature1" + end + end + + Given 'I click link "bug"' do + click_link "bug" + end + + Given 'I click link "feature"' do + click_link "feature" + end + + And 'project "Shop" has issue "Bugfix1" with tags: "bug", "feature"' do + project = Project.find_by(name: "Shop") + create(:issue, title: "Bugfix1", project: project, label_list: ['bug', 'feature']) + end + + And 'project "Shop" has issue "Bugfix2" with tags: "bug", "enhancement"' do + project = Project.find_by(name: "Shop") + create(:issue, title: "Bugfix2", project: project, label_list: ['bug', 'enhancement']) + end + + And 'project "Shop" has issue "Feature1" with tags: "feature"' do + project = Project.find_by(name: "Shop") + create(:issue, title: "Feature1", project: project, label_list: 'feature') + end +end From 9d637d576cbac348b6e6e0bee1b98f184f4e2a26 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 14:21:13 +0000 Subject: [PATCH 092/112] Fix tests --- spec/features/issues_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 1d225e8bad..834ed73549 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -183,7 +183,7 @@ describe "Issues" do it 'with dropdown menu' do visit project_issue_path(project, issue) - find('.edit-issue.inline-update').select(project.team.members.first.name, from: 'issue_assignee_id') + find('.edit-issue.inline-update #issue_assignee_id').set project.team.members.first.id click_button 'Update Issue' page.should have_content "currently assigned to" @@ -258,4 +258,4 @@ describe "Issues" do def last_issue all("ul.issues-list li").last.text end -end +end \ No newline at end of file From b05a67f4e3fdf94477539d61bff6d74337d2ddef Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 16:22:57 +0200 Subject: [PATCH 093/112] Split merge request coffee Signed-off-by: Dmitriy Zaporozhets --- .../javascripts/merge_request.js.coffee | 103 ++++++++++++++++++ .../javascripts/merge_requests.js.coffee | 96 ---------------- 2 files changed, 103 insertions(+), 96 deletions(-) create mode 100644 app/assets/javascripts/merge_request.js.coffee diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee new file mode 100644 index 0000000000..c0f83c9302 --- /dev/null +++ b/app/assets/javascripts/merge_request.js.coffee @@ -0,0 +1,103 @@ +class MergeRequest + constructor: (@opts) -> + @initContextWidget() + this.$el = $('.merge-request') + @diffs_loaded = if @opts.action == 'diffs' then true else false + @commits_loaded = false + + this.activateTab(@opts.action) + + this.bindEvents() + + this.initMergeWidget() + this.$('.show-all-commits').on 'click', => + this.showAllCommits() + + modal = $('#modal_merge_info').modal(show: false) + + disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request' + + + # Local jQuery finder + $: (selector) -> + this.$el.find(selector) + + initContextWidget: -> + $('.edit-merge_request.inline-update input[type="submit"]').hide() + $(".issue-box .inline-update").on "change", "select", -> + $(this).submit() + $(".issue-box .inline-update").on "change", "#merge_request_assignee_id", -> + $(this).submit() + + initMergeWidget: -> + this.showState( @opts.current_status ) + + if this.$('.automerge_widget').length and @opts.check_enable + $.get @opts.url_to_automerge_check, (data) => + this.showState( data.merge_status ) + , 'json' + + if @opts.ci_enable + $.get @opts.url_to_ci_check, (data) => + this.showCiState data.status + , 'json' + + bindEvents: -> + this.$('.nav-tabs').on 'click', 'a', (event) => + a = $(event.currentTarget) + + href = a.attr('href') + History.replaceState {path: href}, document.title, href + + event.preventDefault() + + this.$('.nav-tabs').on 'click', 'li', (event) => + this.activateTab($(event.currentTarget).data('action')) + + this.$('.accept_merge_request').on 'click', -> + $('.automerge_widget.can_be_merged').hide() + $('.merge-in-progress').show() + + activateTab: (action) -> + this.$('.nav-tabs li').removeClass 'active' + this.$('.tab-content').hide() + switch action + when 'diffs' + this.$('.nav-tabs .diffs-tab').addClass 'active' + this.loadDiff() unless @diffs_loaded + this.$('.diffs').show() + else + this.$('.nav-tabs .notes-tab').addClass 'active' + this.$('.notes').show() + + showState: (state) -> + $('.automerge_widget').hide() + $('.automerge_widget.' + state).show() + + showCiState: (state) -> + $('.ci_widget').hide() + $('.ci_widget.ci-' + state).show() + + loadDiff: (event) -> + $.ajax + type: 'GET' + url: this.$('.nav-tabs .diffs-tab a').attr('href') + beforeSend: => + this.$('.status').addClass 'loading' + complete: => + @diffs_loaded = true + this.$('.status').removeClass 'loading' + success: (data) => + this.$(".diffs").html(data.html) + dataType: 'json' + + showAllCommits: -> + this.$('.first-commits').remove() + this.$('.all-commits').removeClass 'hide' + + alreadyOrCannotBeMerged: -> + this.$('.automerge_widget').hide() + this.$('.merge-in-progress').hide() + this.$('.automerge_widget.already_cannot_be_merged').show() + +this.MergeRequest = MergeRequest diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee index ff843c68d6..9201c84c5e 100644 --- a/app/assets/javascripts/merge_requests.js.coffee +++ b/app/assets/javascripts/merge_requests.js.coffee @@ -6,99 +6,3 @@ $('#milestone_id').select2() $('#milestone_id, #assignee_id').on 'change', -> $(this).closest('form').submit() - -class MergeRequest - - constructor: (@opts) -> - this.$el = $('.merge-request') - @diffs_loaded = if @opts.action == 'diffs' then true else false - @commits_loaded = false - - this.activateTab(@opts.action) - - this.bindEvents() - - this.initMergeWidget() - this.$('.show-all-commits').on 'click', => - this.showAllCommits() - - modal = $('#modal_merge_info').modal(show: false) - - disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request' - - # Local jQuery finder - $: (selector) -> - this.$el.find(selector) - - initMergeWidget: -> - this.showState( @opts.current_status ) - - if this.$('.automerge_widget').length and @opts.check_enable - $.get @opts.url_to_automerge_check, (data) => - this.showState( data.merge_status ) - , 'json' - - if @opts.ci_enable - $.get @opts.url_to_ci_check, (data) => - this.showCiState data.status - , 'json' - - bindEvents: -> - this.$('.nav-tabs').on 'click', 'a', (event) => - a = $(event.currentTarget) - - href = a.attr('href') - History.replaceState {path: href}, document.title, href - - event.preventDefault() - - this.$('.nav-tabs').on 'click', 'li', (event) => - this.activateTab($(event.currentTarget).data('action')) - - this.$('.accept_merge_request').on 'click', -> - $('.automerge_widget.can_be_merged').hide() - $('.merge-in-progress').show() - - activateTab: (action) -> - this.$('.nav-tabs li').removeClass 'active' - this.$('.tab-content').hide() - switch action - when 'diffs' - this.$('.nav-tabs .diffs-tab').addClass 'active' - this.loadDiff() unless @diffs_loaded - this.$('.diffs').show() - else - this.$('.nav-tabs .notes-tab').addClass 'active' - this.$('.notes').show() - - showState: (state) -> - $('.automerge_widget').hide() - $('.automerge_widget.' + state).show() - - showCiState: (state) -> - $('.ci_widget').hide() - $('.ci_widget.ci-' + state).show() - - loadDiff: (event) -> - $.ajax - type: 'GET' - url: this.$('.nav-tabs .diffs-tab a').attr('href') - beforeSend: => - this.$('.status').addClass 'loading' - complete: => - @diffs_loaded = true - this.$('.status').removeClass 'loading' - success: (data) => - this.$(".diffs").html(data.html) - dataType: 'json' - - showAllCommits: -> - this.$('.first-commits').remove() - this.$('.all-commits').removeClass 'hide' - - alreadyOrCannotBeMerged: -> - this.$('.automerge_widget').hide() - this.$('.merge-in-progress').hide() - this.$('.automerge_widget.already_cannot_be_merged').show() - -this.MergeRequest = MergeRequest From 702128892b5edd093e8671527fb9860d3631f5eb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 16:24:19 +0200 Subject: [PATCH 094/112] Allow change assignee/milestone from MergeRequest show page Signed-off-by: Dmitriy Zaporozhets --- .../projects/merge_requests_controller.rb | 9 +++++++- .../projects/issues/_issue_context.html.haml | 2 +- .../merge_requests/show/_context.html.haml | 23 +++++++++++++++++++ .../merge_requests/show/_mr_box.html.haml | 10 +------- .../projects/merge_requests/update.js.haml | 2 ++ 5 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 app/views/projects/merge_requests/show/_context.html.haml create mode 100644 app/views/projects/merge_requests/update.js.haml diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index d36b5b27e8..e3a0699ef3 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -108,8 +108,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id)) @merge_request.reload_code @merge_request.mark_as_unchecked + @merge_request.reset_events_cache - redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.' + + respond_to do |format| + format.js + format.html do + redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.' + end + end else render "edit" end diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml index fb124a8ab4..e5418c25b2 100644 --- a/app/views/projects/issues/_issue_context.html.haml +++ b/app/views/projects/issues/_issue_context.html.haml @@ -4,7 +4,7 @@ \ and currently assigned to - if can?(current_user, :modify_issue, @issue) - = project_users_select_tag('issue[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @issue.assignee_id) + = project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @issue.assignee_id) - elsif issue.assignee = link_to_member(@project, @issue.assignee) diff --git a/app/views/projects/merge_requests/show/_context.html.haml b/app/views/projects/merge_requests/show/_context.html.haml new file mode 100644 index 0000000000..705eeb9894 --- /dev/null +++ b/app/views/projects/merge_requests/show/_context.html.haml @@ -0,0 +1,23 @@ += form_for [@project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update'} do |f| + Created by #{link_to_member(@project, merge_request.author)}  + - if merge_request.assignee + \ and currently assigned to + + - if can?(current_user, :modify_merge_request, @merge_request) + = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @merge_request.assignee_id) + - elsif merge_request.assignee + = link_to_member(@project, @merge_request.assignee) + + + .pull-right.hidden-sm.hidden-xs + - if merge_request.milestone + - milestone = merge_request.milestone + %cite.cgray Attached to milestone + + - if can?(current_user, :modify_merge_request, @merge_request) + = f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone (none):" }, {class: 'select2 select2-compact'}) + + = hidden_field_tag :merge_request_context + = f.submit class: 'btn' + - elsif merge_request.milestone + = link_to merge_request.milestone.title, project_milestone_path diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml index b4f648ab19..7c3f9b9344 100644 --- a/app/views/projects/merge_requests/show/_mr_box.html.haml +++ b/app/views/projects/merge_requests/show/_mr_box.html.haml @@ -4,15 +4,7 @@ .context %cite.cgray - Created by #{link_to_member(@project, @merge_request.author)}. - - if @merge_request.assignee - Currently assigned to #{link_to_member(@project, @merge_request.assignee)}. - - if @merge_request.milestone - .pull-right - - milestone = @merge_request.milestone - %cite.cgray Attached to milestone - %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone) - + = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request } - if @merge_request.description.present? .description diff --git a/app/views/projects/merge_requests/update.js.haml b/app/views/projects/merge_requests/update.js.haml new file mode 100644 index 0000000000..6452cc6382 --- /dev/null +++ b/app/views/projects/merge_requests/update.js.haml @@ -0,0 +1,2 @@ +- if params[:merge_request_context] + $('.issue-box .context').effect('highlight'); From 0007db8352fa56be06d663f4046a2b5602e51bc0 Mon Sep 17 00:00:00 2001 From: dosire Date: Tue, 18 Feb 2014 15:38:07 +0100 Subject: [PATCH 095/112] Doesn't exist for user endpoint. --- doc/api/projects.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 12e0c47ee6..e795298c67 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -255,7 +255,6 @@ Parameters: + `user_id` (required) - user_id of owner + `name` (required) - new project name -+ `namespace_id` (optional) - namespace for the new project (defaults to user) + `description` (optional) - short project description + `default_branch` (optional) - 'master' by default + `issues_enabled` (optional) From 0bf4e568ea3accebbcafa7be1f74a15b672ae31a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 16:49:50 +0200 Subject: [PATCH 096/112] Use same avatar size for all event rows Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/sections/events.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index 801233519b..6ef12b20a5 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -37,8 +37,8 @@ &.event-inline { .avatar { - width: 16px; - height: 16px; + position: relative; + top: -2px; } } From 555c25e601fb32f23e652ee301c02f4d5ee8e59f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 17:34:22 +0200 Subject: [PATCH 097/112] Fix random failing test Signed-off-by: Dmitriy Zaporozhets --- features/project/merge_requests.feature | 1 - features/steps/project/project_merge_requests.rb | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 3ca099b957..556b96338d 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -29,7 +29,6 @@ Feature: Project Merge Requests And I click link "Close" Then I should see closed merge request "Bug NS-04" - @javascript Scenario: I submit new unassigned merge request Given I click link "New Merge Request" And I submit new merge request "Wiki Feature" diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index fcbae8b8fb..cc2648c620 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -60,20 +60,8 @@ class ProjectMergeRequests < Spinach::FeatureSteps step 'I submit new merge request "Wiki Feature"' do fill_in "merge_request_title", with: "Wiki Feature" - - # this must come first, so that the target branch is set - # by the time the "select" for "notes_refactoring" is executed - select project.path_with_namespace, from: "merge_request_target_project_id" select "master", from: "merge_request_source_branch" - - find(:select, "merge_request_target_project_id", {}).value.should == project.id.to_s - find(:select, "merge_request_source_project_id", {}).value.should == project.id.to_s - - # using "notes_refactoring" because "Bug NS-04" uses master/stable, - # this will fail merge_request validation if the branches are the same - find(:select, "merge_request_target_branch", {}).find(:option, "notes_refactoring", {}).value.should == "notes_refactoring" select "notes_refactoring", from: "merge_request_target_branch" - click_button "Submit merge request" end From f0750b9166dd729383c4b3f865c80bb024d03798 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 20:09:31 +0200 Subject: [PATCH 098/112] Add close button to MR comment form Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/generic/buttons.scss | 17 ++++++++++++++++- app/assets/stylesheets/sections/issues.scss | 15 --------------- app/views/projects/issues/show.html.haml | 8 ++++---- .../projects/merge_requests/_show.html.haml | 6 ++++++ 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss index 219e6ebd68..4cb41a79ff 100644 --- a/app/assets/stylesheets/generic/buttons.scss +++ b/app/assets/stylesheets/generic/buttons.scss @@ -118,7 +118,6 @@ @extend .btn-primary; } - &.btn-close, &.btn-remove { @extend .btn-danger; } @@ -143,6 +142,22 @@ line-height: 16px; margin: 2px; } + + &.btn-close { + color: #B94A48; + font-weight: bold; + &:hover { + color: #B94A48; + } + } + + &.btn-reopen { + color: #468847; + font-weight: bold; + &:hover { + color: #468847; + } + } } .btn-block { diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss index a7fa900faf..4cb8117633 100644 --- a/app/assets/stylesheets/sections/issues.scss +++ b/app/assets/stylesheets/sections/issues.scss @@ -65,21 +65,6 @@ } } -.btn.close_issue { - color: #B94A48; - font-weight: bold; - &:hover { - color: #B94A48; - } -} -.btn.reopen_issue { - color: #468847; - font-weight: bold; - &:hover { - color: #468847; - } -} - @media (min-width: 800px) { .issues_filters select { width: 160px; } } @media (min-width: 1200px) { .issues_filters select { width: 220px; } } diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index cd4a158e42..c1bd114791 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -16,9 +16,9 @@ New Issue - if can?(current_user, :modify_issue, @issue) - if @issue.closed? - = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" + = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped btn-reopen" - else - = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" + = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped btn-close", title: "Close Issue" = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do %i.icon-edit @@ -54,9 +54,9 @@ - content_for :note_actions do - if can?(current_user, :modify_issue, @issue) - if @issue.closed? - = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" + = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped btn-reopen" - else - = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" + = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped btn-close", title: "Close Issue" .participants %cite.cgray #{@issue.participants.count} participants diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 0b9e4df3fd..ec9249be00 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -22,6 +22,12 @@ %i.icon-list-alt Diff + - content_for :note_actions do + - if can?(current_user, :modify_merge_request, @merge_request) + - unless @merge_request.closed? + = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn grouped btn-close", title: "Close merge request" + + .notes.tab-content.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } = render "projects/notes/notes_with_form" .diffs.tab-content From 1c61ac1c64e136b391d472a24bbc5538352e299d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 20:17:26 +0200 Subject: [PATCH 099/112] Refactor MR code reload Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/merge_requests_controller.rb | 3 --- app/models/merge_request.rb | 9 +++++++++ lib/api/merge_requests.rb | 2 -- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index e3a0699ef3..2b410c5a61 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -106,9 +106,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController params[:merge_request].delete(:target_project_id) if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id)) - @merge_request.reload_code - @merge_request.mark_as_unchecked - @merge_request.reset_events_cache respond_to do |format| diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index a3d786c213..b596d7eb9c 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -32,7 +32,9 @@ class MergeRequest < ActiveRecord::Base belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" has_one :merge_request_diff, dependent: :destroy + after_create :create_merge_request_diff + after_update :update_merge_request_diff delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil @@ -125,6 +127,13 @@ class MergeRequest < ActiveRecord::Base end end + def update_merge_request_diff + if source_branch_changed? || target_branch_changed? + reload_code + mark_as_unchecked + end + end + def reload_code if merge_request_diff && opened? merge_request_diff.reload_content diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 0f62cac9a0..58d2f79faf 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -116,8 +116,6 @@ module API authorize! :modify_merge_request, merge_request if merge_request.update_attributes attrs - merge_request.reload_code - merge_request.mark_as_unchecked present merge_request, with: Entities::MergeRequest else handle_merge_request_errors! merge_request.errors From 638f8541dcd4a718e0c8187bb1dd4dfddffeb57d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 20:36:03 +0200 Subject: [PATCH 100/112] Hide labels filter for MRs and remove unnecessary padding Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/issues/_issues.html.haml | 2 +- app/views/projects/issues/index.html.haml | 2 +- app/views/shared/_project_filter.html.haml | 23 +++++++++++---------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index 676bf4a02e..2d69af0b2d 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -2,7 +2,7 @@ .check-all-holder = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" .issues-filters - .dropdown.inline.prepend-left-10 + .dropdown.inline %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %i.icon-user %span.light assignee: diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index 71a89af61a..5e899d412c 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -1,6 +1,6 @@ = render "head" .row .col-md-3 - = render 'shared/project_filter', project_entities_path: project_issues_path(@project) + = render 'shared/project_filter', project_entities_path: project_issues_path(@project), labels: true .col-md-9.issues-holder = render "issues" diff --git a/app/views/shared/_project_filter.html.haml b/app/views/shared/_project_filter.html.haml index 0d4023bbd7..abb2a80b7b 100644 --- a/app/views/shared/_project_filter.html.haml +++ b/app/views/shared/_project_filter.html.haml @@ -26,17 +26,18 @@ = link_to project_filter_path(state: 'all') do All - %fieldset - %legend Labels - %ul.list-group - - issue_label_names.each do |label_name| - = link_to labels_filter_path(label_name), class: label_filter_class(label_name) do - %span{class: "label #{label_css_class(label_name)}"} - %i.icon-tag - = label_name - - if selected_label?(label_name) - .pull-right - %i.icon-remove + - if defined?(labels) + %fieldset + %legend Labels + %ul.list-group + - issue_label_names.each do |label_name| + = link_to labels_filter_path(label_name), class: label_filter_class(label_name) do + %span{class: "label #{label_css_class(label_name)}"} + %i.icon-tag + = label_name + - if selected_label?(label_name) + .pull-right + %i.icon-remove %fieldset - if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any? From a718a9af3e9a4f7431cab066fc81f3311f9fe639 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 20:48:02 +0200 Subject: [PATCH 101/112] Restyle labels filter to match common style Signed-off-by: Dmitriy Zaporozhets --- app/helpers/projects_helper.rb | 4 ++-- app/views/shared/_project_filter.html.haml | 17 +++++++++-------- features/steps/project/project_filter_labels.rb | 6 +++--- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 204950a04b..e943045e41 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -83,9 +83,9 @@ module ProjectsHelper def label_filter_class(label_name) if selected_label?(label_name) - 'list-group-item active' + 'label-filter-item active' else - 'list-group-item' + 'label-filter-item light' end end diff --git a/app/views/shared/_project_filter.html.haml b/app/views/shared/_project_filter.html.haml index abb2a80b7b..1315c76fbb 100644 --- a/app/views/shared/_project_filter.html.haml +++ b/app/views/shared/_project_filter.html.haml @@ -29,15 +29,16 @@ - if defined?(labels) %fieldset %legend Labels - %ul.list-group + %ul.nav.nav-pills.nav-stacked.nav-small.labels-filter - issue_label_names.each do |label_name| - = link_to labels_filter_path(label_name), class: label_filter_class(label_name) do - %span{class: "label #{label_css_class(label_name)}"} - %i.icon-tag - = label_name - - if selected_label?(label_name) - .pull-right - %i.icon-remove + %li{class: label_filter_class(label_name)} + = link_to labels_filter_path(label_name) do + %span{class: "label #{label_css_class(label_name)}"} + %i.icon-tag + = label_name + - if selected_label?(label_name) + .pull-right + %i.icon-remove %fieldset - if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any? diff --git a/features/steps/project/project_filter_labels.rb b/features/steps/project/project_filter_labels.rb index d507d3417e..5926d69d6c 100644 --- a/features/steps/project/project_filter_labels.rb +++ b/features/steps/project/project_filter_labels.rb @@ -4,19 +4,19 @@ class ProjectFilterLabels < Spinach::FeatureSteps include SharedPaths Then 'I should see "bug" in labels filter' do - within ".list-group" do + within ".labels-filter" do page.should have_content "bug" end end And 'I should see "feature" in labels filter' do - within ".list-group" do + within ".labels-filter" do page.should have_content "feature" end end And 'I should see "enhancement" in labels filter' do - within ".list-group" do + within ".labels-filter" do page.should have_content "enhancement" end end From 7e42084fb800546070d3c5d0d704320d1785fdda Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 21:18:46 +0200 Subject: [PATCH 102/112] Move author/date info for Issue#show, MR#show pages to issue-box Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/generic/issue_box.scss | 7 +++++++ .../projects/issues/_issue_context.html.haml | 19 +++++++++---------- app/views/projects/issues/show.html.haml | 6 +++--- .../merge_requests/show/_context.html.haml | 19 +++++++++---------- .../merge_requests/show/_mr_box.html.haml | 3 +++ .../merge_requests/show/_mr_title.html.haml | 2 -- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss index 033b4b20f5..a6573fa0e5 100644 --- a/app/assets/stylesheets/generic/issue_box.scss +++ b/app/assets/stylesheets/generic/issue_box.scss @@ -17,6 +17,13 @@ margin-bottom: 0; } + .creator { + padding: 8px 25px; + background: #eee; + border-bottom: 1px solid #DDD; + color: #777; + } + .title { font-size: 22px; font-weight: 500; diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml index e5418c25b2..aae101cf40 100644 --- a/app/views/projects/issues/_issue_context.html.haml +++ b/app/views/projects/issues/_issue_context.html.haml @@ -1,23 +1,22 @@ = form_for [@project, @issue], remote: true, html: {class: 'edit-issue inline-update'} do |f| - Created by #{link_to_member(@project, issue.author)}  - - if issue.assignee - \ and currently assigned to + %strong.append-right-10 + Assignee: - if can?(current_user, :modify_issue, @issue) = project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @issue.assignee_id) - elsif issue.assignee = link_to_member(@project, @issue.assignee) + - else + None - - .pull-right.hidden-sm.hidden-xs - - if issue.milestone - - milestone = issue.milestone - %cite.cgray Attached to milestone - + .pull-right + %strong.append-right-10 + Milestone: - if can?(current_user, :modify_issue, @issue) = f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone (none):" }, {class: 'select2 select2-compact'}) - = hidden_field_tag :issue_context = f.submit class: 'btn' - elsif issue.milestone = link_to issue.milestone.title, project_milestone_path + - else + None diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index c1bd114791..101f1ddbd1 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -1,9 +1,6 @@ %h3.page-title Issue ##{@issue.iid} - %small - created #{time_ago_with_tooltip(@issue.created_at)} - - if @issue.closed? %span.state-label.state-label-red Closed - else @@ -38,6 +35,9 @@ = @issue.milestone.title .issue-box + .creator + Created by #{link_to_member(@project, @issue.author)} #{time_ago_with_tooltip(@issue.created_at)} + %h4.title = gfm escape_once(@issue.title) diff --git a/app/views/projects/merge_requests/show/_context.html.haml b/app/views/projects/merge_requests/show/_context.html.haml index 705eeb9894..2bd850426a 100644 --- a/app/views/projects/merge_requests/show/_context.html.haml +++ b/app/views/projects/merge_requests/show/_context.html.haml @@ -1,23 +1,22 @@ = form_for [@project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update'} do |f| - Created by #{link_to_member(@project, merge_request.author)}  - - if merge_request.assignee - \ and currently assigned to + %strong.append-right-10 + Assignee: - if can?(current_user, :modify_merge_request, @merge_request) = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @merge_request.assignee_id) - elsif merge_request.assignee = link_to_member(@project, @merge_request.assignee) + - else + None - - .pull-right.hidden-sm.hidden-xs - - if merge_request.milestone - - milestone = merge_request.milestone - %cite.cgray Attached to milestone - + .pull-right + %strong.append-right-10 + Milestone: - if can?(current_user, :modify_merge_request, @merge_request) = f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone (none):" }, {class: 'select2 select2-compact'}) - = hidden_field_tag :merge_request_context = f.submit class: 'btn' - elsif merge_request.milestone = link_to merge_request.milestone.title, project_milestone_path + - else + None diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml index 7c3f9b9344..15c3d311bd 100644 --- a/app/views/projects/merge_requests/show/_mr_box.html.haml +++ b/app/views/projects/merge_requests/show/_mr_box.html.haml @@ -1,4 +1,7 @@ .issue-box + .creator + Created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)} + %h4.title = gfm escape_once(@merge_request.title) diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index 7540c8a640..8c63ce6622 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -1,7 +1,5 @@ %h3.page-title = "Merge Request ##{@merge_request.iid}" - %small - created #{time_ago_with_tooltip(@merge_request.created_at)} - if @merge_request.merged? %span.state-label.state-label-green From c0e29f2540587c037456d11d17002ef6a22c8bf4 Mon Sep 17 00:00:00 2001 From: dosire Date: Tue, 18 Feb 2014 20:59:34 +0100 Subject: [PATCH 103/112] Add apps to readme. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 90237268da..02766a334f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ * [GitLab CI](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab. +* Unofficial third-party [iPhone app](http://gitlabcontrol.com/) and [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en) for GitLab + ### Requirements * Ubuntu/Debian** From 88b8b15dbdc1247b349c9fc6f8d71377322890b9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 22:05:44 +0200 Subject: [PATCH 104/112] Improve UI for Issue/MR Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/generic/common.scss | 10 +++++++--- app/assets/stylesheets/generic/issue_box.scss | 7 +++---- app/helpers/issues_helper.rb | 8 ++++++++ app/helpers/merge_requests_helper.rb | 10 ++++++++++ app/views/projects/issues/show.html.haml | 15 ++++++++------- .../merge_requests/show/_mr_box.html.haml | 18 ++++++++++++++---- .../merge_requests/show/_mr_title.html.haml | 13 ------------- 7 files changed, 50 insertions(+), 31 deletions(-) diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss index 9161868808..7afa74400c 100644 --- a/app/assets/stylesheets/generic/common.scss +++ b/app/assets/stylesheets/generic/common.scss @@ -88,11 +88,15 @@ pre.well-pre { /** Big Labels **/ .state-label { font-size: 14px; - padding: 6px 25px; + padding: 9px 25px; text-align: center; - @include border-radius(4px); text-shadow: none; - margin-left: 10px; + margin-right: 20px; + + &.state-label-blue { + background: #31708f; + color: #FFF; + } &.state-label-green { background: #4A4; diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss index a6573fa0e5..3baad20caa 100644 --- a/app/assets/stylesheets/generic/issue_box.scss +++ b/app/assets/stylesheets/generic/issue_box.scss @@ -17,11 +17,10 @@ margin-bottom: 0; } - .creator { - padding: 8px 25px; - background: #eee; + .state { + height: 34px; border-bottom: 1px solid #DDD; - color: #777; + line-height: 32px; } .title { diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 16981edd98..0374992ebf 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -84,4 +84,12 @@ module IssuesHelper def milestone_options object options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id) end + + def issue_alert_class(issue) + if issue.closed? + 'alert-danger' + else + 'alert-success' + end + end end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 5e3f82fe9c..62f061bb07 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -41,4 +41,14 @@ module MergeRequestsHelper "Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}" end end + + def merge_request_alert_class(merge_request) + if merge_request.merged? + 'alert-info' + elsif merge_request.closed? + 'alert-danger' + else + 'alert-success' + end + end end diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 101f1ddbd1..3455028117 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -1,11 +1,6 @@ %h3.page-title Issue ##{@issue.iid} - - if @issue.closed? - %span.state-label.state-label-red Closed - - else - %span.state-label.state-label-green Open - %span.pull-right - if can?(current_user, :write_issue, @project) = link_to new_project_issue_path(@project), class: "btn grouped", title: "New Issue", id: "new_issue_link" do @@ -35,8 +30,14 @@ = @issue.milestone.title .issue-box - .creator - Created by #{link_to_member(@project, @issue.author)} #{time_ago_with_tooltip(@issue.created_at)} + .state{ class: issue_alert_class(@issue) } + - if @issue.closed? + %span.state-label.state-label-red Closed + - else + %span.state-label.state-label-green Open + + %span.creator + Created by #{link_to_member(@project, @issue.author)} #{time_ago_with_tooltip(@issue.created_at)} %h4.title = gfm escape_once(@issue.title) diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml index 15c3d311bd..8c85318ca3 100644 --- a/app/views/projects/merge_requests/show/_mr_box.html.haml +++ b/app/views/projects/merge_requests/show/_mr_box.html.haml @@ -1,6 +1,16 @@ .issue-box - .creator - Created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)} + .state{ class: merge_request_alert_class(@merge_request) } + - if @merge_request.merged? + %span.state-label.state-label-blue + Merged + - elsif @merge_request.closed? + %span.state-label.state-label-red + Closed + - else + %span.state-label.state-label-green + Open + %span.creator + Created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)} %h4.title = gfm escape_once(@merge_request.title) @@ -16,13 +26,13 @@ = markdown @merge_request.description - if @merge_request.closed? - .description.alert-danger + .description %span %i.icon-remove Closed by #{link_to_member(@project, @merge_request.closed_event.author)} #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}. - if @merge_request.merged? - .description.alert-success + .description %span %i.icon-ok Merged by #{link_to_member(@project, @merge_request.merge_event.author)} diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index 8c63ce6622..b27522e46a 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -1,19 +1,6 @@ %h3.page-title = "Merge Request ##{@merge_request.iid}" - - if @merge_request.merged? - %span.state-label.state-label-green - %i.icon-ok - Merged - - elsif @merge_request.closed? - %span.state-label.state-label-red - Closed - - else - %span.state-label.state-label-green - Open - - - %span.pull-right - if can?(current_user, :modify_merge_request, @merge_request) - if @merge_request.opened? From 83d35399d13fa46020b004f966d67fb527b8809c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 18 Feb 2014 22:29:12 +0200 Subject: [PATCH 105/112] Move MR alert info out of issue-box Signed-off-by: Dmitriy Zaporozhets --- .../merge_requests/show/_mr_box.html.haml | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml index 8c85318ca3..e05d2215f9 100644 --- a/app/views/projects/merge_requests/show/_mr_box.html.haml +++ b/app/views/projects/merge_requests/show/_mr_box.html.haml @@ -25,22 +25,22 @@ = preserve do = markdown @merge_request.description - - if @merge_request.closed? - .description - %span - %i.icon-remove - Closed by #{link_to_member(@project, @merge_request.closed_event.author)} - #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}. - - if @merge_request.merged? - .description - %span - %i.icon-ok - Merged by #{link_to_member(@project, @merge_request.merge_event.author)} - #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}. - - if !@closes_issues.empty? && @merge_request.opened? - .description.alert-info - %span - %i.icon-ok - Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'} - = succeed '.' do - != gfm(@closes_issues.map { |i| "##{i.iid}" }.to_sentence) +- if @merge_request.closed? + .alert.alert-info + %span + %i.icon-remove + Closed by #{link_to_member(@project, @merge_request.closed_event.author)} + #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}. +- if @merge_request.merged? + .alert.alert-info + %span + %i.icon-ok + Merged by #{link_to_member(@project, @merge_request.merge_event.author)} + #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}. +- if !@closes_issues.empty? && @merge_request.opened? + .alert.alert-info.alert-info + %span + %i.icon-ok + Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'} + = succeed '.' do + != gfm(@closes_issues.map { |i| "##{i.iid}" }.to_sentence) From ee750298675f0beed94688a9798d3e0b8362b455 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 19 Feb 2014 09:38:01 +0200 Subject: [PATCH 106/112] Move assignee/milestone below description of Issue Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/generic/issue_box.scss | 7 ++++--- app/views/projects/issues/show.html.haml | 8 ++++---- app/views/projects/merge_requests/show/_mr_box.html.haml | 8 ++++---- features/steps/project/project_merge_requests.rb | 6 ++++-- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss index 3baad20caa..0e0a365a82 100644 --- a/app/assets/stylesheets/generic/issue_box.scss +++ b/app/assets/stylesheets/generic/issue_box.scss @@ -29,20 +29,21 @@ line-height: 1.5; margin: 0; color: #333; + padding-bottom: 0; + padding: 15px 25px; } .context { border: none; border-top: 1px solid #eee; + padding: 15px 25px; } .description { - border-top: 1px solid #eee; + padding: 0 25px 15px 25px; } .title, .context, .description { - padding: 15px 25px; - .clearfix { margin: 0; } diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 3455028117..7aa37eda96 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -42,15 +42,15 @@ %h4.title = gfm escape_once(@issue.title) - .context - %cite.cgray - = render partial: 'issue_context', locals: { issue: @issue } - - if @issue.description.present? .description .wiki = preserve do = markdown @issue.description + .context + %cite.cgray + = render partial: 'issue_context', locals: { issue: @issue } + - content_for :note_actions do - if can?(current_user, :modify_issue, @issue) diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml index e05d2215f9..803e00292b 100644 --- a/app/views/projects/merge_requests/show/_mr_box.html.haml +++ b/app/views/projects/merge_requests/show/_mr_box.html.haml @@ -15,16 +15,16 @@ %h4.title = gfm escape_once(@merge_request.title) - .context - %cite.cgray - = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request } - - if @merge_request.description.present? .description .wiki = preserve do = markdown @merge_request.description + .context + %cite.cgray + = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request } + - if @merge_request.closed? .alert.alert-info %span diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index cc2648c620..adf9e77e13 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -55,7 +55,9 @@ class ProjectMergeRequests < Spinach::FeatureSteps end step 'I click link "Close"' do - click_link "Close" + within '.page-title' do + click_link "Close" + end end step 'I submit new merge request "Wiki Feature"' do @@ -163,7 +165,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps end step 'I should see merged request' do - within '.page-title' do + within '.issue-box' do page.should have_content "Merged" end end From ededfd2d29bea4fff7c69634dc813c274eb346ee Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 19 Feb 2014 10:35:24 +0200 Subject: [PATCH 107/112] Fix tests Signed-off-by: Dmitriy Zaporozhets --- spec/features/issues_spec.rb | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 834ed73549..ffe6d02d2f 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -186,7 +186,7 @@ describe "Issues" do find('.edit-issue.inline-update #issue_assignee_id').set project.team.members.first.id click_button 'Update Issue' - page.should have_content "currently assigned to" + page.should have_content "Assignee:" page.has_select?('issue_assignee_id', :selected => project.team.members.first.name) end end @@ -206,11 +206,9 @@ describe "Issues" do login_with guest visit project_issue_path(project, issue) - page.should have_content "currently assigned to #{issue.assignee.name}" - + page.should have_content issue.assignee.name end end - end describe 'update milestone from issue#show' do @@ -225,17 +223,16 @@ describe "Issues" do find('.edit-issue.inline-update').select(milestone.title, from: 'issue_milestone_id') click_button 'Update Issue' - page.should have_content "Attached to milestone" + page.should have_content "Milestone" page.has_select?('issue_assignee_id', :selected => milestone.title) end end context 'by unauthorized user' do - let(:guest) { create(:user) } before :each do - project.team << [[guest], :guest] + project.team << [guest, :guest] issue.milestone = milestone issue.save end @@ -245,8 +242,7 @@ describe "Issues" do login_with guest visit project_issue_path(project, issue) - - page.should have_content "Attached to milestone #{milestone.title}" + page.should have_content milestone.title end end end @@ -258,4 +254,4 @@ describe "Issues" do def last_issue all("ul.issues-list li").last.text end -end \ No newline at end of file +end From c9befd3d1b91fa7c559f8718f88b274f24688c59 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 19 Feb 2014 11:55:26 +0200 Subject: [PATCH 108/112] Update rails to version 4.0.3 Signed-off-by: Dmitriy Zaporozhets --- Gemfile.lock | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 91d04e2ec7..ba29e0ddc7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,11 +9,11 @@ GEM remote: https://rubygems.org/ specs: ace-rails-ap (2.0.1) - actionmailer (4.0.2) - actionpack (= 4.0.2) + actionmailer (4.0.3) + actionpack (= 4.0.3) mail (~> 2.5.4) - actionpack (4.0.2) - activesupport (= 4.0.2) + actionpack (4.0.3) + activesupport (= 4.0.3) builder (~> 3.1.0) erubis (~> 2.7.0) rack (~> 1.5.2) @@ -22,16 +22,16 @@ GEM actionpack (>= 4.0.0, < 5.0) actionpack-page_caching (1.0.2) actionpack (>= 4.0.0, < 5) - activemodel (4.0.2) - activesupport (= 4.0.2) + activemodel (4.0.3) + activesupport (= 4.0.3) builder (~> 3.1.0) - activerecord (4.0.2) - activemodel (= 4.0.2) + activerecord (4.0.3) + activemodel (= 4.0.3) activerecord-deprecated_finders (~> 1.0.2) - activesupport (= 4.0.2) + activesupport (= 4.0.3) arel (~> 4.0.0) activerecord-deprecated_finders (1.0.3) - activesupport (4.0.2) + activesupport (4.0.3) i18n (~> 0.6, >= 0.6.4) minitest (~> 4.2) multi_json (~> 1.3) @@ -43,7 +43,7 @@ GEM annotate (2.6.0) activerecord (>= 2.3.0) rake (>= 0.8.7) - arel (4.0.1) + arel (4.0.2) asciidoctor (0.1.4) atomic (1.1.14) awesome_print (1.2.0) @@ -320,7 +320,7 @@ GEM cliver (~> 0.2.1) multi_json (~> 1.0) websocket-driver (>= 0.2.0) - polyglot (0.3.3) + polyglot (0.3.4) posix-spawn (0.3.8) protected_attributes (1.0.5) activemodel (>= 4.0.1, < 5.0) @@ -346,13 +346,13 @@ GEM rack rack-test (0.6.2) rack (>= 1.0) - rails (4.0.2) - actionmailer (= 4.0.2) - actionpack (= 4.0.2) - activerecord (= 4.0.2) - activesupport (= 4.0.2) + rails (4.0.3) + actionmailer (= 4.0.3) + actionpack (= 4.0.3) + activerecord (= 4.0.3) + activesupport (= 4.0.3) bundler (>= 1.3.0, < 2.0) - railties (= 4.0.2) + railties (= 4.0.3) sprockets-rails (~> 2.0.0) rails-observers (0.1.2) activemodel (~> 4.0) @@ -365,13 +365,13 @@ GEM i18n require_all ruby-progressbar - railties (4.0.2) - actionpack (= 4.0.2) - activesupport (= 4.0.2) + railties (4.0.3) + actionpack (= 4.0.3) + activesupport (= 4.0.3) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) raindrops (0.12.0) - rake (10.1.0) + rake (10.1.1) raphael-rails (2.1.2) rb-fsevent (0.9.3) rb-inotify (0.9.2) From 0bd0c8149bd83f422c38c8aff20d5b698b84f6bb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 19 Feb 2014 12:06:10 +0200 Subject: [PATCH 109/112] More for changelog Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 22a01ddfaa..32e7caa89a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,8 @@ v 6.6.0 - Improve application to work faster with large groups (100+ members) - Multiple emails per user - Show last commit for file when view file source + - Restyle Issue#show page and MR#show page + - Ability to filter by multiple labels for Issues page v 6.5.1 - Fix branch selectbox when create merge request from fork @@ -644,4 +646,4 @@ v 0.8.0 - stability - security fixes - increased test coverage - - email notification \ No newline at end of file + - email notification From 2b8d2891304b4ecc71c0c9eae0952633a15b42fb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 19 Feb 2014 13:10:31 +0200 Subject: [PATCH 110/112] Fix readme h4 style Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/sections/tree.scss | 2 +- app/views/projects/tree/_readme.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss index f72c660718..55a5819b55 100644 --- a/app/assets/stylesheets/sections/tree.scss +++ b/app/assets/stylesheets/sections/tree.scss @@ -127,7 +127,7 @@ border-top: 1px dashed #CCC; padding-top: 10px; - h4 { + .readme-file-title { font-size: 14px; margin-bottom: 20px; color: #777; diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml index ab572f2e97..16a9602ac9 100644 --- a/app/views/projects/tree/_readme.html.haml +++ b/app/views/projects/tree/_readme.html.haml @@ -1,5 +1,5 @@ .readme-holder#README - %h4 + %h4.readme-file-title %i.icon-file = readme.name .wiki From 06fc7e31b5427795e59829c469ae5262c537101c Mon Sep 17 00:00:00 2001 From: dosire Date: Wed, 19 Feb 2014 13:12:55 +0100 Subject: [PATCH 111/112] Refer to release docs. --- MAINTENANCE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTENANCE.md b/MAINTENANCE.md index 0dca62974c..95d9f0a5e7 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -21,3 +21,5 @@ release where the minor version is increased numerically by increments of one (eg. `5.0 -> 5.1`). We encourage everyone to run the latest stable release to ensure that you can easily upgrade to the most secure and feature rich GitLab experience. In order to make sure you can easily run the most recent stable release, we are working hard to keep the update process simple and reliable. + +More information about the release procedures can be found in the doc/release directory. From dad6b0213c96bc0b6a5b78714878ee542b7bee2d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 19 Feb 2014 14:49:44 +0200 Subject: [PATCH 112/112] Mention new rails in changelog Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 32e7caa89a..5f42f851b0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,7 @@ v 6.6.0 - Show last commit for file when view file source - Restyle Issue#show page and MR#show page - Ability to filter by multiple labels for Issues page + - Rails version to 4.0.3 v 6.5.1 - Fix branch selectbox when create merge request from fork