Merge branch 'master' into fixes/api

5-0-stable
Sebastian Ziebell 2013-02-27 10:16:48 +01:00
commit ac4a09e9cc
94 changed files with 935 additions and 731 deletions

View File

@ -1,6 +1,5 @@
language: ruby
env:
- DB=postgresql
- DB=mysql
before_install:
- sudo apt-get install libicu-dev -y

View File

@ -1,10 +1,33 @@
v 5.0.0
- Replaced gitolite with gitlab-shell
- Removed gitolite-related libraries
- State machine added
- Setup gitlab as git user
- Internal API
- Show team tab for empty projects
- Import repository feature
- Updated rails
- Use lambda for scopes
- Redesign admin area -> users
- Redesign admin area -> user
- Secure link to file attachments
- Add validations for Group and Team names
- Restyle team page for project
- Update capybara, rspec-rails, poltergeist to recent versions
v 4.2.0
- Teams
- User show page. Via /u/username
- Show help contents on pages for better navigation
- Async gitolite calls
- added satellites logs
- can_create_group, can_create_team booleans for User
- Process web hooks async
- GFM: Fix images escaped inside links
- Network graph improved
- Switchable branches for network graph
- API: Groups
- Fixed project download
v 4.1.0
- Optional Sign-Up

16
Gemfile
View File

@ -22,7 +22,7 @@ gem 'omniauth-twitter'
gem 'omniauth-github'
# GITLAB patched libs
gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '7f35cb98ff17d534a07e3ce6ec3d580f67402837'
gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '9e98418ce2d654485b967003726aa2706a10060b'
gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8'
gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e'
@ -81,8 +81,8 @@ gem "draper", "~> 0.18.0"
# Background jobs
gem 'slim'
gem 'sinatra', :require => nil
gem 'sidekiq', '2.6.4'
gem 'sinatra', require: nil
gem 'sidekiq', '2.7.3'
# HTTP requests
gem "httparty"
@ -134,12 +134,12 @@ end
group :development, :test do
gem 'rails-dev-tweaks'
gem 'spinach-rails'
gem "rspec-rails"
gem "capybara"
gem 'spinach-rails', '0.2.0'
gem "rspec-rails", '2.12.2'
gem "capybara", '2.0.2'
gem "pry"
gem "awesome_print"
gem "database_cleaner", ref: "f89c34300e114be99532f14c115b2799a3380ac6", git: "https://github.com/bmabey/database_cleaner.git"
gem "database_cleaner", ref: "9f898fc50d87a5d51760f9dcf374bf5ffda21baf", git: "https://github.com/bmabey/database_cleaner.git"
gem "launchy"
gem 'factory_girl_rails'
@ -153,7 +153,7 @@ group :development, :test do
gem 'rb-inotify', require: linux_only('rb-inotify')
# PhantomJS driver for Capybara
gem 'poltergeist', git: 'https://github.com/jonleighton/poltergeist.git', ref: '5c2e092001074a8cf09f332d3714e9ba150bc8ca'
gem 'poltergeist', '1.1.0'
end
group :test do

View File

