Commit 43fa2510 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce-6-7-rc' into 'master'

GitLab CE 6.7.0.rc1
parents faa08fe6 3fa2dd11
...@@ -19,10 +19,10 @@ rvm: ...@@ -19,10 +19,10 @@ rvm:
services: services:
- redis-server - redis-server
before_script: before_script:
- "bundle exec rake db:setup"
- "bundle exec rake db:seed_fu"
- "cp config/database.yml.$DB config/database.yml" - "cp config/database.yml.$DB config/database.yml"
- "cp config/gitlab.yml.example config/gitlab.yml" - "cp config/gitlab.yml.example config/gitlab.yml"
- "bundle exec rake db:setup"
- "bundle exec rake db:seed_fu"
script: "bundle exec rake $TASK --trace" script: "bundle exec rake $TASK --trace"
notifications: notifications:
email: false email: false
...@@ -9,6 +9,7 @@ v 6.7.0 ...@@ -9,6 +9,7 @@ v 6.7.0
- Show contribution guide link for new issue form (Jeroen van Baarsen) - Show contribution guide link for new issue form (Jeroen van Baarsen)
- Fix CI status for merge requests from fork - Fix CI status for merge requests from fork
- Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard) - Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
- New page load indicator that includes a spinner that scrolls with the page
- Converted all the help sections into markdown - Converted all the help sections into markdown
- LDAP user filters - LDAP user filters
- Streamline the content of notification emails (Pierre de La Morinerie) - Streamline the content of notification emails (Pierre de La Morinerie)
...@@ -24,6 +25,12 @@ v 6.7.0 ...@@ -24,6 +25,12 @@ v 6.7.0
- Faster authorized_keys rebuilding in `rake gitlab:shell:setup` (requires gitlab-shell 1.8.5) - Faster authorized_keys rebuilding in `rake gitlab:shell:setup` (requires gitlab-shell 1.8.5)
- Create and Update MR calls now support the description parameter (Greg Messner) - Create and Update MR calls now support the description parameter (Greg Messner)
- Markdown relative links in the wiki link to wiki pages, markdown relative links in repositories link to files in the repository - Markdown relative links in the wiki link to wiki pages, markdown relative links in repositories link to files in the repository
- Added Slack service integration (Federico Ravasio)
- Better API responses for access_levels (sponsored by O'Reilly Media)
- Requires at least 2 unicorn workers
- Requires gitlab-shell v1.9+
- Replaced gemoji(due to closed licencing problem) with Phantom Open Emoji library(combined SIL Open Font License, MIT License and the CC 3.0 License)
- Fix `/:username.keys` response content type (Dmitry Medvinsky)
v 6.6.5 v 6.6.5
- Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard) - Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
......
...@@ -133,6 +133,9 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2" ...@@ -133,6 +133,9 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2"
# Gemnasium integration # Gemnasium integration
gem "gemnasium-gitlab-service", "~> 0.2" gem "gemnasium-gitlab-service", "~> 0.2"
# Slack integration
gem "slack-notifier", "~> 0.2.0"
# d3 # d3
gem "d3_rails", "~> 3.1.4" gem "d3_rails", "~> 3.1.4"
...@@ -163,8 +166,9 @@ gem "modernizr", "2.6.2" ...@@ -163,8 +166,9 @@ gem "modernizr", "2.6.2"
gem "raphael-rails", "~> 2.1.2" gem "raphael-rails", "~> 2.1.2"
gem 'bootstrap-sass', '~> 3.0' gem 'bootstrap-sass', '~> 3.0'
gem "font-awesome-rails", '~> 3.2' gem "font-awesome-rails", '~> 3.2'
gem "gemoji", "~> 1.3.0" gem "gitlab_emoji", "~> 0.0.1.1"
gem "gon", '~> 5.0.0' gem "gon", '~> 5.0.0'
gem 'nprogress-rails'
group :development do group :development do
gem "annotate", "~> 2.6.0.beta2" gem "annotate", "~> 2.6.0.beta2"
......
...@@ -128,6 +128,8 @@ GEM ...@@ -128,6 +128,8 @@ GEM
mail (~> 2.2) mail (~> 2.2)
email_validator (1.4.0) email_validator (1.4.0)
activemodel activemodel
emoji (1.0.1)
json
enumerize (0.7.0) enumerize (0.7.0)
activesupport (>= 3.2) activesupport (>= 3.2)
equalizer (0.0.8) equalizer (0.0.8)
...@@ -165,7 +167,6 @@ GEM ...@@ -165,7 +167,6 @@ GEM
formatador (0.2.4) formatador (0.2.4)
gemnasium-gitlab-service (0.2.1) gemnasium-gitlab-service (0.2.1)
rugged (~> 0.19) rugged (~> 0.19)
gemoji (1.3.1)
gherkin-ruby (0.3.1) gherkin-ruby (0.3.1)
racc racc
github-markdown (0.5.5) github-markdown (0.5.5)
...@@ -190,6 +191,8 @@ GEM ...@@ -190,6 +191,8 @@ GEM
charlock_holmes (~> 0.6.6) charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.4) escape_utils (~> 0.2.4)
mime-types (~> 1.19) mime-types (~> 1.19)
gitlab_emoji (0.0.1.1)
emoji (~> 1.0.1)
gitlab_git (5.7.1) gitlab_git (5.7.1)
activesupport (~> 4.0.0) activesupport (~> 4.0.0)
charlock_holmes (~> 0.6.9) charlock_holmes (~> 0.6.9)
...@@ -297,6 +300,7 @@ GEM ...@@ -297,6 +300,7 @@ GEM
net-ssh (>= 1.99.1) net-ssh (>= 1.99.1)
net-ssh (2.7.0) net-ssh (2.7.0)
nokogiri (1.5.10) nokogiri (1.5.10)
nprogress-rails (0.1.2.3)
oauth (0.4.7) oauth (0.4.7)
oauth2 (0.8.1) oauth2 (0.8.1)
faraday (~> 0.8) faraday (~> 0.8)
...@@ -468,6 +472,7 @@ GEM ...@@ -468,6 +472,7 @@ GEM
rack-protection (~> 1.4) rack-protection (~> 1.4)
tilt (~> 1.3, >= 1.3.4) tilt (~> 1.3, >= 1.3.4)
six (0.2.0) six (0.2.0)
slack-notifier (0.2.0)
slim (2.0.2) slim (2.0.2)
temple (~> 0.6.6) temple (~> 0.6.6)
tilt (>= 1.3.3, < 2.1) tilt (>= 1.3.3, < 2.1)
...@@ -591,12 +596,12 @@ DEPENDENCIES ...@@ -591,12 +596,12 @@ DEPENDENCIES
font-awesome-rails (~> 3.2) font-awesome-rails (~> 3.2)
foreman foreman
gemnasium-gitlab-service (~> 0.2) gemnasium-gitlab-service (~> 0.2)
gemoji (~> 1.3.0)
github-markup (~> 0.7.4)! github-markup (~> 0.7.4)!
gitlab-flowdock-git-hook (~> 0.4.2) gitlab-flowdock-git-hook (~> 0.4.2)
gitlab-gollum-lib (~> 1.1.0) gitlab-gollum-lib (~> 1.1.0)
gitlab-grack (~> 2.0.0.pre) gitlab-grack (~> 2.0.0.pre)
gitlab-linguist (~> 3.0.0) gitlab-linguist (~> 3.0.0)
gitlab_emoji (~> 0.0.1.1)
gitlab_git (~> 5.7.1) gitlab_git (~> 5.7.1)
gitlab_meta (= 6.0) gitlab_meta (= 6.0)
gitlab_omniauth-ldap (= 1.0.4) gitlab_omniauth-ldap (= 1.0.4)
...@@ -621,6 +626,7 @@ DEPENDENCIES ...@@ -621,6 +626,7 @@ DEPENDENCIES
modernizr (= 2.6.2) modernizr (= 2.6.2)
mysql2 mysql2
net-ldap net-ldap
nprogress-rails
omniauth (~> 1.1.3) omniauth (~> 1.1.3)
omniauth-github omniauth-github
omniauth-google-oauth2 omniauth-google-oauth2
...@@ -653,6 +659,7 @@ DEPENDENCIES ...@@ -653,6 +659,7 @@ DEPENDENCIES
simplecov simplecov
sinatra sinatra
six six
slack-notifier (~> 0.2.0)
slim slim
spinach-rails spinach-rails
spork (~> 1.0rc) spork (~> 1.0rc)
......
6.7.0.pre-ee 6.7.0.rc1-ee
...@@ -29,3 +29,5 @@ ...@@ -29,3 +29,5 @@
//= require_tree . //= require_tree .
//= require d3 //= require d3
//= require underscore //= require underscore
//= require nprogress
//= require nprogress-turbolinks
...@@ -41,19 +41,11 @@ window.linkify = (str) -> ...@@ -41,19 +41,11 @@ window.linkify = (str) ->
window.simpleFormat = (str) -> window.simpleFormat = (str) ->
linkify(sanitize(str).replace(/\n/g, '<br />')) linkify(sanitize(str).replace(/\n/g, '<br />'))
window.startSpinner = ->
$('.turbolink-spinner').fadeIn()
window.stopSpinner = ->
$('.turbolink-spinner').fadeOut()
window.unbindEvents = -> window.unbindEvents = ->
$(document).unbind('scroll') $(document).unbind('scroll')
$(document).off('scroll') $(document).off('scroll')
document.addEventListener("page:fetch", startSpinner)
document.addEventListener("page:fetch", unbindEvents) document.addEventListener("page:fetch", unbindEvents)
document.addEventListener("page:change", stopSpinner)
$ -> $ ->
# Click a .one_click_select field, select the contents # Click a .one_click_select field, select the contents
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
*= require select2 *= require select2
*= require highlightjs.min *= require highlightjs.min
*= require_self *= require_self
*= require nprogress
*= require nprogress-bootstrap
*/ */
@import "main/variables.scss"; @import "main/variables.scss";
......
class PasswordsController < Devise::PasswordsController
def create
email = resource_params[:email]
resource_found = resource_class.find_by_email(email)
if resource_found && resource_found.ldap_user?
flash[:alert] = "Cannot reset password for LDAP user."
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name)) and return
end
self.resource = resource_class.send_reset_password_instructions(resource_params)
if successfully_sent?(resource)
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
else
respond_with(resource)
end
end
end
...@@ -41,7 +41,7 @@ class Profiles::KeysController < ApplicationController ...@@ -41,7 +41,7 @@ class Profiles::KeysController < ApplicationController
begin begin
user = User.find_by_username(params[:username]) user = User.find_by_username(params[:username])
if user.present? if user.present?
render text: user.all_ssh_keys.join("\n") render text: user.all_ssh_keys.join("\n"), content_type: "text/plain"
else else
render_404 and return render_404 and return
end end
......
...@@ -40,7 +40,7 @@ module TreeHelper ...@@ -40,7 +40,7 @@ module TreeHelper
# Returns boolean # Returns boolean
def markup?(filename) def markup?(filename)
filename.downcase.end_with?(*%w(.textile .rdoc .org .creole filename.downcase.end_with?(*%w(.textile .rdoc .org .creole
.mediawiki .rst .asciidoc .pod)) .mediawiki .rst .adoc .asciidoc .pod))
end end
def gitlab_markdown?(filename) def gitlab_markdown?(filename)
......
...@@ -199,7 +199,8 @@ class Note < ActiveRecord::Base ...@@ -199,7 +199,8 @@ class Note < ActiveRecord::Base
def downvote? def downvote?
votable? && (note.start_with?('-1') || votable? && (note.start_with?('-1') ||
note.start_with?(':-1:') || note.start_with?(':-1:') ||
note.start_with?(':thumbsdown:') note.start_with?(':thumbsdown:') ||
note.start_with?(':thumbs_down_sign:')
) )
end end
...@@ -249,7 +250,8 @@ class Note < ActiveRecord::Base ...@@ -249,7 +250,8 @@ class Note < ActiveRecord::Base
def upvote? def upvote?
votable? && (note.start_with?('+1') || votable? && (note.start_with?('+1') ||
note.start_with?(':+1:') || note.start_with?(':+1:') ||
note.start_with?(':thumbsup:') note.start_with?(':thumbsup:') ||
note.start_with?(':thumbs_up_sign:')
) )
end end
......
...@@ -57,6 +57,7 @@ class Project < ActiveRecord::Base ...@@ -57,6 +57,7 @@ class Project < ActiveRecord::Base
has_one :flowdock_service, dependent: :destroy has_one :flowdock_service, dependent: :destroy
has_one :assembla_service, dependent: :destroy has_one :assembla_service, dependent: :destroy
has_one :gemnasium_service, dependent: :destroy has_one :gemnasium_service, dependent: :destroy
has_one :slack_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link has_one :forked_from_project, through: :forked_project_link
# Merge Requests for target project should be removed with it # Merge Requests for target project should be removed with it
...@@ -308,7 +309,7 @@ class Project < ActiveRecord::Base ...@@ -308,7 +309,7 @@ class Project < ActiveRecord::Base
end end
def available_services_names def available_services_names
%w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium) %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack)
end end
def gitlab_ci? def gitlab_ci?
......
require 'slack-notifier'
class SlackMessage
def initialize(params)
@after = params.fetch(:after)
@before = params.fetch(:before)
@commits = params.fetch(:commits, [])
@project_name = params.fetch(:project_name)
@project_url = params.fetch(:project_url)
@ref = params.fetch(:ref).gsub('refs/heads/', '')
@username = params.fetch(:user_name)
end
def compose
format(message)
end
private
attr_reader :after
attr_reader :before
attr_reader :commits
attr_reader :project_name
attr_reader :project_url
attr_reader :ref
attr_reader :username
def message
if new_branch?
new_branch_message
elsif removed_branch?
removed_branch_message
else
push_message << commit_messages
end
end
def format(string)
Slack::Notifier::LinkFormatter.format(string)
end
def new_branch_message
"#{username} pushed new branch #{branch_link} to #{project_link}"
end
def removed_branch_message
"#{username} removed branch #{ref} from #{project_link}"
end
def push_message
"#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})"
end
def commit_messages
commits.each_with_object('') do |commit, str|
str << compose_commit_message(commit)
end
end
def compose_commit_message(commit)
id = commit.fetch(:id)[0..5]
message = commit.fetch(:message)
url = commit.fetch(:url)
"\n - #{message} ([#{id}](#{url}))"
end
def new_branch?
before =~ /000000/
end
def removed_branch?
after =~ /000000/
end
def branch_url
"#{project_url}/commits/#{ref}"
end
def compare_url
"#{project_url}/compare/#{before}...#{after}"
end
def branch_link
"[#{ref}](#{branch_url})"
end
def project_link
"[#{project_name}](#{project_url})"
end
def compare_link
"[Compare changes](#{compare_url})"
end
end
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# api_key :string(255)
#
class SlackService < Service
attr_accessible :room
attr_accessible :subdomain
validates :room, presence: true, if: :activated?
validates :subdomain, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
def title
'Slack'
end
def description
'A team communication tool for the 21st century'
end
def to_param
'slack'
end
def fields
[
{ type: 'text', name: 'subdomain', placeholder: '' },
{ type: 'text', name: 'token', placeholder: '' },
{ type: 'text', name: 'room', placeholder: 'Ex. #general' },
]
end
def execute(push_data)
message = SlackMessage.new(push_data.merge(
project_url: project_url,
project_name: project_name
))
notifier = Slack::Notifier.new(subdomain, token)
notifier.channel = room
notifier.ping(message.compose)
end
private
def project_name
project.name_with_namespace.gsub(/\s/, '')
end
def project_url
project.web_url
end
end
...@@ -249,7 +249,7 @@ class User < ActiveRecord::Base ...@@ -249,7 +249,7 @@ class User < ActiveRecord::Base
def namespace_uniq def namespace_uniq
namespace_name = self.username namespace_name = self.username
if Namespace.find_by(path: namespace_name) if Namespace.find_by(path: namespace_name)
self.errors.add :username, "already exist" self.errors.add :username, "already exists"
end end
end end
......
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
- if providers.present? - if providers.present?
%hr %hr
%div{:'data-no-turbolink' => 'data-no-turbolink'} %div{:'data-no-turbolink' => 'data-no-turbolink'}
%span Sign in with: &nbsp; %span Sign in with*: &nbsp;
- providers.each do |provider| - providers.each do |provider|
%span %span
- if default_providers.include?(provider) - if default_providers.include?(provider)
= link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
- else - else
= link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn" = link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn"
%br
%small * Make sure your email address is public
...@@ -14,10 +14,6 @@ ...@@ -14,10 +14,6 @@
.navbar-collapse.collapse .navbar-collapse.collapse
%ul.nav.navbar-nav %ul.nav.navbar-nav
%li.hidden-sm.hidden-xs
%a
%div.hide.turbolink-spinner
%i.icon-refresh.icon-spin
%li.hidden-sm.hidden-xs %li.hidden-sm.hidden-xs
= render "layouts/search" = render "layouts/search"
%li.visible-sm.visible-xs %li.visible-sm.visible-xs
......
:javascript :javascript
GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project)}" GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project)}"
GitLab.GfmAutoComplete.Emoji.assetBase = "#{Gitlab.config.gitlab.relative_url_root + '/assets/emoji'}" GitLab.GfmAutoComplete.Emoji.assetBase = "#{Gitlab.config.gitlab.relative_url_root + Emoji.asset_path}"
GitLab.GfmAutoComplete.setup(); GitLab.GfmAutoComplete.setup();
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
%i.icon-thumbs-up %i.icon-thumbs-up
\+1 \+1
- if note.downvote? - if note.downvote?
%span.vote.downvote.label.label-error %span.vote.downvote.label.label-danger
%i.icon-thumbs-down %i.icon-thumbs-down
\-1 \-1
......
# Workaround for https://github.com/github/gemoji/pull/18
require 'gemoji'
Gitlab::Application.config.assets.paths << Emoji.images_path
...@@ -175,7 +175,7 @@ Gitlab::Application.routes.draw do ...@@ -175,7 +175,7 @@ Gitlab::Application.routes.draw do
resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create] resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create]
devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations } devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations , passwords: :passwords}
# #
# Project Area # Project Area
......
All methods require admin authorization. All methods require admin authorization.
The url endpoint of the system hooks can be configured in [the admin area under hooks](/admin/hooks). The url endpoint of the system hooks can be configured in [the admin area under hooks](/admin/hooks).
## List system hooks ## List system hooks
Get list of system hooks Get list of system hooks
``` ```
GET /hooks GET /hooks
``` ```
Parameters: Parameters:
+ **none** + **none**
```json ```json
[ [
{ {
"id":3, "id":3,
"url":"http://example.com/hook", "url":"http://example.com/hook",
"created_at":"2013-10-02T10:15:31Z" "created_at":"2013-10-02T10:15:31Z"
} }
] ]
``` ```
## Add new system hook hook ## Add new system hook hook
``` ```
POST /hooks POST /hooks
``` ```
Parameters: Parameters:
+ `url` (required) - The hook URL + `url` (required) - The hook URL
## Test system hook ## Test system hook
``` ```
GET /hooks/:id GET /hooks/:id
``` ```
Parameters: Parameters:
+ `id` (required) - The ID of hook + `id` (required) - The ID of hook
```json ```json
{ {
"event_name":"project_create", "event_name":"project_create",
"name":"Ruby", "name":"Ruby",
"path":"ruby", "path":"ruby",
"project_id":1, "project_id":1,
"owner_name":"Someone", "owner_name":"Someone",
"owner_email":"example@gitlabhq.com" "owner_email":"example@gitlabhq.com"
} }
``` ```
## Delete system hook ## Delete system hook
Deletes a system hook. This is an idempotent API function and returns `200 Ok` even if the hook Deletes a system hook. This is an idempotent API function and returns `200 Ok` even if the hook
is not available. If the hook is deleted it is also returned as JSON. is not available. If the hook is deleted it is also returned as JSON.
``` ```
DELETE /hooks/:id DELETE /hooks/:id
``` ```
Parameters: Parameters:
+ `id` (required) - The ID of hook + `id` (required) - The ID of hook
...@@ -18,7 +18,7 @@ New releases are generally around the same time as GitLab CE releases with excep ...@@ -18,7 +18,7 @@ New releases are generally around the same time as GitLab CE releases with excep
# System Layout # System Layout
When referring to ~git in the picures it means the home directory of the git user which is typically /home/git. When referring to ~git in the pictures it means the home directory of the git user which is typically /home/git.
GitLab is primarily installed within the `/home/git` user home directory as `git` user. GitLab is primarily installed within the `/home/git` user home directory as `git` user.
Within the home directory is where the gitlabhq server software resides as well as the repositories (though the repository location is configurable). Within the home directory is where the gitlabhq server software resides as well as the repositories (though the repository location is configurable).
......
...@@ -61,11 +61,11 @@ After making the release branch new commits are cherry-picked from master. When ...@@ -61,11 +61,11 @@ After making the release branch new commits are cherry-picked from master. When
* 17th: feature freeze (stop merging new features in master) * 17th: feature freeze (stop merging new features in master)
* 18th: UI freeze (stop merging changes to the user interface) * 18th: UI freeze (stop merging changes to the user interface)
* 19th: code freeze (stop merging non-essential code improvements) * 19th: code freeze (stop merging non-essential code improvements)
* 20th: release candidate 1 (VERSION x.x.0.rc1, tag and tweet about x.x.0.rc1) * 20th: release candidate 1 (VERSION x.x.0.rc1, tag, tweet and upgrade Cloud)
* 21st: optional release candidate 2 (x.x.0.rc2, only if rc1 had problems) * 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) * 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) * 23nd: optional patch releases (x.x.1, x.x.2, etc., only if there are serious regressions)
* 24-end of month: release Enterprise Edition and upgrade GitLab Cloud * 24-end of month: release Enterprise Edition and upgrade GitLab Cloud to latest patch
* 1-7th: official merge window (see contributing guide) * 1-7th: official merge window (see contributing guide)
* 8-16th: bugfixes and sponsored features * 8-16th: bugfixes and sponsored features
......
Deploy keys allow read-only access one or multiple projects with a single SSH key.
This is really useful for cloning repositories to your Continuous Integration (CI) server.
By using a deploy keys you don't have to setup a dummy user account.
If you are a project master or owner you can add a deploy key in the project settings under the section Deploy Keys.
Press the 'New Deploy Key' button and upload a public ssh key.
After this the machine that uses the corresponding private key has read-only access to the project.
You can't add the same deploy key twice with the 'New Deploy Key' option.
If you want to add the same key to another project please enable it in the list that says 'Deploy keys from projects available to you'.
You need to be the owner of the deploy key to see it in this list.
...@@ -37,6 +37,12 @@ Feature: Project Services ...@@ -37,6 +37,12 @@ Feature: Project Services
And I fill Assembla settings And I fill Assembla settings
Then I should see Assembla service settings saved Then I should see Assembla service settings saved
Scenario: Activate Slack service
When I visit project "Shop" services page
And I click Slack service link
And I fill Slack settings
Then I should see Slack service settings saved
Scenario: Activate email on push service Scenario: Activate email on push service
When I visit project "Shop" services page When I visit project "Shop" services page
And I click email on push service link And I click email on push service link
......
...@@ -4,7 +4,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps ...@@ -4,7 +4,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
include SharedProject include SharedProject
step 'public project "Community"' do step 'public project "Community"' do
create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC create :project, :public, name: 'Community'
end end
step 'private project "Enterprise"' do step 'private project "Enterprise"' do
......
...@@ -100,4 +100,22 @@ class ProjectServices < Spinach::FeatureSteps ...@@ -100,4 +100,22 @@ class ProjectServices < Spinach::FeatureSteps
step 'I should see email on push service settings saved' do step 'I should see email on push service settings saved' do
find_field('Recipients').value.should == 'qa@company.name' find_field('Recipients').value.should == 'qa@company.name'
end end
step 'I click Slack service link' do
click_link 'Slack'
end
step 'I fill Slack settings' do
check 'Active'
fill_in 'Subdomain', with: 'gitlab'
fill_in 'Room', with: '#gitlab'
fill_in 'Token', with: 'verySecret'
click_button 'Save'
end
step 'I should see Slack service settings saved' do
find_field('Subdomain').value.should == 'gitlab'
find_field('Room').value.should == '#gitlab'
find_field('Token').value.should == 'verySecret'
end
end end
...@@ -4,7 +4,7 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps ...@@ -4,7 +4,7 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps
include SharedProject include SharedProject
step 'public empty project "Empty Public Project"' do step 'public empty project "Empty Public Project"' do
create :empty_project, name: 'Empty Public Project', visibility_level: Gitlab::VisibilityLevel::PUBLIC create :empty_project, :public, name: 'Empty Public Project'
end end
step 'I should see project "Empty Public Project"' do step 'I should see project "Empty Public Project"' do
......
...@@ -79,7 +79,7 @@ module SharedProject ...@@ -79,7 +79,7 @@ module SharedProject
end end
step 'internal project "Internal"' do step 'internal project "Internal"' do
create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL create :project, :internal, name: 'Internal'
end end
step 'I should see project "Internal"' do step 'I should see project "Internal"' do
...@@ -91,7 +91,7 @@ module SharedProject ...@@ -91,7 +91,7 @@ module SharedProject
end end
step 'public project "Community"' do step 'public project "Community"' do
create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC create :project, :public, name: 'Community'
end end
step 'I should see project "Community"' do step 'I should see project "Community"' do
...@@ -112,14 +112,14 @@ module SharedProject ...@@ -112,14 +112,14 @@ module SharedProject
step '"John Doe" is authorized to internal project "Internal"' do step '"John Doe" is authorized to internal project "Internal"' do
user = user_exists("John Doe", username: "john_doe") user = user_exists("John Doe", username: "john_doe")
project = Project.find_by(name: "Internal") project = Project.find_by(name: "Internal")
project ||= create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL project ||= create :project, :internal, name: 'Internal'
project.team << [user, :master] project.team << [user, :master]
end end
step '"John Doe" is authorized to public project "Community"' do step '"John Doe" is authorized to public project "Community"' do
user = user_exists("John Doe", username: "john_doe") user = user_exists("John Doe", username: "john_doe")
project = Project.find_by(name: "Community") project = Project.find_by(name: "Community")
project ||= create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC project ||= create :project, :public, name: 'Community'
project.team << [user, :master] project.team << [user, :master]
end end
end end
...@@ -48,7 +48,6 @@ module Gitlab ...@@ -48,7 +48,6 @@ module Gitlab
else else
:push_code :push_code
end end
user.can?(action, project) && user.can?(action, project) &&
pass_git_hooks?(user, project, ref, oldrev, newrev) pass_git_hooks?(user, project, ref, oldrev, newrev)
else else
......
...@@ -152,7 +152,7 @@ module Gitlab ...@@ -152,7 +152,7 @@ module Gitlab
# #
# Returns boolean # Returns boolean
def valid_emoji?(emoji) def valid_emoji?(emoji)
Emoji.names.include? emoji Emoji.find_by_name emoji
end end
# Private: Dispatches to a dedicated processing method based on reference # Private: Dispatches to a dedicated processing method based on reference
......
...@@ -66,6 +66,7 @@ namespace :gitlab do ...@@ -66,6 +66,7 @@ namespace :gitlab do
puts "no".green puts "no".green
else else
puts "yes".red puts "yes".red
puts "Please fix this by removing the SQLite entry from the database.yml".blue
for_more_information( for_more_information(
"https://github.com/gitlabhq/gitlabhq/wiki/Migrate-from-SQLite-to-MySQL", "https://github.com/gitlabhq/gitlabhq/wiki/Migrate-from-SQLite-to-MySQL",
see_database_guide see_database_guide
...@@ -741,7 +742,7 @@ namespace :gitlab do ...@@ -741,7 +742,7 @@ namespace :gitlab do
end end
def check_gitlab_shell def check_gitlab_shell
required_version = Gitlab::VersionInfo.new(1, 8, 5) required_version = Gitlab::VersionInfo.new(1, 9, 0)
current_version = Gitlab::VersionInfo.parse(gitlab_shell_version) current_version = Gitlab::VersionInfo.parse(gitlab_shell_version)
print "GitLab Shell version >= #{required_version} ? ... " print "GitLab Shell version >= #{required_version} ? ... "
......
...@@ -24,6 +24,11 @@ describe Profiles::KeysController do ...@@ -24,6 +24,11 @@ describe Profiles::KeysController do
expect(response.body).to eq("") expect(response.body).to eq("")
end end
it "should respond with text/plain content type" do
get :get_keys, username: user.username
expect(response.content_type).to eq("text/plain")
end
end end
describe "user with keys" do describe "user with keys" do
...@@ -44,6 +49,11 @@ describe Profiles::KeysController do ...@@ -44,6 +49,11 @@ describe Profiles::KeysController do
expect(response.body).not_to eq("") expect(response.body).not_to eq("")
expect(response.body).to eq(user.all_ssh_keys.join("\n")) expect(response.body).to eq(user.all_ssh_keys.join("\n"))
end end
it "should respond with text/plain content type" do
get :get_keys, username: user.username
expect(response.content_type).to eq("text/plain")
end
end end
end end
end end
...@@ -32,6 +32,18 @@ FactoryGirl.define do ...@@ -32,6 +32,18 @@ FactoryGirl.define do
path { name.downcase.gsub(/\s/, '_') } path { name.downcase.gsub(/\s/, '_') }
namespace namespace
creator creator
trait :public do
visibility_level Gitlab::VisibilityLevel::PUBLIC
end
trait :internal do
visibility_level Gitlab::VisibilityLevel::INTERNAL
end
trait :private do
visibility_level Gitlab::VisibilityLevel::PRIVATE
end
end end
# Generates a test repository from the repository stored under `spec/seed_project.tar.gz`. # Generates a test repository from the repository stored under `spec/seed_project.tar.gz`.
...@@ -146,6 +158,11 @@ FactoryGirl.define do ...@@ -146,6 +158,11 @@ FactoryGirl.define do
state :reopened state :reopened
end end
trait :simple do
source_branch "simple_merge_request"
target_branch "master"
end
factory :closed_merge_request, traits: [:closed] factory :closed_merge_request, traits: [:closed]
factory :reopened_merge_request, traits: [:reopened] factory :reopened_merge_request, traits: [:reopened]
factory :merge_request_with_diffs, traits: [:with_diffs] factory :merge_request_with_diffs, traits: [:with_diffs]
...@@ -161,7 +178,6 @@ FactoryGirl.define do ...@@ -161,7 +178,6 @@ FactoryGirl.define do
factory :note_on_issue, traits: [:on_issue], aliases: [:votable_note] factory :note_on_issue, traits: [:on_issue], aliases: [:votable_note]
factory :note_on_merge_request, traits: [:on_merge_request] factory :note_on_merge_request, traits: [:on_merge_request]
factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff] factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff]
factory :note_on_merge_request_with_attachment, traits: [:on_merge_request, :with_attachment]
trait :on_commit do trait :on_commit do
project factory: :project project factory: :project
......
require 'spec_helper' require 'spec_helper'
describe "On a merge request", js: true do describe "On a merge request", js: true do
let!(:project) { create(:project) } let!(:merge_request) { create(:merge_request, :simple) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let!(:project) { merge_request.source_project }
let!(:note) { create(:note_on_merge_request_with_attachment, project: project) } let!(:note) { create(:note_on_merge_request, :with_attachment, project: project) }
before do before do
login_as :user login_as :admin
project.team << [@user, :master]
visit project_merge_request_path(project, merge_request) visit project_merge_request_path(project, merge_request)
end end
...@@ -134,22 +132,20 @@ describe "On a merge request", js: true do ...@@ -134,22 +132,20 @@ describe "On a merge request", js: true do
end end
end end
describe "On a merge request diff", js: true, focus: true do describe "On a merge request diff", js: true do
let!(:project) { create(:project) } let(:merge_request) { create(:merge_request, :with_diffs, :simple) }
let!(:merge_request) { create(:merge_request_with_diffs, source_project: project, target_project: project) } let(:project) { merge_request.source_project }
before do before do
login_as :user login_as :admin
project.team << [@user, :master]
visit diffs_project_merge_request_path(project, merge_request) visit diffs_project_merge_request_path(project, merge_request)
end end
subject { page } subject { page }
describe "when adding a note" do describe "when adding a note" do
before do before do
find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185"]').click find('a[data-line-code="8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7"]').click
end end
describe "the notes holder" do describe "the notes holder" do
...@@ -160,13 +156,13 @@ describe "On a merge request diff", js: true, focus: true do ...@@ -160,13 +156,13 @@ describe "On a merge request diff", js: true, focus: true do
describe "the note form" do describe "the note form" do
it "shouldn't add a second form for same row" do it "shouldn't add a second form for same row" do
find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185"]').click find('a[data-line-code="8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7"]').click
should have_css("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185'] + .js-temp-notes-holder form", count: 1) should have_css("tr[id='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7'] + .js-temp-notes-holder form", count: 1)
end end
it "should be removed when canceled" do it "should be removed when canceled" do
within(".diff-file form[rel$='4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185']") do within(".diff-file form[rel$='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7']") do
find(".js-close-discussion-note-form").trigger("click") find(".js-close-discussion-note-form").trigger("click")
end end
...@@ -176,12 +172,9 @@ describe "On a merge request diff", js: true, focus: true do ...@@ -176,12 +172,9 @@ describe "On a merge request diff", js: true, focus: true do
end end
describe "with muliple note forms" do describe "with muliple note forms" do
let!(:project) { create(:project) }
let!(:merge_request) { create(:merge_request_with_diffs, source_project: project, target_project: project) }
before do before do
find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185"]').click find('a[data-line-code="8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7"]').click
find('a[data-line-code="342e16cbbd482ac2047dc679b2749d248cc1428f_18_17"]').click find('a[data-line-code="8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_10_10"]').click
end end
it { should have_css(".js-temp-notes-holder", count: 2) } it { should have_css(".js-temp-notes-holder", count: 2) }
...@@ -189,12 +182,12 @@ describe "On a merge request diff", js: true, focus: true do ...@@ -189,12 +182,12 @@ describe "On a merge request diff", js: true, focus: true do
describe "previewing them separately" do describe "previewing them separately" do
before do before do
# add two separate texts and trigger previews on both # add two separate texts and trigger previews on both
within("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185'] + .js-temp-notes-holder") do within("tr[id='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7'] + .js-temp-notes-holder") do
fill_in "note[note]", with: "One comment on line 185" fill_in "note[note]", with: "One comment on line 7"
find(".js-note-preview-button").trigger("click") find(".js-note-preview-button").trigger("click")
end end
within("tr[id='342e16cbbd482ac2047dc679b2749d248cc1428f_18_17'] + .js-temp-notes-holder") do within("tr[id='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_10_10'] + .js-temp-notes-holder") do
fill_in "note[note]", with: "Another comment on line 17" fill_in "note[note]", with: "Another comment on line 10"
find(".js-note-preview-button").trigger("click") find(".js-note-preview-button").trigger("click")
end end
end end
...@@ -202,14 +195,14 @@ describe "On a merge request diff", js: true, focus: true do ...@@ -202,14 +195,14 @@ describe "On a merge request diff", js: true, focus: true do
describe "posting a note" do describe "posting a note" do
before do before do
within("tr[id='342e16cbbd482ac2047dc679b2749d248cc1428f_18_17'] + .js-temp-notes-holder") do within("tr[id='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_10_10'] + .js-temp-notes-holder") do
fill_in "note[note]", with: "Another comment on line 17" fill_in "note[note]", with: "Another comment on line 10"
click_button("Add Comment") click_button("Add Comment")
end end
end end
it 'should be added as discussion' do it 'should be added as discussion' do
should have_content("Another comment on line 17") should have_content("Another comment on line 10")
should have_css(".notes_holder") should have_css(".notes_holder")
should have_css(".notes_holder .note", count: 1) should have_css(".notes_holder .note", count: 1)
should have_link("Reply") should have_link("Reply")
......
...@@ -16,7 +16,7 @@ describe "Group with internal project access" do ...@@ -16,7 +16,7 @@ describe "Group with internal project access" do
group.add_user(reporter, Gitlab::Access::REPORTER) group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST) group.add_user(guest, Gitlab::Access::GUEST)
create(:project, group: group, visibility_level: Gitlab::VisibilityLevel::INTERNAL) create(:project, :internal, group: group)
end end
describe "GET /groups/:path" do describe "GET /groups/:path" do
......
...@@ -16,8 +16,8 @@ describe "Group access" do ...@@ -16,8 +16,8 @@ describe "Group access" do
group.add_user(reporter, Gitlab::Access::REPORTER) group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST) group.add_user(guest, Gitlab::Access::GUEST)
create(:project, path: "internal_project", group: group, visibility_level: Gitlab::VisibilityLevel::INTERNAL) create(:project, :internal, path: "internal_project", group: group)
create(:project, path: "public_project", group: group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) create(:project, :public, path: "public_project", group: group)
end end
describe "GET /groups/:path" do describe "GET /groups/:path" do
......
...@@ -16,7 +16,7 @@ describe "Group with public project access" do ...@@ -16,7 +16,7 @@ describe "Group with public project access" do
group.add_user(reporter, Gitlab::Access::REPORTER) group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST) group.add_user(guest, Gitlab::Access::GUEST)
create(:project, group: group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) create(:project, :public, group: group)
end end
describe "GET /groups/:path" do describe "GET /groups/:path" do
......
require 'spec_helper' require 'spec_helper'
describe "Internal Project Access" do describe "Internal Project Access" do
let(:project) { create(:project) } let(:project) { create(:project, :internal) }
let(:master) { create(:user) } let(:master) { create(:user) }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:reporter) { create(:user) } let(:reporter) { create(:user) }
before do before do
# internal project
project.visibility_level = Gitlab::VisibilityLevel::INTERNAL
project.save!
# full access # full access
project.team << [master, :master] project.team << [master, :master]
# readonly # readonly
project.team << [reporter, :reporter] project.team << [reporter, :reporter]
end end
describe "Project should be internal" do describe "Project should be internal" do
......
require 'spec_helper' require 'spec_helper'
describe MergeRequestsFinder do describe MergeRequestsFinder do
let(:user) { create :user } let(:user) { create :user }
let(:user2) { create :user } let(:user2) { create :user }
let(:project1) { create(:project) } let(:project1) { create(:project) }
let(:project2) { create(:project) } let(:project2) { create(:project) }
let(:merge_request1) { create(:merge_request, author: user, source_project: project1, target_project: project2) }
let(:merge_request2) { create(:merge_request, author: user, source_project: project2, target_project: project1) } let!(:merge_request1) { create(:merge_request, :simple, author: user, source_project: project1, target_project: project2) }
let(:merge_request3) { create(:merge_request, author: user, source_project: project2, target_project: project2) } let!(:merge_request2) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1) }
let!(:merge_request3) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project2) }
before do before do
project1.team << [user, :master] project1.team << [user, :master]
...@@ -15,13 +17,7 @@ describe MergeRequestsFinder do ...@@ -15,13 +17,7 @@ describe MergeRequestsFinder do
project2.team << [user2, :developer] project2.team << [user2, :developer]
end end
describe :execute do describe "#execute" do
before :each do
merge_request1
merge_request2
merge_request3
end
it 'should filter by scope' do it 'should filter by scope' do
params = { scope: 'authored', state: 'opened' } params = { scope: 'authored', state: 'opened' }
merge_requests = MergeRequestsFinder.new.execute(user, params) merge_requests = MergeRequestsFinder.new.execute(user, params)
......
...@@ -4,10 +4,10 @@ describe ProjectsFinder do ...@@ -4,10 +4,10 @@ describe ProjectsFinder do
let(:user) { create :user } let(:user) { create :user }
let(:group) { create :group } let(:group) { create :group }
let(:project1) { create(:empty_project, group: group, visibility_level: Project::PUBLIC) } let(:project1) { create(:empty_project, :public, group: group) }
let(:project2) { create(:empty_project, group: group, visibility_level: Project::INTERNAL) } let(:project2) { create(:empty_project, :internal, group: group) }
let(:project3) { create(:empty_project, group: group, visibility_level: Project::PRIVATE) } let(:project3) { create(:empty_project, :private, group: group) }
let(:project4) { create(:empty_project, group: group, visibility_level: Project::PRIVATE) } let(:project4) { create(:empty_project, :private, group: group) }
context 'non authenticated' do context 'non authenticated' do
subject { ProjectsFinder.new.execute(nil, group: group) } subject { ProjectsFinder.new.execute(nil, group: group) }
......
...@@ -47,6 +47,7 @@ describe Project do ...@@ -47,6 +47,7 @@ describe Project do
it { should have_many(:hooks).dependent(:destroy) } it { should have_many(:hooks).dependent(:destroy) }
it { should have_many(:protected_branches).dependent(:destroy) } it { should have_many(:protected_branches).dependent(:destroy) }
it { should have_one(:forked_project_link).dependent(:destroy) } it { should have_one(:forked_project_link).dependent(:destroy) }
it { should have_one(:slack_service).dependent(:destroy) }
end end
describe "Mass assignment" do describe "Mass assignment" do
......
require_relative '../../app/models/project_services/slack_message'
describe SlackMessage do
subject { SlackMessage.new(args) }
let(:args) {
{
after: 'after',
before: 'before',
project_name: 'project_name',
ref: 'refs/heads/master',
user_name: 'user_name',
project_url: 'url'
}
}
context 'push' do
before do
args[:commits] = [
{ message: 'message1', url: 'url1', id: 'abcdefghi' },
{ message: 'message2', url: 'url2', id: '123456789' },
]
end
it 'returns a message regarding pushes' do
subject.compose.should ==
'user_name pushed to branch <url/commits/master|master> of ' <<
'<url|project_name> (<url/compare/before...after|Compare changes>)' <<
"\n - message1 (<url1|abcdef>)" <<
"\n - message2 (<url2|123456>)"
end
end
context 'new branch' do
before do
args[:before] = '000000'
end
it 'returns a message regarding a new branch' do
subject.compose.should ==
'user_name pushed new branch <url/commits/master|master> to ' <<
'<url|project_name>'
end
end
context 'removed branch' do
before do
args[:after] = '000000'
end
it 'returns a message regarding a removed branch' do
subject.compose.should ==
'user_name removed branch master from <url|project_name>'
end
end
end
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# api_key :string(255)
#
require 'spec_helper'
describe SlackService do
describe "Associations" do
it { should belong_to :project }
it { should have_one :service_hook }
end
describe "Validations" do
context "active" do
before do
subject.active = true
end
it { should validate_presence_of :room }
it { should validate_presence_of :subdomain }
it { should validate_presence_of :token }
end
end
describe "Execute" do
let(:slack) { SlackService.new }
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:sample_data) { GitPushService.new.sample_data(project, user) }
let(:subdomain) { 'gitlab' }
let(:token) { 'verySecret' }
let(:api_url) {
"https://#{subdomain}.slack.com/services/hooks/incoming-webhook?token=#{token}"
}
before do
slack.stub(
project: project,
project_id: project.id,
room: '#gitlab',
service_hook: true,
subdomain: subdomain,
token: token
)
WebMock.stub_request(:post, api_url)
end
it "should call Slack API" do
slack.execute(sample_data)
WebMock.should have_requested(:post, api_url).once
end
end
end
...@@ -133,7 +133,7 @@ describe API::API do ...@@ -133,7 +133,7 @@ describe API::API do
end end
it "should set a project as public" do it "should set a project as public" do
project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PUBLIC }) project = attributes_for(:project, :public)
post api("/projects", user), project post api("/projects", user), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
...@@ -147,21 +147,21 @@ describe API::API do ...@@ -147,21 +147,21 @@ describe API::API do
end end
it "should set a project as internal" do it "should set a project as internal" do
project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::INTERNAL }) project = attributes_for(:project, :internal)
post api("/projects", user), project post api("/projects", user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as internal overriding :public" do it "should set a project as internal overriding :public" do
project = attributes_for(:project, { public: true, visibility_level: Gitlab::VisibilityLevel::INTERNAL }) project = attributes_for(:project, :internal, { public: true })
post api("/projects", user), project post api("/projects", user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as private" do it "should set a project as private" do
project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PRIVATE }) project = attributes_for(:project, :private)
post api("/projects", user), project post api("/projects", user), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
...@@ -215,7 +215,7 @@ describe API::API do ...@@ -215,7 +215,7 @@ describe API::API do
end end
it "should set a project as public" do it "should set a project as public" do
project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PUBLIC }) project = attributes_for(:project, :public)
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_true json_response['public'].should be_true
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
...@@ -229,21 +229,21 @@ describe API::API do ...@@ -229,21 +229,21 @@ describe API::API do
end end
it "should set a project as internal" do it "should set a project as internal" do
project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::INTERNAL }) project = attributes_for(:project, :internal)
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as internal overriding :public" do it "should set a project as internal overriding :public" do
project = attributes_for(:project, { public: true, visibility_level: Gitlab::VisibilityLevel::INTERNAL }) project = attributes_for(:project, :internal, { public: true })
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
end end
it "should set a project as private" do it "should set a project as private" do
project = attributes_for(:project, { visibility_level: Gitlab::VisibilityLevel::PRIVATE }) project = attributes_for(:project, :private)
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
json_response['public'].should be_false json_response['public'].should be_false
json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
...@@ -490,10 +490,10 @@ describe API::API do ...@@ -490,10 +490,10 @@ describe API::API do
describe :fork_admin do describe :fork_admin do
let(:project_fork_target) { create(:project) } let(:project_fork_target) { create(:project) }
let(:project_fork_source) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let(:project_fork_source) { create(:project, :public) }
describe "POST /projects/:id/fork/:forked_from_id" do describe "POST /projects/:id/fork/:forked_from_id" do
let(:new_project_fork_source) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let(:new_project_fork_source) { create(:project, :public) }
it "shouldn't available for non admin users" do it "shouldn't available for non admin users" do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
...@@ -593,10 +593,10 @@ describe API::API do ...@@ -593,10 +593,10 @@ describe API::API do
let!(:post) { create(:empty_project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } let!(:post) { create(:empty_project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) }
let!(:pre_post) { create(:empty_project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } let!(:pre_post) { create(:empty_project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) }
let!(:unfound) { create(:empty_project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } let!(:unfound) { create(:empty_project, name: 'unfound', creator_id: user.id, namespace: user.namespace) }
let!(:internal) { create(:empty_project, name: "internal #{query}", visibility_level: Gitlab::VisibilityLevel::INTERNAL) } let!(:internal) { create(:empty_project, :internal, name: "internal #{query}") }
let!(:unfound_internal) { create(:empty_project, name: 'unfound internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL) } let!(:unfound_internal) { create(:empty_project, :internal, name: 'unfound internal') }
let!(:public) { create(:empty_project, name: "public #{query}", visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let!(:public) { create(:empty_project, :public, name: "public #{query}") }
let!(:unfound_public) { create(:empty_project, name: 'unfound public', visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let!(:unfound_public) { create(:empty_project, :public, name: 'unfound public') }
context "when unauthenticated" do context "when unauthenticated" do
it "should return authentication error" do it "should return authentication error" do
......
No preview for this file type
require 'spec_helper' require 'spec_helper'
describe 'Search::GlobalService' do describe 'Search::GlobalService' do
let(:found_namespace) { create(:namespace, name: 'searchable namespace', path:'another_thing') }
let(:user) { create(:user, namespace: found_namespace) } let(:user) { create(:user, namespace: found_namespace) }
let!(:found_project) { create(:project, name: 'searchable_project', creator_id: user.id, namespace: found_namespace, visibility_level: Gitlab::VisibilityLevel::PRIVATE) } let(:public_user) { create(:user, namespace: public_namespace) }
let(:internal_user) { create(:user, namespace: internal_namespace) }
let(:found_namespace) { create(:namespace, name: 'searchable namespace', path:'another_thing') }
let(:unfound_namespace) { create(:namespace, name: 'unfound namespace', path: 'yet_something_else') } let(:unfound_namespace) { create(:namespace, name: 'unfound namespace', path: 'yet_something_else') }
let!(:unfound_project) { create(:project, name: 'unfound_project', creator_id: user.id, namespace: unfound_namespace, visibility_level: Gitlab::VisibilityLevel::PRIVATE) } let(:internal_namespace) { create(:namespace, name: 'searchable internal namespace', path: 'something_internal') }
let(:public_namespace) { create(:namespace, name: 'searchable public namespace', path: 'something_public') }
let(:internal_namespace) { create(:namespace, path: 'something_internal',name: 'searchable internal namespace') } let!(:found_project) { create(:project, :private, name: 'searchable_project', creator_id: user.id, namespace: found_namespace) }
let(:internal_user) { create(:user, namespace: internal_namespace) } let!(:unfound_project) { create(:project, :private, name: 'unfound_project', creator_id: user.id, namespace: unfound_namespace) }
let!(:internal_project) { create(:project, name: 'searchable_internal_project', creator_id: internal_user.id, namespace: internal_namespace, visibility_level: Gitlab::VisibilityLevel::INTERNAL) } let!(:internal_project) { create(:project, :internal, name: 'searchable_internal_project', creator_id: internal_user.id, namespace: internal_namespace) }
let!(:public_project) { create(:project, :public, name: 'searchable_public_project', creator_id: public_user.id, namespace: public_namespace) }
let(:public_namespace) { create(:namespace, path: 'something_public',name: 'searchable public namespace') }
let(:public_user) { create(:user, namespace: public_namespace) }
let!(:public_project) { create(:project, name: 'searchable_public_project', creator_id: public_user.id, namespace: public_namespace, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
describe '#execute' do describe '#execute' do
context 'unauthenticated' do context 'unauthenticated' do
it 'should return public projects only' do it 'should return public projects only' do
context = Search::GlobalService.new(nil, search: "searchable") context = Search::GlobalService.new(nil, search: "searchable")
results = context.execute results = context.execute
results[:projects].should have(1).items results[:projects].should match_array [public_project]
results[:projects].should include(public_project)
end end
end end
...@@ -30,24 +28,19 @@ describe 'Search::GlobalService' do ...@@ -30,24 +28,19 @@ describe 'Search::GlobalService' do
it 'should return public, internal and private projects' do it 'should return public, internal and private projects' do
context = Search::GlobalService.new(user, search: "searchable") context = Search::GlobalService.new(user, search: "searchable")
results = context.execute results = context.execute
results[:projects].should have(3).items results[:projects].should match_array [public_project, found_project, internal_project]
results[:projects].should include(public_project)
results[:projects].should include(found_project)
results[:projects].should include(internal_project)
end end
it 'should return only public & internal projects' do it 'should return only public & internal projects' do
context = Search::GlobalService.new(internal_user, search: "searchable") context = Search::GlobalService.new(internal_user, search: "searchable")
results = context.execute results = context.execute
results[:projects].should have(2).items results[:projects].should match_array [internal_project, public_project]
results[:projects].should include(internal_project)
results[:projects].should include(public_project)
end end
it 'namespace name should be searchable' do it 'namespace name should be searchable' do
context = Search::GlobalService.new(user, search: "searchable namespace") context = Search::GlobalService.new(user, search: "searchable namespace")
results = context.execute results = context.execute
results[:projects].should == [found_project] results[:projects].should match_array [found_project]
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment