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

Merge remote-tracking branch 'origin/master' into backup_restore_drop_sequences

Conflicts:
	CHANGELOG
parents 8146271d c58edd7c
...@@ -4,8 +4,18 @@ v 7.5.0 ...@@ -4,8 +4,18 @@ v 7.5.0
- Fix LDAP authentication for Git HTTP access - Fix LDAP authentication for Git HTTP access
- Fix LDAP config lookup for provider 'ldap' - Fix LDAP config lookup for provider 'ldap'
- Drop all sequences during Postgres database restore - Drop all sequences during Postgres database restore
- Project title links to project homepage (Ben Bodenmiller)
- Add Atlassian Bamboo CI service (Drew Blessing) - Add Atlassian Bamboo CI service (Drew Blessing)
- Mentioned @user will receive email even if he is not participating in issue or commit - Mentioned @user will receive email even if he is not participating in issue or commit
- Session API: Use case-insensitive authentication like in UI (Andrey Krivko)
- Tie up loose ends with annotated tags: API & UI (Sean Edge)
- Return valid json for deleting branch via API (sponsored by O'Reilly Media)
- Expose username in project events API (sponsored by O'Reilly Media)
v 7.4.3
- Fix raw snippets view
- Fix security issue for member api
- Fix buildbox integration
v 7.4.2 v 7.4.2
- Fix internal snippet exposing for unauthenticated users - Fix internal snippet exposing for unauthenticated users
...@@ -50,7 +60,7 @@ v 7.4.0 ...@@ -50,7 +60,7 @@ v 7.4.0
- Fix ambiguous sha problem with mentioned commit - Fix ambiguous sha problem with mentioned commit
- Fixed bug with apostrophe when at mentioning users - Fixed bug with apostrophe when at mentioning users
- Add active directory ldap option - Add active directory ldap option
- Developers can push to wiki repo. Protected branches does not affect wiki repo any more - Developers can push to wiki repo. Protected branches does not affect wiki repo any more
- Faster rev list - Faster rev list
- Fix branch removal - Fix branch removal
......
...@@ -54,6 +54,8 @@ We welcome merge requests with fixes and improvements to GitLab code, tests, and ...@@ -54,6 +54,8 @@ We welcome merge requests with fixes and improvements to GitLab code, tests, and
Merge requests can be filed either at [gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests) or [github.com](https://github.com/gitlabhq/gitlabhq/pulls). Merge requests can be filed either at [gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests) or [github.com](https://github.com/gitlabhq/gitlabhq/pulls).
If you are new to GitLab development (or web development in general), search for the label `easyfix` ([gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=easyfix), [github](https://github.com/gitlabhq/gitlabhq/labels/easyfix)). Those are issues easy to fix, marked by the GitLab core-team. If you are unsure how to proceed but want to help, mention one of the core-team members to give you a hint.
### Merge request guidelines ### Merge request guidelines
If you can, please submit a merge request with the fix or improvements including tests. If you don't know how to fix the issue but can write a test that exposes the issue we will accept that as well. In general bug fixes that include a regression test are merged quickly while new features without proper tests are least likely to receive timely feedback. The workflow to make a merge request is as follows: If you can, please submit a merge request with the fix or improvements including tests. If you don't know how to fix the issue but can write a test that exposes the issue we will accept that as well. In general bug fixes that include a regression test are merged quickly while new features without proper tests are least likely to receive timely feedback. The workflow to make a merge request is as follows:
......
...@@ -143,7 +143,7 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2" ...@@ -143,7 +143,7 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2"
gem "gemnasium-gitlab-service", "~> 0.2" gem "gemnasium-gitlab-service", "~> 0.2"
# Slack integration # Slack integration
gem "slack-notifier", "~> 0.3.2" gem "slack-notifier", "~> 1.0.0"
# d3 # d3
gem "d3_rails", "~> 3.1.4" gem "d3_rails", "~> 3.1.4"
......
...@@ -488,7 +488,7 @@ GEM ...@@ -488,7 +488,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.3.2) slack-notifier (1.0.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)
...@@ -689,7 +689,7 @@ DEPENDENCIES ...@@ -689,7 +689,7 @@ DEPENDENCIES
simplecov simplecov
sinatra sinatra
six six
slack-notifier (~> 0.3.2) slack-notifier (~> 1.0.0)
slim slim
spinach-rails spinach-rails
spring (= 1.1.3) spring (= 1.1.3)
......
...@@ -58,8 +58,6 @@ class Dispatcher ...@@ -58,8 +58,6 @@ class Dispatcher
when 'groups:show', 'projects:show' when 'groups:show', 'projects:show'
new Activities() new Activities()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'projects:teams:members:index'
new TeamMembers()
when 'groups:members' when 'groups:members'
new GroupMembers() new GroupMembers()
new UsersSelect() new UsersSelect()
......
class @TeamMembers
constructor: ->
$('.team-members .project-access-select').on "change", ->
$(this.form).submit()
// Details // Details
//-------- //--------
.js-details-container .content { display: none; } .js-details-container {
.js-details-container .content.hide { display: block; } .content {
.js-details-container.open .content { display: block; } display: none;
.js-details-container.open .content.hide { display: none; } &.hide { display: block; }
}
&.open .content {
display: block;
&.hide { display: none; }
}
}
// Toggle between two states. // Toggle between two states.
.js-toggler-container .turn-on { display: block; } .js-toggler-container {
.js-toggler-container .turn-off { display: none; } .turn-on { display: block; }
.js-toggler-container.on .turn-on { display: none; } .turn-off { display: none; }
.js-toggler-container.on .turn-off { display: block; } &.on {
.turn-on { display: none; }
.turn-off { display: block; }
}
}
...@@ -186,3 +186,11 @@ ...@@ -186,3 +186,11 @@
} }
} }
} }
.readme-holder .wiki, .note-body, .wiki-holder {
.white {
.highlight, pre, .hljs {
background: #F9F9F9;
}
}
}
class Projects::BaseTreeController < Projects::ApplicationController class Projects::BaseTreeController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
end end
......
...@@ -3,7 +3,6 @@ class Projects::BlameController < Projects::ApplicationController ...@@ -3,7 +3,6 @@ class Projects::BlameController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
...@@ -3,7 +3,6 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -3,7 +3,6 @@ class Projects::BlobController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :authorize_push_code!, only: [:destroy] before_filter :authorize_push_code!, only: [:destroy]
......
class Projects::BranchesController < Projects::ApplicationController class Projects::BranchesController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :authorize_download_code! before_filter :authorize_download_code!
...@@ -19,6 +18,7 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -19,6 +18,7 @@ class Projects::BranchesController < Projects::ApplicationController
def create def create
result = CreateBranchService.new(project, current_user). result = CreateBranchService.new(project, current_user).
execute(params[:branch_name], params[:ref]) execute(params[:branch_name], params[:ref])
if result[:status] == :success if result[:status] == :success
@branch = result[:branch] @branch = result[:branch]
redirect_to project_tree_path(@project, @branch.name) redirect_to project_tree_path(@project, @branch.name)
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
# Not to be confused with CommitsController, plural. # Not to be confused with CommitsController, plural.
class Projects::CommitController < Projects::ApplicationController class Projects::CommitController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :commit before_filter :commit
......
...@@ -4,7 +4,6 @@ class Projects::CommitsController < Projects::ApplicationController ...@@ -4,7 +4,6 @@ class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::CompareController < Projects::ApplicationController class Projects::CompareController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::GraphsController < Projects::ApplicationController class Projects::GraphsController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
...@@ -3,7 +3,6 @@ class Projects::NetworkController < Projects::ApplicationController ...@@ -3,7 +3,6 @@ class Projects::NetworkController < Projects::ApplicationController
include ApplicationHelper include ApplicationHelper
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
...@@ -3,7 +3,6 @@ class Projects::RawController < Projects::ApplicationController ...@@ -3,7 +3,6 @@ class Projects::RawController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
...@@ -2,7 +2,6 @@ class Projects::RefsController < Projects::ApplicationController ...@@ -2,7 +2,6 @@ class Projects::RefsController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::RepositoriesController < Projects::ApplicationController class Projects::RepositoriesController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::TagsController < Projects::ApplicationController class Projects::TagsController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :authorize_push_code!, only: [:create] before_filter :authorize_push_code!, only: [:create]
before_filter :authorize_admin_project!, only: [:destroy] before_filter :authorize_admin_project!, only: [:destroy]
......
...@@ -4,7 +4,6 @@ class ProjectsController < ApplicationController ...@@ -4,7 +4,6 @@ class ProjectsController < ApplicationController
before_filter :repository, except: [:new, :create] before_filter :repository, except: [:new, :create]
# Authorize # Authorize
before_filter :authorize_read_project!, except: [:index, :new, :create]
before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive, :retry_import] before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive, :retry_import]
layout 'navless', only: [:new, :create, :fork] layout 'navless', only: [:new, :create, :fork]
...@@ -52,8 +51,6 @@ class ProjectsController < ApplicationController ...@@ -52,8 +51,6 @@ class ProjectsController < ApplicationController
return return
end end
return authenticate_user! unless @project.public? || current_user
limit = (params[:limit] || 20).to_i limit = (params[:limit] || 20).to_i
@events = @project.events.recent @events = @project.events.recent
@events = event_filter.apply_filter(@events) @events = event_filter.apply_filter(@events)
......
...@@ -62,6 +62,19 @@ module IssuesHelper ...@@ -62,6 +62,19 @@ module IssuesHelper
'' ''
end end
def issue_timestamp(issue)
# Shows the created at time and the updated at time if different
ts = "#{time_ago_with_tooltip(issue.created_at, 'bottom', 'note_created_ago')}"
if issue.updated_at != issue.created_at
ts << capture_haml do
haml_tag :small do
haml_concat " (Edited #{time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_edited_ago')})"
end
end
end
ts.html_safe
end
# Checks if issues_tracker setting exists in gitlab.yml # Checks if issues_tracker setting exists in gitlab.yml
def external_issues_tracker_enabled? def external_issues_tracker_enabled?
Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any? Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any?
......
...@@ -42,12 +42,12 @@ module ProjectsHelper ...@@ -42,12 +42,12 @@ module ProjectsHelper
def project_title(project) def project_title(project)
if project.group if project.group
content_tag :span do content_tag :span do
link_to(simple_sanitize(project.group.name), group_path(project.group)) + " / " + project.name link_to(simple_sanitize(project.group.name), group_path(project.group)) + ' / ' + link_to(simple_sanitize(project.name), project_path(project))
end end
else else
owner = project.namespace.owner owner = project.namespace.owner
content_tag :span do content_tag :span do
link_to(simple_sanitize(owner.name), user_path(owner)) + " / " + project.name link_to(simple_sanitize(owner.name), user_path(owner)) + ' / ' + link_to(simple_sanitize(project.name), project_path(project))
end end
end end
end end
......
...@@ -66,7 +66,7 @@ module TreeHelper ...@@ -66,7 +66,7 @@ module TreeHelper
def tree_breadcrumbs(tree, max_links = 2) def tree_breadcrumbs(tree, max_links = 2)
if @path.present? if @path.present?
part_path = "" part_path = ""
parts = @path.split("\/") parts = @path.split('/')
yield('..', nil) if parts.count > max_links yield('..', nil) if parts.count > max_links
......
...@@ -131,9 +131,10 @@ module Issuable ...@@ -131,9 +131,10 @@ module Issuable
users.concat(mentions.reduce([], :|)).uniq users.concat(mentions.reduce([], :|)).uniq
end end
def to_hook_data def to_hook_data(user)
{ {
object_kind: self.class.name.underscore, object_kind: self.class.name.underscore,
user: user.hook_attrs,
object_attributes: hook_attrs object_attributes: hook_attrs
} }
end end
......
...@@ -186,10 +186,6 @@ class Event < ActiveRecord::Base ...@@ -186,10 +186,6 @@ class Event < ActiveRecord::Base
data[:ref]["refs/heads"] data[:ref]["refs/heads"]
end end
def new_branch?
commit_from =~ /^00000/
end
def new_ref? def new_ref?
commit_from =~ /^00000/ commit_from =~ /^00000/
end end
......
...@@ -90,7 +90,7 @@ class Note < ActiveRecord::Base ...@@ -90,7 +90,7 @@ class Note < ActiveRecord::Base
note_options.merge!(noteable: noteable) note_options.merge!(noteable: noteable)
end end
create(note_options) create(note_options) unless cross_reference_disallowed?(noteable, mentioner)
end end
def create_milestone_change_note(noteable, project, author, milestone) def create_milestone_change_note(noteable, project, author, milestone)
...@@ -165,6 +165,15 @@ class Note < ActiveRecord::Base ...@@ -165,6 +165,15 @@ class Note < ActiveRecord::Base
[:discussion, type.try(:underscore), id, line_code].join("-").to_sym [:discussion, type.try(:underscore), id, line_code].join("-").to_sym
end end
# Determine if cross reference note should be created.
# eg. mentioning a commit in MR comments which exists inside a MR
# should not create "mentioned in" note.
def cross_reference_disallowed?(noteable, mentioner)
if mentioner.kind_of?(MergeRequest)
mentioner.commits.map(&:id).include? noteable.id
end
end
# Determine whether or not a cross-reference note already exists. # Determine whether or not a cross-reference note already exists.
def cross_reference_exists?(noteable, mentioner) def cross_reference_exists?(noteable, mentioner)
gfm_reference = mentioner_gfm_ref(noteable, mentioner) gfm_reference = mentioner_gfm_ref(noteable, mentioner)
...@@ -251,8 +260,8 @@ class Note < ActiveRecord::Base ...@@ -251,8 +260,8 @@ class Note < ActiveRecord::Base
def commit_author def commit_author
@commit_author ||= @commit_author ||=
project.users.find_by(email: noteable.author_email) || project.team.users.find_by(email: noteable.author_email) ||
project.users.find_by(name: noteable.author_name) project.team.users.find_by(name: noteable.author_name)
rescue rescue
nil nil
end end
......
...@@ -402,43 +402,8 @@ class Project < ActiveRecord::Base ...@@ -402,43 +402,8 @@ class Project < ActiveRecord::Base
end end
def update_merge_requests(oldrev, newrev, ref, user) def update_merge_requests(oldrev, newrev, ref, user)
return true unless ref =~ /heads/ MergeRequests::RefreshService.new(self, user).
branch_name = ref.gsub("refs/heads/", "") execute(oldrev, newrev, ref)
commits = self.repository.commits_between(oldrev, newrev)
c_ids = commits.map(&:id)
# Close merge requests
mrs = self.merge_requests.opened.where(target_branch: branch_name).to_a
mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
mrs.uniq.each do |merge_request|
MergeRequests::MergeService.new.execute(merge_request, user, nil)
end
# Update code for merge requests into project between project branches
mrs = self.merge_requests.opened.by_branch(branch_name).to_a
# Update code for merge requests between project and project fork
mrs += self.fork_merge_requests.opened.by_branch(branch_name).to_a
mrs.uniq.each do |merge_request|
merge_request.reload_code
merge_request.mark_as_unchecked
end
# Add comment about pushing new commits to merge requests
comment_mr_with_commits(branch_name, commits, user)
true
end
def comment_mr_with_commits(branch_name, commits, user)
mrs = self.origin_merge_requests.opened.where(source_branch: branch_name).to_a
mrs += self.fork_merge_requests.opened.where(source_branch: branch_name).to_a
mrs.uniq.each do |merge_request|
Note.create_new_commits_note(merge_request, merge_request.project,
user, commits)
end
end end
def valid_repo? def valid_repo?
......
...@@ -37,13 +37,12 @@ class FlowdockService < Service ...@@ -37,13 +37,12 @@ class FlowdockService < Service
end end
def execute(push_data) def execute(push_data)
repo_path = File.join(Gitlab.config.gitlab_shell.repos_path, "#{project.path_with_namespace}.git")
Flowdock::Git.post( Flowdock::Git.post(
push_data[:ref], push_data[:ref],
push_data[:before], push_data[:before],
push_data[:after], push_data[:after],
token: token, token: token,
repo: repo_path, repo: project.repository.path_to_repo,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}", repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s", commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s", diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s",
......
...@@ -38,14 +38,13 @@ class GemnasiumService < Service ...@@ -38,14 +38,13 @@ class GemnasiumService < Service
end end
def execute(push_data) def execute(push_data)
repo_path = File.join(Gitlab.config.gitlab_shell.repos_path, "#{project.path_with_namespace}.git")
Gemnasium::GitlabService.execute( Gemnasium::GitlabService.execute(
ref: push_data[:ref], ref: push_data[:ref],
before: push_data[:before], before: push_data[:before],
after: push_data[:after], after: push_data[:after],
token: token, token: token,
api_key: api_key, api_key: api_key,
repo: repo_path repo: project.repository.path_to_repo
) )
end end
end end
...@@ -28,7 +28,7 @@ class GitlabCiService < CiService ...@@ -28,7 +28,7 @@ class GitlabCiService < CiService
end end
def commit_status_path(sha) def commit_status_path(sha)
project_url + "/builds/#{sha}/status.json?token=#{token}" project_url + "/commits/#{sha}/status.json?token=#{token}"
end end
def get_ci_build(sha) def get_ci_build(sha)
...@@ -55,7 +55,7 @@ class GitlabCiService < CiService ...@@ -55,7 +55,7 @@ class GitlabCiService < CiService
end end
def build_page(sha) def build_page(sha)
project_url + "/builds/#{sha}" project_url + "/commits/#{sha}"
end end
def builds_path def builds_path
......
...@@ -30,24 +30,20 @@ class SlackService < Service ...@@ -30,24 +30,20 @@ class SlackService < Service
def fields def fields
[ [
{ type: 'text', name: 'webhook', placeholder: '' } { type: 'text', name: 'webhook', placeholder: 'https://hooks.slack.com/services/...' }
] ]
end end
def execute(push_data) def execute(push_data)
return unless webhook.present?
message = SlackMessage.new(push_data.merge( message = SlackMessage.new(push_data.merge(
project_url: project_url, project_url: project_url,
project_name: project_name project_name: project_name
)) ))
credentials = webhook.match(/([\w-]*).slack.com.*services\/(.*)/) notifier = Slack::Notifier.new(webhook)
notifier.ping(message.pretext, attachments: message.attachments)
if credentials.present?
subdomain = credentials[1]
token = credentials[2].split("token=").last
notifier = Slack::Notifier.new(subdomain, token)
notifier.ping(message.pretext, attachments: message.attachments)
end
end end
private private
......
...@@ -226,6 +226,11 @@ class User < ActiveRecord::Base ...@@ -226,6 +226,11 @@ class User < ActiveRecord::Base
where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%") where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%")
end end
def by_login(login)
where('lower(username) = :value OR lower(email) = :value',
value: login.to_s.downcase).first
end
def by_username_or_id(name_or_id) def by_username_or_id(name_or_id)
where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
end end
...@@ -493,6 +498,14 @@ class User < ActiveRecord::Base ...@@ -493,6 +498,14 @@ class User < ActiveRecord::Base
end end
end end
def hook_attrs
{
name: name,
username: username,
avatar_url: avatar_url
}
end
def ensure_namespace_correct def ensure_namespace_correct
# Ensure user has namespace # Ensure user has namespace
self.create_namespace!(path: self.username, name: self.username) unless self.namespace self.create_namespace!(path: self.username, name: self.username) unless self.namespace
......
...@@ -160,19 +160,19 @@ class GitPushService ...@@ -160,19 +160,19 @@ class GitPushService
ref_parts = ref.split('/') ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits) # Return if this is not a push to a branch (e.g. new commits)
ref_parts[1] =~ /heads/ && oldrev != "0000000000000000000000000000000000000000" ref_parts[1] =~ /heads/ && oldrev != Gitlab::Git::BLANK_SHA
end end
def push_to_new_branch?(ref, oldrev) def push_to_new_branch?(ref, oldrev)
ref_parts = ref.split('/') ref_parts = ref.split('/')
ref_parts[1] =~ /heads/ && oldrev == "0000000000000000000000000000000000000000" ref_parts[1] =~ /heads/ && oldrev == Gitlab::Git::BLANK_SHA
end end
def push_remove_branch?(ref, newrev) def push_remove_branch?(ref, newrev)
ref_parts = ref.split('/') ref_parts = ref.split('/')
ref_parts[1] =~ /heads/ && newrev == "0000000000000000000000000000000000000000" ref_parts[1] =~ /heads/ && newrev == Gitlab::Git::BLANK_SHA
end end
def push_to_branch?(ref) def push_to_branch?(ref)
......
...@@ -4,7 +4,7 @@ module Issues ...@@ -4,7 +4,7 @@ module Issues
private private
def execute_hooks(issue, action = 'open') def execute_hooks(issue, action = 'open')
issue_data = issue.to_hook_data issue_data = issue.to_hook_data(current_user)
issue_url = Gitlab::UrlBuilder.new(:issue).build(issue.id) issue_url = Gitlab::UrlBuilder.new(:issue).build(issue.id)
issue_data[:object_attributes].merge!(url: issue_url, action: action) issue_data[:object_attributes].merge!(url: issue_url, action: action)
issue.project.execute_hooks(issue_data, :issue_hooks) issue.project.execute_hooks(issue_data, :issue_hooks)
......
...@@ -13,7 +13,8 @@ module MergeRequests ...@@ -13,7 +13,8 @@ module MergeRequests
def execute_project_hooks(merge_request) def execute_project_hooks(merge_request)
if merge_request.project if merge_request.project
merge_request.project.execute_hooks(merge_request.to_hook_data, :merge_request_hooks) hook_data = merge_request.to_hook_data(current_user)
merge_request.project.execute_hooks(hook_data, :merge_request_hooks)
end end
end end
end end
......
...@@ -7,7 +7,8 @@ module MergeRequests ...@@ -7,7 +7,8 @@ module MergeRequests
def execute_hooks(merge_request) def execute_hooks(merge_request)
if merge_request.project if merge_request.project
merge_request.project.execute_hooks(merge_request.to_hook_data, :merge_request_hooks) hook_data = merge_request.to_hook_data(current_user)
merge_request.project.execute_hooks(hook_data, :merge_request_hooks)
end end
end end
end end
......
module MergeRequests
class RefreshService < MergeRequests::BaseService
def execute(oldrev, newrev, ref)
return true unless ref =~ /heads/
@branch_name = ref.gsub("refs/heads/", "")
@fork_merge_requests = @project.fork_merge_requests.opened
@commits = @project.repository.commits_between(oldrev, newrev)
close_merge_requests
reload_merge_requests
comment_mr_with_commits
true
end
private
# Collect open merge requests that target same branch we push into
# and close if push to master include last commit from merge request
# We need this to close(as merged) merge requests that were merged into
# target branch manually
def close_merge_requests
commit_ids = @commits.map(&:id)
merge_requests = @project.merge_requests.opened.where(target_branch: @branch_name).to_a
merge_requests = merge_requests.select(&:last_commit)
merge_requests = merge_requests.select do |merge_request|
commit_ids.include?(merge_request.last_commit.id)
end
merge_requests.uniq.select(&:source_project).each do |merge_request|
MergeRequests::MergeService.new.execute(merge_request, @current_user, nil)
end
end
# Refresh merge request diff if we push to source or target branch of merge request
# Note: we should update merge requests from forks too
def reload_merge_requests
merge_requests = @project.merge_requests.opened.by_branch(@branch_name).to_a
merge_requests += @fork_merge_requests.by_branch(@branch_name).to_a
merge_requests = filter_merge_requests(merge_requests)
merge_requests.each do |merge_request|
merge_request.reload_code
merge_request.mark_as_unchecked
end
end
# Add comment about pushing new commits to merge requests
def comment_mr_with_commits
merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
merge_requests += @fork_merge_requests.where(source_branch: @branch_name).to_a
merge_requests = filter_merge_requests(merge_requests)
merge_requests.each do |merge_request|
Note.create_new_commits_note(merge_request, merge_request.project,
@current_user, @commits)
end
end
def filter_merge_requests(merge_requests)
merge_requests.uniq.select(&:source_project)
end
end
end
...@@ -18,7 +18,7 @@ class SystemHooksService ...@@ -18,7 +18,7 @@ class SystemHooksService
def build_event_data(model, event) def build_event_data(model, event)
data = { data = {
event_name: build_event_name(model, event), event_name: build_event_name(model, event),
created_at: model.created_at created_at: model.created_at.xmlschema
} }
case model case model
......
...@@ -26,6 +26,10 @@ class AttachmentUploader < CarrierWave::Uploader::Base ...@@ -26,6 +26,10 @@ class AttachmentUploader < CarrierWave::Uploader::Base
Gitlab.config.gitlab.relative_url_root + "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}" Gitlab.config.gitlab.relative_url_root + "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}"
end end
def url
Gitlab.config.gitlab.relative_url_root + super unless super.nil?
end
def file_storage? def file_storage?
self.class.storage == CarrierWave::Storage::File self.class.storage == CarrierWave::Storage::File
end end
......
...@@ -6,5 +6,5 @@ ...@@ -6,5 +6,5 @@
title: title:
%code= @key.title %code= @key.title
%p %p
If this key was added in error, you can remove it here: If this key was added in error, you can remove it under
= link_to "SSH Keys", profile_keys_url = link_to "SSH Keys", profile_keys_url
...@@ -2,6 +2,6 @@ Hi <%= @user.name %>! ...@@ -2,6 +2,6 @@ Hi <%= @user.name %>!
A new public key was added to your account: A new public key was added to your account:
title.................. <%= @key.title %> Title: <%= @key.title %>
If this key was added in error, you can remove it here: <%= profile_keys_url %> If this key was added in error, you can remove it at <%= profile_keys_url %>
...@@ -23,5 +23,6 @@ ...@@ -23,5 +23,6 @@
tree_join(@commit.sha, @path)), class: 'btn btn-small' tree_join(@commit.sha, @path)), class: 'btn btn-small'
- if allowed_tree_edit? - if allowed_tree_edit?
= link_to '#modal-remove-blob', class: "remove-blob btn btn-small btn-remove", "data-toggle" => "modal" do = button_tag class: 'remove-blob btn btn-small btn-remove',
'data-toggle' => 'modal', 'data-target' => '#modal-remove-blob' do
Remove Remove
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
- if @commit.parent_ids.present? - if @commit.parent_ids.present?
= view_file_btn(@commit.parent_id, diff_file, project) = view_file_btn(@commit.parent_id, diff_file, project)
- else - else
%span= diff_file.new_path - if diff_file.renamed_file
%span= "#{diff_file.old_path} renamed to #{diff_file.new_path}"
- else
%span= diff_file.new_path
- if diff_file.mode_changed? - if diff_file.mode_changed?
%span.file-mode= "#{diff_file.diff.a_mode}#{diff_file.diff.b_mode}" %span.file-mode= "#{diff_file.diff.a_mode}#{diff_file.diff.b_mode}"
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
Open Open
.creator .creator
Created by #{link_to_member(@project, @issue.author)} #{time_ago_with_tooltip(@issue.created_at)} Created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)}
%h4.title %h4.title
= gfm escape_once(@issue.title) = gfm escape_once(@issue.title)
......
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
- target_remote = @merge_request.target_project.namespace.nil? ? "target" :@merge_request.target_project.namespace.path - target_remote = @merge_request.target_project.namespace.nil? ? "target" :@merge_request.target_project.namespace.path
%p %p
%strong Step 1. %strong Step 1.
Checkout the branch we are going to merge and pull in the code Fetch the code and create a new branch pointing to it
%pre.dark %pre.dark
:preserve :preserve
git checkout -b #{@merge_request.source_project_path}-#{@merge_request.source_branch} #{@merge_request.target_branch} git fetch #{@merge_request.source_project.http_url_to_repo} #{@merge_request.source_branch}
git pull #{@merge_request.source_project.http_url_to_repo} #{@merge_request.source_branch} git checkout -b #{@merge_request.source_project_path}-#{@merge_request.source_branch} FETCH_HEAD
%p %p
%strong Step 2. %strong Step 2.
Merge the branch and push the changes to GitLab Merge the branch and push the changes to GitLab
......
...@@ -19,14 +19,14 @@ ...@@ -19,14 +19,14 @@
Encoding Encoding
.col-sm-10 .col-sm-10
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control' = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
= render 'shared/commit_message_container', params: params,
placeholder: 'Add new file'
.file-holder .file-holder
.file-title .file-title
%i.fa.fa-file %i.fa.fa-file
.file-content.code .file-content.code
%pre#editor= params[:content] %pre#editor= params[:content]
= render 'shared/commit_message_container', params: params,
placeholder: 'Add new file'
= hidden_field_tag 'content', '', id: 'file-content' = hidden_field_tag 'content', '', id: 'file-content'
= render 'projects/commit_button', ref: @ref, = render 'projects/commit_button', ref: @ref,
cancel_path: project_tree_path(@project, @id) cancel_path: project_tree_path(@project, @id)
......
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
- if note.attachment.image? - if note.attachment.image?
= link_to note.attachment.secure_url, target: '_blank' do = link_to note.attachment.secure_url, target: '_blank' do
= image_tag note.attachment.secure_url, class: 'note-image-attach' = image_tag note.attachment.secure_url, class: 'note-image-attach'
.attachment.pull-right .attachment
= link_to note.attachment.secure_url, target: "_blank" do = link_to note.attachment.secure_url, target: "_blank" do
%i.fa.fa-paperclip %i.fa.fa-paperclip
= note.attachment_identifier = note.attachment_identifier
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
= link_to project_commits_path(@project, tag.name), class: "" do = link_to project_commits_path(@project, tag.name), class: "" do
%i.fa.fa-tag %i.fa.fa-tag
= tag.name = tag.name
- if tag.message.present?
&nbsp;
= tag.message
.pull-right .pull-right
- if can? current_user, :download_code, @project - if can? current_user, :download_code, @project
= render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-small' = render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-small'
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
- unless @project.personal? && user == current_user - unless @project.personal? && user == current_user
.pull-left .pull-left
= form_for(member, as: :project_member, url: project_team_member_path(@project, member.user)) do |f| = form_for(member, as: :project_member, url: project_team_member_path(@project, member.user)) do |f|
= f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level), {}, class: "medium project-access-select span2 trigger-submit" = f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level), {}, class: "trigger-submit"
&nbsp; &nbsp;
= link_to project_team_member_path(@project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do = link_to project_team_member_path(@project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do
%i.fa.fa-minus.fa-inverse %i.fa.fa-minus.fa-inverse
......
...@@ -22,11 +22,6 @@ module Gitlab ...@@ -22,11 +22,6 @@ module Gitlab
# :all can be used as a placeholder for all plugins not explicitly named. # :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ] # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# NOTE: Please prefer set time zone on config/gitlab.yml configuration file.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de # config.i18n.default_locale = :de
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# Use at least one worker per core if you're on a dedicated server, # Use at least one worker per core if you're on a dedicated server,
# more will usually help for _short_ waits on databases/caches. # more will usually help for _short_ waits on databases/caches.
# The minimum is 2
worker_processes 2 worker_processes 2
# Since Unicorn is never exposed to outside clients, it does not need to # Since Unicorn is never exposed to outside clients, it does not need to
......
password = if ENV['GITLAB_ROOT_PASSWORD'].blank? if ENV['GITLAB_ROOT_PASSWORD'].blank?
"5iveL!fe" password = '5iveL!fe'
else expire_time = Time.now
ENV['GITLAB_ROOT_PASSWORD'] else
end password = ENV['GITLAB_ROOT_PASSWORD']
expire_time = nil
end
admin = User.create( admin = User.create(
email: "admin@example.com", email: "admin@example.com",
...@@ -10,7 +12,7 @@ admin = User.create( ...@@ -10,7 +12,7 @@ admin = User.create(
username: 'root', username: 'root',
password: password, password: password,
password_confirmation: password, password_confirmation: password,
password_expires_at: Time.now, password_expires_at: expire_time,
theme_id: Gitlab::Theme::MARS theme_id: Gitlab::Theme::MARS
) )
......
...@@ -23,7 +23,7 @@ class SerializeServiceProperties < ActiveRecord::Migration ...@@ -23,7 +23,7 @@ class SerializeServiceProperties < ActiveRecord::Migration
associations[service.type.to_sym].each do |attribute| associations[service.type.to_sym].each do |attribute|
service.send("#{attribute}=", service.attributes[attribute.to_s]) service.send("#{attribute}=", service.attributes[attribute.to_s])
end end
service.save! service.save
end end
remove_column :services, :project_url, :string remove_column :services, :project_url, :string
......
...@@ -10,7 +10,7 @@ class MoveSlackServiceToWebhook < ActiveRecord::Migration ...@@ -10,7 +10,7 @@ class MoveSlackServiceToWebhook < ActiveRecord::Migration
slack_service.properties.delete('subdomain') slack_service.properties.delete('subdomain')
# Room is configured on the Slack side # Room is configured on the Slack side
slack_service.properties.delete('room') slack_service.properties.delete('room')
slack_service.save! slack_service.save
end end
end end
end end
......
...@@ -211,3 +211,11 @@ Parameters: ...@@ -211,3 +211,11 @@ Parameters:
It return 200 if succeed, 404 if the branch to be deleted does not exist It return 200 if succeed, 404 if the branch to be deleted does not exist
or 400 for other reasons. In case of an error, an explaining message is provided. or 400 for other reasons. In case of an error, an explaining message is provided.
Success response:
```json
{
"branch_name": "my-removed-branch"
}
```
...@@ -186,6 +186,7 @@ Parameters: ...@@ -186,6 +186,7 @@ Parameters:
"target_id": 830, "target_id": 830,
"target_type": "Issue", "target_type": "Issue",
"author_id": 1, "author_id": 1,
"author_username": "john",
"data": null, "data": null,
"target_title": "Public project search field" "target_title": "Public project search field"
}, },
...@@ -196,6 +197,7 @@ Parameters: ...@@ -196,6 +197,7 @@ Parameters:
"target_id": null, "target_id": null,
"target_type": null, "target_type": null,
"author_id": 1, "author_id": 1,
"author_username": "john",
"data": { "data": {
"before": "50d4420237a9de7be1304607147aec22e4a14af7", "before": "50d4420237a9de7be1304607147aec22e4a14af7",
"after": "c5feabde2d8cd023215af4d2ceeb7a64839fc428", "after": "c5feabde2d8cd023215af4d2ceeb7a64839fc428",
...@@ -231,6 +233,7 @@ Parameters: ...@@ -231,6 +233,7 @@ Parameters:
"target_id": 840, "target_id": 840,
"target_type": "Issue", "target_type": "Issue",
"author_id": 1, "author_id": 1,
"author_username": "john",
"data": null, "data": null,
"target_title": "Finish & merge Code search PR" "target_title": "Finish & merge Code search PR"
} }
......
...@@ -56,6 +56,7 @@ Parameters: ...@@ -56,6 +56,7 @@ Parameters:
[ [
{ {
"name": "v1.0.0", "name": "v1.0.0",
"message": "Release 1.0.0",
"commit": { "commit": {
"id": "2695effb5807a22ff3d138d593fd856244e155e7", "id": "2695effb5807a22ff3d138d593fd856244e155e7",
"parents": [], "parents": [],
...@@ -67,10 +68,11 @@ Parameters: ...@@ -67,10 +68,11 @@ Parameters:
"committed_date": "2012-05-28T04:42:42-07:00", "committed_date": "2012-05-28T04:42:42-07:00",
"committer_email": "jack@example.com" "committer_email": "jack@example.com"
}, },
"protected": false
} }
] ]
``` ```
The message will be `nil` when creating a lightweight tag otherwise
it will contain the annotation.
It returns 200 if the operation succeed. In case of an error, It returns 200 if the operation succeed. In case of an error,
405 with an explaining error message is returned. 405 with an explaining error message is returned.
......
...@@ -78,7 +78,8 @@ GET /users ...@@ -78,7 +78,8 @@ GET /users
"is_admin": false, "is_admin": false,
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg", "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
"can_create_group": true, "can_create_group": true,
"can_create_project": true "can_create_project": true,
"projects_limit": 100
} }
] ]
``` ```
...@@ -140,7 +141,8 @@ Parameters: ...@@ -140,7 +141,8 @@ Parameters:
"color_scheme_id": 2, "color_scheme_id": 2,
"is_admin": false, "is_admin": false,
"can_create_group": true, "can_create_group": true,
"can_create_project": true "can_create_project": true,
"projects_limit": 100
} }
``` ```
...@@ -240,7 +242,8 @@ GET /user ...@@ -240,7 +242,8 @@ GET /user
"color_scheme_id": 2, "color_scheme_id": 2,
"is_admin": false, "is_admin": false,
"can_create_group": true, "can_create_group": true,
"can_create_project": true "can_create_project": true,
"projects_limit": 100
} }
``` ```
......
...@@ -76,6 +76,7 @@ Is the system packaged Git too old? Remove it and compile from source. ...@@ -76,6 +76,7 @@ Is the system packaged Git too old? Remove it and compile from source.
cd /tmp cd /tmp
curl -L --progress https://www.kernel.org/pub/software/scm/git/git-2.1.2.tar.gz | tar xz curl -L --progress https://www.kernel.org/pub/software/scm/git/git-2.1.2.tar.gz | tar xz
cd git-2.1.2/ cd git-2.1.2/
./configure
make prefix=/usr/local all make prefix=/usr/local all
# Install into /usr/local/bin # Install into /usr/local/bin
...@@ -91,7 +92,7 @@ Then select 'Internet Site' and press enter to confirm the hostname. ...@@ -91,7 +92,7 @@ Then select 'Internet Site' and press enter to confirm the hostname.
## 2. Ruby ## 2. Ruby
The use of ruby version managers such as [RVM](http://rvm.io/), [rbenv](https://github.com/sstephenson/rbenv) or [chruby](https://github.com/postmodern/chruby) with GitLab in production frequently leads to hard to diagnose problems. For example, GitLab Shell is called from OpenSSH and having a version manager can prevent pushing and pulling over SSH. Version managers are not supported and we strongly advise everyone to follow the instructions below to use a system ruby. The use of Ruby version managers such as [RVM](http://rvm.io/), [rbenv](https://github.com/sstephenson/rbenv) or [chruby](https://github.com/postmodern/chruby) with GitLab in production frequently leads to hard to diagnose problems. For example, GitLab Shell is called from OpenSSH and having a version manager can prevent pushing and pulling over SSH. Version managers are not supported and we strongly advise everyone to follow the instructions below to use a system Ruby.
Remove the old Ruby 1.8 if present Remove the old Ruby 1.8 if present
...@@ -126,7 +127,8 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da ...@@ -126,7 +127,8 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
# Login to PostgreSQL # Login to PostgreSQL
sudo -u postgres psql -d template1 sudo -u postgres psql -d template1
# Create a user for GitLab. # Create a user for GitLab
# Do not type the 'template1=#', this is part of the prompt
template1=# CREATE USER git CREATEDB; template1=# CREATE USER git CREATEDB;
# Create the GitLab production database & grant all privileges on database # Create the GitLab production database & grant all privileges on database
...@@ -137,6 +139,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da ...@@ -137,6 +139,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
# Try connecting to the new database with the new user # Try connecting to the new database with the new user
sudo -u git -H psql -d gitlabhq_production sudo -u git -H psql -d gitlabhq_production
# Quit the database session
gitlabhq_production> \q
## 5. Redis ## 5. Redis
...@@ -194,7 +199,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da ...@@ -194,7 +199,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
# Make sure GitLab can write to the log/ and tmp/ directories # Make sure GitLab can write to the log/ and tmp/ directories
sudo chown -R git log/ sudo chown -R git log/
sudo chown -R git tmp/ sudo chown -R git tmp/
sudo chmod -R u+rwX log/ sudo chmod -R u+rwX,go-w log/
sudo chmod -R u+rwX tmp/ sudo chmod -R u+rwX tmp/
# Create directory for satellites # Create directory for satellites
......
...@@ -4,15 +4,23 @@ ...@@ -4,15 +4,23 @@
To enable Slack integration you must create an Incoming WebHooks integration on Slack; To enable Slack integration you must create an Incoming WebHooks integration on Slack;
1. Sign in to [Slack](https://slack.com) (https://YOURSUBDOMAIN.slack.com/services) 1. [Sign in to Slack](https://slack.com/signin)
1. Click on the Integrations menu at the top of the page.
1. Add a new Integration. 1. Select **Configure Integrations** from the dropdown next to your team name.
1. Select the **All Services** tab
1. Click **Add** next to Incoming Webhooks
1. Pick Incoming WebHooks 1. Pick Incoming WebHooks
1. Choose the channel name you want to send notifications to, in the Settings section
1. Add Integrations.
- Optional step; You can change bot's name and avatar by clicking "change the name of your bot", and "change the icon" after that you have to click "Save settings".
Now, Slack is ready to get external hooks. Before you leave this page don't forget to get the Token that you'll need on GitLab. You can find it by clicking Expand button, located in the "Instructions for creating Incoming WebHooks" section. It's a random alpha-numeric text 24 characters long. 1. Choose the channel name you want to send notifications to
1. Click **Add Incoming WebHooks Integration**Add Integrations.
- Optional step; You can change bot's name and avatar by clicking modifying the bot name or avatar under **Integration Settings**.
1. Copy the **Webhook URL**, we'll need this later for GitLab.
## On GitLab ## On GitLab
...@@ -26,10 +34,8 @@ After Slack is ready we need to setup GitLab. Here are the steps to achieve this ...@@ -26,10 +34,8 @@ After Slack is ready we need to setup GitLab. Here are the steps to achieve this
1. Fill in your Slack details 1. Fill in your Slack details
- Mark as active it - Mark it as active
- Type your subdomain's prefix (If your subdomain is https://somedomain.slack.com you only have to type the somedomain) - Paste in the webhook url you got from Slack
- Type in the token you got from Slack
- Type in the channel name you want to use (eg. #announcements)
Have fun :) Have fun :)
......
# Import # Import bare repositories into your GitLab instance
## Import bare repositories into GitLab project instance ## Notes
Notes: - The owner of the project will be the first admin
- The groups will be created as needed
- The owner of the group will be the first admin
- Existing projects will be skipped
- project owner will be a first admin ## How to use
- groups will be created as needed
- group owner will be the first admin
- existing projects will be skipped
How to use: ### Create a new folder inside the git repositories path. This will be the name of the new group.
1. copy your bare repos under git repos_path (see `config/gitlab.yml` gitlab_shell -> repos_path) - For omnibus-gitlab, it is located at: `/var/opt/gitlab/git-data/repositories` by default, unless you changed
1. run the command below it in the `/etc/gitlab/gitlab.rb` file.
- For manual installations, it is usually located at: `/home/git/repositories` or you can see where
your repositories are located by looking at `config/gitlab.yml` under the `gitlab_shell => repos_path` entry.
### Copy your bare repositories inside this newly created folder:
```
$ cp -r /old/git/foo.git/ /home/git/repositories/new_group/
```
### Run the command below depending on your type of installation:
#### Omnibus Installation
```
$ sudo gitlab-rake gitlab:import:repos
``` ```
# omnibus-gitlab
sudo gitlab-rake gitlab:import:repos
# installation from source or cookbook #### Manual Installation
bundle exec rake gitlab:import:repos RAILS_ENV=production
Before running this command you need to change the directory to where your GitLab installation is located:
```
$ cd /home/git/gitlab
$ sudo -u git -H bundle exec rake gitlab:import:repos RAILS_ENV=production
``` ```
Example output: #### Example output
``` ```
Processing abcd.git Processing abcd.git
......
...@@ -143,35 +143,28 @@ Make sure the code quality indicators are green / good. ...@@ -143,35 +143,28 @@ Make sure the code quality indicators are green / good.
- [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq) - [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq)
### **4. Set VERSION** ### **4. Run release tool**
Change version in VERSION to `x.x.0.rc1`. **Make sure EE `master` has latest changes from CE `master`**
### **5. Tag** Get release tools
Create an annotated tag that points to the version change commit:
``` ```
git tag -a vx.x.0.rc1 -m 'Version x.x.0.rc1' git clone git@dev.gitlab.org:gitlab/release-tools.git
cd release-tools
``` ```
Tags should be created for both GitLab CE and GitLab EE. Don't forget to push tags to all remotes. Release candidate creates stable branch from master.
So we need to sync master branch between all CE remotes. Also do same for EE.
``` ```
git push remote_name vx.x.0.rc1 bundle exec rake sync
``` ```
### **6. Create stable branches** Create release candidate and stable branch:
For GitLab EE, append `-ee` to the branch.
`x-x-stable-ee`
``` ```
git checkout master bundle exec rake release["x.x.0.rc1"]
git pull
git checkout -b x-x-stable
git push <remote> x-x-stable
``` ```
Now developers can use master for merging new features. Now developers can use master for merging new features.
...@@ -245,69 +238,45 @@ create an issue about it in order to discuss the next steps after the release. ...@@ -245,69 +238,45 @@ create an issue about it in order to discuss the next steps after the release.
# **22nd - Release CE and EE** # **22nd - Release CE and EE**
For GitLab EE, append `-ee` to the branches and tags. **Make sure EE `x-x-stable-ee` has latest changes from CE `x-x-stable`**
`x-x-stable-ee`
`v.x.x.0-ee` ### **1. Release code**
Note: Merge CE into EE if needed. Get release tools
### **1. Set VERSION to x.x.x and push**
- Change the GITLAB_SHELL_VERSION file in `master` of the CE repository if the version changed.
- Change the GITLAB_SHELL_VERSION file in `master` of the EE repository if the version changed.
- Change the VERSION file in `master` branch of the CE repository and commit and push to origin.
- Change the VERSION file in `master` branch of the EE repository and commit and push to origin.
### **2. Update installation.md**
Update [installation.md](/doc/install/installation.md) to the newest version in master.
### **3. Push latest changes from x-x-stable branch to dev.gitlab.org**
``` ```
git checkout -b x-x-stable git clone git@dev.gitlab.org:gitlab/release-tools.git
git push origin x-x-stable cd release-tools
``` ```
### **4. Build the Omnibus packages** Bump version, create release tag and push to remotes:
Follow the [release doc in the Omnibus repository](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md).
This can happen before tagging because Omnibus uses tags in its own repo and SHA1's to refer to the GitLab codebase.
### **5. Create annotated tag vx.x.x**
In `x-x-stable` branch check for the SHA-1 of the commit with VERSION file changed. Tag that commit,
``` ```
git tag -a vx.x.0 -m 'Version x.x.0' xxxxx bundle exec rake release["x.x.0"]
``` ```
where `xxxxx` is SHA-1.
### **6. Push the tag and x-x-stable branch to the remotes** ### **2. Update installation.md**
For GitLab CE, push to dev, GitLab.com and GitHub. Update [installation.md](/doc/install/installation.md) to the newest version in master.
For GitLab EE, push to the subscribers repo.
Make sure the branch is marked 'protected' on each of the remotes you pushed to. ### **3. Build the Omnibus packages**
Follow the [release doc in the Omnibus repository](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md).
This can happen before tagging because Omnibus uses tags in its own repo and SHA1's to refer to the GitLab codebase.
```
git push <remote> x-x-stable(-ee)
git push <remote> vx.x.0
```
### **7. Publish packages for new release** ### **4. Publish packages for new release**
Update `downloads/index.html` and `downloads/archive/index.html` in `www-gitlab-com` repository. Update `downloads/index.html` and `downloads/archive/index.html` in `www-gitlab-com` repository.
### **8. Publish blog for new release** ### **5. Publish blog for new release**
Merge the [blog merge request](#1-prepare-the-blog-post) in `www-gitlab-com` repository. Merge the [blog merge request](#1-prepare-the-blog-post) in `www-gitlab-com` repository.
### **9. Tweet to blog** ### **6. Tweet to blog**
Send out a tweet to share the good news with the world. Send out a tweet to share the good news with the world.
List the most important features and link to the blog post. List the most important features and link to the blog post.
......
...@@ -10,6 +10,8 @@ Otherwise include it in the monthly release and note there was a regression fix ...@@ -10,6 +10,8 @@ Otherwise include it in the monthly release and note there was a regression fix
## Release Procedure ## Release Procedure
### Preparation
1. Verify that the issue can be reproduced 1. Verify that the issue can be reproduced
1. Note in the 'GitLab X.X regressions' that you will create a patch 1. Note in the 'GitLab X.X regressions' that you will create a patch
1. Create an issue on private GitLab development server 1. Create an issue on private GitLab development server
...@@ -17,12 +19,33 @@ Otherwise include it in the monthly release and note there was a regression fix ...@@ -17,12 +19,33 @@ Otherwise include it in the monthly release and note there was a regression fix
1. Fix the issue on a feature branch, do this on the private GitLab development server 1. Fix the issue on a feature branch, do this on the private GitLab development server
1. Consider creating and testing workarounds 1. Consider creating and testing workarounds
1. After the branch is merged into master, cherry pick the commit(s) into the current stable branch 1. After the branch is merged into master, cherry pick the commit(s) into the current stable branch
1. Make sure that the build has passed and all tests are passing
1. In a separate commit in the stable branch update the CHANGELOG 1. In a separate commit in the stable branch update the CHANGELOG
1. For EE, update the CHANGELOG-EE if it is EE specific fix. Otherwise, merge the stable CE branch and add to CHANGELOG-EE "Merge community edition changes for version X.X.X" 1. For EE, update the CHANGELOG-EE if it is EE specific fix. Otherwise, merge the stable CE branch and add to CHANGELOG-EE "Merge community edition changes for version X.X.X"
1. In a separate commit in the stable branch update the VERSION
1. Create an annotated tag vX.X.X for CE and another patch release for EE `git tag -a vx.x.x -m 'Version x.x.x'` ### Bump version
1. Make sure that the build has passed and all tests are passing
1. Push the code and the tags to all the CE and EE repositories Get release tools
```
git clone git@dev.gitlab.org:gitlab/release-tools.git
cd release-tools
```
Bump version in stable branch, create release tag and push to remotes:
```
bundle exec rake release["x.x.x"]
```
Or if you need to release only EE:
```
CE=false be rake release['x.x.x']
```
### Release
1. Apply the patch to GitLab Cloud and the private GitLab development server 1. Apply the patch to GitLab Cloud and the private GitLab development server
1. [Build new packages with the latest version](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md) 1. [Build new packages with the latest version](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md)
1. Cherry-pick the changelog update back into master 1. Cherry-pick the changelog update back into master
......
# From 6.x or 7.x to 7.3 # From 6.x or 7.x to 7.4
This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.3. This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.4.
## Global issue numbers ## Global issue numbers
...@@ -70,7 +70,7 @@ sudo -u git -H git checkout -- db/schema.rb # local changes will be restored aut ...@@ -70,7 +70,7 @@ sudo -u git -H git checkout -- db/schema.rb # local changes will be restored aut
For GitLab Community Edition: For GitLab Community Edition:
```bash ```bash
sudo -u git -H git checkout 7-3-stable sudo -u git -H git checkout 7-4-stable
``` ```
OR OR
...@@ -78,7 +78,7 @@ OR ...@@ -78,7 +78,7 @@ OR
For GitLab Enterprise Edition: For GitLab Enterprise Edition:
```bash ```bash
sudo -u git -H git checkout 7-3-stable-ee sudo -u git -H git checkout 7-4-stable-ee
``` ```
## 4. Install additional packages ## 4. Install additional packages
...@@ -154,14 +154,14 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab ...@@ -154,14 +154,14 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
TIP: to see what changed in `gitlab.yml.example` in this release use next command: TIP: to see what changed in `gitlab.yml.example` in this release use next command:
``` ```
git diff 6-0-stable:config/gitlab.yml.example 7-3-stable:config/gitlab.yml.example git diff 6-0-stable:config/gitlab.yml.example 7-4-stable:config/gitlab.yml.example
``` ```
* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/config/gitlab.yml.example but with your settings. * Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/config/gitlab.yml.example but with your settings.
* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/config/unicorn.rb.example but with your settings. * Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/config/unicorn.rb.example but with your settings.
* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.0.1/config.yml.example but with your settings. * Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.0.1/config.yml.example but with your settings.
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/lib/support/nginx/gitlab but with your settings. * HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/lib/support/nginx/gitlab but with your settings.
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/lib/support/nginx/gitlab-ssl but with your settings. * HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/lib/support/nginx/gitlab-ssl but with your settings.
* Copy rack attack middleware config * Copy rack attack middleware config
```bash ```bash
...@@ -267,6 +267,7 @@ mysql> \q ...@@ -267,6 +267,7 @@ mysql> \q
# Set production -> username: git # Set production -> username: git
# Set production -> password: the password your replaced $password with earlier # Set production -> password: the password your replaced $password with earlier
sudo -u git -H editor /home/git/gitlab/config/database.yml sudo -u git -H editor /home/git/gitlab/config/database.yml
```
## Things went south? Revert to previous version (6.0) ## Things went south? Revert to previous version (6.0)
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
```bash ```bash
cd /home/git/gitlab cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
### 2. Get latest code ### 2. Get latest code
......
...@@ -26,16 +26,14 @@ sudo -u git -H git checkout LATEST_TAG ...@@ -26,16 +26,14 @@ sudo -u git -H git checkout LATEST_TAG
Replace LATEST_TAG with the latest GitLab tag you want to upgrade to, for example `v6.6.3`. Replace LATEST_TAG with the latest GitLab tag you want to upgrade to, for example `v6.6.3`.
### 3. Update gitlab-shell if it is not the latest version ### 3. Update gitlab-shell to the corresponding version
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch sudo -u git -H git fetch
sudo -u git -H git checkout LATEST_TAG sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`
``` ```
Replace LATEST_TAG with the latest GitLab Shell tag you want to upgrade to, for example `v1.7.9`.
### 4. Install libs, migrations, etc. ### 4. Install libs, migrations, etc.
```bash ```bash
......
...@@ -43,28 +43,31 @@ Check if GitLab and its dependencies are configured correctly: ...@@ -43,28 +43,31 @@ Check if GitLab and its dependencies are configured correctly:
If all items are green, then congratulations upgrade is complete! If all items are green, then congratulations upgrade is complete!
## 5. Upgrade GitLab Shell (if needed) ## 5. Upgrade GitLab Shell
If the `gitlab:check` task reports an outdated version of `gitlab-shell` you should upgrade it. GitLab Shell might be outdated, running the commands below ensures you're using a compatible version:
Upgrade it by running the commands below after replacing 2.0.1 with the correct version number:
``` ```
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch sudo -u git -H git fetch
sudo -u git -H git checkout v2.0.1 sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`
``` ```
## One line upgrade command ## One line upgrade command
You've read through the entire guide and probably already did all the steps one by one. You've read through the entire guide and probably already did all the steps one by one.
Here is a one line command with step 1 to 4 for the next time you upgrade: Here is a one line command with step 1 to 5 for the next time you upgrade:
```bash ```bash
cd /home/git/gitlab; sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production; \ cd /home/git/gitlab; \
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production; \
sudo service gitlab stop; \ sudo service gitlab stop; \
if [ -f bin/upgrade.rb ]; then sudo -u git -H ruby bin/upgrade.rb -y; else sudo -u git -H ruby script/upgrade.rb -y; fi; \ if [ -f bin/upgrade.rb ]; then sudo -u git -H ruby bin/upgrade.rb -y; else sudo -u git -H ruby script/upgrade.rb -y; fi; \
cd /home/git/gitlab-shell; \
sudo -u git -H git fetch; \
sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`; \
cd /home/git/gitlab; \
sudo service gitlab start; \ sudo service gitlab start; \
sudo service nginx restart; sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production sudo service nginx restart; sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
``` ```
...@@ -63,6 +63,11 @@ Triggered when a new issue is created or an existing issue was updated/closed/re ...@@ -63,6 +63,11 @@ Triggered when a new issue is created or an existing issue was updated/closed/re
```json ```json
{ {
"object_kind": "issue", "object_kind": "issue",
"user": {
"name": "Administrator",
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"object_attributes": { "object_attributes": {
"id": 301, "id": 301,
"title": "New API: create/update/delete file", "title": "New API: create/update/delete file",
...@@ -92,6 +97,11 @@ Triggered when a new merge request is created or an existing merge request was u ...@@ -92,6 +97,11 @@ Triggered when a new merge request is created or an existing merge request was u
```json ```json
{ {
"object_kind": "merge_request", "object_kind": "merge_request",
"user": {
"name": "Administrator",
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"object_attributes": { "object_attributes": {
"id": 99, "id": 99,
"target_branch": "master", "target_branch": "master",
......
...@@ -29,7 +29,7 @@ class Spinach::Features::EventFilters < Spinach::FeatureSteps ...@@ -29,7 +29,7 @@ class Spinach::Features::EventFilters < Spinach::FeatureSteps
step 'this project has push event' do step 'this project has push event' do
data = { data = {
before: "0000000000000000000000000000000000000000", before: Gitlab::Git::BLANK_SHA,
after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e", after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e",
ref: "refs/heads/new_design", ref: "refs/heads/new_design",
user_id: @user.id, user_id: @user.id,
......
...@@ -109,12 +109,12 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps ...@@ -109,12 +109,12 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
step 'I fill Slack settings' do step 'I fill Slack settings' do
check 'Active' check 'Active'
fill_in 'Webhook', with: 'https://gitlabhq.slack.com/services/hooks?token=cdIj4r4LfXUOySDUjp0tk3OI' fill_in 'Webhook', with: 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685'
click_button 'Save' click_button 'Save'
end end
step 'I should see Slack service settings saved' do step 'I should see Slack service settings saved' do
find_field('Webhook').value.should == 'https://gitlabhq.slack.com/services/hooks?token=cdIj4r4LfXUOySDUjp0tk3OI' find_field('Webhook').value.should == 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685'
end end
step 'I click Pushover service link' do step 'I click Pushover service link' do
......
...@@ -78,7 +78,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -78,7 +78,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end end
step 'I click on "Remove"' do step 'I click on "Remove"' do
click_link 'Remove' click_button 'Remove'
end end
step 'I click on "Remove file"' do step 'I click on "Remove file"' do
......
...@@ -32,7 +32,7 @@ module SharedProject ...@@ -32,7 +32,7 @@ module SharedProject
@project = Project.find_by(name: "Shop") @project = Project.find_by(name: "Shop")
data = { data = {
before: "0000000000000000000000000000000000000000", before: Gitlab::Git::BLANK_SHA,
after: "6d394385cf567f80a8fd85055db1ab4c5295806f", after: "6d394385cf567f80a8fd85055db1ab4c5295806f",
ref: "refs/heads/fix", ref: "refs/heads/fix",
user_id: @user.id, user_id: @user.id,
......
...@@ -82,6 +82,7 @@ module API ...@@ -82,6 +82,7 @@ module API
authorize_push_project authorize_push_project
result = CreateBranchService.new(user_project, current_user). result = CreateBranchService.new(user_project, current_user).
execute(params[:branch_name], params[:ref]) execute(params[:branch_name], params[:ref])
if result[:status] == :success if result[:status] == :success
present result[:branch], present result[:branch],
with: Entities::RepoObject, with: Entities::RepoObject,
...@@ -104,7 +105,9 @@ module API ...@@ -104,7 +105,9 @@ module API
execute(params[:branch]) execute(params[:branch])
if result[:status] == :success if result[:status] == :success
true {
branch_name: params[:branch]
}
else else
render_api_error!(result[:message], result[:return_code]) render_api_error!(result[:message], result[:return_code])
end end
......
...@@ -16,7 +16,8 @@ module API ...@@ -16,7 +16,8 @@ module API
class UserFull < User class UserFull < User
expose :email expose :email
expose :theme_id, :color_scheme_id, :extern_uid, :provider expose :theme_id, :color_scheme_id, :extern_uid, :provider, \
:projects_limit
expose :can_create_group?, as: :can_create_group expose :can_create_group?, as: :can_create_group
expose :can_create_project?, as: :can_create_project expose :can_create_project?, as: :can_create_project
end end
...@@ -73,6 +74,25 @@ module API ...@@ -73,6 +74,25 @@ module API
end end
end end
class RepoTag < Grape::Entity
expose :name
expose :message do |repo_obj, _options|
if repo_obj.respond_to?(:message)
repo_obj.message
else
nil
end
end
expose :commit do |repo_obj, options|
if repo_obj.respond_to?(:commit)
repo_obj.commit
elsif options[:project]
options[:project].repository.commit(repo_obj.target)
end
end
end
class RepoObject < Grape::Entity class RepoObject < Grape::Entity
expose :name expose :name
...@@ -164,6 +184,12 @@ module API ...@@ -164,6 +184,12 @@ module API
expose :target_id, :target_type, :author_id expose :target_id, :target_type, :author_id
expose :data, :target_title expose :data, :target_title
expose :created_at expose :created_at
expose :author_username do |event, options|
if event.author
event.author.username
end
end
end end
class Namespace < Grape::Entity class Namespace < Grape::Entity
......
...@@ -23,7 +23,8 @@ module API ...@@ -23,7 +23,8 @@ module API
# Example Request: # Example Request:
# GET /projects/:id/repository/tags # GET /projects/:id/repository/tags
get ":id/repository/tags" do get ":id/repository/tags" do
present user_project.repo.tags.sort_by(&:name).reverse, with: Entities::RepoObject, project: user_project present user_project.repo.tags.sort_by(&:name).reverse,
with: Entities::RepoTag, project: user_project
end end
# Create tag # Create tag
...@@ -43,7 +44,7 @@ module API ...@@ -43,7 +44,7 @@ module API
if result[:status] == :success if result[:status] == :success
present result[:tag], present result[:tag],
with: Entities::RepoObject, with: Entities::RepoTag,
project: user_project project: user_project
else else
render_api_error!(result[:message], 400) render_api_error!(result[:message], 400)
......
...@@ -91,7 +91,7 @@ module Backup ...@@ -91,7 +91,7 @@ module Backup
protected protected
def path_to_repo(project) def path_to_repo(project)
File.join(repos_path, project.path_with_namespace + '.git') project.repository.path_to_repo
end end
def path_to_bundle(project) def path_to_bundle(project)
......
module Gitlab module Gitlab
class Auth class Auth
def find(login, password) def find(login, password)
user = User.find_by(email: login) || User.find_by(username: login) user = User.by_login(login)
# If no user is found, or it's an LDAP server, try LDAP. # If no user is found, or it's an LDAP server, try LDAP.
# LDAP users are only authenticated via LDAP # LDAP users are only authenticated via LDAP
......
...@@ -8,6 +8,13 @@ module Gitlab ...@@ -8,6 +8,13 @@ module Gitlab
end end
end end
class << self
def version_required
@version_required ||= File.read(Rails.root.
join('GITLAB_SHELL_VERSION')).strip
end
end
# Init new repository # Init new repository
# #
# name - project path with namespace # name - project path with namespace
...@@ -16,7 +23,8 @@ module Gitlab ...@@ -16,7 +23,8 @@ module Gitlab
# add_repository("gitlab/gitlab-ci") # add_repository("gitlab/gitlab-ci")
# #
def add_repository(name) def add_repository(name)
system "#{gitlab_shell_path}/bin/gitlab-projects", "add-project", "#{name}.git" Gitlab::Utils.system_silent([gitlab_shell_projects_path,
'add-project', "#{name}.git"])
end end
# Import repository # Import repository
...@@ -27,7 +35,8 @@ module Gitlab ...@@ -27,7 +35,8 @@ module Gitlab
# import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git") # import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git")
# #
def import_repository(name, url) def import_repository(name, url)
system "#{gitlab_shell_path}/bin/gitlab-projects", "import-project", "#{name}.git", url, '240' Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'import-project',
"#{name}.git", url, '240'])
end end
# Move repository # Move repository
...@@ -39,7 +48,8 @@ module Gitlab ...@@ -39,7 +48,8 @@ module Gitlab
# mv_repository("gitlab/gitlab-ci", "randx/gitlab-ci-new.git") # mv_repository("gitlab/gitlab-ci", "randx/gitlab-ci-new.git")
# #
def mv_repository(path, new_path) def mv_repository(path, new_path)
system "#{gitlab_shell_path}/bin/gitlab-projects", "mv-project", "#{path}.git", "#{new_path}.git" Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'mv-project',
"#{path}.git", "#{new_path}.git"])
end end
# Update HEAD for repository # Update HEAD for repository
...@@ -51,7 +61,8 @@ module Gitlab ...@@ -51,7 +61,8 @@ module Gitlab
# update_repository_head("gitlab/gitlab-ci", "3-1-stable") # update_repository_head("gitlab/gitlab-ci", "3-1-stable")
# #
def update_repository_head(path, branch) def update_repository_head(path, branch)
system "#{gitlab_shell_path}/bin/gitlab-projects", "update-head", "#{path}.git", branch Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'update-head',
"#{path}.git", branch])
end end
# Fork repository to new namespace # Fork repository to new namespace
...@@ -63,7 +74,8 @@ module Gitlab ...@@ -63,7 +74,8 @@ module Gitlab
# fork_repository("gitlab/gitlab-ci", "randx") # fork_repository("gitlab/gitlab-ci", "randx")
# #
def fork_repository(path, fork_namespace) def fork_repository(path, fork_namespace)
system "#{gitlab_shell_path}/bin/gitlab-projects", "fork-project", "#{path}.git", fork_namespace Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'fork-project',
"#{path}.git", fork_namespace])
end end
# Remove repository from file system # Remove repository from file system
...@@ -74,7 +86,8 @@ module Gitlab ...@@ -74,7 +86,8 @@ module Gitlab
# remove_repository("gitlab/gitlab-ci") # remove_repository("gitlab/gitlab-ci")
# #
def remove_repository(name) def remove_repository(name)
system "#{gitlab_shell_path}/bin/gitlab-projects", "rm-project", "#{name}.git" Gitlab::Utils.system_silent([gitlab_shell_projects_path,
'rm-project', "#{name}.git"])
end end
# Add repository branch from passed ref # Add repository branch from passed ref
...@@ -87,7 +100,8 @@ module Gitlab ...@@ -87,7 +100,8 @@ module Gitlab
# add_branch("gitlab/gitlab-ci", "4-0-stable", "master") # add_branch("gitlab/gitlab-ci", "4-0-stable", "master")
# #
def add_branch(path, branch_name, ref) def add_branch(path, branch_name, ref)
system "#{gitlab_shell_path}/bin/gitlab-projects", "create-branch", "#{path}.git", branch_name, ref Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'create-branch',
"#{path}.git", branch_name, ref])
end end
# Remove repository branch # Remove repository branch
...@@ -99,7 +113,8 @@ module Gitlab ...@@ -99,7 +113,8 @@ module Gitlab
# rm_branch("gitlab/gitlab-ci", "4-0-stable") # rm_branch("gitlab/gitlab-ci", "4-0-stable")
# #
def rm_branch(path, branch_name) def rm_branch(path, branch_name)
system "#{gitlab_shell_path}/bin/gitlab-projects", "rm-branch", "#{path}.git", branch_name Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'rm-branch',
"#{path}.git", branch_name])
end end
# Add repository tag from passed ref # Add repository tag from passed ref
...@@ -117,7 +132,7 @@ module Gitlab ...@@ -117,7 +132,7 @@ module Gitlab
cmd = %W(#{gitlab_shell_path}/bin/gitlab-projects create-tag #{path}.git cmd = %W(#{gitlab_shell_path}/bin/gitlab-projects create-tag #{path}.git
#{tag_name} #{ref}) #{tag_name} #{ref})
cmd << message unless message.nil? || message.empty? cmd << message unless message.nil? || message.empty?
system *cmd Gitlab::Utils.system_silent(cmd)
end end
# Remove repository tag # Remove repository tag
...@@ -129,7 +144,8 @@ module Gitlab ...@@ -129,7 +144,8 @@ module Gitlab
# rm_tag("gitlab/gitlab-ci", "v4.0") # rm_tag("gitlab/gitlab-ci", "v4.0")
# #
def rm_tag(path, tag_name) def rm_tag(path, tag_name)
system "#{gitlab_shell_path}/bin/gitlab-projects", "rm-tag", "#{path}.git", tag_name Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'rm-tag',
"#{path}.git", tag_name])
end end
# Add new key to gitlab-shell # Add new key to gitlab-shell
...@@ -138,7 +154,8 @@ module Gitlab ...@@ -138,7 +154,8 @@ module Gitlab
# add_key("key-42", "sha-rsa ...") # add_key("key-42", "sha-rsa ...")
# #
def add_key(key_id, key_content) def add_key(key_id, key_content)
system "#{gitlab_shell_path}/bin/gitlab-keys", "add-key", key_id, key_content Gitlab::Utils.system_silent([gitlab_shell_keys_path,
'add-key', key_id, key_content])
end end
# Batch-add keys to authorized_keys # Batch-add keys to authorized_keys
...@@ -157,7 +174,8 @@ module Gitlab ...@@ -157,7 +174,8 @@ module Gitlab
# remove_key("key-342", "sha-rsa ...") # remove_key("key-342", "sha-rsa ...")
# #
def remove_key(key_id, key_content) def remove_key(key_id, key_content)
system "#{gitlab_shell_path}/bin/gitlab-keys", "rm-key", key_id, key_content Gitlab::Utils.system_silent([gitlab_shell_keys_path,
'rm-key', key_id, key_content])
end end
# Remove all ssh keys from gitlab shell # Remove all ssh keys from gitlab shell
...@@ -166,7 +184,7 @@ module Gitlab ...@@ -166,7 +184,7 @@ module Gitlab
# remove_all_keys # remove_all_keys
# #
def remove_all_keys def remove_all_keys
system "#{gitlab_shell_path}/bin/gitlab-keys", "clear" Gitlab::Utils.system_silent([gitlab_shell_keys_path, 'clear'])
end end
# Add empty directory for storing repositories # Add empty directory for storing repositories
...@@ -249,5 +267,13 @@ module Gitlab ...@@ -249,5 +267,13 @@ module Gitlab
def exists?(dir_name) def exists?(dir_name)
File.exists?(full_path(dir_name)) File.exists?(full_path(dir_name))
end end
def gitlab_shell_projects_path
File.join(gitlab_shell_path, 'bin', 'gitlab-projects')
end
def gitlab_shell_keys_path
File.join(gitlab_shell_path, 'bin', 'gitlab-keys')
end
end end
end end
module Gitlab
module Git
BLANK_SHA = '0' * 40
end
end
...@@ -67,7 +67,7 @@ module Gitlab ...@@ -67,7 +67,7 @@ module Gitlab
if forced_push?(project, oldrev, newrev) if forced_push?(project, oldrev, newrev)
:force_push_code_to_protected_branches :force_push_code_to_protected_branches
# and we dont allow remove of protected branch # and we dont allow remove of protected branch
elsif newrev =~ /0000000/ elsif newrev == Gitlab::Git::BLANK_SHA
:remove_protected_branches :remove_protected_branches
else else
:push_code_to_protected_branches :push_code_to_protected_branches
...@@ -85,7 +85,7 @@ module Gitlab ...@@ -85,7 +85,7 @@ module Gitlab
def forced_push?(project, oldrev, newrev) def forced_push?(project, oldrev, newrev)
return false if project.empty_repo? return false if project.empty_repo?
if oldrev !~ /00000000/ && newrev !~ /00000000/ if oldrev != Gitlab::Git::BLANK_SHA && newrev != Gitlab::Git::BLANK_SHA
missed_refs = IO.popen(%W(git --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})).read missed_refs = IO.popen(%W(git --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})).read
missed_refs.split("\n").size > 0 missed_refs.split("\n").size > 0
else else
......
...@@ -5,7 +5,8 @@ module Gitlab ...@@ -5,7 +5,8 @@ module Gitlab
# #
# Returns true for a valid reference name, false otherwise # Returns true for a valid reference name, false otherwise
def validate(ref_name) def validate(ref_name)
system *%W(git check-ref-format refs/#{ref_name}) Gitlab::Utils.system_silent(
%W(git check-ref-format refs/#{ref_name}))
end end
end end
end end
...@@ -15,7 +15,6 @@ module Gitlab ...@@ -15,7 +15,6 @@ module Gitlab
{ title: "support", color: yellow }, { title: "support", color: yellow },
{ title: "discussion", color: blue }, { title: "discussion", color: blue },
{ title: "suggestion", color: blue }, { title: "suggestion", color: blue },
{ title: "feature", color: green },
{ title: "enhancement", color: green } { title: "enhancement", color: green }
] ]
......
...@@ -67,8 +67,7 @@ module Gitlab ...@@ -67,8 +67,7 @@ module Gitlab
def default_regex_message def default_regex_message
"can contain only letters, digits, '_', '-' and '.'. " \ "can contain only letters, digits, '_', '-' and '.'. " \
"It must start with letter, digit or '_', optionally preceeded by '.'. " \ "Cannot start with '-' or end in '.git'" \
"It must not end in '.git'."
end end
def default_regex def default_regex
......
module Gitlab
module Utils
extend self
# Run system command without outputting to stdout.
#
# @param cmd [Array<String>]
# @return [Boolean]
def system_silent(cmd)
Popen::popen(cmd).last.zero?
end
end
end
## GitLab ## GitLab
## Maintainer: @randx ## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller
## ##
## Lines starting with two hashes (##) are comments with information. ## Lines starting with two hashes (##) are comments with information.
## Lines starting with one hash (#) are configuration parameters that can be uncommented. ## Lines starting with one hash (#) are configuration parameters that can be uncommented.
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
## - installing an old version of Nginx with the chunkin module [2] compiled in, or ## - installing an old version of Nginx with the chunkin module [2] compiled in, or
## - using a newer version of Nginx. ## - using a newer version of Nginx.
## ##
## At the time of writing we do not know if either of these theoretical solutions works. ## At the time of writing we do not know if either of these theoretical solutions works.
## As a workaround users can use Git over SSH to push large files. ## As a workaround users can use Git over SSH to push large files.
## ##
## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99 ## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
## configuration ## ## configuration ##
################################### ###################################
## ##
## See installation.md#using-https for additional HTTPS configuration details.
upstream gitlab { upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
...@@ -33,7 +34,8 @@ upstream gitlab { ...@@ -33,7 +34,8 @@ upstream gitlab {
## Normal HTTP host ## Normal HTTP host
server { server {
listen *:80 default_server; listen 0.0.0.0:80 default_server;
listen [::]:80 default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public; root /home/git/gitlab/public;
...@@ -42,6 +44,8 @@ server { ...@@ -42,6 +44,8 @@ server {
## Or if you want to accept large git objects over http ## Or if you want to accept large git objects over http
client_max_body_size 20m; client_max_body_size 20m;
## See app/controllers/application_controller.rb for headers set
## Individual nginx logs for this GitLab vhost ## Individual nginx logs for this GitLab vhost
access_log /var/log/nginx/gitlab_access.log; access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log; error_log /var/log/nginx/gitlab_error.log;
......
## GitLab ## GitLab
## Contributors: randx, yin8086, sashkab, orkoden, axilleas ## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller
## ##
## Modified from nginx http version ## Modified from nginx http version
## Modified from http://blog.phusion.nl/2012/04/21/tutorial-setting-up-gitlab-on-debian-6/ ## Modified from http://blog.phusion.nl/2012/04/21/tutorial-setting-up-gitlab-on-debian-6/
...@@ -26,9 +26,8 @@ ...@@ -26,9 +26,8 @@
## [1] https://github.com/agentzh/chunkin-nginx-module#status ## [1] https://github.com/agentzh/chunkin-nginx-module#status
## [2] https://github.com/agentzh/chunkin-nginx-module ## [2] https://github.com/agentzh/chunkin-nginx-module
## ##
##
################################### ###################################
## SSL configuration ## ## configuration ##
################################### ###################################
## ##
## See installation.md#using-https for additional HTTPS configuration details. ## See installation.md#using-https for additional HTTPS configuration details.
...@@ -37,22 +36,24 @@ upstream gitlab { ...@@ -37,22 +36,24 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
} }
## Normal HTTP host ## Redirects all HTTP traffic to the HTTPS host
server { server {
listen *:80 default_server; listen 0.0.0.0:80;
listen [::]:80 default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice server_tokens off; ## Don't show the nginx version number, a security best practice
return 301 https://$server_name$request_uri;
## Redirects all traffic to the HTTPS host access_log /var/log/nginx/gitlab_access.log;
root /nowhere; ## root doesn't have to be a valid path since we are redirecting error_log /var/log/nginx/gitlab_error.log;
rewrite ^ https://$server_name$request_uri? permanent;
} }
## HTTPS host ## HTTPS host
server { server {
listen 443 ssl; listen 0.0.0.0:443 ssl;
listen [::]:443 ssl default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
server_tokens off; server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public; root /home/git/gitlab/public;
## Increase this if you want to upload large attachments ## Increase this if you want to upload large attachments
...@@ -70,12 +71,9 @@ server { ...@@ -70,12 +71,9 @@ server {
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on; ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m; ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
## [WARNING] The following header states that the browser should only communicate ## See app/controllers/application_controller.rb for headers set
## with your server over a secure connection for the next 24 months.
add_header Strict-Transport-Security max-age=63072000;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
## [Optional] If your certficate has OCSP, enable OCSP stapling to reduce the overhead and latency of running SSL. ## [Optional] If your certficate has OCSP, enable OCSP stapling to reduce the overhead and latency of running SSL.
## Replace with your ssl_trusted_certificate. For more info see: ## Replace with your ssl_trusted_certificate. For more info see:
......
...@@ -574,20 +574,16 @@ namespace :gitlab do ...@@ -574,20 +574,16 @@ namespace :gitlab do
Gitlab::Shell.new.version Gitlab::Shell.new.version
end end
def required_gitlab_shell_version
File.read(File.join(Rails.root, "GITLAB_SHELL_VERSION")).strip
end
def gitlab_shell_major_version def gitlab_shell_major_version
required_gitlab_shell_version.split(".")[0].to_i Gitlab::Shell.version_required.split('.')[0].to_i
end end
def gitlab_shell_minor_version def gitlab_shell_minor_version
required_gitlab_shell_version.split(".")[1].to_i Gitlab::Shell.version_required.split('.')[1].to_i
end end
def gitlab_shell_patch_version def gitlab_shell_patch_version
required_gitlab_shell_version.split(".")[2].to_i Gitlab::Shell.version_required.split('.')[2].to_i
end end
def has_gitlab_shell3? def has_gitlab_shell3?
......
...@@ -4,7 +4,7 @@ namespace :gitlab do ...@@ -4,7 +4,7 @@ namespace :gitlab do
task :install, [:tag, :repo] => :environment do |t, args| task :install, [:tag, :repo] => :environment do |t, args|
warn_user_is_not_gitlab warn_user_is_not_gitlab
default_version = File.read(File.join(Rails.root, "GITLAB_SHELL_VERSION")).strip default_version = Gitlab::Shell.version_required
args.with_defaults(tag: 'v' + default_version, repo: "https://gitlab.com/gitlab-org/gitlab-shell.git") args.with_defaults(tag: 'v' + default_version, repo: "https://gitlab.com/gitlab-org/gitlab-shell.git")
user = Gitlab.config.gitlab.user user = Gitlab.config.gitlab.user
...@@ -76,7 +76,7 @@ namespace :gitlab do ...@@ -76,7 +76,7 @@ namespace :gitlab do
desc "GITLAB | Build missing projects" desc "GITLAB | Build missing projects"
task build_missing_projects: :environment do task build_missing_projects: :environment do
Project.find_each(batch_size: 1000) do |project| Project.find_each(batch_size: 1000) do |project|
path_to_repo = File.join(Gitlab.config.gitlab_shell.repos_path, "#{project.path_with_namespace}.git") path_to_repo = project.repository.path_to_repo
if File.exists?(path_to_repo) if File.exists?(path_to_repo)
print '-' print '-'
else else
......
...@@ -10,13 +10,21 @@ describe Gitlab::Auth do ...@@ -10,13 +10,21 @@ describe Gitlab::Auth do
password: password, password: password,
password_confirmation: password) password_confirmation: password)
end end
let(:username) { 'john' } let(:username) { 'John' } # username isn't lowercase, test this
let(:password) { 'my-secret' } let(:password) { 'my-secret' }
it "should find user by valid login/password" do it "should find user by valid login/password" do
expect( gl_auth.find(username, password) ).to eql user expect( gl_auth.find(username, password) ).to eql user
end end
it 'should find user by valid email/password with case-insensitive email' do
expect(gl_auth.find(user.email.upcase, password)).to eql user
end
it 'should find user by valid username/password with case-insensitive username' do
expect(gl_auth.find(username.upcase, password)).to eql user
end
it "should not find user with invalid password" do it "should not find user with invalid password" do
password = 'wrong' password = 'wrong'
expect( gl_auth.find(username, password) ).to_not eql user expect( gl_auth.find(username, password) ).to_not eql user
......
...@@ -55,12 +55,13 @@ describe Gitlab::GitAccess do ...@@ -55,12 +55,13 @@ describe Gitlab::GitAccess do
def changes def changes
{ {
push_new_branch: '000000000 570e7b2ab refs/heads/wow', push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow",
push_master: '6f6d7e7ed 570e7b2ab refs/heads/master', push_master: '6f6d7e7ed 570e7b2ab refs/heads/master',
push_protected_branch: '6f6d7e7ed 570e7b2ab refs/heads/feature', push_protected_branch: '6f6d7e7ed 570e7b2ab refs/heads/feature',
push_remove_protected_branch: '570e7b2ab 000000000 refs/heads/feature', push_remove_protected_branch: "570e7b2ab #{Gitlab::Git::BLANK_SHA} "\
'refs/heads/feature',
push_tag: '6f6d7e7ed 570e7b2ab refs/tags/v1.0.0', push_tag: '6f6d7e7ed 570e7b2ab refs/tags/v1.0.0',
push_new_tag: '000000000 570e7b2ab refs/tags/v7.8.9', push_new_tag: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/tags/v7.8.9",
push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature'] push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature']
} }
end end
......
...@@ -36,7 +36,7 @@ describe Event do ...@@ -36,7 +36,7 @@ describe Event do
@user = project.owner @user = project.owner
data = { data = {
before: "0000000000000000000000000000000000000000", before: Gitlab::Git::BLANK_SHA,
after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e", after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e",
ref: "refs/heads/master", ref: "refs/heads/master",
user_id: @user.id, user_id: @user.id,
...@@ -60,7 +60,6 @@ describe Event do ...@@ -60,7 +60,6 @@ describe Event do
it { @event.push?.should be_true } it { @event.push?.should be_true }
it { @event.proper?.should be_true } it { @event.proper?.should be_true }
it { @event.new_branch?.should be_true }
it { @event.tag?.should be_false } it { @event.tag?.should be_false }
it { @event.branch_name.should == "master" } it { @event.branch_name.should == "master" }
it { @event.author.should == @user } it { @event.author.should == @user }
......
...@@ -34,11 +34,11 @@ describe GitlabCiService do ...@@ -34,11 +34,11 @@ describe GitlabCiService do
end end
describe :commit_status_path do describe :commit_status_path do
it { @service.commit_status_path("2ab7834c").should == "http://ci.gitlab.org/projects/2/builds/2ab7834c/status.json?token=verySecret"} it { @service.commit_status_path("2ab7834c").should == "http://ci.gitlab.org/projects/2/commits/2ab7834c/status.json?token=verySecret"}
end end
describe :build_page do describe :build_page do
it { @service.build_page("2ab7834c").should == "http://ci.gitlab.org/projects/2/builds/2ab7834c"} it { @service.build_page("2ab7834c").should == "http://ci.gitlab.org/projects/2/commits/2ab7834c"}
end end
end end
end end
...@@ -249,6 +249,12 @@ describe Note do ...@@ -249,6 +249,12 @@ describe Note do
its(:note) { should == "_mentioned in merge request !#{mergereq.iid}_" } its(:note) { should == "_mentioned in merge request !#{mergereq.iid}_" }
end end
context 'commit contained in a merge request' do
subject { Note.create_cross_reference_note(mergereq.commits.first, mergereq, author, project) }
it { should be_nil }
end
context 'commit from issue' do context 'commit from issue' do
subject { Note.create_cross_reference_note(commit, issue, author, project) } subject { Note.create_cross_reference_note(commit, issue, author, project) }
......
...@@ -145,63 +145,6 @@ describe Project do ...@@ -145,63 +145,6 @@ describe Project do
end end
end end
describe 'comment merge requests with commits' do
before do
@user = create(:user)
group = create(:group)
group.add_owner(@user)
@project = create(:project, namespace: group)
@fork_project = Projects::ForkService.new(@project, @user).execute
@merge_request = create(:merge_request, source_project: @project,
source_branch: 'master',
target_branch: 'feature',
target_project: @project)
@fork_merge_request = create(:merge_request, source_project: @fork_project,
source_branch: 'master',
target_branch: 'feature',
target_project: @project)
@commits = @merge_request.commits
end
context 'push to origin repo source branch' do
before do
@project.comment_mr_with_commits('master', @commits, @user)
end
it { @merge_request.notes.should_not be_empty }
it { @fork_merge_request.notes.should be_empty }
end
context 'push to origin repo target branch' do
before do
@project.comment_mr_with_commits('feature', @commits, @user)
end
it { @merge_request.notes.should be_empty }
it { @fork_merge_request.notes.should be_empty }
end
context 'push to fork repo source branch' do
before do
@fork_project.comment_mr_with_commits('master', @commits, @user)
end
it { @merge_request.notes.should be_empty }
it { @fork_merge_request.notes.should_not be_empty }
end
context 'push to fork repo target branch' do
before do
@fork_project.comment_mr_with_commits('feature', @commits, @user)
end
it { @merge_request.notes.should be_empty }
it { @fork_merge_request.notes.should be_empty }
end
end
describe :find_with_namespace do describe :find_with_namespace do
context 'with namespace' do context 'with namespace' do
before do before do
......
require_relative '../../app/models/project_services/slack_message' require 'spec_helper'
describe SlackMessage do describe SlackMessage do
subject { SlackMessage.new(args) } subject { SlackMessage.new(args) }
...@@ -26,11 +26,11 @@ describe SlackMessage do ...@@ -26,11 +26,11 @@ describe SlackMessage do
it 'returns a message regarding pushes' do it 'returns a message regarding pushes' do
subject.pretext.should == subject.pretext.should ==
'user_name pushed to branch <url/commits/master|master> of ' << 'user_name pushed to branch <url/commits/master|master> of '\
'<url|project_name> (<url/compare/before...after|Compare changes>)' '<url|project_name> (<url/compare/before...after|Compare changes>)'
subject.attachments.should == [ subject.attachments.should == [
{ {
text: "<url1|abcdefghi>: message1 - author1\n" << text: "<url1|abcdefghi>: message1 - author1\n"\
"<url2|123456789>: message2 - author2", "<url2|123456789>: message2 - author2",
color: color, color: color,
} }
...@@ -45,7 +45,7 @@ describe SlackMessage do ...@@ -45,7 +45,7 @@ describe SlackMessage do
it 'returns a message regarding a new branch' do it 'returns a message regarding a new branch' do
subject.pretext.should == subject.pretext.should ==
'user_name pushed new branch <url/commits/master|master> to ' << 'user_name pushed new branch <url/commits/master|master> to '\
'<url|project_name>' '<url|project_name>'
subject.attachments.should be_empty subject.attachments.should be_empty
end end
......
...@@ -31,71 +31,27 @@ describe SlackService do ...@@ -31,71 +31,27 @@ describe SlackService do
end end
describe "Execute" do describe "Execute" do
let(:slack) { SlackService.new } let(:slack) { SlackService.new }
let(:slack_service) { SlackService.new } let(:user) { create(:user) }
let(:user) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:project) }
let(:sample_data) { GitPushService.new.sample_data(project, user) } let(:sample_data) { GitPushService.new.sample_data(project, user) }
let(:webhook) { 'https://gitlabhq.slack.com/services/hooks?token=cdIj4r4LfXUOySDUjp0tk3OI' } let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' }
let(:new_webhook) { 'https://hooks.gitlabhq.slack.com/services/cdIj4r4LfXUOySDUjp0tk3OI' }
let(:api_url) {
'https://gitlabhq.slack.com/services/hooks/incoming-webhook?token=cdIj4r4LfXUOySDUjp0tk3OI'
}
before do before do
slack.stub( slack.stub(
project: project, project: project,
project_id: project.id, project_id: project.id,
service_hook: true, service_hook: true,
webhook: webhook webhook: webhook_url
) )
WebMock.stub_request(:post, api_url) WebMock.stub_request(:post, webhook_url)
end end
it "should call Slack API" do it "should call Slack API" do
slack.execute(sample_data) slack.execute(sample_data)
WebMock.should have_requested(:post, api_url).once WebMock.should have_requested(:post, webhook_url).once
end
context 'with new webhook syntax' do
before do
slack_service.stub(
project: project,
project_id: project.id,
service_hook: true,
webhook: new_webhook
)
WebMock.stub_request(:post, api_url)
end
it "should call Slack API" do
slack_service.execute(sample_data)
WebMock.should have_requested(:post, api_url).once
end
end
context 'with new webhook syntax with slack allowed team name' do
before do
@allowed_webhook = 'https://gitlab-hq-123.slack.com/services/hooks/incoming-webhook?token=cdIj4r4LfXUOySDUjp0tk3OI'
slack_service.stub(
project: project,
project_id: project.id,
service_hook: true,
webhook: @allowed_webhook
)
WebMock.stub_request(:post, @allowed_webhook)
end
it "should call Slack API" do
slack_service.execute(sample_data)
WebMock.should have_requested(:post, @allowed_webhook).once
end
end end
end end
end end
...@@ -287,6 +287,20 @@ describe User do ...@@ -287,6 +287,20 @@ describe User do
end end
end end
describe '.by_login' do
let(:username) { 'John' }
let!(:user) { create(:user, username: username) }
it 'should get the correct user' do
expect(User.by_login(user.email.upcase)).to eq user
expect(User.by_login(user.email)).to eq user
expect(User.by_login(username.downcase)).to eq user
expect(User.by_login(username)).to eq user
expect(User.by_login(nil)).to be_nil
expect(User.by_login('')).to be_nil
end
end
describe 'all_ssh_keys' do describe 'all_ssh_keys' do
it { should have_many(:keys).dependent(:destroy) } it { should have_many(:keys).dependent(:destroy) }
......
...@@ -146,6 +146,7 @@ describe API::API, api: true do ...@@ -146,6 +146,7 @@ describe API::API, api: true do
it "should remove branch" do it "should remove branch" do
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user) delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
response.status.should == 200 response.status.should == 200
json_response['branch_name'].should == branch_name
end end
it 'should return 404 if branch not exists' do it 'should return 404 if branch not exists' do
......
...@@ -203,15 +203,12 @@ describe API::API, api: true do ...@@ -203,15 +203,12 @@ describe API::API, api: true do
json_response['message']['name'].should == [ json_response['message']['name'].should == [
'can\'t be blank', 'can\'t be blank',
'is too short (minimum is 0 characters)', 'is too short (minimum is 0 characters)',
'can contain only letters, digits, \'_\', \'-\' and \'.\' and '\ Gitlab::Regex.project_regex_message
'space. It must start with letter, digit or \'_\'.'
] ]
json_response['message']['path'].should == [ json_response['message']['path'].should == [
'can\'t be blank', 'can\'t be blank',
'is too short (minimum is 0 characters)', 'is too short (minimum is 0 characters)',
'can contain only letters, digits, \'_\', \'-\' and \'.\'. It must '\ Gitlab::Regex.send(:default_regex_message)
'start with letter, digit or \'_\', optionally preceeded by \'.\'. '\
'It must not end in \'.git\'.'
] ]
end end
...@@ -339,6 +336,7 @@ describe API::API, api: true do ...@@ -339,6 +336,7 @@ describe API::API, api: true do
json_event['action_name'].should == 'joined' json_event['action_name'].should == 'joined'
json_event['project_id'].to_i.should == project.id json_event['project_id'].to_i.should == project.id
json_event['author_username'].should == user.username
end end
it "should return a 404 error if not found" do it "should return a 404 error if not found" do
......
...@@ -34,21 +34,23 @@ describe API::API, api: true do ...@@ -34,21 +34,23 @@ describe API::API, api: true do
end end
end end
# TODO: fix this test for CI context 'annotated tag' do
#context 'annotated tag' do it 'should create a new annotated tag' do
#it 'should create a new annotated tag' do # Identity must be set in .gitconfig to create annotated tag.
#post api("/projects/#{project.id}/repository/tags", user), repo_path = project.repository.path_to_repo
#tag_name: 'v7.1.0', system(*%W(git --git-dir=#{repo_path} config user.name #{user.name}))
#ref: 'master', system(*%W(git --git-dir=#{repo_path} config user.email #{user.email}))
#message: 'tag message'
post api("/projects/#{project.id}/repository/tags", user),
#response.status.should == 201 tag_name: 'v7.1.0',
#json_response['name'].should == 'v7.1.0' ref: 'master',
# The message is not part of the JSON response. message: 'Release 7.1.0'
# Additional changes to the gitlab_git gem may be required.
# json_response['message'].should == 'tag message' response.status.should == 201
#end json_response['name'].should == 'v7.1.0'
#end json_response['message'].should == 'Release 7.1.0'
end
end
it 'should deny for user without push access' do it 'should deny for user without push access' do
post api("/projects/#{project.id}/repository/tags", user2), post api("/projects/#{project.id}/repository/tags", user2),
......
...@@ -19,6 +19,32 @@ describe API::API, api: true do ...@@ -19,6 +19,32 @@ describe API::API, api: true do
end end
end end
context 'when email has case-typo and password is valid' do
it 'should return private token' do
post api('/session'), email: user.email.upcase, password: '12345678'
expect(response.status).to eq 201
expect(json_response['email']).to eq user.email
expect(json_response['private_token']).to eq user.private_token
expect(json_response['is_admin']).to eq user.is_admin?
expect(json_response['can_create_project']).to eq user.can_create_project?
expect(json_response['can_create_group']).to eq user.can_create_group?
end
end
context 'when login has case-typo and password is valid' do
it 'should return private token' do
post api('/session'), login: user.username.upcase, password: '12345678'
expect(response.status).to eq 201
expect(json_response['email']).to eq user.email
expect(json_response['private_token']).to eq user.private_token
expect(json_response['is_admin']).to eq user.is_admin?
expect(json_response['can_create_project']).to eq user.can_create_project?
expect(json_response['can_create_group']).to eq user.can_create_group?
end
end
context "when invalid password" do context "when invalid password" do
it "should return authentication error" do it "should return authentication error" do
post api("/session"), email: user.email, password: '123' post api("/session"), email: user.email, password: '123'
......
...@@ -140,9 +140,7 @@ describe API::API, api: true do ...@@ -140,9 +140,7 @@ describe API::API, api: true do
json_response['message']['projects_limit']. json_response['message']['projects_limit'].
should == ['must be greater than or equal to 0'] should == ['must be greater than or equal to 0']
json_response['message']['username']. json_response['message']['username'].
should == ['can contain only letters, digits, '\ should == [Gitlab::Regex.send(:default_regex_message)]
'\'_\', \'-\' and \'.\'. It must start with letter, digit or '\
'\'_\', optionally preceeded by \'.\'. It must not end in \'.git\'.']
end end
it "shouldn't available for non admin users" do it "shouldn't available for non admin users" do
...@@ -284,9 +282,7 @@ describe API::API, api: true do ...@@ -284,9 +282,7 @@ describe API::API, api: true do
json_response['message']['projects_limit']. json_response['message']['projects_limit'].
should == ['must be greater than or equal to 0'] should == ['must be greater than or equal to 0']
json_response['message']['username']. json_response['message']['username'].
should == ['can contain only letters, digits, '\ should == [Gitlab::Regex.send(:default_regex_message)]
'\'_\', \'-\' and \'.\'. It must start with letter, digit or '\
'\'_\', optionally preceeded by \'.\'. It must not end in \'.git\'.']
end end
context "with existing user" do context "with existing user" do
...@@ -433,6 +429,7 @@ describe API::API, api: true do ...@@ -433,6 +429,7 @@ describe API::API, api: true do
json_response['is_admin'].should == user.is_admin? json_response['is_admin'].should == user.is_admin?
json_response['can_create_project'].should == user.can_create_project? json_response['can_create_project'].should == user.can_create_project?
json_response['can_create_group'].should == user.can_create_group? json_response['can_create_group'].should == user.can_create_group?
json_response['projects_limit'].should == user.projects_limit
end end
it "should return 401 error if user is unauthenticated" do it "should return 401 error if user is unauthenticated" do
......
...@@ -8,7 +8,7 @@ describe GitPushService do ...@@ -8,7 +8,7 @@ describe GitPushService do
let (:service) { GitPushService.new } let (:service) { GitPushService.new }
before do before do
@blankrev = '0000000000000000000000000000000000000000' @blankrev = Gitlab::Git::BLANK_SHA
@oldrev = sample_commit.parent_id @oldrev = sample_commit.parent_id
@newrev = sample_commit.id @newrev = sample_commit.id
@ref = 'refs/heads/master' @ref = 'refs/heads/master'
......
require 'spec_helper'
describe MergeRequests::RefreshService do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:service) { MergeRequests::RefreshService }
describe :execute do
before do
@user = create(:user)
group = create(:group)
group.add_owner(@user)
@project = create(:project, namespace: group)
@fork_project = Projects::ForkService.new(@project, @user).execute
@merge_request = create(:merge_request, source_project: @project,
source_branch: 'master',
target_branch: 'feature',
target_project: @project)
@fork_merge_request = create(:merge_request, source_project: @fork_project,
source_branch: 'master',
target_branch: 'feature',
target_project: @project)
@commits = @merge_request.commits
@oldrev = @commits.last.id
@newrev = @commits.first.id
end
context 'push to origin repo source branch' do
before do
service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
end
it { @merge_request.notes.should_not be_empty }
it { @merge_request.should be_open }
it { @fork_merge_request.should be_open }
it { @fork_merge_request.notes.should be_empty }
end
context 'push to origin repo target branch' do
before do
service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
reload_mrs
end
it { @merge_request.notes.should be_empty }
it { @merge_request.should be_merged }
it { @fork_merge_request.should be_merged }
it { @fork_merge_request.notes.should be_empty }
end
context 'push to fork repo source branch' do
before do
service.new(@fork_project, @user).execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
end
it { @merge_request.notes.should be_empty }
it { @merge_request.should be_open }
it { @fork_merge_request.notes.should_not be_empty }
it { @fork_merge_request.should be_open }
end
context 'push to fork repo target branch' do
before do
service.new(@fork_project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
reload_mrs
end
it { @merge_request.notes.should be_empty }
it { @merge_request.should be_open }
it { @fork_merge_request.notes.should be_empty }
it { @fork_merge_request.should be_open }
end
context 'push to origin repo target branch after fork project was removed' do
before do
@fork_project.destroy
service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
reload_mrs
end
it { @merge_request.notes.should be_empty }
it { @merge_request.should be_merged }
it { @fork_merge_request.should be_open }
it { @fork_merge_request.notes.should be_empty }
end
def reload_mrs
@merge_request.reload
@fork_merge_request.reload
end
end
end
...@@ -3,6 +3,16 @@ require 'rspec/mocks' ...@@ -3,6 +3,16 @@ require 'rspec/mocks'
module TestEnv module TestEnv
extend self extend self
# When developing the seed repository, comment out the branch you will modify.
BRANCH_SHA = {
'feature' => '0b4bc9a',
'feature_conflict' => 'bb5206f',
'fix' => '12d65c8',
'improve/awesome' => '5937ac0',
'markdown' => '0ed8c6c',
'master' => '5937ac0'
}
# Test environment # Test environment
# #
# See gitlab.yml.example test section for paths # See gitlab.yml.example test section for paths
...@@ -18,13 +28,13 @@ module TestEnv ...@@ -18,13 +28,13 @@ module TestEnv
if File.directory?(tmp_test_path) if File.directory?(tmp_test_path)
Dir.entries(tmp_test_path).each do |entry| Dir.entries(tmp_test_path).each do |entry|
unless ['.', '..', 'gitlab-shell'].include?(entry) unless ['.', '..', 'gitlab-shell', factory_repo_name].include?(entry)
FileUtils.rm_r(File.join(tmp_test_path, entry)) FileUtils.rm_r(File.join(tmp_test_path, entry))
end end
end end
end end
FileUtils.mkdir_p(tmp_test_path) FileUtils.mkdir_p(repos_path)
# Setup GitLab shell for test instance # Setup GitLab shell for test instance
setup_gitlab_shell setup_gitlab_shell
...@@ -49,13 +59,32 @@ module TestEnv ...@@ -49,13 +59,32 @@ module TestEnv
clone_url = "https://gitlab.com/gitlab-org/#{factory_repo_name}.git" clone_url = "https://gitlab.com/gitlab-org/#{factory_repo_name}.git"
unless File.directory?(factory_repo_path) unless File.directory?(factory_repo_path)
git_cmd = %W(git clone --bare #{clone_url} #{factory_repo_path}) system(*%W(git clone #{clone_url} #{factory_repo_path}))
system(*git_cmd) end
Dir.chdir(factory_repo_path) do
BRANCH_SHA.each do |branch, sha|
# Try to reset without fetching to avoid using the network.
reset = %W(git update-ref refs/heads/#{branch} #{sha})
unless system(*reset)
if system(*%w(git fetch origin))
unless system(*reset)
raise 'The fetched test seed '\
'does not contain the required revision.'
end
else
raise 'Could not fetch test seed repository.'
end
end
end
end end
# We must copy bare repositories because we will push to them.
system(*%W(git clone --bare #{factory_repo_path} #{factory_repo_path_bare}))
end end
def copy_repo(project) def copy_repo(project)
base_repo_path = File.expand_path(factory_repo_path) base_repo_path = File.expand_path(factory_repo_path_bare)
target_repo_path = File.expand_path(repos_path + "/#{project.namespace.path}/#{project.path}.git") target_repo_path = File.expand_path(repos_path + "/#{project.namespace.path}/#{project.path}.git")
FileUtils.mkdir_p(target_repo_path) FileUtils.mkdir_p(target_repo_path)
FileUtils.cp_r("#{base_repo_path}/.", target_repo_path) FileUtils.cp_r("#{base_repo_path}/.", target_repo_path)
...@@ -69,7 +98,11 @@ module TestEnv ...@@ -69,7 +98,11 @@ module TestEnv
private private
def factory_repo_path def factory_repo_path
@factory_repo_path ||= repos_path + "/root/#{factory_repo_name}.git" @factory_repo_path ||= Rails.root.join('tmp', 'tests', factory_repo_name)
end
def factory_repo_path_bare
factory_repo_path.to_s + '_bare'
end end
def factory_repo_name def factory_repo_name
......
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