@ -1,7 +1,7 @@
GIT
remote: https://github.com/bmabey/database_cleaner.git
revision: f89c34300e114be99532f14c115b2799a3380ac6
ref: f89c34300e114be99532f14c115b2799a3380ac6
revision: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf
ref: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf
specs:
database_cleaner (0.9.1)
@ -23,8 +23,8 @@ GIT
GIT
remote: https://github.com/gitlabhq/grit.git
revision: 7f35cb98ff17d534a07e3ce6ec3d580f67402837
ref: 7f35cb98ff17d534a07e3ce6ec3d580f67402837
revision: 9e98418ce2d654485b967003726aa2706a10060b
ref: 9e98418ce2d654485b967003726aa2706a10060b
specs:
grit (2.5.0)
diff-lcs (~> 1.1)
@ -54,18 +54,6 @@ GIT
specs:
raphael-rails (2.1.0)
GIT
remote: https://github.com/jonleighton/poltergeist.git
revision: 5c2e092001074a8cf09f332d3714e9ba150bc8ca
ref: 5c2e092001074a8cf09f332d3714e9ba150bc8ca
specs:
poltergeist (1.0.2)
capybara (~> 1.1)
childprocess (~> 0.3)
faye-websocket (~> 0.4, >= 0.4.4)
http_parser.rb (~> 0.5.3)
multi_json (~> 1.0)
GEM
remote: http://rubygems.org/
specs:
@ -110,13 +98,13 @@ GEM
bootstrap-sass (2.2.1.1)
sass (~> 3.2)
builder (3.0.4)
capybara (1.1.3)
capybara (2.0.2)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
selenium-webdriver (~> 2.0)
xpath (~> 0.1.4)
xpath (~> 1.0.0)
carrierwave (0.7.1)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
@ -124,8 +112,8 @@ GEM
facter (>= 1.6.12)
timers (>= 1.0.0)
charlock_holmes (0.6.9)
childprocess (0.3.6)
ffi (~> 1.0, >= 1.0.6)
childprocess (0.3.8)
ffi (~> 1.0, >= 1.0.11)
chosen-rails (0.9.8)
railties (~> 3.0)
thor (~> 0.14)
@ -169,10 +157,10 @@ GEM
railties (>= 3.0.0)
faraday (0.8.4)
multipart-post (~> 1.1)
faye-websocket (0.4.6)
faye-websocket (0.4.7)
eventmachine (>= 0.12.0)
ffaker (1.15.0)
ffi (1.1.5)
ffi (1.4.0)
font-awesome-sass-rails (3.0.0.1)
railties (>= 3.1.1)
sass-rails (>= 3.1.1)
@ -249,8 +237,6 @@ GEM
letter_opener (1.0.0)
launchy (>= 2.0.4)
libv8 (3.3.10.4)
libwebsocket (0.1.6)
websocket
listen (0.5.3)
lumberjack (1.0.2)
mail (2.4.4)
@ -261,12 +247,12 @@ GEM
mime-types (1.21)
modernizr (2.6.2)
sprockets (~> 2.0)
multi_json (1.5.1)
multi_json (1.6.1)
multi_xml (0.5.1)
multipart-post (1.1.5)
mysql2 (0.3.11)
net-ldap (0.2.2)
nokogiri (1.5.5)
nokogiri (1.5.6)
oauth (0.4.7)
oauth2 (0.8.0)
faraday (~> 0.8)
@ -294,6 +280,10 @@ GEM
omniauth-oauth (~> 1.0)
orm_adapter (0.4.0)
pg (0.14.1)
poltergeist (1.1.0)
capybara (~> 2.0, >= 2.0.1)
faye-websocket (~> 0.4, >= 0.4.4)
http_parser.rb (~> 0.5.3)
polyglot (0.3.3)
posix-spawn (0.3.6)
progressbar (0.12.0)
@ -364,7 +354,7 @@ GEM
rspec-expectations (2.12.0)
diff-lcs (~> 1.1.3)
rspec-mocks (2.12.0)
rspec-rails (2.12.0)
rspec-rails (2.12.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
@ -384,16 +374,16 @@ GEM
seed-fu (2.2.0)
activerecord (~> 3.1)
activesupport (~> 3.1)
selenium-webdriver (2.26.0)
selenium-webdriver (2.30.0)
childprocess (>= 0.2.5)
libwebsocket (~> 0.1.3)
multi_json (~> 1.0)
rubyzip
websocket (~> 1.0.4)
settingslogic (2.0.8)
sexp_processor (4.1.3)
shoulda-matchers (1.3.0)
activesupport (>= 3.0.0)
sidekiq (2.6.4)
sidekiq (2.7.3)
celluloid (~> 0.12.0)
connection_pool (~> 1.0)
multi_json (~> 1)
@ -412,11 +402,11 @@ GEM
temple (~> 0.5.5)
tilt (~> 1.3.3)
slop (3.3.3)
spinach (0.5.2)
spinach (0.7.0)
colorize
gherkin-ruby (~> 0.2.0)
spinach-rails (0.1.8)
capybara (~> 1)
spinach-rails (0.2.0)
capybara (~> 2.0.0)
railties (>= 3)
spinach (>= 0.4)
sprockets (2.2.2)
@ -436,7 +426,7 @@ GEM
rack (>= 1.0.0)
thor (0.17.0)
tilt (1.3.3)
timers (1.0.2)
timers (1.1.0)
treetop (1.4.12)
polyglot
polyglot (>= 0.3.1)
@ -455,8 +445,8 @@ GEM
webmock (1.9.0)
addressable (>= 2.2.7)
crack (>= 0.1.7)
websocket (1.0.2)
xpath (0.1.4)
websocket (1.0.7)
xpath (1.0.0)
nokogiri (~> 1.3)
yajl-ruby (1.1.0)
@ -470,7 +460,7 @@ DEPENDENCIES
better_errors
binding_of_caller
bootstrap-sass (= 2.2.1.1)
capybara
capybara (= 2.0.2)
carrierwave (~> 0.7.1)
chosen-rails (= 0.9.8)
coffee-rails (~> 3.2.2)
@ -512,7 +502,7 @@ DEPENDENCIES
omniauth-google-oauth2
omniauth-twitter
pg
poltergeist!
poltergeist (= 1.1.0)
pry
pygments.rb!
quiet_assets (~> 1.0.1)
@ -524,18 +514,18 @@ DEPENDENCIES
rb-fsevent
rb-inotify
redcarpet (~> 2.2.2)
rspec-rails
rspec-rails (= 2.12.2)
sass-rails (~> 3.2.5)
sdoc
seed-fu
settingslogic
shoulda-matchers (= 1.3.0)
sidekiq (= 2.6.4)
sidekiq (= 2.7.3)
simplecov
sinatra
six
slim
spinach-rails
spinach-rails (= 0.2.0)
stamp
state_machine
test_after_commit

View File

@ -31,7 +31,7 @@ class MergeRequest
if this.$('.automerge_widget').length and @opts.check_enable
$.get @opts.url_to_automerge_check, (data) =>
this.showState( data.state )
this.showState( data.merge_status )
, 'json'
if @opts.ci_enable

View File

@ -24,6 +24,14 @@
background-image: -o-linear-gradient($from, $to);
}
@mixin transition($transition) {
-webkit-transition: $transition;
-moz-transition: $transition;
-ms-transition: $transition;
-o-transition: $transition;
transition: $transition;
}
/**
* Prefilled mixins
* Mixins with fixed values

View File

@ -90,6 +90,7 @@ header {
@include border-radius(3px);
border: 1px solid #c6c6c6;
box-shadow: none;
@include transition(all 0.15s ease-in 0s);
&:focus {
@extend .span3;
}

View File

@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext
end
merge_requests = merge_requests.page(params[:page]).per(20)
merge_requests = merge_requests.includes(:author, :project).order("state, created_at desc")
merge_requests = merge_requests.includes(:author, :project).order("created_at desc")
# Filter by specific assignee_id (or lack thereof)?
if params[:assignee_id].present?

View File

@ -1,8 +1,7 @@
class TestHookContext < BaseContext
def execute
hook = project.hooks.find(params[:id])
commits = project.repository.commits(project.default_branch, nil, 3)
data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user)
data = GitPushService.new.sample_data(project, current_user)
hook.execute(data)
end
end

View File

@ -1,3 +1,5 @@
require 'gitlab/satellite/satellite'
class MergeRequestsController < ProjectResourceController
before_filter :module_enabled
before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status]
@ -73,7 +75,7 @@ class MergeRequestsController < ProjectResourceController
if @merge_request.unchecked?
@merge_request.check_if_can_be_merged
end
render json: {merge_status: @merge_request.human_merge_status}
render json: {merge_status: @merge_request.merge_status_name}
rescue Gitlab::SatelliteNotExistError
render json: {merge_status: :no_satellite}
end

View File

@ -1,4 +1,6 @@
class ProfilesController < ApplicationController
include ActionView::Helpers::SanitizeHelper
before_filter :user
layout 'profile'
@ -12,7 +14,7 @@ class ProfilesController < ApplicationController
end
def update
if @user.update_attributes(params[:user])
if @user.update_attributes(user_attributes)
flash[:notice] = "Profile was successfully updated"
else
flash[:alert] = "Failed to update profile"
@ -65,4 +67,17 @@ class ProfilesController < ApplicationController
def user
@user = current_user
end
def user_attributes
user_attributes = params[:user]
# Sanitize user input because we dont have strict
# validation for this fields
%w(name skype linkedin twitter bio).each do |attr|
value = user_attributes[attr]
user_attributes[attr] = sanitize(value) if value.present?
end
user_attributes
end
end

View File

@ -72,7 +72,7 @@ module ApplicationHelper
end
def search_autocomplete_source
projects = current_user.authorized_projects.map { |p| { label: "project: #{p.name_with_namespace}", url: project_path(p) } }
projects = current_user.authorized_projects.map { |p| { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } }
groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } }
teams = current_user.authorized_teams.map { |team| { label: "team: #{simple_sanitize(team.name)}", url: team_path(team) } }
@ -98,15 +98,15 @@ module ApplicationHelper
project_nav = []
if @project && @project.repository && @project.repository.root_ref
project_nav = [
{ label: "#{@project.name_with_namespace} - Issues", url: project_issues_path(@project) },
{ label: "#{@project.name_with_namespace} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{@project.name_with_namespace} - Merge Requests", url: project_merge_requests_path(@project) },
{ label: "#{@project.name_with_namespace} - Milestones", url: project_milestones_path(@project) },
{ label: "#{@project.name_with_namespace} - Snippets", url: project_snippets_path(@project) },
{ label: "#{@project.name_with_namespace} - Team", url: project_team_index_path(@project) },
{ label: "#{@project.name_with_namespace} - Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{@project.name_with_namespace} - Wall", url: wall_project_path(@project) },
{ label: "#{@project.name_with_namespace} - Wiki", url: project_wikis_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Merge Requests", url: project_merge_requests_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Milestones", url: project_milestones_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Snippets", url: project_snippets_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Team", url: project_team_index_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Wall", url: wall_project_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Wiki", url: project_wikis_path(@project) },
]
end

View File

@ -57,6 +57,31 @@ module CommitsHelper
end
end
def each_diff_line_near(diff, index, expected_line_code)
max_number_of_lines = 16
prev_match_line = nil
prev_lines = []
each_diff_line(diff, index) do |full_line, type, line_code, line_new, line_old|
line = [full_line, type, line_code, line_new, line_old]
if line_code != expected_line_code
if type == "match"
prev_lines.clear
prev_match_line = line
else
prev_lines.push(line)
prev_lines.shift if prev_lines.length >= max_number_of_lines
end
else
yield(prev_match_line) if !prev_match_line.nil?
prev_lines.each { |ln| yield(ln) }
yield(line)
break
end
end
end
def image_diff_class(diff)
if diff.deleted_file
"deleted"

View File

@ -21,7 +21,6 @@ class Key < ActiveRecord::Base
attr_accessible :key, :title
before_validation :strip_white_space
before_save :set_identifier
validates :title, presence: true, length: { within: 0..255 }
validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / }, uniqueness: true
@ -48,14 +47,6 @@ class Key < ActiveRecord::Base
errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0
end
def set_identifier
if is_deploy_key
self.identifier = "deploy_#{Digest::MD5.hexdigest(key)}"
else
self.identifier = "#{user.identifier}_#{Time.now.to_i}"
end
end
def is_deploy_key
!!project_id
end

View File

@ -24,6 +24,8 @@ require Rails.root.join("lib/static_model")
class MergeRequest < ActiveRecord::Base
include Issuable
BROKEN_DIFF = "--broken-diff"
attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id,
:author_id_of_changes, :state_event
@ -51,47 +53,41 @@ class MergeRequest < ActiveRecord::Base
state :merged
end
BROKEN_DIFF = "--broken-diff"
state_machine :merge_status, initial: :unchecked do
event :mark_as_unchecked do
transition [:can_be_merged, :cannot_be_merged] => :unchecked
end
UNCHECKED = 1
CAN_BE_MERGED = 2
CANNOT_BE_MERGED = 3
event :mark_as_mergeable do
transition unchecked: :can_be_merged
end
event :mark_as_unmergeable do
transition unchecked: :cannot_be_merged
end
state :unchecked
state :can_be_merged
state :cannot_be_merged
end
serialize :st_commits
serialize :st_diffs
validates :source_branch, presence: true
validates :target_branch, presence: true
validate :validate_branches
validate :validate_branches
scope :merged, -> { with_state(:merged) }
scope :by_branch, ->(branch_name) { where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) }
scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
scope :by_milestone, ->(milestone) { where(milestone_id: milestone) }
class << self
def find_all_by_branch(branch_name)
where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name)
end
def cared(user)
where('assignee_id = :user OR author_id = :user', user: user.id)
end
def find_all_by_branch(branch_name)
where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name)
end
def find_all_by_milestone(milestone)
where("milestone_id = :milestone_id", milestone_id: milestone)
end
end
def human_merge_status
merge_statuses = {
CAN_BE_MERGED => "can_be_merged",
CANNOT_BE_MERGED => "cannot_be_merged",
UNCHECKED => "unchecked"
}
merge_statuses[self.merge_status]
end
# Closed scope for merge request should return
# both merged and closed mr's
scope :closed, -> { with_states(:closed, :merged) }
def validate_branches
if target_branch == source_branch
@ -104,26 +100,12 @@ class MergeRequest < ActiveRecord::Base
self.reloaded_diffs
end
def unchecked?
merge_status == UNCHECKED
end
def mark_as_unchecked
self.merge_status = UNCHECKED
self.save
end
def can_be_merged?
merge_status == CAN_BE_MERGED
end
def check_if_can_be_merged
self.merge_status = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
CAN_BE_MERGED
else
CANNOT_BE_MERGED
end
self.save
if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
mark_as_mergeable
else
mark_as_unmergeable
end
end
def diffs
@ -178,11 +160,6 @@ class MergeRequest < ActiveRecord::Base
commits.any? && opened?
end
def mark_as_unmergable
self.merge_status = CANNOT_BE_MERGED
self.save
end
def reloaded_commits
if opened? && unmerged_commits.any?
self.st_commits = unmerged_commits
@ -217,7 +194,7 @@ class MergeRequest < ActiveRecord::Base
true
end
rescue
self.mark_as_unmergable
mark_as_unmergeable
false
end

View File

@ -247,32 +247,6 @@ class Project < ActiveRecord::Base
users_projects.find_by_user_id(user_id)
end
def transfer(new_namespace)
Project.transaction do
old_namespace = namespace
self.namespace = new_namespace
old_dir = old_namespace.try(:path) || ''
new_dir = new_namespace.try(:path) || ''
old_repo = if old_dir.present?
File.join(old_dir, self.path)
else
self.path
end
if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present?
raise TransferError.new("Project with same path in target namespace already exists")
end
Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
save!
end
rescue Gitlab::ProjectMover::ProjectMoveError => ex
raise Project::TransferError.new(ex.message)
end
def name_with_namespace
@name_with_namespace ||= begin
if namespace
@ -295,51 +269,8 @@ class Project < ActiveRecord::Base
end
end
# This method will be called after each post receive and only if the provided
# user is present in GitLab.
#
# All callbacks for post receive should be placed here.
def trigger_post_receive(oldrev, newrev, ref, user)
data = post_receive_data(oldrev, newrev, ref, user)
# Create satellite
self.satellite.create unless self.satellite.exists?
# Create push event
self.observe_push(data)
if push_to_branch? ref, oldrev
# Close merged MR
self.update_merge_requests(oldrev, newrev, ref, user)
# Execute web hooks
self.execute_hooks(data.dup)
# Execute project services
self.execute_services(data.dup)
end
# Discover the default branch, but only if it hasn't already been set to
# something else
if repository && default_branch.nil?
update_attributes(default_branch: self.repository.discover_default_branch)
end
end
def push_to_branch? ref, oldrev
ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits)
!(ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000")
end
def observe_push(data)
Event.create(
project: self,
action: Event::PUSHED,
data: data,
author_id: data[:user_id]
)
def transfer(new_namespace)
ProjectTransferService.new.transfer(self, new_namespace)
end
def execute_hooks(data)
@ -354,68 +285,12 @@ class Project < ActiveRecord::Base
end
end
# Produce a hash of post-receive data
#
# data = {
# before: String,
# after: String,
# ref: String,
# user_id: String,
# user_name: String,
# repository: {
# name: String,
# url: String,
# description: String,
# homepage: String,
# },
# commits: Array,
# total_commits_count: Fixnum
# }
#
def post_receive_data(oldrev, newrev, ref, user)
push_commits = repository.commits_between(oldrev, newrev)
# Total commits count
push_commits_count = push_commits.size
# Get latest 20 commits ASC
push_commits_limited = push_commits.last(20)
# Hash to be passed as post_receive_data
data = {
before: oldrev,
after: newrev,
ref: ref,
user_id: user.id,
user_name: user.name,
repository: {
name: name,
url: url_to_repo,
description: description,
homepage: web_url,
},
commits: [],
total_commits_count: push_commits_count
}
# For perfomance purposes maximum 20 latest commits
# will be passed as post receive hook data.
#
push_commits_limited.each do |commit|
data[:commits] << {
id: commit.id,
message: commit.safe_message,
timestamp: commit.date.xmlschema,
url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}",
author: {
name: commit.author_name,
email: commit.author_email
}
}
def discover_default_branch
# Discover the default branch, but only if it hasn't already been set to
# something else
if repository && default_branch.nil?
update_attributes(default_branch: self.repository.discover_default_branch)
end
data
end
def update_merge_requests(oldrev, newrev, ref, user)
@ -424,7 +299,7 @@ class Project < ActiveRecord::Base
c_ids = self.repository.commits_between(oldrev, newrev).map(&:id)
# Update code for merge requests
mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all
mrs = self.merge_requests.opened.by_branch(branch_name).all
mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
# Close merge requests
@ -446,6 +321,10 @@ class Project < ActiveRecord::Base
!repository || repository.empty?
end
def ensure_satellite_exists
self.satellite.create unless self.satellite.exists?
end
def satellite
@satellite ||= Gitlab::Satellite::Satellite.new(self)
end

View File

@ -66,28 +66,6 @@ class ProjectTeam
members.masters.map(&:user)
end
def repository_readers
repository_members[UsersProject::REPORTER]
end
def repository_writers
repository_members[UsersProject::DEVELOPER]
end
def repository_masters
repository_members[UsersProject::MASTER]
end
def repository_members
keys = Hash.new {|h,k| h[k] = [] }
UsersProject.select("keys.identifier, project_access").
joins(user: :keys).where(project_id: project.id).
each {|row| keys[row.project_access] << [row.identifier] }
keys[UsersProject::REPORTER] += project.deploy_keys.pluck(:identifier)
keys
end
def import(source_project)
target_project = project

View File

@ -12,13 +12,4 @@
#
class SystemHook < WebHook
def self.all_hooks_fire(data)
SystemHook.all.each do |sh|
sh.async_execute data
end
end
def async_execute(data)
Sidekiq::Client.enqueue(SystemHookWorker, id, data)
end
end

View File

@ -70,6 +70,7 @@ class User < ActiveRecord::Base
has_many :team_projects, through: :user_team_project_relationships
validates :name, presence: true
validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ }
validates :bio, length: { within: 0..255 }
validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
@ -215,17 +216,6 @@ class User < ActiveRecord::Base
UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id)
end
# Returns a string for use as a Gitolite user identifier
#
# Note that Gitolite 2.x requires the following pattern for users:
#
# ^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$
def identifier
# Replace non-word chars with underscores, then make sure it starts with
# valid chars
email.gsub(/\W/, '_').gsub(/\A([\W\_])+/, '')
end
def is_admin?
admin
end

View File

@ -28,10 +28,14 @@ class WebHook < ActiveRecord::Base
WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" })
else
post_url = url.gsub("#{parsed_url.userinfo}@", "")
auth = {
username: URI.decode(parsed_url.user),
password: URI.decode(parsed_url.password),
}
WebHook.post(post_url,
body: data.to_json,
headers: {"Content-Type" => "application/json"},
basic_auth: {username: parsed_url.user, password: parsed_url.password})
basic_auth: auth)
end
end

View File

@ -21,22 +21,22 @@ class ActivityObserver < ActiveRecord::Observer
end
def after_close(record, transition)
Event.create(
project: record.project,
target_id: record.id,
target_type: record.class.name,
action: Event::CLOSED,
author_id: record.author_id_of_changes
)
Event.create(
project: record.project,
target_id: record.id,
target_type: record.class.name,
action: Event::CLOSED,
author_id: record.author_id_of_changes
)
end
def after_reopen(record, transition)
Event.create(
project: record.project,
target_id: record.id,
target_type: record.class.name,
action: Event::REOPENED,
author_id: record.author_id_of_changes
)
Event.create(
project: record.project,
target_id: record.id,
target_type: record.class.name,
action: Event::REOPENED,
author_id: record.author_id_of_changes
)
end
end

View File

@ -1,5 +1,4 @@
class NoteObserver < ActiveRecord::Observer
def after_create(note)
send_notify_mails(note)
end

View File

@ -1,67 +1,11 @@
class SystemHookObserver < ActiveRecord::Observer
observe :user, :project, :users_project
def after_create(model)
if model.kind_of? Project
SystemHook.all_hooks_fire({
event_name: "project_create",
name: model.name,
path: model.path,
project_id: model.id,
owner_name: model.owner.name,
owner_email: model.owner.email,
created_at: model.created_at
})
elsif model.kind_of? User
SystemHook.all_hooks_fire({
event_name: "user_create",
name: model.name,
email: model.email,
created_at: model.created_at
})
elsif model.kind_of? UsersProject
SystemHook.all_hooks_fire({
event_name: "user_add_to_team",
project_name: model.project.name,
project_path: model.project.path,
project_id: model.project_id,
user_name: model.user.name,
user_email: model.user.email,
project_access: model.repo_access_human,
created_at: model.created_at
})
end
SystemHooksService.execute_hooks_for(model, :create)
end
def after_destroy(model)
if model.kind_of? Project
SystemHook.all_hooks_fire({
event_name: "project_destroy",
name: model.name,
path: model.path,
project_id: model.id,
owner_name: model.owner.name,
owner_email: model.owner.email,
})
elsif model.kind_of? User
SystemHook.all_hooks_fire({
event_name: "user_destroy",
name: model.name,
email: model.email
})
elsif model.kind_of? UsersProject
SystemHook.all_hooks_fire({
event_name: "user_remove_from_team",
project_name: model.project.name,
project_path: model.project.path,
project_id: model.project_id,
user_name: model.user.name,
user_email: model.user.email,
project_access: model.repo_access_human
})
end
SystemHooksService.execute_hooks_for(model, :destroy)
end
end

View File

@ -0,0 +1,124 @@
class GitPushService
attr_accessor :project, :user, :push_data
# This method will be called after each git update
# and only if the provided user and project is present in GitLab.
#
# All callbacks for post receive action should be placed here.
#
# Now this method do next:
# 1. Ensure project satellite exists
# 2. Update merge requests
# 3. Execute project web hooks
# 4. Execute project services
# 5. Create Push Event
#
def execute(project, user, oldrev, newrev, ref)
@project, @user = project, user
# Collect data for this git push
@push_data = post_receive_data(oldrev, newrev, ref)
project.ensure_satellite_exists
project.discover_default_branch
if push_to_branch?(ref, oldrev)
project.update_merge_requests(oldrev, newrev, ref, @user)
project.execute_hooks(@push_data.dup)
project.execute_services(@push_data.dup)
end
create_push_event
end
# This method provide a sample data
# generated with post_receive_data method
# for given project
#
def sample_data(project, user)
@project, @user = project, user
commits = project.repository.commits(project.default_branch, nil, 3)
post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}")
end
protected
def create_push_event
Event.create(
project: project,
action: Event::PUSHED,
data: push_data,
author_id: push_data[:user_id]
)
end
# Produce a hash of post-receive data
#
# data = {
# before: String,
# after: String,
# ref: String,
# user_id: String,
# user_name: String,
# repository: {
# name: String,
# url: String,
# description: String,
# homepage: String,
# },
# commits: Array,
# total_commits_count: Fixnum
# }
#
def post_receive_data(oldrev, newrev, ref)
push_commits = project.repository.commits_between(oldrev, newrev)
# Total commits count
push_commits_count = push_commits.size
# Get latest 20 commits ASC
push_commits_limited = push_commits.last(20)
# Hash to be passed as post_receive_data
data = {
before: oldrev,
after: newrev,
ref: ref,
user_id: user.id,
user_name: user.name,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url,
},
commits: [],
total_commits_count: push_commits_count
}
# For perfomance purposes maximum 20 latest commits
# will be passed as post receive hook data.
#
push_commits_limited.each do |commit|
data[:commits] << {
id: commit.id,
message: commit.safe_message,
timestamp: commit.date.xmlschema,
url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{commit.id}",
author: {
name: commit.author_name,
email: commit.author_email
}
}
end
data
end
def push_to_branch? ref, oldrev
ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits)
!(ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000")
end
end

View File

@ -0,0 +1,34 @@
# ProjectTransferService class
#
# Used for transfer project to another namespace
#
class ProjectTransferService
attr_accessor :project
def transfer(project, new_namespace)
Project.transaction do
old_namespace = project.namespace
project.namespace = new_namespace
old_dir = old_namespace.try(:path) || ''
new_dir = new_namespace.try(:path) || ''
old_repo = if old_dir.present?
File.join(old_dir, project.path)
else
project.path
end
if Project.where(path: project.path, namespace_id: new_namespace.try(:id)).present?
raise TransferError.new("Project with same path in target namespace already exists")
end
Gitlab::ProjectMover.new(project, old_dir, new_dir).execute
save!
end
rescue Gitlab::ProjectMover::ProjectMoveError => ex
raise Project::TransferError.new(ex.message)
end
end

View File

@ -0,0 +1,59 @@
class SystemHooksService
def self.execute_hooks_for(model, event)
execute_hooks(build_event_data(model, event))
end
private
def self.execute_hooks(data)
SystemHook.all.each do |sh|
async_execute_hook sh, data
end
end
def self.async_execute_hook(hook, data)
Sidekiq::Client.enqueue(SystemHookWorker, hook.id, data)
end
def self.build_event_data(model, event)
data = {
event_name: build_event_name(model, event),
created_at: model.created_at
}
case model
when Project
data.merge!({
name: model.name,
path: model.path,
project_id: model.id,
owner_name: model.owner.name,
owner_email: model.owner.email
})
when User
data.merge!({
name: model.name,
email: model.email
})
when UsersProject
data.merge!({
project_name: model.project.name,
project_path: model.project.path,
project_id: model.project_id,
user_name: model.user.name,
user_email: model.user.email,
project_access: model.repo_access_human
})
end
end
def self.build_event_name(model, event)
case model
when UsersProject
return "user_add_to_team" if event == :create
return "user_remove_from_team" if event == :destroy
else
"#{model.class.name.downcase}_#{event.to_s}"
end
end
end

View File

@ -17,7 +17,7 @@
= link_to_project project
%ul.well-list.issues_table
- group[1].each do |issue|
= render(partial: 'issues/show', locals: {issue: issue})
= render issue
%hr
= paginate @issues, theme: "gitlab"
- else

View File

@ -16,7 +16,7 @@
= link_to_project project
%ul.well-list.issues_table
- group[1].each do |issue|
= render(partial: 'issues/show', locals: {issue: issue})
= render issue
%hr
= paginate @issues, theme: "gitlab"
- else

View File

@ -1,5 +1,4 @@
- @issues.each do |issue|
= render(partial: 'issues/show', locals: {issue: issue})
= render @issues
- if @issues.present?
%li.bottom

View File

@ -6,12 +6,12 @@
= @issue.created_at.stamp("Aug 21, 2011")
%span.pull-right
- if can?(current_user, :admin_project, @project) || @issue.author == current_user
- 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"
- 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"
- if can?(current_user, :admin_project, @project) || @issue.author == current_user
= link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do
%i.icon-edit
Edit
@ -55,5 +55,11 @@
= preserve do
= markdown @issue.description
- 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"
- 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"
.voting_notes#notes= render "notes/notes_with_form"

View File

@ -29,10 +29,10 @@
$(function(){
merge_request = new MergeRequest({
url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}",
check_enable: #{@merge_request.merge_status == MergeRequest::UNCHECKED ? "true" : "false"},
check_enable: #{@merge_request.unchecked? ? "true" : "false"},
url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}",
ci_enable: #{@project.gitlab_ci? ? "true" : "false"},
current_status: "#{@merge_request.human_merge_status}",
current_status: "#{@merge_request.merge_status_name}",
action: "#{controller.action_name}"
});
});

View File

@ -9,7 +9,7 @@
%br/
.content
%table
- each_diff_line(diff, note.diff_file_index) do |line, type, line_code, line_new, line_old|
- each_diff_line_near(diff, note.diff_file_index, note.line_code) do |line, type, line_code, line_new, line_old|
%tr.line_holder{ id: line_code }
- if type == "match"
%td.old_line= "..."
@ -22,4 +22,3 @@
- if line_code == note.line_code
= render "notes/diff_notes_with_reply", notes: discussion_notes
- break # cut off diff after notes

View File

@ -22,6 +22,8 @@
.note-form-actions
.buttons
= f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button"
= yield(:note_actions)
%a.btn.grouped.js-close-discussion-note-form Cancel
.note-form-option

View File

@ -9,7 +9,7 @@
%fieldset
%fieldset.update-token
%legend
Private token
%span.cred.pull-right
@ -29,7 +29,7 @@
%span You don`t have one yet. Click generate to fix it.
= f.submit 'Generate', class: "btn success btn-build-token"
%fieldset
%fieldset.update-password
%legend Password
= form_for @user, url: update_password_profile_path, method: :put do |f|
.padded

View File

@ -4,7 +4,7 @@
= @snippet.title
%small= @snippet.file_name
- if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user
= link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right"
= link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right", title: 'Edit Snippet'
%br
%div= render 'blob'

View File

@ -16,7 +16,7 @@
= link_to_project @project
%ul.well-list.issues_table
- group[1].each do |issue|
= render(partial: 'issues/show', locals: {issue: issue})
= render issue
%hr
= paginate @issues, theme: "gitlab"
- else

View File

@ -26,5 +26,5 @@
- elsif user.blocked
%span.btn.disabled.blocked Blocked
- elsif allow_admin
= link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do
= link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do
%i.icon-minus.icon-white

View File

@ -42,6 +42,6 @@ class PostReceive
return false
end
project.trigger_post_receive(oldrev, newrev, ref, user)
GitPushService.new.execute(project, user, oldrev, newrev, ref)
end
end

View File

@ -1,16 +1,16 @@
class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration
def up
MergeRequest.transaction do
MergeRequest.where("closed = 1 AND merged = 1").update_all("state = 'merged'")
MergeRequest.where("closed = 1 AND merged = 0").update_all("state = 'closed'")
MergeRequest.where("closed = 0").update_all("state = 'opened'")
MergeRequest.where(closed: true, merged: true).update_all("state = 'merged'")
MergeRequest.where(closed: true, merged: true).update_all("state = 'closed'")
MergeRequest.where(closed: false).update_all("state = 'opened'")
end
end
def down
MergeRequest.transaction do
MergeRequest.where(state: :closed).update_all("closed = 1")
MergeRequest.where(state: :merged).update_all("closed = 1, merged = 1")
MergeRequest.where(state: :closed).update_all(closed: true)
MergeRequest.where(state: :merged).update_all(closed: true, merged: true)
end
end
end

View File

@ -0,0 +1,5 @@
class AddNewMergeStatusToMergeRequest < ActiveRecord::Migration
def change
add_column :merge_requests, :new_merge_status, :string
end
end

View File

@ -0,0 +1,17 @@
class ConvertMergeStatusInMergeRequest < ActiveRecord::Migration
def up
MergeRequest.transaction do
MergeRequest.where(merge_status: 1).update_all("new_merge_status = 'unchecked'")
MergeRequest.where(merge_status: 2).update_all("new_merge_status = 'can_be_merged'")
MergeRequest.where(merge_status: 3).update_all("new_merge_status = 'cannot_be_merged'")
end
end
def down
MergeRequest.transaction do
MergeRequest.where(new_merge_status: :unchecked).update_all("merge_status = 1")
MergeRequest.where(new_merge_status: :can_be_merged).update_all("merge_status = 2")
MergeRequest.where(new_merge_status: :cannot_be_merged).update_all("merge_status = 3")
end
end
end

View File

@ -0,0 +1,9 @@
class RemoveMergeStatusFromMergeRequest < ActiveRecord::Migration
def up
remove_column :merge_requests, :merge_status
end
def down
add_column :merge_requests, :merge_status, :integer
end
end

View File

@ -0,0 +1,5 @@
class RenameNewMergeStatusToMergeStatusInMilestone < ActiveRecord::Migration
def change
rename_column :merge_requests, :new_merge_status, :merge_status
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130218141554) do
ActiveRecord::Schema.define(:version => 20130220133245) do
create_table "events", :force => true do |t|
t.string "target_type"
@ -68,19 +68,19 @@ ActiveRecord::Schema.define(:version => 20130218141554) do
add_index "keys", ["user_id"], :name => "index_keys_on_user_id"
create_table "merge_requests", :force => true do |t|
t.string "target_branch", :null => false
t.string "source_branch", :null => false
t.integer "project_id", :null => false
t.string "target_branch", :null => false
t.string "source_branch", :null => false
t.integer "project_id", :null => false
t.integer "author_id"
t.integer "assignee_id"
t.string "title"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.text "st_commits", :limit => 2147483647
t.text "st_diffs", :limit => 2147483647
t.integer "merge_status", :default => 1, :null => false
t.integer "milestone_id"
t.string "state"
t.string "merge_status"
end
add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id"
@ -106,11 +106,11 @@ ActiveRecord::Schema.define(:version => 20130218141554) do
add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id"
create_table "namespaces", :force => true do |t|
t.string "name", :null => false
t.string "path", :null => false
t.integer "owner_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "name", :null => false
t.string "path", :null => false
t.integer "owner_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "type"
end
@ -142,16 +142,16 @@ ActiveRecord::Schema.define(:version => 20130218141554) do
t.string "name"
t.string "path"
t.text "description"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "creator_id"
t.string "default_branch"
t.boolean "issues_enabled", :default => true, :null => false
t.boolean "wall_enabled", :default => true, :null => false
t.boolean "merge_requests_enabled", :default => true, :null => false
t.boolean "wiki_enabled", :default => true, :null => false
t.boolean "issues_enabled", :default => true, :null => false
t.boolean "wall_enabled", :default => true, :null => false
t.boolean "merge_requests_enabled", :default => true, :null => false
t.boolean "wiki_enabled", :default => true, :null => false
t.integer "namespace_id"
t.boolean "public", :default => false, :null => false
t.boolean "public", :default => false, :null => false
end
add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id"
@ -230,8 +230,8 @@ ActiveRecord::Schema.define(:version => 20130218141554) do
t.string "name"
t.string "path"
t.integer "owner_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true do |t|

View File

@ -31,7 +31,6 @@ Dumping database tables:
- Dumping table wikis... [DONE]
Dumping repositories:
- Dumping repository abcd... [DONE]
- Dumping repository gitolite-admin.git... [DONE]
Creating backup archive: $TIMESTAMP_gitlab_backup.tar [DONE]
Deleting tmp directories...[DONE]
Deleting old backups... [SKIPPING]
@ -77,6 +76,5 @@ Restoring database tables:
- Loading fixture wikis...[SKIPPING]
Restoring repositories:
- Restoring repository abcd... [DONE]
- Restoring repository gitolite-admin.git... [DONE]
Deleting tmp directories...[DONE]
```

View File

@ -1,10 +1,4 @@
### Remove grabage from gitolite config and filesystem. Important! Data loss!
Remove projects from gitolite config if they dont exist in GitLab database
```
bundle exec rake gitlab:cleanup:config RAILS_ENV=production
```
### Remove grabage from filesystem. Important! Data loss!
Remove namespaces(dirs) from /home/git/repositories if they dont exist in GitLab database

View File

@ -17,12 +17,12 @@ bundle exec rake gitlab:enable_namespaces RAILS_ENV=production
```
### Enable auto merge
### Rebuild project satellites
This command will enable the auto merge feature. After this you will be able to **merge a merge request** via GitLab and use the **online editor**.
This command will build missing satellites for projects. After this you will be able to **merge a merge request** via GitLab and use the **online editor**.
```
bundle exec rake gitlab:enable_automerge RAILS_ENV=production
bundle exec rake gitlab:satellites:create RAILS_ENV=production
```
Example output:

View File

@ -31,12 +31,10 @@ SSH Clone URL: git@localhost:some-project.git
Using LDAP: no
Using Omniauth: no
Gitolite information
Version: v3.04-4-g4524f01
Admin URI: git@localhost:gitolite-admin
Admin Key: gitlab
GitLab Shell
Version: 1.0.4
Repositories: /home/git/repositories/
Hooks: /home/git/.gitolite/hooks/
Hooks: /home/git/gitlab-shell/hooks/
Git: /usr/bin/git
```
@ -46,8 +44,8 @@ Git: /usr/bin/git
Runs the following rake tasks:
* gitlab:env:check
* gitlab:gitolite:check
* gitlab:resque:check
* gitlab:gitlab_shell:check
* gitlab:sidekiq:check
* gitlab:app:check
It will check that each component was setup according to the installation guide and suggest fixes for issues found.
@ -74,16 +72,12 @@ Checking Environment ... Finished
Checking Gitolite ...
Using recommended version ... yes
Repo umask is 0007 in .gitolite.rc? ... yes
Allow all Git config keys in .gitolite.rc ... yes
Config directory exists? ... yes
Config directory owned by git:git? ... yes
Config directory access is drwxr-x---? ... yes
Repo base directory exists? ... yes
Repo base owned by git:git? ... yes
Repo base access is drwxrws---? ... yes
Can clone gitolite-admin? ... yes
Can commit to gitolite-admin? ... yes
post-receive hook exists? ... yes
post-receive hook up-to-date? ... yes
post-receive hooks in repos are links: ...
@ -135,24 +129,6 @@ If necessary, remove the `tmp/repo_satellites` directory and rerun the command b
bundle exec rake gitlab:satellites:create RAILS_ENV=production
```
### Rebuild each key at gitolite config
This will send all users ssh public keys to gitolite and grant them access (based on their permission) to their projects.
```
bundle exec rake gitlab:gitolite:update_keys RAILS_ENV=production
```
### Rebuild each project at gitolite config
This makes sure that all projects are present in gitolite and can be accessed.
```
bundle exec rake gitlab:gitolite:update_repos RAILS_ENV=production
```
### Import bare repositories into GitLab project instance
Notes:

View File

@ -12,7 +12,7 @@ Feature: Project Browse files
Then I should see files from repository for "8470d70"
Scenario: I browse file content
Given I click on "Gemfile" file in repo
Given I click on "Gemfile.lock" file in repo
Then I should see it content
Scenario: I browse raw file
@ -22,6 +22,6 @@ Feature: Project Browse files
@javascript
Scenario: I can edit file
Given I click on "Gemfile" file in repo
Given I click on "Gemfile.lock" file in repo
And I click button "edit"
Then I can edit code

View File

@ -5,6 +5,6 @@ Feature: Project Browse git repo
Given I visit project source page
Scenario: I blame file
Given I click on "Gemfile" file in repo
Given I click on "Gemfile.lock" file in repo
And I click blame button
Then I should see git file blame

View File

@ -9,7 +9,7 @@ class AdminTeams < Spinach::FeatureSteps
end
And 'Create gitlab user "John"' do
@user = create(:user, :name => "John")
@user = create(:user, name: "John")
end
And 'I click new team link' do
@ -50,8 +50,8 @@ class AdminTeams < Spinach::FeatureSteps
When 'I select user "John" from user list as "Developer"' do
@user ||= User.find_by_name("John")
within "#team_members" do
select @user.name, :from => "user_ids"
select "Developer", :from => "default_project_access"
select "#{@user.name} (#{@user.email})", from: "user_ids"
select "Developer", from: "default_project_access"
end
end
@ -89,8 +89,8 @@ class AdminTeams < Spinach::FeatureSteps
When 'I select project "Shop" with max access "Reporter"' do
@project ||= Project.find_by_name("Shop")
within "#assign_projects" do
select @project.name, :from => "project_ids"
select "Reporter", :from => "greatest_project_access"
select @project.name, from: "project_ids"
select "Reporter", from: "greatest_project_access"
end
end
@ -127,8 +127,8 @@ class AdminTeams < Spinach::FeatureSteps
When 'I select user "Jimm" ub team members list as "Master"' do
user = User.find_by_name("Jimm")
within "#team_members" do
select user.name, :from => "user_ids"
select "Developer", :from => "default_project_access"
select "#{user.name} (#{user.email})", from: "user_ids"
select "Developer", from: "default_project_access"
end
end

View File

@ -23,15 +23,19 @@ class Profile < Spinach::FeatureSteps
end
Then 'I change my password' do
fill_in "user_password", :with => "222333"
fill_in "user_password_confirmation", :with => "222333"
click_button "Save"
within '.update-password' do
fill_in "user_password", :with => "222333"
fill_in "user_password_confirmation", :with => "222333"
click_button "Save"
end
end
When 'I unsuccessfully change my password' do
fill_in "user_password", with: "password"
fill_in "user_password_confirmation", with: "confirmation"
click_button "Save"
within '.update-password' do
fill_in "user_password", with: "password"
fill_in "user_password_confirmation", with: "confirmation"
click_button "Save"
end
end
Then "I should see a password error message" do
@ -43,8 +47,10 @@ class Profile < Spinach::FeatureSteps
end
Then 'I reset my token' do
@old_token = @user.private_token
click_button "Reset"
within '.update-token' do
@old_token = @user.private_token
click_button "Reset"
end
end
And 'I should see new token' do

View File

@ -16,12 +16,12 @@ class ProjectBrowseFiles < Spinach::FeatureSteps
page.should have_content "Gemfile"
end
Given 'I click on "Gemfile" file in repo' do
click_link "Gemfile"
Given 'I click on "Gemfile.lock" file in repo' do
click_link "Gemfile.lock"
end
Then 'I should see it content' do
page.should have_content "rubygems.org"
page.should have_content "DEPENDENCIES"
end
And 'I click link "raw"' do

View File

@ -3,8 +3,8 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps
include SharedProject
include SharedPaths
Given 'I click on "Gemfile" file in repo' do
click_link "Gemfile"
Given 'I click on "Gemfile.lock" file in repo' do
click_link "Gemfile.lock"
end
And 'I click blame button' do
@ -12,7 +12,7 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps
end
Then 'I should see git file blame' do
page.should have_content "rubygems.org"
page.should have_content "DEPENDENCIES"
page.should have_content "Dmitriy Zaporozhets"
page.should have_content "Moving to rails 3.2"
end

View File

@ -53,7 +53,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps
end
Given 'I click link "Sam"' do
click_link "Sam"
first(:link, "Sam").click
end
Then 'I should see "Sam" team profile' do

View File

@ -22,7 +22,7 @@ module SharedDiffNote
Given 'I leave a diff comment like "Typo, please fix"' do
find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click")
within(".file") do
within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do
fill_in "note[note]", with: "Typo, please fix"
#click_button("Add Comment")
find(".js-comment-button").trigger("click")
@ -32,7 +32,7 @@ module SharedDiffNote
Given 'I preview a diff comment text like "Should fix it :smile:"' do
find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click")
within(".file") do
within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do
fill_in "note[note]", with: "Should fix it :smile:"
find(".js-note-preview-button").trigger("click")
end
@ -40,7 +40,7 @@ module SharedDiffNote
Given 'I preview another diff comment text like "DRY this up"' do
find("#586fb7c4e1add2d4d24e27566ed7064680098646_57_41.line_holder .js-add-diff-note-button").trigger("click")
within(".file") do
within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_57_41']") do
fill_in "note[note]", with: "DRY this up"
find(".js-note-preview-button").trigger("click")
end

View File

@ -173,12 +173,10 @@ module SharedPaths
# ----------------------------------------
And 'I visit project "Shop" page' do
project = Project.find_by_name("Shop")
visit project_path(project)
end
When 'I visit edit project "Shop" page' do
project = Project.find_by_name("Shop")
visit edit_project_path(project)
end
@ -219,7 +217,7 @@ module SharedPaths
end
And 'I visit project "Shop" issues page' do
visit project_issues_path(Project.find_by_name("Shop"))
visit project_issues_path(project)
end
Given 'I visit issue page "Release 0.4"' do
@ -228,7 +226,7 @@ module SharedPaths
end
Given 'I visit project "Shop" labels page' do
visit project_labels_path(Project.find_by_name("Shop"))
visit project_labels_path(project)
end
Given 'I visit merge request page "Bug NS-04"' do
@ -242,20 +240,18 @@ module SharedPaths
end
And 'I visit project "Shop" merge requests page' do
visit project_merge_requests_path(Project.find_by_name("Shop"))
visit project_merge_requests_path(project)
end
Given 'I visit project "Shop" milestones page' do
@project = Project.find_by_name("Shop")
visit project_milestones_path(@project)
visit project_milestones_path(project)
end
Then 'I visit project "Shop" team page' do
visit project_team_index_path(Project.find_by_name("Shop"))
visit project_team_index_path(project)
end
Then 'I visit project "Shop" wall page' do
project = Project.find_by_name("Shop")
visit wall_project_path(project)
end
@ -266,4 +262,8 @@ module SharedPaths
def root_ref
@project.repository.root_ref
end
def project
project = Project.find_by_name!("Shop")
end
end

View File

@ -177,8 +177,8 @@ class Userteams < Spinach::FeatureSteps
And 'I select user "John" from list with role "Reporter"' do
user = User.find_by_name("John")
within "#team_members" do
select user.name, :from => "user_ids"
select "Reporter", :from => "default_project_access"
select "#{user.name} (#{user.email})", from: "user_ids"
select "Reporter", from: "default_project_access"
end
click_button "Add"
end
@ -213,8 +213,8 @@ class Userteams < Spinach::FeatureSteps
When 'I submit form with selected project and max access' do
within "#assign_projects" do
select @project.name_with_namespace, :from => "project_ids"
select "Reporter", :from => "greatest_project_access"
select @project.name_with_namespace, from: "project_ids"
select "Reporter", from: "greatest_project_access"
end
click_button "Add"
end

View File

@ -5,6 +5,12 @@ module Gitlab
#
# Check if ssh key has access to project code
#
# Params:
# key_id - SSH Key id
# project - project path with namespace
# action - git action (git-upload-pack or git-receive-pack)
# ref - branch name
#
get "/allowed" do
key = Key.find(params[:key_id])
project = Project.find_with_namespace(params[:project])

View File

@ -255,7 +255,6 @@ namespace :gitlab do
warn_user_is_not_gitlab
start_checking "Environment"
check_issue_1059_shell_profile_error
check_gitlab_git_config
check_python2_exists
check_python2_version
@ -294,30 +293,6 @@ namespace :gitlab do
end
end
# see https://github.com/gitlabhq/gitlabhq/issues/1059
def check_issue_1059_shell_profile_error
gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user
print "Has no \"-e\" in ~#{gitlab_shell_ssh_user}/.profile ... "
profile_file = File.join(gitlab_shell_user_home, ".profile")
unless File.read(profile_file) =~ /^-e PATH/
puts "yes".green
else
puts "no".red
try_fixing_it(
"Open #{profile_file}",
"Find the line starting with \"-e PATH\"",
"Remove \"-e \" so the line starts with PATH"
)
for_more_information(
see_installation_guide_section("Gitlab Shell"),
"https://github.com/gitlabhq/gitlabhq/issues/1059"
)
fix_and_rerun
end
end
def check_python2_exists
print "Has python2? ... "

View File

@ -82,7 +82,6 @@ describe "Admin::Users" do
it "should have user info" do
page.should have_content(@user.email)
page.should have_content(@user.name)
page.should have_content(@user.projects_limit)
end
end

View File

@ -169,32 +169,40 @@ describe "Gitlab Flavored Markdown" do
describe "for notes" do
it "should render in commits#show", js: true do
visit project_commit_path(project, commit)
fill_in "note_note", with: "see ##{issue.id}"
click_button "Add Comment"
within ".new_note.js-main-target-form" do
fill_in "note_note", with: "see ##{issue.id}"
click_button "Add Comment"
end
page.should have_link("##{issue.id}")
end
it "should render in issue#show", js: true do
visit project_issue_path(project, issue)
fill_in "note_note", with: "see ##{issue.id}"
click_button "Add Comment"
within ".new_note.js-main-target-form" do
fill_in "note_note", with: "see ##{issue.id}"
click_button "Add Comment"
end
page.should have_link("##{issue.id}")
end
it "should render in merge_request#show", js: true do
visit project_merge_request_path(project, merge_request)
fill_in "note_note", with: "see ##{issue.id}"
click_button "Add Comment"
within ".new_note.js-main-target-form" do
fill_in "note_note", with: "see ##{issue.id}"
click_button "Add Comment"
end
page.should have_link("##{issue.id}")
end
it "should render in projects#wall", js: true do
visit wall_project_path(project)
fill_in "note_note", with: "see ##{issue.id}"
click_button "Add Comment"
within ".new_note.js-main-target-form" do
fill_in "note_note", with: "see ##{issue.id}"
click_button "Add Comment"
end
page.should have_link("##{issue.id}")
end

View File

@ -18,7 +18,7 @@ describe "On a merge request", js: true do
it { should have_css(".js-main-target-form", visible: true, count: 1) }
# button initalization
it { within(".js-main-target-form") { should have_button("Add Comment") } }
it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" }
it { within(".js-main-target-form") { should_not have_link("Cancel") } }
# notifiactions
@ -67,7 +67,7 @@ describe "On a merge request", js: true do
end
# note added
it { within(".js-main-target-form") { should have_content("This is awsome!") } }
it { should have_content("This is awsome!") }
# reset form
it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } }
@ -97,7 +97,9 @@ describe "On a merge request diff", js: true, focus: true do
visit diffs_project_merge_request_path(project, merge_request)
click_link("Diff")
within '.diffs-tab' do
click_link("Diff")
end
end
subject { page }
@ -134,7 +136,9 @@ describe "On a merge request diff", js: true, focus: true do
end
it "should be removed when canceled" do
find(".js-close-discussion-note-form").trigger("click")
within(".file form[rel$='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185']") do
find(".js-close-discussion-note-form").trigger("click")
end
should have_no_css(".js-temp-notes-holder")
end

View File

@ -17,7 +17,7 @@ describe "On the project wall", js: true do
it { should have_css(".js-main-target-form", visible: true, count: 1) }
# button initalization
it { within(".js-main-target-form") { should have_button("Add Comment") } }
it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" }
it { within(".js-main-target-form") { should_not have_link("Cancel") } }
# notifiactions
@ -66,7 +66,7 @@ describe "On the project wall", js: true do
end
# note added
it { within(".js-main-target-form") { should have_content("This is awsome!") } }
it { should have_content("This is awsome!") }
# reset form
it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } }

View File

@ -6,8 +6,11 @@ describe "Search" do
@project = create(:project)
@project.team << [@user, :reporter]
visit search_path
fill_in "search", with: @project.name[0..3]
click_button "Search"
within '.search-holder' do
fill_in "search", with: @project.name[0..3]
click_button "Search"
end
end
it "should show project in search results" do

View File

@ -72,7 +72,7 @@ describe "Snippets" do
author: @user,
project: project)
visit project_snippet_path(project, @snippet)
click_link "Edit"
click_link "Edit Snippet"
end
it "should open edit page" do

View File

@ -0,0 +1,19 @@
require 'spec_helper'
describe 'Users' do
describe "GET /users/sign_up" do
before do
Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
end
it "should create a new user account" do
visit new_user_registration_path
fill_in "user_name", with: "Name Surname"
fill_in "user_username", with: "Great"
fill_in "user_email", with: "name@mail.com"
fill_in "user_password", with: "password1234"
fill_in "user_password_confirmation", with: "password1234"
expect { click_button "Sign up" }.to change {User.count}.by(1)
end
end
end

29
spec/lib/popen_spec.rb Normal file
View File

@ -0,0 +1,29 @@
require 'spec_helper'
describe 'Gitlab::Popen', no_db: true do
let (:path) { Rails.root.join('tmp').to_s }
before do
@klass = Class.new(Object)
@klass.send(:include, Gitlab::Popen)
end
context 'zero status' do
before do
@output, @status = @klass.new.popen('ls', path)
end
it { @status.should be_zero }
it { @output.should include('cache') }
end
context 'non-zero status' do
before do
@output, @status = @klass.new.popen('cat NOTHING', path)
end
it { @status.should == 1 }
it { @output.should include('No such file or directory') }
end
end

View File

@ -32,6 +32,12 @@ describe MergeRequest do
it { should_not allow_mass_assignment_of(:project_id) }
end
describe "Respond to" do
it { should respond_to(:unchecked?) }
it { should respond_to(:can_be_merged?) }
it { should respond_to(:cannot_be_merged?) }
end
describe 'modules' do
it { should include_module(Issuable) }
end

View File

@ -1,128 +0,0 @@
require 'spec_helper'
describe Project, "Hooks" do
let(:project) { create(:project) }
before do
@key = create(:key, user: project.owner)
@user = @key.user
@key_id = @key.identifier
end
describe "Post Receive Event" do
it "should create push event" do
oldrev, newrev, ref = '00000000000000000000000000000000', 'newrev', 'refs/heads/master'
data = project.post_receive_data(oldrev, newrev, ref, @user)
project.observe_push(data)
event = Event.last
event.should_not be_nil
event.project.should == project
event.action.should == Event::PUSHED
event.data.should == data
end
end
describe "Project hooks" do
context "with no web hooks" do
it "raises no errors" do
lambda {
project.execute_hooks({})
}.should_not raise_error
end
end
context "with web hooks" do
before do
@project_hook = create(:project_hook)
@project_hook_2 = create(:project_hook)
project.hooks << [@project_hook, @project_hook_2]
stub_request(:post, @project_hook.url)
stub_request(:post, @project_hook_2.url)
end
it "executes multiple web hook" do
@project_hook.should_receive(:async_execute).once
@project_hook_2.should_receive(:async_execute).once
project.trigger_post_receive('oldrev', 'newrev', 'refs/heads/master', @user)
end
end
context "does not execute web hooks" do
before do
@project_hook = create(:project_hook)
project.hooks << [@project_hook]
end
it "when pushing a branch for the first time" do
@project_hook.should_not_receive(:execute)
project.trigger_post_receive('00000000000000000000000000000000', 'newrev', 'refs/heads/master', @user)
end
it "when pushing tags" do
@project_hook.should_not_receive(:execute)
project.trigger_post_receive('oldrev', 'newrev', 'refs/tags/v1.0.0', @user)
end
end
context "when pushing new branches" do
end
context "when gathering commit data" do
before do
@oldrev, @newrev, @ref = project.repository.fresh_commits(2).last.sha,
project.repository.fresh_commits(2).first.sha, 'refs/heads/master'
@commit = project.repository.fresh_commits(2).first
# Fill nil/empty attributes
project.description = "This is a description"
@data = project.post_receive_data(@oldrev, @newrev, @ref, @user)
end
subject { @data }
it { should include(before: @oldrev) }
it { should include(after: @newrev) }
it { should include(ref: @ref) }
it { should include(user_id: project.owner.id) }
it { should include(user_name: project.owner.name) }
context "with repository data" do
subject { @data[:repository] }
it { should include(name: project.name) }
it { should include(url: project.url_to_repo) }
it { should include(description: project.description) }
it { should include(homepage: project.web_url) }
end
context "with commits" do
subject { @data[:commits] }
it { should be_an(Array) }
it { should have(1).element }
context "the commit" do
subject { @data[:commits].first }
it { should include(id: @commit.id) }
it { should include(message: @commit.safe_message) }
it { should include(timestamp: @commit.date.xmlschema) }
it { should include(url: "#{Gitlab.config.gitlab.url}/#{project.code}/commit/#{@commit.id}") }
context "with a author" do
subject { @data[:commits].first[:author] }
it { should include(name: @commit.author_name) }
it { should include(email: @commit.author_email) }
end
end
end
end
end
end

View File

@ -72,11 +72,8 @@ describe Project do
it { should respond_to(:url_to_repo) }
it { should respond_to(:repo_exists?) }
it { should respond_to(:satellite) }
it { should respond_to(:observe_push) }
it { should respond_to(:update_merge_requests) }
it { should respond_to(:execute_hooks) }
it { should respond_to(:post_receive_data) }
it { should respond_to(:trigger_post_receive) }
it { should respond_to(:transfer) }
it { should respond_to(:name_with_namespace) }
it { should respond_to(:namespace_owner) }

View File

@ -10,9 +10,6 @@ describe ProjectTeam do
it { should respond_to(:masters) }
it { should respond_to(:reporters) }
it { should respond_to(:guests) }
it { should respond_to(:repository_writers) }
it { should respond_to(:repository_masters) }
it { should respond_to(:repository_readers) }
end
end

View File

@ -69,28 +69,10 @@ describe User do
describe "Respond to" do
it { should respond_to(:is_admin?) }
it { should respond_to(:identifier) }
it { should respond_to(:name) }
it { should respond_to(:private_token) }
end
describe '#identifier' do
it "should return valid identifier" do
user = build(:user, email: "test@mail.com")
user.identifier.should == "test_mail_com"
end
it "should return identifier without + sign" do
user = build(:user, email: "test+foo@mail.com")
user.identifier.should == "test_foo_mail_com"
end
it "should conform to Gitolite's required identifier pattern" do
user = build(:user, email: "_test@example.com")
user.identifier.should == 'test_example_com'
end
end
describe '#generate_password' do
it "should execute callback when force_random_password specified" do
user = build(:user, force_random_password: true)

View File

@ -0,0 +1,103 @@
require 'spec_helper'
describe Gitlab::API do
include ApiHelpers
let(:user) { create(:user) }
let(:key) { create(:key, user: user) }
let(:project) { create(:project) }
describe "GET /internal/check", no_db: true do
it do
get api("/internal/check")
response.status.should == 200
json_response['api_version'].should == Gitlab::API.version
end
end
describe "GET /internal/discover" do
it do
get(api("/internal/discover"), key_id: key.id)
response.status.should == 200
json_response['email'].should == user.email
end
end
describe "GET /internal/allowed" do
context "access granted" do
before do
project.team << [user, :developer]
end
context "git pull" do
it do
get(
api("/internal/allowed"),
ref: 'master',
key_id: key.id,
project: project.path_with_namespace,
action: 'git-upload-pack'
)
response.status.should == 200
response.body.should == 'true'
end
end
context "git push" do
it do
get(
api("/internal/allowed"),
ref: 'master',
key_id: key.id,
project: project.path_with_namespace,
action: 'git-receive-pack'
)
response.status.should == 200
response.body.should == 'true'
end
end
end
context "access denied" do
before do
project.team << [user, :guest]
end
context "git pull" do
it do
get(
api("/internal/allowed"),
ref: 'master',
key_id: key.id,
project: project.path_with_namespace,
action: 'git-upload-pack'
)
response.status.should == 200
response.body.should == 'false'
end
end
context "git push" do
it do
get(
api("/internal/allowed"),
ref: 'master',
key_id: key.id,
project: project.path_with_namespace,
action: 'git-receive-pack'
)
response.status.should == 200
response.body.should == 'false'
end
end
end
end
end

View File

@ -97,32 +97,27 @@ describe Gitlab::API do
end
describe "GET /users/sign_up" do
before do
Gitlab.config.gitlab.stub(:signup_enabled).and_return(false)
end
it "should redirect to sign in page if signup is disabled" do
get "/users/sign_up"
response.status.should == 302
response.should redirect_to(new_user_session_path)
end
end
context 'enabled' do
before do
Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
end
describe "GET /users/sign_up" do
before do
Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
it "should return sign up page if signup is enabled" do
get "/users/sign_up"
response.status.should == 200
end
end
it "should return sign up page if signup is enabled" do
get "/users/sign_up"
response.status.should == 200
end
it "should create a new user account" do
visit new_user_registration_path
fill_in "user_name", with: "Name Surname"
fill_in "user_username", with: "Great"
fill_in "user_email", with: "name@mail.com"
fill_in "user_password", with: "password1234"
fill_in "user_password_confirmation", with: "password1234"
expect { click_button "Sign up" }.to change {User.count}.by(1)
context 'disabled' do
before do
Gitlab.config.gitlab.stub(:signup_enabled).and_return(false)
end
it "should redirect to sign in page if signup is disabled" do
get "/users/sign_up"
response.status.should == 302
response.should redirect_to(new_user_session_path)
end
end
end

View File

@ -0,0 +1,111 @@
require 'spec_helper'
describe GitPushService do
let (:user) { create :user }
let (:project) { create :project }
let (:service) { GitPushService.new }
before do
@oldrev = 'b98a310def241a6fd9c9a9a3e7934c48e498fe81'
@newrev = 'b19a04f53caeebf4fe5ec2327cb83e9253dc91bb'
@ref = 'refs/heads/master'
end
describe "Git Push Data" do
before do
service.execute(project, user, @oldrev, @newrev, @ref)
@push_data = service.push_data
@commit = project.repository.commit(@newrev)
end
subject { @push_data }
it { should include(before: @oldrev) }
it { should include(after: @newrev) }
it { should include(ref: @ref) }
it { should include(user_id: user.id) }
it { should include(user_name: user.name) }
context "with repository data" do
subject { @push_data[:repository] }
it { should include(name: project.name) }
it { should include(url: project.url_to_repo) }
it { should include(description: project.description) }
it { should include(homepage: project.web_url) }
end
context "with commits" do
subject { @push_data[:commits] }
it { should be_an(Array) }
it { should have(1).element }
context "the commit" do
subject { @push_data[:commits].first }
it { should include(id: @commit.id) }
it { should include(message: @commit.safe_message) }
it { should include(timestamp: @commit.date.xmlschema) }
it { should include(url: "#{Gitlab.config.gitlab.url}/#{project.code}/commit/#{@commit.id}") }
context "with a author" do
subject { @push_data[:commits].first[:author] }
it { should include(name: @commit.author_name) }
it { should include(email: @commit.author_email) }
end
end
end
end
describe "Push Event" do
before do
service.execute(project, user, @oldrev, @newrev, @ref)
@event = Event.last
end
it { @event.should_not be_nil }
it { @event.project.should == project }
it { @event.action.should == Event::PUSHED }
it { @event.data.should == service.push_data }
end
describe "Web Hooks" do
context "with web hooks" do
before do
@project_hook = create(:project_hook)
@project_hook_2 = create(:project_hook)
project.hooks << [@project_hook, @project_hook_2]
stub_request(:post, @project_hook.url)
stub_request(:post, @project_hook_2.url)
end
it "executes multiple web hook" do
@project_hook.should_receive(:async_execute).once
@project_hook_2.should_receive(:async_execute).once
service.execute(project, user, @oldrev, @newrev, @ref)
end
end
context "does not execute web hooks" do
before do
@project_hook = create(:project_hook)
project.hooks << [@project_hook]
end
it "when pushing a branch for the first time" do
@project_hook.should_not_receive(:execute)
service.execute(project, user, '00000000000000000000000000000000', 'newrev', 'refs/heads/master')
end
it "when pushing tags" do
@project_hook.should_not_receive(:execute)
service.execute(project, user, 'newrev', 'newrev', 'refs/tags/v1.0.0')
end
end
end
end

View File

@ -0,0 +1,41 @@
require 'spec_helper'
describe SystemHooksService do
let (:user) { create :user }
let (:project) { create :project }
let (:users_project) { create :users_project }
context 'it should build event data' do
it 'should build event data for user' do
SystemHooksService.build_event_data(user, :create).should include(:event_name, :name, :created_at, :email)
end
it 'should build event data for project' do
SystemHooksService.build_event_data(project, :create).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email)
end
it 'should build event data for users project' do
SystemHooksService.build_event_data(users_project, :create).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :project_access)
end
end
context 'it should build event names' do
it 'should build event names for user' do
SystemHooksService.build_event_name(user, :create).should eq "user_create"
SystemHooksService.build_event_name(user, :destroy).should eq "user_destroy"
end
it 'should build event names for project' do
SystemHooksService.build_event_name(project, :create).should eq "project_create"
SystemHooksService.build_event_name(project, :destroy).should eq "project_destroy"
end
it 'should build event names for users project' do
SystemHooksService.build_event_name(users_project, :create).should eq "user_add_to_team"
SystemHooksService.build_event_name(users_project, :destroy).should eq "user_remove_from_team"
end
end
end

View File

@ -10,19 +10,19 @@ require 'capybara/rspec'
require 'webmock/rspec'
require 'email_spec'
require 'sidekiq/testing/inline'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
WebMock.disable_net_connect!(allow_localhost: true)
RSpec.configure do |config|
config.mock_with :rspec
config.include LoginHelpers, type: :feature
config.include LoginHelpers, type: :request
config.include FactoryGirl::Syntax::Methods
config.include Devise::TestHelpers, type: :controller

View File

@ -9,10 +9,14 @@ RSpec.configure do |config|
DatabaseCleaner.strategy = :transaction
end
DatabaseCleaner.start
unless example.metadata[:no_db]
DatabaseCleaner.start
end
end
config.after do
DatabaseCleaner.clean
unless example.metadata[:no_db]
DatabaseCleaner.clean
end
end
end

View File

@ -1,5 +1,6 @@
require "repository"
require "project"
require "merge_request"
require "shell"
# Stubs out all Git repository access done by models so that specs can run
@ -32,6 +33,12 @@ class Project
end
end
class MergeRequest
def check_if_can_be_merged
true
end
end
class GitLabTestRepo < Repository
def repo
@repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq'))

View File

@ -21,7 +21,6 @@ describe PostReceive do
it "does not run if the author is not in the project" do
Key.stub(find_by_id: nil)
project.should_not_receive(:observe_push)
project.should_not_receive(:execute_hooks)
PostReceive.new.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id).should be_false
@ -32,7 +31,6 @@ describe PostReceive do
project.should_receive(:execute_hooks)
project.should_receive(:execute_services)
project.should_receive(:update_merge_requests)
project.should_receive(:observe_push)
PostReceive.new.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id)
end