Commit 860a80ea authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq

Conflicts:
	app/assets/stylesheets/common.scss
	db/schema.rb
parents cc36f6dc 96e89ec3
v 6.0.0 v 6.0.0
- Feature: Replace teams with group membership - Feature: Replace teams with group membership
We introduce group membership in 6.0 as a replacement for teams.
The old combination of groups and teams was confusing for a lot of people.
And when the members of a team where changed this wasn't reflected in the project permissions.
In GitLab 6.0 you will be able to add members to a group with a permission level for each member.
These group members will have access to the projects in that group.
Any changes to group members will immediately be reflected in the project permissions.
You can even have multiple owners for a group, greatly simplifying administration.
- Feature: Ability to have multiple owners for group - Feature: Ability to have multiple owners for group
- Feature: Merge Requests between fork and project (Izaak Alpert) - Feature: Merge Requests between fork and project (Izaak Alpert)
- Feature: Generate fingerprint for ssh keys - Feature: Generate fingerprint for ssh keys
...@@ -24,7 +31,7 @@ v 6.0.0 ...@@ -24,7 +31,7 @@ v 6.0.0
- Move all project controllers/views under Projects:: module - Move all project controllers/views under Projects:: module
- Move all profile controllers/views under Profiles:: module - Move all profile controllers/views under Profiles:: module
- Apply user project limit only for personal projects - Apply user project limit only for personal projects
- Unicorn is default web server for new installations - Unicorn is default web server again
- Store satellites lock files inside satellites dir - Store satellites lock files inside satellites dir
- Disabled threadsafety mode in rails - Disabled threadsafety mode in rails
- Fixed bug with loosing MR comments - Fixed bug with loosing MR comments
......
...@@ -23,7 +23,7 @@ gem 'omniauth-github' ...@@ -23,7 +23,7 @@ gem 'omniauth-github'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", "~> 2.0.0.pre" gem "gitlab_git", '2.0.1'
# Ruby/Rack Git Smart-HTTP Server Handler # Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 1.0.1', require: 'grack' gem 'gitlab-grack', '~> 1.0.1', require: 'grack'
......
...@@ -186,7 +186,7 @@ GEM ...@@ -186,7 +186,7 @@ GEM
gitlab-pygments.rb (0.3.2) gitlab-pygments.rb (0.3.2)
posix-spawn (~> 0.3.6) posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0) yajl-ruby (~> 1.1.0)
gitlab_git (2.0.0.pre) gitlab_git (2.0.1)
activesupport (~> 3.2.13) activesupport (~> 3.2.13)
github-linguist (~> 2.3.4) github-linguist (~> 2.3.4)
gitlab-grit (~> 2.6.0) gitlab-grit (~> 2.6.0)
...@@ -285,7 +285,7 @@ GEM ...@@ -285,7 +285,7 @@ GEM
minitest (4.7.4) minitest (4.7.4)
modernizr (2.6.2) modernizr (2.6.2)
sprockets (~> 2.0) sprockets (~> 2.0)
multi_json (1.7.8) multi_json (1.7.9)
multi_xml (0.5.4) multi_xml (0.5.4)
multipart-post (1.2.0) multipart-post (1.2.0)
mysql2 (0.3.11) mysql2 (0.3.11)
...@@ -578,7 +578,7 @@ DEPENDENCIES ...@@ -578,7 +578,7 @@ DEPENDENCIES
gitlab-gollum-lib (~> 1.0.1) gitlab-gollum-lib (~> 1.0.1)
gitlab-grack (~> 1.0.1) gitlab-grack (~> 1.0.1)
gitlab-pygments.rb (~> 0.3.2) gitlab-pygments.rb (~> 0.3.2)
gitlab_git (~> 2.0.0.pre) gitlab_git (= 2.0.1)
gitlab_meta (= 6.0) gitlab_meta (= 6.0)
gitlab_omniauth-ldap (= 1.0.3) gitlab_omniauth-ldap (= 1.0.3)
gon gon
......
class ProjectImport
constructor: ->
setTimeout ->
Turbolinks.visit(location.href)
, 5000
@ProjectImport = ProjectImport
...@@ -16,7 +16,7 @@ class window.ContributorsStatGraph ...@@ -16,7 +16,7 @@ class window.ContributorsStatGraph
_.each(limited_author_data, (d) => _.each(limited_author_data, (d) =>
author_header = @create_author_header(d) author_header = @create_author_header(d)
$(".contributors-list").append(author_header) $(".contributors-list").append(author_header)
@authors[d.author] = author_graph = new ContributorsAuthorGraph(d.dates) @authors[d.author_name] = author_graph = new ContributorsAuthorGraph(d.dates)
author_graph.draw() author_graph.draw()
) )
format_author_commit_info: (author) -> format_author_commit_info: (author) ->
...@@ -46,13 +46,15 @@ class window.ContributorsStatGraph ...@@ -46,13 +46,15 @@ class window.ContributorsStatGraph
class: 'person' class: 'person'
style: 'display: block;' style: 'display: block;'
}) })
author_name = $('<h4>' + author.author + '</h4>') author_name = $('<h4>' + author.author_name + '</h4>')
author_email = $('<p class="graph-author-email">' + author.author_email + '</p>')
author_commit_info_span = $('<span/>', { author_commit_info_span = $('<span/>', {
class: 'commits' class: 'commits'
}) })
author_commit_info = @format_author_commit_info(author) author_commit_info = @format_author_commit_info(author)
author_commit_info_span.html(author_commit_info) author_commit_info_span.html(author_commit_info)
list_item.append(author_name) list_item.append(author_name)
list_item.append(author_email)
list_item.append(author_commit_info_span) list_item.append(author_commit_info_span)
list_item list_item
redraw_master: -> redraw_master: ->
...@@ -65,9 +67,9 @@ class window.ContributorsStatGraph ...@@ -65,9 +67,9 @@ class window.ContributorsStatGraph
author_commits = ContributorsStatGraphUtil.get_author_data(@parsed_log, @field, x_domain) author_commits = ContributorsStatGraphUtil.get_author_data(@parsed_log, @field, x_domain)
_.each(author_commits, (d) => _.each(author_commits, (d) =>
@redraw_author_commit_info(d) @redraw_author_commit_info(d)
$(@authors[d.author].list_item).appendTo("ol") $(@authors[d.author_name].list_item).appendTo("ol")
@authors[d.author].set_data(d.dates) @authors[d.author_name].set_data(d.dates)
@authors[d.author].redraw() @authors[d.author_name].redraw()
) )
set_current_field: (field) -> set_current_field: (field) ->
@field = field @field = field
...@@ -77,6 +79,6 @@ class window.ContributorsStatGraph ...@@ -77,6 +79,6 @@ class window.ContributorsStatGraph
print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]) print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1])
$("#date_header").text(print) $("#date_header").text(print)
redraw_author_commit_info: (author) -> redraw_author_commit_info: (author) ->
author_list_item = $(@authors[author.author].list_item) author_list_item = $(@authors[author.author_name].list_item)
author_commit_info = @format_author_commit_info(author) author_commit_info = @format_author_commit_info(author)
author_list_item.find("span").html(author_commit_info) author_list_item.find("span").html(author_commit_info)
class window.ContributorsGraph class window.ContributorsGraph
MARGIN: MARGIN:
top: 20 top: 20
right: 20 right: 20
bottom: 30 bottom: 30
left: 50 left: 50
x_domain: null x_domain: null
y_domain: null y_domain: null
...@@ -38,7 +38,7 @@ class window.ContributorsGraph ...@@ -38,7 +38,7 @@ class window.ContributorsGraph
@y = d3.scale.linear().range([height, 0]).nice() @y = d3.scale.linear().range([height, 0]).nice()
draw_x_axis: -> draw_x_axis: ->
@svg.append("g").attr("class", "x axis").attr("transform", "translate(0, #{@height})") @svg.append("g").attr("class", "x axis").attr("transform", "translate(0, #{@height})")
.call(@x_axis); .call(@x_axis)
draw_y_axis: -> draw_y_axis: ->
@svg.append("g").attr("class", "y axis").call(@y_axis) @svg.append("g").attr("class", "y axis").call(@y_axis)
set_data: (data) -> set_data: (data) ->
...@@ -51,7 +51,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph ...@@ -51,7 +51,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph
else else
@width = 870 @width = 870
@height = 125 @height = 200
@x = null @x = null
@y = null @y = null
@x_axis = null @x_axis = null
...@@ -61,7 +61,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph ...@@ -61,7 +61,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph
@brush = null @brush = null
@x_max_domain = null @x_max_domain = null
process_dates: (data) -> process_dates: (data) ->
dates = @get_dates(data) dates = @get_dates(data)
@parse_dates(data) @parse_dates(data)
ContributorsGraph.set_dates(dates) ContributorsGraph.set_dates(dates)
get_dates: (data) -> get_dates: (data) ->
...@@ -87,14 +87,16 @@ class window.ContributorsMasterGraph extends ContributorsGraph ...@@ -87,14 +87,16 @@ class window.ContributorsMasterGraph extends ContributorsGraph
@area = d3.svg.area().x((d) -> @area = d3.svg.area().x((d) ->
x(d.date) x(d.date)
).y0(@height).y1((d) -> ).y0(@height).y1((d) ->
y(d.commits = d.commits ? d.additions ? d.deletions) xa = d.commits = d.commits ? d.additions ? d.deletions
console.log(xa)
y(xa)
).interpolate("basis") ).interpolate("basis")
create_brush: -> create_brush: ->
@brush = d3.svg.brush().x(@x).on("brushend", @update_content); @brush = d3.svg.brush().x(@x).on("brushend", @update_content)
draw_path: (data) -> draw_path: (data) ->
@svg.append("path").datum(data).attr("class", "area").attr("d", @area); @svg.append("path").datum(data).attr("class", "area").attr("d", @area)
add_brush: -> add_brush: ->
@svg.append("g").attr("class", "selection").call(@brush).selectAll("rect").attr("height", @height); @svg.append("g").attr("class", "selection").call(@brush).selectAll("rect").attr("height", @height)
update_content: => update_content: =>
ContributorsGraph.set_x_domain(if @brush.empty() then @x_max_domain else @brush.extent()) ContributorsGraph.set_x_domain(if @brush.empty() then @x_max_domain else @brush.extent())
$("#brush_change").trigger('change') $("#brush_change").trigger('change')
...@@ -126,8 +128,8 @@ class window.ContributorsAuthorGraph extends ContributorsGraph ...@@ -126,8 +128,8 @@ class window.ContributorsAuthorGraph extends ContributorsGraph
@width = 490 @width = 490
else else
@width = 380 @width = 380
@height = 130 @height = 200
@x = null @x = null
@y = null @y = null
@x_axis = null @x_axis = null
......
...@@ -4,9 +4,9 @@ window.ContributorsStatGraphUtil = ...@@ -4,9 +4,9 @@ window.ContributorsStatGraphUtil =
by_author = {} by_author = {}
for entry in log for entry in log
@add_date(entry.date, total) unless total[entry.date]? @add_date(entry.date, total) unless total[entry.date]?
@add_author(entry.author, by_author) unless by_author[entry.author]? @add_author(entry, by_author) unless by_author[entry.author_name]?
@add_date(entry.date, by_author[entry.author]) unless by_author[entry.author][entry.date] @add_date(entry.date, by_author[entry.author_name]) unless by_author[entry.author_name][entry.date]
@store_data(entry, total[entry.date], by_author[entry.author][entry.date]) @store_data(entry, total[entry.date], by_author[entry.author_name][entry.date])
total = _.toArray(total) total = _.toArray(total)
by_author = _.toArray(by_author) by_author = _.toArray(by_author)
total: total, by_author: by_author total: total, by_author: by_author
...@@ -16,8 +16,9 @@ window.ContributorsStatGraphUtil = ...@@ -16,8 +16,9 @@ window.ContributorsStatGraphUtil =
collection[date].date = date collection[date].date = date
add_author: (author, by_author) -> add_author: (author, by_author) ->
by_author[author] = {} by_author[author.author_name] = {}
by_author[author].author = author by_author[author.author_name].author_name = author.author_name
by_author[author.author_name].author_email = author.author_email
store_data: (entry, total, by_author) -> store_data: (entry, total, by_author) ->
@store_commits(total, by_author) @store_commits(total, by_author)
...@@ -71,10 +72,11 @@ window.ContributorsStatGraphUtil = ...@@ -71,10 +72,11 @@ window.ContributorsStatGraphUtil =
parse_log_entry: (log_entry, field, date_range) -> parse_log_entry: (log_entry, field, date_range) ->
parsed_entry = {} parsed_entry = {}
parsed_entry.author = log_entry.author parsed_entry.author_name = log_entry.author_name
parsed_entry.author_email = log_entry.author_email
parsed_entry.dates = {} parsed_entry.dates = {}
parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0 parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0
_.each(_.omit(log_entry, 'author'), (value, key) => _.each(_.omit(log_entry, 'author_name', 'author_email'), (value, key) =>
if @in_range(value.date, date_range) if @in_range(value.date, date_range)
parsed_entry.dates[value.date] = value[field] parsed_entry.dates[value.date] = value[field]
parsed_entry.commits += value.commits parsed_entry.commits += value.commits
...@@ -88,4 +90,4 @@ window.ContributorsStatGraphUtil = ...@@ -88,4 +90,4 @@ window.ContributorsStatGraphUtil =
true true
else else
false false
\ No newline at end of file
...@@ -365,3 +365,10 @@ img.emoji { ...@@ -365,3 +365,10 @@ img.emoji {
.available-groups form { .available-groups form {
margin: 5px 0; margin: 5px 0;
} }
table {
td.permission-x {
background: #D9EDF7 !important;
text-align: center;
}
}
/** COLORS **/ /** COLORS **/
.cgray { color:gray } .cgray { color: gray }
.cred { color:#D12F19 } .cred { color: #D12F19 }
.cgreen { color:#4a2 } .cgreen { color: #4a2 }
.cblue { color:#29A } .cblue { color: #29A }
.cblack { color:#111 } .cblack { color: #111 }
.cdark { color:#444 } .cdark { color: #444 }
.cwhite { color:#fff!important } .cwhite { color: #fff!important }
.bgred { background:#F2DEDE!important } .bgred { background: #F2DEDE!important }
/** COMMON CLASSES **/ /** COMMON CLASSES **/
.left { float:left } .left { float:left }
......
...@@ -24,6 +24,10 @@ input { ...@@ -24,6 +24,10 @@ input {
input[type="radio"], input[type="checkbox"] { input[type="radio"], input[type="checkbox"] {
margin-top: 6px; margin-top: 6px;
} }
.add-on {
padding: 6px;
}
} }
} }
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
&.nav-stacked-menu { &.nav-stacked-menu {
background: #FAFAFA; background: #FAFAFA;
li > a { li > a {
padding: 20px; padding: 16px;
} }
} }
} }
......
...@@ -436,19 +436,28 @@ ...@@ -436,19 +436,28 @@
background: none; background: none;
border: none; border: none;
margin: 0; margin: 0;
padding: 0;
margin-top: 10px;
} }
.ui-box.commit-box { .commit-box {
margin-top: 0; margin: 10px 0;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
padding: 20px 0;
.commit-committer-link, .commit-title {
.commit-author-link { margin: 0;
color: #333; font-size: 20px;
font-weight: bold; font-weight: bold;
text-shadow: 0 1px 1px #FFF; }
.commit-description {
margin-top: 15px;
} }
} }
.commit-stat-summary { .commit-stat-summary {
color: #666; color: #666;
line-height: 2; line-height: 2;
...@@ -475,3 +484,15 @@ li.commit { ...@@ -475,3 +484,15 @@ li.commit {
.commit-breadcrumb { .commit-breadcrumb {
padding: 0; padding: 0;
} }
.commit-info-row {
margin-bottom: 10px;
.avatar {
@extend .avatar-inline;
}
.commit-committer-link,
.commit-author-link {
color: #444;
font-weight: bold;
}
}
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
.graph-author-commits-count { .graph-author-commits-count {
} }
.graph-author-email {
float: right;
color: #777;
}
.graph-additions { .graph-additions {
color: #4a2; color: #4a2;
} }
......
...@@ -7,6 +7,13 @@ ...@@ -7,6 +7,13 @@
} }
} }
.project-name-holder {
.help-inline {
vertical-align: top;
padding: 7px;
}
}
.project_clone_panel { .project_clone_panel {
@include border-radius(4px); @include border-radius(4px);
@include bg-gray-gradient; @include bg-gray-gradient;
......
...@@ -26,7 +26,7 @@ module Projects ...@@ -26,7 +26,7 @@ module Projects
# Ex. # Ex.
# 'GitLab HQ'.parameterize => "gitlab-hq" # 'GitLab HQ'.parameterize => "gitlab-hq"
# #
@project.path = @project.name.dup.parameterize @project.path = @project.name.dup.parameterize unless @project.path.present?
if namespace_id if namespace_id
...@@ -45,26 +45,15 @@ module Projects ...@@ -45,26 +45,15 @@ module Projects
@project.creator = current_user @project.creator = current_user
# Import project from cloneable resource
if @project.valid? && @project.import_url.present?
shell = Gitlab::Shell.new
if shell.import_repository(@project.path_with_namespace, @project.import_url)
# We should create satellite for imported repo
@project.satellite.create unless @project.satellite.exists?
@project.imported = true
true
else
@project.errors.add(:import_url, 'cannot clone repo')
end
end
if @project.save if @project.save
@project.discover_default_branch
unless @project.group unless @project.group
@project.users_projects.create(project_access: UsersProject::MASTER, user: current_user) @project.users_projects.create(
project_access: UsersProject::MASTER,
user: current_user
)
end end
@project.discover_default_branch
end end
@project @project
......
...@@ -19,8 +19,8 @@ class SearchContext ...@@ -19,8 +19,8 @@ class SearchContext
if params[:search_code].present? if params[:search_code].present?
result[:blobs] = project.repository.search_files(query, params[:repository_ref]) unless project.empty_repo? result[:blobs] = project.repository.search_files(query, params[:repository_ref]) unless project.empty_repo?
else else
result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).limit(20) result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).order('updated_at DESC').limit(20)
result[:issues] = Issue.where(project_id: project_ids).search(query).limit(20) result[:issues] = Issue.where(project_id: project_ids).search(query).order('updated_at DESC').limit(20)
result[:wiki_pages] = [] result[:wiki_pages] = []
end end
result result
......
...@@ -57,6 +57,10 @@ class ProjectsController < Projects::ApplicationController ...@@ -57,6 +57,10 @@ class ProjectsController < Projects::ApplicationController
limit = (params[:limit] || 20).to_i limit = (params[:limit] || 20).to_i
@events = @project.events.recent.limit(limit).offset(params[:offset] || 0) @events = @project.events.recent.limit(limit).offset(params[:offset] || 0)
# Ensure project default branch is set if it possible
# Normally it defined on push or during creation
@project.discover_default_branch
respond_to do |format| respond_to do |format|
format.html do format.html do
if @project.empty_repo? if @project.empty_repo?
......
...@@ -36,16 +36,16 @@ class Commit ...@@ -36,16 +36,16 @@ class Commit
# Returns the commits title. # Returns the commits title.
# #
# Usually, the commit title is the first line of the commit message. # Usually, the commit title is the first line of the commit message.
# In case this first line is longer than 80 characters, it is cut off # In case this first line is longer than 100 characters, it is cut off
# after 70 characters and ellipses (`&hellp;`) are appended. # after 80 characters and ellipses (`&hellp;`) are appended.
def title def title
title = safe_message title = safe_message
return no_commit_message if title.blank? return no_commit_message if title.blank?
title_end = title.index(/\n/) title_end = title.index(/\n/)
if (!title_end && title.length > 80) || (title_end && title_end > 80) if (!title_end && title.length > 100) || (title_end && title_end > 100)
title[0..69] << "&hellip;".html_safe title[0..79] << "&hellip;".html_safe
else else
title.split(/\n/, 2).first title.split(/\n/, 2).first
end end
...@@ -58,8 +58,8 @@ class Commit ...@@ -58,8 +58,8 @@ class Commit
description = safe_message description = safe_message
title_end = description.index(/\n/) title_end = description.index(/\n/)
if (!title_end && description.length > 80) || (title_end && title_end > 80) if (!title_end && description.length > 100) || (title_end && title_end > 100)
"&hellip;".html_safe << description[70..-1] "&hellip;".html_safe << description[80..-1]
else else
description.split(/\n/, 2)[1].try(:chomp) description.split(/\n/, 2)[1].try(:chomp)
end end
......
...@@ -37,8 +37,6 @@ class Project < ActiveRecord::Base ...@@ -37,8 +37,6 @@ class Project < ActiveRecord::Base
acts_as_taggable_on :labels, :issues_default_labels acts_as_taggable_on :labels, :issues_default_labels
attr_accessor :import_url
# Relations # Relations
belongs_to :creator, foreign_key: "creator_id", class_name: "User" belongs_to :creator, foreign_key: "creator_id", class_name: "User"
belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'"
...@@ -78,11 +76,11 @@ class Project < ActiveRecord::Base ...@@ -78,11 +76,11 @@ class Project < ActiveRecord::Base
validates :description, length: { within: 0..2000 } validates :description, length: { within: 0..2000 }
validates :name, presence: true, length: { within: 0..255 }, validates :name, presence: true, length: { within: 0..255 },
format: { with: Gitlab::Regex.project_name_regex, format: { with: Gitlab::Regex.project_name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed. Letter should be first" } message: "only letters, digits, spaces & '_' '-' '.' allowed. Letter or digit should be first" }
validates :path, presence: true, length: { within: 0..255 }, validates :path, presence: true, length: { within: 0..255 },
exclusion: { in: Gitlab::Blacklist.path }, exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex, format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } message: "only letters, digits & '_' '-' '.' allowed. Letter or digit should be first" }
validates :issues_enabled, :wall_enabled, :merge_requests_enabled, validates :issues_enabled, :wall_enabled, :merge_requests_enabled,
:wiki_enabled, inclusion: { in: [true, false] } :wiki_enabled, inclusion: { in: [true, false] }
validates :issues_tracker_id, length: { within: 0..255 } validates :issues_tracker_id, length: { within: 0..255 }
...@@ -94,7 +92,7 @@ class Project < ActiveRecord::Base ...@@ -94,7 +92,7 @@ class Project < ActiveRecord::Base
format: { with: URI::regexp(%w(git http https)), message: "should be a valid url" }, format: { with: URI::regexp(%w(git http https)), message: "should be a valid url" },
if: :import? if: :import?
validate :check_limit validate :check_limit, on: :create
# Scopes # Scopes
scope :without_user, ->(user) { where("projects.id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) } scope :without_user, ->(user) { where("projects.id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) }
...@@ -160,6 +158,10 @@ class Project < ActiveRecord::Base ...@@ -160,6 +158,10 @@ class Project < ActiveRecord::Base
import_url.present? import_url.present?
end end
def imported?
imported
end
def check_limit def check_limit
unless creator.can_create_project? unless creator.can_create_project?
errors[:limit_reached] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it") errors[:limit_reached] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it")
...@@ -313,7 +315,7 @@ class Project < ActiveRecord::Base ...@@ -313,7 +315,7 @@ class Project < ActiveRecord::Base
def discover_default_branch def discover_default_branch
# Discover the default branch, but only if it hasn't already been set to # Discover the default branch, but only if it hasn't already been set to
# something else # something else
if repository && default_branch.nil? if repository.exists? && default_branch.nil?
update_attributes(default_branch: self.repository.discover_default_branch) update_attributes(default_branch: self.repository.discover_default_branch)
end end
end end
...@@ -414,10 +416,6 @@ class Project < ActiveRecord::Base ...@@ -414,10 +416,6 @@ class Project < ActiveRecord::Base
!(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?)
end end
def imported?
imported
end
def personal? def personal?
!group !group
end end
......
...@@ -105,7 +105,11 @@ class Repository ...@@ -105,7 +105,11 @@ class Repository
def commit_count def commit_count
Rails.cache.fetch(cache_key(:commit_count)) do Rails.cache.fetch(cache_key(:commit_count)) do
raw_repository.raw.commit_count begin
raw_repository.raw.commit_count
rescue
0
end
end end
end end
......
...@@ -29,11 +29,11 @@ class ActivityObserver < BaseObserver ...@@ -29,11 +29,11 @@ class ActivityObserver < BaseObserver
def create_event(record, status) def create_event(record, status)
Event.create( Event.create(
project: record.project, project: record.project,
target_id: record.id, target_id: record.id,
target_type: record.class.name, target_type: record.class.name,
action: status, action: status,
author_id: record.author_id author_id: current_user.id
) )
end end
end end
...@@ -46,8 +46,7 @@ class MergeRequestObserver < ActivityObserver ...@@ -46,8 +46,7 @@ class MergeRequestObserver < ActivityObserver
target_id: record.id, target_id: record.id,
target_type: record.class.name, target_type: record.class.name,
action: status, action: status,
author_id: record.author_id author_id: current_user.id
) )
end end
end end
class ProjectObserver < BaseObserver class ProjectObserver < BaseObserver
def after_create(project) def after_create(project)
return true if project.forked? || project.imported? project.update_column(:last_activity_at, project.created_at)
GitlabShellWorker.perform_async( return true if project.forked?
:add_repository,
project.path_with_namespace if project.import?
) RepositoryImportWorker.perform_in(5.seconds, project.id)
else
GitlabShellWorker.perform_async(
:add_repository,
project.path_with_namespace
)
log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"") log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"")
end
end end
def after_update(project) def after_update(project)
......
.alert.alert-info .alert.alert-info
%span %span
Post receive hooks for binding events. Post-receive hooks for binding events.
%br %br
Read more about system hooks Read more about system hooks
%strong #{link_to "here", help_system_hooks_path, class: "vlink"} %strong #{link_to "here", help_system_hooks_path, class: "vlink"}
......
%h3.nothing_here_message %h3.nothing_here_message
There are no projects you have access to. You don't have access to any projects.
%br %br
- if current_user.can_create_project? - if current_user.can_create_project?
You can create up to You can create up to
= current_user.projects_limit = pluralize(current_user.projects_limit, "project") + "."
projects. Click on button below to add a new one Click on the button below to add a new one
.link_holder .link_holder
= link_to new_project_path, class: "btn btn-primary" do = link_to new_project_path, class: "btn btn-primary" do
New Project » New Project »
- else - else
If you will be added to project - it will be displayed here If you are added to a project, it will be displayed here
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
%span.pull-right #{@issues.total_count} issues %span.pull-right #{@issues.total_count} issues
%p.light %p.light
For all issues you should visit project issues page. Or you can use search panel to find specific issue For all issues you should visit the project's issues page, or use the search panel to find a specific issue.
%hr %hr
.row .row
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
%p.light %p.light
Only merge requests authored or assigned to you are listed here. Only merge requests created by you or assigned to you are listed here.
%hr %hr
.row .row
.span3 .span3
......
%h3.page-title My Projects %h3.page-title My Projects
%p.light %p.light
All projects you have access to are listed here. Public projects are not included here unless you have membership in it All projects you have access to are listed here. Public projects are not included here unless you are a member
%hr %hr
.row .row
.span3 .span3
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
- else - else
= private_icon = private_icon
= link_to project_path(project), class: dom_class(project) do = link_to project_path(project), class: dom_class(project) do
= project.name_with_namespace %strong= project.name_with_namespace
- if project.forked_from_project - if project.forked_from_project
%small.pull-right %small.pull-right
......
%h3.page-title %h3.page-title
Issues Issues assigned to me
%small (assigned to you) %span.pull-right #{@issues.total_count} issues
%small.pull-right #{@issues.total_count} issues
%p.light
Only issues from
%strong #{@group.name}
group are listed here. To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
%hr %hr
.row .row
.span3 .span3
= render 'shared/filter', entity: 'issue' = render 'shared/filter', entity: 'issue'
......
%h3.page-title %h3.page-title
Merge Requests Merge Requests
%small (authored by or assigned to you) %span.pull-right #{@merge_requests.total_count} merge requests
%small.pull-right #{@merge_requests.total_count} merge requests
%p.light
Authored or assigned to you from
%strong #{@group.name}
group. To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
%hr %hr
.row .row
.span3 .span3
......
.row .row
.span3 .span3
= link_to help_path, class: 'btn append-bottom-20 btn-small' do .append-bottom-20
%i.icon-angle-left = link_to help_path, class: 'btn btn-small' do
Back to help %i.icon-angle-left
%br Back to help
%ul.nav.nav-pills.nav-stacked %ul.nav.nav-pills.nav-stacked
- %w(README projects project_snippets repositories deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file| - %w(README projects project_snippets repositories deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file|
%li{class: file == @category ? 'active' : nil} %li{class: file == @category ? 'active' : nil}
......
= render layout: 'help/layout' do = render layout: 'help/layout' do
%h3.page-title Permissions %h3.page-title Permissions
%fieldset %table.table
%legend Guest %thead
%ul %tr
%li Create new issue %th Action
%li Leave comments %th Guest
%li Write on project wall %th Reporter
%th Developer
%fieldset %th Master
%legend Reporter %th Owner
%ul %tbody
%li Create new issue %tr
%li Leave comments %td Create new issue
%li Write on project wall %td.permission-x &#10003;
%li Pull project code %td.permission-x &#10003;
%li Download project %td.permission-x &#10003;
%li Create a code snippets %td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%fieldset %td Leave comments
%legend Developer %td.permission-x &#10003;
%ul %td.permission-x &#10003;
%li Create new issue %td.permission-x &#10003;
%li Leave comments %td.permission-x &#10003;
%li Write on project wall %td.permission-x &#10003;
%li Pull project code %tr
%li Download project %td Write on project wall
%li Create new merge request %td.permission-x &#10003;
%li Create a code snippets %td.permission-x &#10003;
%li Create new branches %td.permission-x &#10003;
%li Push to non-protected branches %td.permission-x &#10003;
%li Remove non-protected branches %td.permission-x &#10003;
%li Add tags %tr
%li Write a wiki %td Pull project code
%td
%fieldset %td.permission-x &#10003;
%legend Master %td.permission-x &#10003;
%ul %td.permission-x &#10003;
%li Create new issue %td.permission-x &#10003;
%li Leave comments %tr
%li Write on project wall %td Download project
%li Pull project code %td
%li Download project %td.permission-x &#10003;
%li Create new merge request %td.permission-x &#10003;
%li Create a code snippets %td.permission-x &#10003;
%li Create new branches %td.permission-x &#10003;
%li Push to non-protected branches %tr
%li Remove non-protected branches %td Create code snippets
%li Add tags %td
%li Write a wiki %td.permission-x &#10003;
%li Add new team members %td.permission-x &#10003;
%li Push to protected branches %td.permission-x &#10003;
%li Remove protected branches %td.permission-x &#10003;
%li Edit project %tr
%li Add Deploy Keys to project %td Create new merge request
%li Configure Project Hooks %td
%td
%fieldset %td.permission-x &#10003;
%legend Owner %td.permission-x &#10003;
%ul %td.permission-x &#10003;
%li Switch public mode %tr
%li Transfer project to another namespace %td Create new branches
%li Remove project %td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Push to non-protected branches
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Remove non-protected branches
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Add tags
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Write a wiki
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Add new team members
%td
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Push to protected branches
%td
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Remove protected branches
%td
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Edit project
%td
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Add Deploy Keys to project
%td
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Configure Project Hooks
%td
%td
%td
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Switch public mode
%td
%td
%td
%td
%td.permission-x &#10003;
%tr
%td Transfer project to another namespace
%td
%td
%td
%td
%td.permission-x &#10003;
%tr
%td Remove project
%td
%td
%td
%td
%td.permission-x &#10003;
%h3.page-title %h3.page-title
Account settings Account settings
%p.light %p.light
You can change password, username, private token here. You can change your password, username and private token here.
- if current_user.ldap_user? - if current_user.ldap_user?
Some options are unavailable for LDAP accounts Some options are unavailable for LDAP accounts
%hr %hr
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
%legend Password %legend Password
= form_for @user, url: update_password_profile_path, method: :put do |f| = form_for @user, url: update_password_profile_path, method: :put do |f|
.padded .padded
%p.slead After successful password update you will be redirected to login page where you should login with new password %p.slead After a successful password update you will be redirected to login page where you should login with your new password
-if @user.errors.any? -if @user.errors.any?
.alert.alert-error .alert.alert-error
%ul %ul
...@@ -49,9 +49,9 @@ ...@@ -49,9 +49,9 @@
= form_for @user, url: reset_private_token_profile_path, method: :put do |f| = form_for @user, url: reset_private_token_profile_path, method: :put do |f|
.data .data
%p.slead %p.slead
Private token used to access application resources without authentication. Your private token is used to access application resources without authentication.
%br %br
It can be used for atom feed or API It can be used for atom feeds or the API.
%p.cgray %p.cgray
- if current_user.private_token - if current_user.private_token
= text_field_tag "token", current_user.private_token, class: "input-xxlarge large_text input-xpadding" = text_field_tag "token", current_user.private_token, class: "input-xxlarge large_text input-xpadding"
...@@ -81,8 +81,8 @@ ...@@ -81,8 +81,8 @@
%i.icon-remove %i.icon-remove
Failed Failed
%ul.cred %ul.cred
%li It will change web url for personal projects. %li This will change the web URL for personal projects.
%li It will change the git path to repositories for personal projects. %li This will change the git path to repositories for personal projects.
.controls .controls
= f.submit 'Save username', class: "btn btn-save" = f.submit 'Save username', class: "btn btn-save"
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
%i.icon-plus %i.icon-plus
New Group New Group
%p.light %p.light
Members of group have access to all group projects. Group members have access to all a group's projects
%hr %hr
.ui-box .ui-box
.title .title
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
Leave Leave
= link_to group, class: 'group-name' do = link_to group, class: 'group-name' do
= group.name %strong= group.name
as #{user_group.human_access} as #{user_group.human_access}
......
%h3.page-title %h3.page-title
Account history Account history
%p.light %p.light
You can see all events authored by your account here All events created by your account are listed here
%hr %hr
.profile_history .profile_history
= render @events = render @events
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
.pull-right .pull-right
= link_to "Add SSH Key", new_profile_key_path, class: "btn btn-new" = link_to "Add SSH Key", new_profile_key_path, class: "btn btn-new"
%p.light %p.light
SSH key allows you to establish a secure connection between your computer and GitLab SSH keys allow you to establish a secure connection between your computer and GitLab
%br %br
Before you can add ssh key you need to Before you can add an SSH key you need to
= link_to "generate it", help_ssh_path = link_to "generate it", help_ssh_path
%hr %hr
......
%h3.page-title %h3.page-title
Notifications settings Notifications settings
%p.light %p.light
Application use email specified in your profile for notifications GitLab uses the email specified in your profile for notifications
%hr %hr
.alert.alert-info .alert.alert-info
%p %p
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
%p %p
%i.icon-circle.cblue %i.icon-circle.cblue
%strong Participating %strong Participating
&ndash; You will receive only notifications from related resources(ex. from assigned issue or your commit) &ndash; You will only receive notifications from related resources (e.g. from your commits or assigned issues)
%p %p
%i.icon-circle.cgreen %i.icon-circle.cgreen
%strong Watch %strong Watch
......
.ui-box.ui-box-show.commit-box .pull-right
.ui-box-head %div
.pull-right - if @notes_count > 0
- if @notes_count > 0 %span.btn.disabled.grouped
%span.btn.disabled.grouped %i.icon-comment
%i.icon-comment = @notes_count
= @notes_count .pull-left.btn-group
.left.btn-group %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} }
%a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} } %i.icon-download-alt
%i.icon-download-alt Download as
Download as %span.caret
%span.caret %ul.dropdown-menu
%ul.dropdown-menu %li= link_to "Email Patches", project_commit_path(@project, @commit, format: :patch)
%li= link_to "Email Patches", project_commit_path(@project, @commit, format: :patch) %li= link_to "Plain Diff", project_commit_path(@project, @commit, format: :diff)
%li= link_to "Plain Diff", project_commit_path(@project, @commit, format: :diff) = link_to project_tree_path(@project, @commit), class: "btn btn-primary grouped" do
= link_to project_tree_path(@project, @commit), class: "btn btn-primary grouped" do %span Browse Code »
%span Browse Code » %div
%h3.commit-title.page-title
= gfm escape_once(@commit.title)
- if @commit.description.present?
%pre.commit-description
= gfm escape_once(@commit.description)
.ui-box-body
.row
.span5
.author
= commit_author_link(@commit, avatar: true, size: 32)
authored
%time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.authored_date)} ago
- if @commit.different_committer?
.committer
&rarr;
= commit_committer_link(@commit)
committed
%time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.committed_date)} ago
.span6.pull-right
.pull-right
.sha-block
%span.cgray commit
%span.label_commit= @commit.id
.clearfix
.pull-right
.sha-block
%span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent|
= link_to parent.id[0...10], project_commit_path(@project, parent)
%p
%span.light Commit
= link_to @commit.id, project_commit_path(@project, @commit)
.commit-info-row
%span.light Authored by
%strong
= commit_author_link(@commit, avatar: true, size: 24)
%time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.authored_date)} ago
- if @commit.different_committer?
.commit-info-row
%span.light Committed by
%strong
= commit_committer_link(@commit, avatar: true, size: 24)
%time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.committed_date)} ago
.commit-info-row
%span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent|
= link_to parent.id[0...10], project_commit_path(@project, parent)
.commit-box
%h3.commit-title
= gfm escape_once(@commit.title)
- if @commit.description.present?
%pre.commit-description
= gfm escape_once(@commit.description)
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
= f.label :key = f.label :key
.controls .controls
%p.light %p.light
Paste a machine public key here. Read more about how generate it Paste a machine public key here. Read more about how to generate it
= link_to "here", help_ssh_path = link_to "here", help_ssh_path
= f.text_area :key, class: "input-xxlarge thin_area" = f.text_area :key, class: "input-xxlarge thin_area"
......
%h3.page-title %h3.page-title
Deploy keys allow read-only access to repository Deploy keys allow read-only access to the repository
= link_to new_project_deploy_key_path(@project), class: "btn btn-new pull-right", title: "New Deploy Key" do = link_to new_project_deploy_key_path(@project), class: "btn btn-new pull-right", title: "New Deploy Key" do
%i.icon-plus %i.icon-plus
New Deploy Key New Deploy Key
%p.light %p.light
They can be used for CI, staging or production servers. Deploy keys can be used for CI, staging or production servers.
You can create a deploy key or add existing one You can create a deploy key or add an existing one
%hr.clearfix %hr.clearfix
...@@ -20,13 +20,13 @@ ...@@ -20,13 +20,13 @@
= render @enabled_keys = render @enabled_keys
- if @enabled_keys.blank? - if @enabled_keys.blank?
.light-well .light-well
%p.nothing_here_message Create #{link_to 'new deploy key', new_project_deploy_key_path(@project)} or add existing one %p.nothing_here_message Create a #{link_to 'new deploy key', new_project_deploy_key_path(@project)} or add an existing one
.span5.available-keys .span5.available-keys
%h5 %h5
%strong Deploy keys %strong Deploy keys
from projects available for you from projects available to you
%ul.bordered-list %ul.bordered-list
= render @available_keys = render @available_keys
- if @available_keys.blank? - if @available_keys.blank?
.light-well .light-well
%p.nothing_here_message All deploy keys created in projects you participate will be displayed here %p.nothing_here_message Deploy keys from projects you have access to will be displayed here
.project-edit-container .project-edit-container
.project-edit-errors .project-edit-errors
.project-edit-content .project-edit-content
.ui-box.white %div
.title %h3.page-title
%strong= @project.name Project settings:
project settings: %p.light Some settings, such as "Transfer Project", are hidden inside the danger area below
%hr
.form-holder .form-holder
= form_for(@project, remote: true) do |f| = form_for(@project, remote: true) do |f|
%fieldset %fieldset
...@@ -100,58 +101,71 @@ ...@@ -100,58 +101,71 @@
.form-actions .form-actions
= f.submit 'Save changes', class: "btn btn-save" = f.submit 'Save changes', class: "btn btn-save"
- if can?(current_user, :change_namespace, @project)
%center.light.prepend-top-20.padded
%h3
%i.icon-warning-sign
Dangerous settings
%p Project settings below may result in data loss!
= link_to '#', class: 'btn js-toggle-visibility-link' do
Show it to me
%i.icon-chevron-down
.js-toggle-visibility-container.hide
- if can?(current_user, :change_namespace, @project)
.ui-box.ui-box-danger
.title Transfer project
.errors-holder
.form-holder
= form_for(@project, url: transfer_project_path(@project), remote: true, html: { class: 'transfer-project' }) do |f|
.control-group
= f.label :namespace_id do
%span Namespace
.controls
.control-group
= f.select :namespace_id, namespaces_options(@project.namespace_id), {prompt: 'Choose a project namespace'}, {class: 'chosen'}
%ul
%li Be careful. Changing the project's namespace can have unintended side effects.
%li You can only transfer the project to namespaces you manage.
%li You will need to update your local repositories to point to the new location.
.form-actions
= f.submit 'Transfer', class: "btn btn-remove"
- else
%p.nothing_here_message Only the project owner can transfer a project
.ui-box.ui-box-danger .ui-box.ui-box-danger
.title Transfer project .title Rename repository
.errors-holder .errors-holder
.form-holder .form-holder
= form_for(@project, url: transfer_project_path(@project), remote: true, html: { class: 'transfer-project' }) do |f| = form_for(@project) do |f|
.control-group .control-group
= f.label :namespace_id do = f.label :path do
%span Namespace %span Path
.controls .controls
.control-group .control-group
= f.select :namespace_id, namespaces_options(@project.namespace_id), {prompt: 'Choose a project namespace'}, {class: 'chosen'} = f.text_field :path
%ul %ul
%li Be careful. Changing project namespace can have unintended side effects %li Be careful. Renaming a project's repository can have unintended side effects.
%li You can transfer project only to namespaces you can manage
%li You will need to update your local repositories to point to the new location. %li You will need to update your local repositories to point to the new location.
.form-actions .form-actions
= f.submit 'Transfer', class: "btn btn-remove" = f.submit 'Rename', class: "btn btn-remove"
- else
%p.nothing_here_message Only project owner can transfer a project
.ui-box.ui-box-danger - if can?(current_user, :remove_project, @project)
.title Rename repository .ui-box.ui-box-danger
.errors-holder .title Remove project
.form-holder .ui-box-body
= form_for(@project) do |f| %p
.control-group Removing the project will delete its repository and all related resources including issues, merge requests etc.
= f.label :path do %br
%span Path %strong Removed projects cannot be restored!
.controls
.control-group
= f.text_field :path
%ul
%li Be careful. Rename of project repo can have unintended side effects
%li You will need to update your local repositories to point to the new location.
.form-actions
= f.submit 'Rename', class: "btn btn-remove"
- if can?(current_user, :remove_project, @project)
.ui-box.ui-box-danger
.title Remove project
.ui-box-body
%p
Remove of project will cause removing repository and all related resources like issues, merge requests etc.
%p
%strong Removed project can not be restored!
= link_to 'Remove project', @project, confirm: remove_project_message(@project), method: :delete, class: "btn btn-remove btn-small" = link_to 'Remove project', @project, confirm: remove_project_message(@project), method: :delete, class: "btn btn-remove"
- else - else
%p.nothing_here_message Only project owner can remove a project %p.nothing_here_message Only project owner can remove a project
.save-project-loader.hide .save-project-loader.hide
%center %center
= image_tag "ajax_loader.gif" = image_tag "ajax_loader.gif"
%h3 Saving project. Please wait a moment, this page will automatically refresh when ready. %h3 Saving project.
%p Please wait a moment, this page will automatically refresh when ready.
= render 'clone_panel' = render 'clone_panel'
%div.git-empty - if @project.import? && !@project.imported
%fieldset .save-project-loader
%legend Git global setup: %center
%pre.dark = image_tag "ajax_loader.gif"
:preserve %h3 Importing repository.
git config --global user.name "#{current_user.name}" %p.monospace git clone --bare #{@project.import_url}
git config --global user.email "#{current_user.email}" %p Please wait until we import repository for you. Refresh at will.
:javascript
new ProjectImport();
%fieldset - else
%legend Create Repository %div.git-empty
%pre.dark %fieldset
:preserve %legend Git global setup:
mkdir #{@project.path} %pre.dark
cd #{@project.path} :preserve
git init git config --global user.name "#{current_user.name}"
touch README git config --global user.email "#{current_user.email}"
git add README
git commit -m 'first commit'
git remote add origin #{@project.url_to_repo}
git push -u origin master
%fieldset %fieldset
%legend Existing Git Repo? %legend Create Repository
%pre.dark %pre.dark
:preserve :preserve
cd existing_git_repo mkdir #{@project.path}
git remote add origin #{@project.url_to_repo} cd #{@project.path}
git push -u origin master git init
touch README
git add README
git commit -m 'first commit'
git remote add origin #{@project.url_to_repo}
git push -u origin master
%fieldset
%legend Existing Git Repo?
%pre.dark
:preserve
cd existing_git_repo
git remote add origin #{@project.url_to_repo}
git push -u origin master
- if can? current_user, :remove_project, @project - if can? current_user, :remove_project, @project
.prepend-top-20 .prepend-top-20
......
.loading-graph .loading-graph
%center %center
.loading .loading
%h3.page-title Building repository graph. Please wait a moment. %h3.page-title Building repository graph.
%p Please wait a moment, this page will automatically refresh when ready.
.stat-graph .stat-graph
.header.clearfix .header.clearfix
...@@ -11,6 +12,8 @@ ...@@ -11,6 +12,8 @@
%option{:value => "additions"} Additions %option{:value => "additions"} Additions
%option{:value => "deletions"} Deletions %option{:value => "deletions"} Deletions
%h3#date_header.page-title %h3#date_header.page-title
%p.light
Commits to #{@project.default_branch}, excluding merge commits. Limited by 8,000 commits
%input#brush_change{:type => "hidden"} %input#brush_change{:type => "hidden"}
.graphs .graphs
#contributors-master #contributors-master
......
- if can? current_user, :admin_project, @project %h3.page-title
.alert.alert-info Post-receive hooks
%span
Post receive hooks for binding events when someone push to repository. %p.light
%br #{link_to "Post-receive hooks ", help_web_hooks_path, class: "vlink"} can be
Read more about web hooks used for binding events when someone pushes to the repository.
%strong #{link_to "here", help_web_hooks_path, class: "vlink"}
%hr.clearfix
= form_for [@project, @hook], as: :hook, url: project_hooks_path(@project), html: { class: 'form-inline' } do |f| = form_for [@project, @hook], as: :hook, url: project_hooks_path(@project), html: { class: 'form-inline' } do |f|
-if @hook.errors.any? -if @hook.errors.any?
......
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
= render @issues = render @issues
- if @issues.blank? - if @issues.blank?
%li %li
%h4.nothing_here_message Nothing to show here %h4.nothing_here_message No issues to show
- if @issues.present? - if @issues.present?
.pull-right .pull-right
......
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
= render @merge_requests = render @merge_requests
- if @merge_requests.blank? - if @merge_requests.blank?
%li %li
%h4.nothing_here_message Nothing to show here %h4.nothing_here_message No merge requests to show
- if @merge_requests.present? - if @merge_requests.present?
.pull-right .pull-right
%span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
......
- unless @allowed_to_merge - unless @allowed_to_merge
.alert .alert
%strong You don't have enough permissions to merge this MR %strong You don't have permission to merge this MR
- if @show_merge_controls - if @show_merge_controls
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
.automerge_widget.no_satellite{style: "display:none"} .automerge_widget.no_satellite{style: "display:none"}
.alert.alert-error .alert.alert-error
%span %span
%strong This repository does not have satellite. Ask administrator to fix this issue %strong This repository does not have satellite. Ask an administrator to fix this issue
.automerge_widget.cannot_be_merged{style: "display:none"} .automerge_widget.cannot_be_merged{style: "display:none"}
.alert.alert-disabled .alert.alert-disabled
......
...@@ -26,6 +26,6 @@ ...@@ -26,6 +26,6 @@
- if @milestones.blank? - if @milestones.blank?
%li %li
%h3.nothing_here_message Nothing to show here %h3.nothing_here_message No milestones to show
= paginate @milestones, theme: "gitlab" = paginate @milestones, theme: "gitlab"
%p.slead .project-edit-container
New projects are private by default. You choose who can see the project and commit to repository.
%hr
.project-edit-container.prepend-top-10
.project-edit-errors .project-edit-errors
= render 'projects/errors' = render 'projects/errors'
.project-edit-content .project-edit-content
%p.slead
New projects are private by default. You choose who can see the project and commit to repository.
%hr
= form_for @project, remote: true do |f| = form_for @project, remote: true do |f|
.control-group.project_name_holder .control-group.project-name-holder
= f.label :name do = f.label :name do
%strong Project name is %strong Project name is
.controls .controls
= f.text_field :name, placeholder: "Example Project", class: "input-xlarge", tabindex: 1, autofocus: true = f.text_field :name, placeholder: "Example Project", class: "input-xlarge", tabindex: 1, autofocus: true
%span.help-inline
= link_to "#", class: 'js-toggle-visibility-link' do
%span Customize repository name?
.control-group.js-toggle-visibility-container.hide
= f.label :path do
%span Repository name
.controls
.input-append
= f.text_field :path
%span.add-on .git
- if current_user.can_select_namespace? - if current_user.can_select_namespace?
.control-group .control-group
...@@ -51,4 +63,5 @@ ...@@ -51,4 +63,5 @@
.save-project-loader.hide .save-project-loader.hide
%center %center
= image_tag "ajax_loader.gif" = image_tag "ajax_loader.gif"
%h3 Creating project &amp; repository. Please wait a moment, this page will automatically refresh when ready. %h3 Creating project &amp; repository.
%p Please wait a moment, this page will automatically refresh when ready.
%h3.page-title Services %h3.page-title Services
%p.light Services allow you to integrate GitLab with other applications
%hr
%ul.bordered-list %ul.bordered-list
- @services.each do |service| - @services.each do |service|
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
%p %p
= link_to pluralize(@repository.round_commit_count, 'commit'), project_commits_path(@project, @ref || @repository.root_ref) = link_to pluralize(@repository.round_commit_count, 'commit'), project_commits_path(@project, @ref || @repository.root_ref)
%p %p
= link_to pluralize(@repository.branch_names.count, 'branch'), project_repository_path(@project) = link_to pluralize(@repository.branch_names.count, 'branch'), project_branches_path(@project)
%p %p
= link_to pluralize(@repository.tag_names.count, 'tag'), project_tags_path(@project) = link_to pluralize(@repository.tag_names.count, 'tag'), project_tags_path(@project)
......
%h3.page-title %h3.page-title
= "Import members from another project" = "Import members from another project"
%p.light %p.light
Only project members will be improted. Group members will be skipped. Only project members will be imported. Group members will be skipped.
%hr %hr
= form_tag apply_import_project_team_members_path(@project), method: 'post' do = form_tag apply_import_project_team_members_path(@project), method: 'post' do
.padded .padded
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
%span.light (#{merge_request.source_project.name_with_namespace}:#{merge_request.source_branch} &rarr; #{merge_request.target_project.name_with_namespace}:#{merge_request.target_branch}) %span.light (#{merge_request.source_project.name_with_namespace}:#{merge_request.source_branch} &rarr; #{merge_request.target_project.name_with_namespace}:#{merge_request.target_branch})
- else - else
%span.light (#{merge_request.source_branch} &rarr; #{merge_request.target_branch}) %span.light (#{merge_request.source_branch} &rarr; #{merge_request.target_branch})
- if merge_request.closed?
%span.label Closed
- @issues.each do |issue| - @issues.each do |issue|
%li %li
issue: issue:
...@@ -38,6 +41,9 @@ ...@@ -38,6 +41,9 @@
%strong.term %strong.term
= truncate issue.title, length: 50 = truncate issue.title, length: 50
%span.light (#{issue.project.name_with_namespace}) %span.light (#{issue.project.name_with_namespace})
- if issue.closed?
%span.label Closed
- @wiki_pages.each do |wiki_page| - @wiki_pages.each do |wiki_page|
%li %li
wiki: wiki:
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= hidden_field_tag :project_id, params[:project_id] = hidden_field_tag :project_id, params[:project_id]
= hidden_field_tag :group_id, params[:group_id] = hidden_field_tag :group_id, params[:group_id]
= hidden_field_tag :search_code, params[:search_code] = hidden_field_tag :search_code, params[:search_code]
= submit_tag 'Search', class: "btn btn-primary wide" = submit_tag 'Search', class: "btn btn-create"
.prepend-top-10 .prepend-top-10
= render 'filter', f: f = render 'filter', f: f
......
...@@ -11,5 +11,5 @@ ...@@ -11,5 +11,5 @@
= render 'projects/issues/issue', issue: issue = render 'projects/issues/issue', issue: issue
= paginate @issues, theme: "gitlab" = paginate @issues, theme: "gitlab"
- else - else
%p.nothing_here_message Nothing to show here %p.nothing_here_message No issues to show
...@@ -10,4 +10,4 @@ ...@@ -10,4 +10,4 @@
= paginate @merge_requests, theme: "gitlab" = paginate @merge_requests, theme: "gitlab"
- else - else
%h3.nothing_here_message Nothing to show here %h3.nothing_here_message No merge requests to show
class RepositoryImportWorker
include Sidekiq::Worker
include Gitlab::ShellAdapter
sidekiq_options queue: :gitlab_shell
def perform(project_id)
project = Project.find(project_id)
result = gitlab_shell.send(:import_repository,
project.path_with_namespace,
project.import_url)
if result
project.imported = true
project.save
project.satellite.create unless project.satellite.exists?
project.discover_default_branch
else
project.imported = false
end
end
end
...@@ -40,7 +40,14 @@ Gitlab::Application.configure do ...@@ -40,7 +40,14 @@ Gitlab::Application.configure do
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production # Use a different cache store in production
config.cache_store = :redis_store config_file = Rails.root.join('config', 'resque.yml')
resque_url = if File.exists?(config_file)
YAML.load_file(config_file)[Rails.env]
else
"redis://localhost:6379"
end
config.cache_store = :redis_store, resque_url
# Enable serving of images, stylesheets, and JavaScripts from an asset server # Enable serving of images, stylesheets, and JavaScripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com" # config.action_controller.asset_host = "http://assets.example.com"
......
class AddImportUrlToProject < ActiveRecord::Migration
def change
add_column :projects, :import_url, :string
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130809124851) do ActiveRecord::Schema.define(:version => 20130812143708) do
create_table "deploy_keys_projects", :force => true do |t| create_table "deploy_keys_projects", :force => true do |t|
t.integer "deploy_key_id", :null => false t.integer "deploy_key_id", :null => false
...@@ -187,6 +187,7 @@ ActiveRecord::Schema.define(:version => 20130809124851) do ...@@ -187,6 +187,7 @@ ActiveRecord::Schema.define(:version => 20130809124851) do
t.boolean "snippets_enabled", :default => true, :null => false t.boolean "snippets_enabled", :default => true, :null => false
t.datetime "last_activity_at" t.datetime "last_activity_at"
t.boolean "imported", :default => false, :null => false t.boolean "imported", :default => false, :null => false
t.string "import_url"
end end
add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id"
......
...@@ -153,10 +153,10 @@ To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install ...@@ -153,10 +153,10 @@ To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install
cd /home/git/gitlab cd /home/git/gitlab
# Checkout to stable release # Checkout to stable release
sudo -u git -H git checkout 5-3-stable sudo -u git -H git checkout 5-4-stable
**Note:** **Note:**
You can change `5-3-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! You can change `5-4-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
## Configure it ## Configure it
......
# From 5.4 to 6.0 # From 5.4 to 6.0
### Deprecations ### Deprecations
#### Global projects #### Global projects
We deprecated root(global) namespace for projects. We deprecated root(global) namespace for projects.
So you need to move all your global projects under group/users manually before update or it will be moved automatically to owner namespace during update. So you need to move all your global projects under group/users manually before update or they will be automatically moved to the owner namespace during the update.
#### Teams #### Teams
We deprecate teams as separate entity in 6.0 in favor of group membership. We introduce group membership in 6.0 as a replacement for teams.
The old combination of groups and teams was confusing for a lot of people. The old combination of groups and teams was confusing for a lot of people.
And when the members of a team where changed this wasn't reflected in the project permissions. And when the members of a team where changed this wasn't reflected in the project permissions.
In GitLab 6.0 you will be able to add members to a group with a permission level for each member. In GitLab 6.0 you will be able to add members to a group with a permission level for each member.
These group members will have access to the projects in that group. These group members will have access to the projects in that group.
Any changes to group members will immediately be reflected in the project permissions. Any changes to group members will immediately be reflected in the project permissions.
You can even have multiple owners for a group, greatly simplifying administration. You can even have multiple owners for a group, greatly simplifying administration.
### 0. Backup ### 0. Backup
It's useful to make a backup just in case things go south: It's useful to make a backup just in case things go south:
(With MySQL, this may require granting "LOCK TABLES" privileges to the GitLab user on the database version) (With MySQL, this may require granting "LOCK TABLES" privileges to the GitLab user on the database version)
```bash ```bash
cd /home/git/gitlab cd /home/git/gitlab
sudo -u git -H RAILS_ENV=production bundle exec rake gitlab:backup:create sudo -u git -H RAILS_ENV=production bundle exec rake gitlab:backup:create
``` ```
### 1. Stop server ### 1. Stop server
sudo service gitlab stop sudo service gitlab stop
### 2. Get latest code ### 2. Get latest code
```bash ```bash
cd /home/git/gitlab cd /home/git/gitlab
sudo -u git -H git fetch sudo -u git -H git fetch
sudo -u git -H git checkout 6-0-dev sudo -u git -H git checkout 6-0-dev
``` ```
### 3. Install additional packages ### 3. Install additional packages
```bash ```bash
# For reStructuredText markup language support install required package: # For reStructuredText markup language support install required package:
sudo apt-get install python-docutils sudo apt-get install python-docutils
``` ```
### 4. Install libs, migrations, etc. ### 4. Install libs, migrations, etc.
```bash ```bash
cd /home/git/gitlab cd /home/git/gitlab
# MySQL # MySQL
sudo -u git -H bundle install --without development test postgres --deployment sudo -u git -H bundle install --without development test postgres --deployment
#PostgreSQL #PostgreSQL
sudo -u git -H bundle install --without development test mysql --deployment sudo -u git -H bundle install --without development test mysql --deployment
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
sudo -u git -H bundle exec rake migrate_groups RAILS_ENV=production sudo -u git -H bundle exec rake migrate_groups RAILS_ENV=production
sudo -u git -H bundle exec rake migrate_global_projects RAILS_ENV=production sudo -u git -H bundle exec rake migrate_global_projects RAILS_ENV=production
sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production
sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production
``` ```
### 5. Update config files ### 5. Update config files
* Make `/home/git/gitlab/config/gitlab.yml` same as https://github.com/gitlabhq/gitlabhq/blob/5-3-stable/config/gitlab.yml.example but with your settings. Note: We switched from Puma in GitLab 5.4 to unicorn in GitLab 6.0.
* Make `/home/git/gitlab/config/puma.rb` same as https://github.com/gitlabhq/gitlabhq/blob/5-3-stable/config/puma.rb.example but with your settings.
* Make `/home/git/gitlab/config/gitlab.yml` the same as https://github.com/gitlabhq/gitlabhq/blob/master/config/gitlab.yml.example but with your settings.
### 6. Update Init script * Make `/home/git/gitlab/config/unicorn.rb` the same as https://github.com/gitlabhq/gitlabhq/blob/master/config/unicorn.rb.example but with your settings.
```bash ### 6. Update Init script
sudo rm /etc/init.d/gitlab
sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/5-3-stable/lib/support/init.d/gitlab ```bash
sudo chmod +x /etc/init.d/gitlab sudo rm /etc/init.d/gitlab
``` sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/master/lib/support/init.d/gitlab
sudo chmod +x /etc/init.d/gitlab
### 7. Start application ```
sudo service gitlab start ### 7. Start application
sudo service nginx restart
sudo service gitlab start
### 8. Check application status sudo service nginx restart
Check if GitLab and its environment are configured correctly: ### 8. Check application status
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production Check if GitLab and its environment are configured correctly:
To make sure you didn't miss anything run a more thorough check with: sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production To make sure you didn't miss anything run a more thorough check with:
If all items are green, then congratulations upgrade complete! sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
If all items are green, then congratulations upgrade complete!
...@@ -61,10 +61,10 @@ module API ...@@ -61,10 +61,10 @@ module API
# name (required) - name for new project # name (required) - name for new project
# description (optional) - short project description # description (optional) - short project description
# default_branch (optional) - 'master' by default # default_branch (optional) - 'master' by default
# issues_enabled (optional) # issues_enabled (optional)
# wall_enabled (optional) # wall_enabled (optional)
# merge_requests_enabled (optional) # merge_requests_enabled (optional)
# wiki_enabled (optional) # wiki_enabled (optional)
# snippets_enabled (optional) # snippets_enabled (optional)
# namespace_id (optional) - defaults to user namespace # namespace_id (optional) - defaults to user namespace
# public (optional) - false by default # public (optional) - false by default
...@@ -73,6 +73,7 @@ module API ...@@ -73,6 +73,7 @@ module API
post do post do
required_attributes! [:name] required_attributes! [:name]
attrs = attributes_for_keys [:name, attrs = attributes_for_keys [:name,
:path,
:description, :description,
:default_branch, :default_branch,
:issues_enabled, :issues_enabled,
...@@ -100,9 +101,9 @@ module API ...@@ -100,9 +101,9 @@ module API
# name (required) - name for new project # name (required) - name for new project
# description (optional) - short project description # description (optional) - short project description
# default_branch (optional) - 'master' by default # default_branch (optional) - 'master' by default
# issues_enabled (optional) # issues_enabled (optional)
# wall_enabled (optional) # wall_enabled (optional)
# merge_requests_enabled (optional) # merge_requests_enabled (optional)
# wiki_enabled (optional) # wiki_enabled (optional)
# snippets_enabled (optional) # snippets_enabled (optional)
# public (optional) # public (optional)
......
...@@ -7,7 +7,7 @@ module Gitlab ...@@ -7,7 +7,7 @@ module Gitlab
end end
def project_name_regex def project_name_regex
/\A[a-zA-Z][a-zA-Z0-9_\-\. ]*\z/ /\A[a-zA-Z0-9][a-zA-Z0-9_\-\. ]*\z/
end end
def name_regex def name_regex
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
protected protected
def default_regex def default_regex
/\A[a-zA-Z][a-zA-Z0-9_\-\.]*\z/ /\A[a-zA-Z0-9][a-zA-Z0-9_\-\.]*\z/
end end
end end
end end
...@@ -31,6 +31,11 @@ namespace :gitlab do ...@@ -31,6 +31,11 @@ namespace :gitlab do
puts "Processing #{repo_path}".yellow puts "Processing #{repo_path}".yellow
if path =~ /.wiki\Z/
puts " * Skipping wiki repo"
next
end
project = Project.find_with_namespace(path) project = Project.find_with_namespace(path)
if project if project
...@@ -40,6 +45,7 @@ namespace :gitlab do ...@@ -40,6 +45,7 @@ namespace :gitlab do
project_params = { project_params = {
name: name, name: name,
path: name
} }
# find group namespace # find group namespace
......
...@@ -9,11 +9,11 @@ describe Commit do ...@@ -9,11 +9,11 @@ describe Commit do
commit.title.should == "--no commit message" commit.title.should == "--no commit message"
end end
it "truncates a message without a newline at 70 characters" do it "truncates a message without a newline at 80 characters" do
message = commit.safe_message * 10 message = commit.safe_message * 10
commit.stub(:safe_message).and_return(message) commit.stub(:safe_message).and_return(message)
commit.title.should == "#{message[0..69]}&hellip;" commit.title.should == "#{message[0..79]}&hellip;"
end end
it "truncates a message with a newline before 80 characters at the newline" do it "truncates a message with a newline before 80 characters at the newline" do
...@@ -27,7 +27,7 @@ describe Commit do ...@@ -27,7 +27,7 @@ describe Commit do
message = (commit.safe_message * 10) + "\n" message = (commit.safe_message * 10) + "\n"
commit.stub(:safe_message).and_return(message) commit.stub(:safe_message).and_return(message)
commit.title.should == "#{message[0..69]}&hellip;" commit.title.should == "#{message[0..79]}&hellip;"
end end
end end
......
...@@ -68,9 +68,10 @@ describe Project do ...@@ -68,9 +68,10 @@ describe Project do
it { should ensure_length_of(:issues_tracker_id).is_within(0..255) } it { should ensure_length_of(:issues_tracker_id).is_within(0..255) }
it "should not allow new projects beyond user limits" do it "should not allow new projects beyond user limits" do
project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1)) project2 = build(:project)
project.should_not be_valid project2.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 0))
project.errors[:limit_reached].first.should match(/Your own projects limit is 1/) project2.should_not be_valid
project2.errors[:limit_reached].first.should match(/Your own projects limit is 0/)
end end
end end
......
...@@ -8,7 +8,6 @@ describe ActivityObserver do ...@@ -8,7 +8,6 @@ describe ActivityObserver do
it { @event.project.should == project } it { @event.project.should == project }
end end
describe "Issue created" do describe "Issue created" do
before do before do
Issue.observers.enable :activity_observer do Issue.observers.enable :activity_observer do
......
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