Merge pull request #2051 from gitlabhq/namespaces

User/Group namespaces for projects
This commit is contained in:
Dmitriy Zaporozhets 2012-11-25 07:07:01 -08:00
commit be942d74af
83 changed files with 698 additions and 423 deletions

View file

@ -139,7 +139,7 @@ group :development, :test do
gem 'rb-inotify', require: linux_only('rb-inotify') gem 'rb-inotify', require: linux_only('rb-inotify')
# PhantomJS driver for Capybara # PhantomJS driver for Capybara
gem 'poltergeist' gem 'poltergeist', git: 'https://github.com/jonleighton/poltergeist.git', ref: '5c2e092001074a8cf09f332d3714e9ba150bc8ca'
end end
group :test do group :test do

View file

@ -59,6 +59,18 @@ GIT
specs: specs:
yaml_db (0.2.2) yaml_db (0.2.2)
GIT
remote: https://github.com/jonleighton/poltergeist.git
revision: 5c2e092001074a8cf09f332d3714e9ba150bc8ca
ref: 5c2e092001074a8cf09f332d3714e9ba150bc8ca
specs:
poltergeist (1.0.2)
capybara (~> 1.1)
childprocess (~> 0.3)
faye-websocket (~> 0.4, >= 0.4.4)
http_parser.rb (~> 0.5.3)
multi_json (~> 1.0)
GEM GEM
remote: http://rubygems.org/ remote: http://rubygems.org/
specs: specs:
@ -279,12 +291,6 @@ GEM
omniauth-oauth (~> 1.0) omniauth-oauth (~> 1.0)
orm_adapter (0.4.0) orm_adapter (0.4.0)
pg (0.14.1) pg (0.14.1)
poltergeist (1.0.2)
capybara (~> 1.1)
childprocess (~> 0.3)
faye-websocket (~> 0.4, >= 0.4.4)
http_parser.rb (~> 0.5.3)
multi_json (~> 1.0)
polyglot (0.3.3) polyglot (0.3.3)
posix-spawn (0.3.6) posix-spawn (0.3.6)
pry (0.9.10) pry (0.9.10)
@ -490,7 +496,7 @@ DEPENDENCIES
omniauth-ldap! omniauth-ldap!
omniauth-twitter omniauth-twitter
pg pg
poltergeist poltergeist!
pry pry
pygments.rb! pygments.rb!
quiet_assets (~> 1.0.1) quiet_assets (~> 1.0.1)

View file

@ -77,3 +77,7 @@ a {
a:focus { a:focus {
outline: none; outline: none;
} }
.monospace {
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
}

View file

@ -48,15 +48,17 @@ class Admin::GroupsController < AdminController
def project_update def project_update
project_ids = params[:project_ids] project_ids = params[:project_ids]
Project.where(id: project_ids).update_all(group_id: @group.id)
Project.where(id: project_ids).each do |project|
project.transfer(@group)
end
redirect_to :back, notice: 'Group was successfully updated.' redirect_to :back, notice: 'Group was successfully updated.'
end end
def remove_project def remove_project
@project = Project.find(params[:project_id]) @project = Project.find(params[:project_id])
@project.group_id = nil @project.transfer(nil)
@project.save
redirect_to :back, notice: 'Group was successfully updated.' redirect_to :back, notice: 'Group was successfully updated.'
end end
@ -70,6 +72,6 @@ class Admin::GroupsController < AdminController
private private
def group def group
@group = Group.find_by_code(params[:id]) @group = Group.find_by_path(params[:id])
end end
end end

View file

@ -1,65 +1,54 @@
class Admin::ProjectsController < AdminController class Admin::ProjectsController < AdminController
before_filter :admin_project, only: [:edit, :show, :update, :destroy, :team_update] before_filter :project, only: [:edit, :show, :update, :destroy, :team_update]
def index def index
@admin_projects = Project.scoped @projects = Project.scoped
@admin_projects = @admin_projects.search(params[:name]) if params[:name].present? @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present?
@admin_projects = @admin_projects.order("name ASC").page(params[:page]).per(20) @projects = @projects.search(params[:name]) if params[:name].present?
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
end end
def show def show
@users = User.scoped @users = User.scoped
@users = @users.not_in_project(@admin_project) if @admin_project.users.present? @users = @users.not_in_project(@project) if @project.users.present?
@users = @users.all @users = @users.all
end end
def new
@admin_project = Project.new
end
def edit def edit
end end
def team_update def team_update
@admin_project.add_users_ids_to_team(params[:user_ids], params[:project_access]) @project.add_users_ids_to_team(params[:user_ids], params[:project_access])
redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.' redirect_to [:admin, @project], notice: 'Project was successfully updated.'
end
def create
@admin_project = Project.new(params[:project])
@admin_project.owner = current_user
if @admin_project.save
redirect_to [:admin, @admin_project], notice: 'Project was successfully created.'
else
render action: "new"
end
end end
def update def update
owner_id = params[:project].delete(:owner_id) owner_id = params[:project].delete(:owner_id)
if owner_id if owner_id
@admin_project.owner = User.find(owner_id) @project.owner = User.find(owner_id)
end end
if @admin_project.update_attributes(params[:project]) if @project.update_attributes(params[:project], as: :admin)
redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.' redirect_to [:admin, @project], notice: 'Project was successfully updated.'
else else
render action: "edit" render action: "edit"
end end
end end
def destroy def destroy
@admin_project.destroy @project.destroy
redirect_to admin_projects_url, notice: 'Project was successfully deleted.' redirect_to projects_url, notice: 'Project was successfully deleted.'
end end
private protected
def admin_project def project
@admin_project = Project.find_by_code(params[:id]) id = params[:project_id] || params[:id]
@project = Project.find_with_namespace(id)
@project || render_404
end end
end end

View file

@ -63,7 +63,9 @@ class ApplicationController < ActionController::Base
end end
def project def project
@project ||= current_user.projects.find_by_code(params[:project_id] || params[:id]) id = params[:project_id] || params[:id]
@project ||= current_user.projects.find_with_namespace(id)
@project || render_404 @project || render_404
end end

View file

@ -4,7 +4,7 @@ class DashboardController < ApplicationController
before_filter :event_filter, only: :index before_filter :event_filter, only: :index
def index def index
@groups = Group.where(id: current_user.projects.pluck(:group_id)) @groups = Group.where(id: current_user.projects.pluck(:namespace_id))
@projects = current_user.projects_sorted_by_activity @projects = current_user.projects_sorted_by_activity
@projects = @projects.page(params[:page]).per(30) @projects = @projects.page(params[:page]).per(30)

View file

@ -4,6 +4,7 @@ class GroupsController < ApplicationController
before_filter :group before_filter :group
before_filter :projects before_filter :projects
before_filter :add_project_abilities
def show def show
@events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0) @events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0)
@ -50,11 +51,11 @@ class GroupsController < ApplicationController
protected protected
def group def group
@group ||= Group.find_by_code(params[:id]) @group ||= Group.find_by_path(params[:id])
end end
def projects def projects
@projects ||= current_user.projects_sorted_by_activity.where(group_id: @group.id) @projects ||= current_user.projects_sorted_by_activity.where(namespace_id: @group.id)
end end
def project_ids def project_ids

View file

@ -34,8 +34,16 @@ class ProjectsController < ProjectResourceController
end end
def update def update
namespace_id = params[:project].delete(:namespace_id)
if namespace_id
namespace = Namespace.find(namespace_id)
project.transfer(namespace)
end
respond_to do |format| respond_to do |format|
if project.update_attributes(params[:project]) if project.update_attributes(params[:project])
flash[:notice] = 'Project was successfully updated.'
format.html { redirect_to edit_project_path(project), notice: 'Project was successfully updated.' } format.html { redirect_to edit_project_path(project), notice: 'Project was successfully updated.' }
format.js format.js
else else

View file

@ -74,6 +74,27 @@ module ApplicationHelper
grouped_options_for_select(options, @ref || @project.default_branch) grouped_options_for_select(options, @ref || @project.default_branch)
end end
def namespaces_options(selected = :current_user, scope = :default)
groups = current_user.namespaces.select {|n| n.type == 'Group'}
users = if scope == :all
Namespace.root
else
current_user.namespaces.reject {|n| n.type == 'Group'}
end
options = [
["Groups", groups.map {|g| [g.human_name, g.id]} ],
[ "Users", users.map {|u| [u.human_name, u.id]} ]
]
if selected == :current_user && current_user.namespace
selected = current_user.namespace.id
end
grouped_options_for_select(options, selected)
end
def search_autocomplete_source def search_autocomplete_source
projects = current_user.projects.map{ |p| { label: p.name, url: project_path(p) } } projects = current_user.projects.map{ |p| { label: p.name, url: project_path(p) } }

View file

@ -7,6 +7,7 @@ class Ability
when "Note" then note_abilities(object, subject) when "Note" then note_abilities(object, subject)
when "Snippet" then snippet_abilities(object, subject) when "Snippet" then snippet_abilities(object, subject)
when "MergeRequest" then merge_request_abilities(object, subject) when "MergeRequest" then merge_request_abilities(object, subject)
when "Group" then group_abilities(object, subject)
else [] else []
end end
end end
@ -61,6 +62,16 @@ class Ability
rules.flatten rules.flatten
end end
def group_abilities user, group
rules = []
rules << [
:manage_group
] if group.owner == user
rules.flatten
end
[:issue, :note, :snippet, :merge_request].each do |name| [:issue, :note, :snippet, :merge_request].each do |name|
define_method "#{name}_abilities" do |user, subject| define_method "#{name}_abilities" do |user, subject|
if subject.author == user if subject.author == user

View file

@ -1,36 +1,22 @@
# == Schema Information # == Schema Information
# #
# Table name: groups # Table name: namespaces
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) not null # name :string(255) not null
# code :string(255) not null # path :string(255) not null
# owner_id :integer not null # owner_id :integer not null
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# type :string(255)
# #
class Group < ActiveRecord::Base class Group < Namespace
attr_accessible :code, :name, :owner_id
has_many :projects
belongs_to :owner, class_name: "User"
validates :name, presence: true, uniqueness: true
validates :code, presence: true, uniqueness: true
validates :owner, presence: true
delegate :name, to: :owner, allow_nil: true, prefix: true
def self.search query
where("name LIKE :query OR code LIKE :query", query: "%#{query}%")
end
def to_param
code
end
def users def users
User.joins(:users_projects).where(users_projects: {project_id: project_ids}).uniq User.joins(:users_projects).where(users_projects: {project_id: project_ids}).uniq
end end
def human_name
name
end
end end

55
app/models/namespace.rb Normal file
View file

@ -0,0 +1,55 @@
# == Schema Information
#
# Table name: namespaces
#
# id :integer not null, primary key
# name :string(255) not null
# path :string(255) not null
# owner_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# type :string(255)
#
class Namespace < ActiveRecord::Base
attr_accessible :name, :path
has_many :projects, dependent: :destroy
belongs_to :owner, class_name: "User"
validates :name, presence: true, uniqueness: true
validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
format: { with: /\A[a-zA-Z][a-zA-Z0-9_\-\.]*\z/,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
validates :owner, presence: true
delegate :name, to: :owner, allow_nil: true, prefix: true
after_create :ensure_dir_exist
after_update :move_dir
scope :root, where('type IS NULL')
def self.search query
where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
end
def to_param
path
end
def human_name
owner_name
end
def ensure_dir_exist
namespace_dir_path = File.join(Gitlab.config.git_base_path, path)
Dir.mkdir(namespace_dir_path) unless File.exists?(namespace_dir_path)
end
def move_dir
old_path = File.join(Gitlab.config.git_base_path, path_was)
new_path = File.join(Gitlab.config.git_base_path, path)
system("mv #{old_path} #{new_path}")
end
end

View file

@ -9,14 +9,13 @@
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# private_flag :boolean default(TRUE), not null # private_flag :boolean default(TRUE), not null
# code :string(255)
# owner_id :integer # owner_id :integer
# default_branch :string(255) # default_branch :string(255)
# issues_enabled :boolean default(TRUE), not null # issues_enabled :boolean default(TRUE), not null
# wall_enabled :boolean default(TRUE), not null # wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null # merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null
# group_id :integer # namespace_id :integer
# #
require "grit" require "grit"
@ -27,12 +26,16 @@ class Project < ActiveRecord::Base
include Authority include Authority
include Team include Team
attr_accessible :name, :path, :description, :code, :default_branch, :issues_enabled, attr_accessible :name, :path, :description, :default_branch, :issues_enabled,
:wall_enabled, :merge_requests_enabled, :wiki_enabled :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin]
attr_accessible :namespace_id, as: :admin
attr_accessor :error_code attr_accessor :error_code
# Relations # Relations
belongs_to :group belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'"
belongs_to :namespace
belongs_to :owner, class_name: "User" belongs_to :owner, class_name: "User"
has_many :users, through: :users_projects has_many :users, through: :users_projects
has_many :events, dependent: :destroy has_many :events, dependent: :destroy
@ -54,15 +57,16 @@ class Project < ActiveRecord::Base
# Validations # Validations
validates :owner, presence: true validates :owner, presence: true
validates :description, length: { within: 0..2000 } validates :description, length: { within: 0..2000 }
validates :name, uniqueness: true, presence: true, length: { within: 0..255 } validates :name, presence: true, length: { within: 0..255 }
validates :path, uniqueness: true, presence: true, length: { within: 0..255 }, validates :path, presence: true, length: { within: 0..255 },
format: { with: /\A[a-zA-Z][a-zA-Z0-9_\-\.]*\z/,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
validates :code, presence: true, uniqueness: true, length: { within: 1..255 },
format: { with: /\A[a-zA-Z][a-zA-Z0-9_\-\.]*\z/, format: { with: /\A[a-zA-Z][a-zA-Z0-9_\-\.]*\z/,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } message: "only letters, digits & '_' '-' '.' allowed. Letter 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_uniqueness_of :name, scope: :namespace_id
validates_uniqueness_of :path, scope: :namespace_id
validate :check_limit, :repo_name validate :check_limit, :repo_name
# Scopes # Scopes
@ -76,14 +80,46 @@ class Project < ActiveRecord::Base
end end
def search query def search query
where("name LIKE :query OR code LIKE :query OR path LIKE :query", query: "%#{query}%") where("projects.name LIKE :query OR projects.path LIKE :query", query: "%#{query}%")
end
def find_with_namespace(id)
if id.include?("/")
id = id.split("/")
namespace_id = Namespace.find_by_path(id.first).id
where(namespace_id: namespace_id).find_by_path(id.last)
else
find_by_path(id)
end
end end
def create_by_user(params, user) def create_by_user(params, user)
namespace_id = params.delete(:namespace_id)
project = Project.new params project = Project.new params
Project.transaction do Project.transaction do
# Parametrize path for project
#
# Ex.
# 'GitLab HQ'.parameterize => "gitlab-hq"
#
project.path = project.name.dup.parameterize
project.owner = user project.owner = user
# Apply namespace if user has access to it
# else fallback to user namespace
project.namespace_id = user.namespace_id
if namespace_id
group = Group.find_by_id(namespace_id)
if user.can? :manage_group, group
project.namespace_id = namespace_id
end
end
project.save! project.save!
# Add user as project master # Add user as project master
@ -134,11 +170,15 @@ class Project < ActiveRecord::Base
end end
def to_param def to_param
code if namespace
namespace.path + "/" + path
else
path
end
end end
def web_url def web_url
[Gitlab.config.url, code].join("/") [Gitlab.config.url, path].join("/")
end end
def common_notes def common_notes
@ -192,4 +232,31 @@ class Project < ActiveRecord::Base
def gitlab_ci? def gitlab_ci?
gitlab_ci_service && gitlab_ci_service.active gitlab_ci_service && gitlab_ci_service.active
end end
def path_with_namespace
if namespace
namespace.path + '/' + path
else
path
end
end
# For compatibility with old code
def code
path
end
def transfer(new_namespace)
Project.transaction do
old_namespace = namespace
self.namespace = new_namespace
old_dir = old_namespace.try(:path) || ''
new_dir = new_namespace.try(:path) || ''
Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
save!
end
end
end end

View file

@ -30,6 +30,7 @@
# locked_at :datetime # locked_at :datetime
# extern_uid :string(255) # extern_uid :string(255)
# provider :string(255) # provider :string(255)
# username :string(255)
# #
class User < ActiveRecord::Base class User < ActiveRecord::Base
@ -38,13 +39,17 @@ class User < ActiveRecord::Base
devise :database_authenticatable, :token_authenticatable, :lockable, devise :database_authenticatable, :token_authenticatable, :lockable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable :recoverable, :rememberable, :trackable, :validatable, :omniauthable
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username,
:skype, :linkedin, :twitter, :dark_scheme, :theme_id, :force_random_password, :skype, :linkedin, :twitter, :dark_scheme, :theme_id, :force_random_password,
:extern_uid, :provider, :as => [:default, :admin] :extern_uid, :provider, :as => [:default, :admin]
attr_accessible :projects_limit, :as => :admin attr_accessible :projects_limit, :as => :admin
attr_accessor :force_random_password attr_accessor :force_random_password
# Namespace for personal projects
has_one :namespace, class_name: "Namespace", foreign_key: :owner_id, conditions: 'type IS NULL', dependent: :destroy
has_many :groups, class_name: "Group", foreign_key: :owner_id
has_many :keys, dependent: :destroy has_many :keys, dependent: :destroy
has_many :projects, through: :users_projects has_many :projects, through: :users_projects
has_many :users_projects, dependent: :destroy has_many :users_projects, dependent: :destroy
@ -60,11 +65,14 @@ class User < ActiveRecord::Base
validates :bio, length: { within: 0..255 } validates :bio, length: { within: 0..255 }
validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider} validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider}
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
validates :username, presence: true
before_validation :generate_password, on: :create before_validation :generate_password, on: :create
before_save :ensure_authentication_token before_save :ensure_authentication_token
alias_attribute :private_token, :authentication_token alias_attribute :private_token, :authentication_token
delegate :path, to: :namespace, allow_nil: true, prefix: true
# Scopes # Scopes
scope :not_in_project, ->(project) { where("id not in (:ids)", ids: project.users.map(&:id) ) } scope :not_in_project, ->(project) { where("id not in (:ids)", ids: project.users.map(&:id) ) }
scope :admins, where(admin: true) scope :admins, where(admin: true)

View file

@ -1,5 +1,7 @@
class UserObserver < ActiveRecord::Observer class UserObserver < ActiveRecord::Observer
def after_create(user) def after_create(user)
user.create_namespace(path: user.username, name: user.name)
log_info("User \"#{user.name}\" (#{user.email}) was created") log_info("User \"#{user.name}\" (#{user.email}) was created")
Notify.new_user_email(user.id, user.password).deliver Notify.new_user_email(user.id, user.password).deliver
@ -9,6 +11,16 @@ class UserObserver < ActiveRecord::Observer
log_info("User \"#{user.name}\" (#{user.email}) was removed") log_info("User \"#{user.name}\" (#{user.email}) was removed")
end end
def after_save user
if user.username_changed?
if user.namespace
user.namespace.update_attributes(path: user.username)
else
user.create_namespace!(path: user.username, name: user.name)
end
end
end
protected protected
def log_info message def log_info message

View file

@ -26,6 +26,18 @@ module Account
is_admin? is_admin?
end end
def abilities
@abilities ||= begin
abilities = Six.new
abilities << Ability
abilities
end
end
def can? action, subject
abilities.allowed?(self, action, subject)
end
def last_activity_project def last_activity_project
projects.first projects.first
end end
@ -70,4 +82,27 @@ module Account
def projects_sorted_by_activity def projects_sorted_by_activity
projects.order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") projects.order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC")
end end
def namespaces
namespaces = []
# Add user account namespace
namespaces << self.namespace if self.namespace
# Add groups you can manage
namespaces += if admin
Group.all
else
groups.all
end
namespaces
end
def several_namespaces?
namespaces.size > 1
end
def namespace_id
namespace.try :id
end
end end

View file

@ -114,7 +114,7 @@ module PushObserver
id: commit.id, id: commit.id,
message: commit.safe_message, message: commit.safe_message,
timestamp: commit.date.xmlschema, timestamp: commit.date.xmlschema,
url: "#{Gitlab.config.url}/#{code}/commits/#{commit.id}", url: "#{Gitlab.config.url}/#{path}/commits/#{commit.id}",
author: { author: {
name: commit.author_name, name: commit.author_name,
email: commit.author_email email: commit.author_email

View file

@ -79,11 +79,15 @@ module Repository
end end
def url_to_repo def url_to_repo
git_host.url_to_repo(path) git_host.url_to_repo(path_with_namespace)
end end
def path_to_repo def path_to_repo
File.join(Gitlab.config.git_base_path, "#{path}.git") File.join(Gitlab.config.git_base_path, namespace_dir, "#{path}.git")
end
def namespace_dir
namespace.try(:path) || ''
end end
def update_repository def update_repository
@ -160,12 +164,12 @@ module Repository
return nil unless commit return nil unless commit
# Build file path # Build file path
file_name = self.code + "-" + commit.id.to_s + ".tar.gz" file_name = self.path + "-" + commit.id.to_s + ".tar.gz"
storage_path = Rails.root.join("tmp", "repositories", self.code) storage_path = Rails.root.join("tmp", "repositories", self.path)
file_path = File.join(storage_path, file_name) file_path = File.join(storage_path, file_name)
# Put files into a directory before archiving # Put files into a directory before archiving
prefix = self.code + "/" prefix = self.path + "/"
# Create file if not exists # Create file if not exists
unless File.exists?(file_path) unless File.exists?(file_path)

View file

@ -27,7 +27,7 @@
= link_to admin_projects_path do = link_to admin_projects_path do
%h1= Project.count %h1= Project.count
%hr %hr
= link_to 'New Project', new_admin_project_path, class: "btn small" = link_to 'New Project', new_project_path, class: "btn small"
.span4 .span4
.ui-box .ui-box
%h5 Users %h5 Users

View file

@ -8,12 +8,12 @@
.input .input
= f.text_field :name, placeholder: "Example Group", class: "xxlarge" = f.text_field :name, placeholder: "Example Group", class: "xxlarge"
.clearfix .clearfix
= f.label :code do = f.label :path do
URL URL
.input .input
.input-prepend .input-prepend
%span.add-on= web_app_url + 'groups/' %span.add-on= web_app_url + 'groups/'
= f.text_field :code, placeholder: "example" = f.text_field :path, placeholder: "example"
.form-actions .form-actions
= f.submit 'Save group', class: "btn save-btn" = f.submit 'Save group', class: "btn save-btn"

View file

@ -14,7 +14,7 @@
%table %table
%thead %thead
%th Name %th Name
%th Code %th Path
%th Projects %th Projects
%th Edit %th Edit
%th.cred Danger Zone! %th.cred Danger Zone!
@ -22,7 +22,7 @@
- @groups.each do |group| - @groups.each do |group|
%tr %tr
%td= link_to group.name, [:admin, group] %td= link_to group.name, [:admin, group]
%td= group.code %td= group.path
%td= group.projects.count %td= group.projects.count
%td= link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small" %td= link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small"
%td.bgred= link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger" %td.bgred= link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger"

View file

@ -20,9 +20,9 @@
%tr %tr
%td %td
%b %b
Code: Path:
%td %td
= @group.code = @group.path
%tr %tr
%td %td
%b %b

View file

@ -11,25 +11,19 @@
.input .input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge" = f.text_field :name, placeholder: "Example Project", class: "xxlarge"
%hr %fieldset.adv_settings
.adv_settings %legend Advanced settings:
%h6 Advanced settings:
.clearfix .clearfix
= f.label :path do = f.label :path do
Path Path
.input .input
.input-prepend = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true
%strong
= text_field_tag :ppath, @admin_project.path_to_repo, class: "xlarge", disabled: true
.clearfix
= f.label :code do
URL
.input
.input-prepend
%span.add-on= web_app_url
= f.text_field :code, placeholder: "example"
- unless project.new_record? - unless project.new_record?
.clearfix
= f.label :namespace_id
.input= f.select :namespace_id, namespaces_options, {}, {class: 'chosen'}
.clearfix .clearfix
= f.label :owner_id = f.label :owner_id
.input= f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'}
@ -40,9 +34,8 @@
.input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;") .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
- unless project.new_record? - unless project.new_record?
%hr %fieldset.adv_settings
.adv_settings %legend Features:
%h6 Features:
.clearfix .clearfix
= f.label :issues_enabled, "Issues" = f.label :issues_enabled, "Issues"

View file

@ -1,29 +0,0 @@
= form_for [:admin, @admin_project] do |f|
- if @admin_project.errors.any?
.alert-message.block-message.error
%span= @admin_project.errors.full_messages.first
.clearfix.project_name_holder
= f.label :name do
Project name is
.input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge"
= f.submit 'Create project', class: "btn primary project-submit"
%hr
%div.adv_settings
%h6 Advanced settings:
.clearfix
= f.label :path do
Git Clone
.input
.input-prepend
%span.add-on= Gitlab.config.ssh_path
= f.text_field :path, placeholder: "example_project", disabled: !@admin_project.new_record?
%span.add-on= ".git"
.clearfix
= f.label :code do
URL
.input
.input-prepend
%span.add-on= web_app_url
= f.text_field :code, placeholder: "example"

View file

@ -1,3 +1,3 @@
%h3.page_title #{@admin_project.name} &rarr; Edit project %h3.page_title #{@project.name} &rarr; Edit project
%hr %hr
= render 'form', project: @admin_project = render 'form', project: @project

View file

@ -1,27 +1,33 @@
= render 'admin/shared/projects_head' = render 'admin/shared/projects_head'
%h3.page_title %h3.page_title
Projects Projects
= link_to 'New Project', new_admin_project_path, class: "btn small right" = link_to 'New Project', new_project_path, class: "btn small right"
%br %br
= form_tag admin_projects_path, method: :get, class: 'form-inline' do = form_tag admin_projects_path, method: :get, class: 'form-inline' do
= select_tag :namespace_id, namespaces_options(params[:namespace_id], :all), class: "chosen xlarge", include_blank: true
= text_field_tag :name, params[:name], class: "xlarge" = text_field_tag :name, params[:name], class: "xlarge"
= submit_tag "Search", class: "btn submit primary" = submit_tag "Search", class: "btn submit primary"
%table %table
%thead %thead
%th Name %th Name
%th Path %th Project
%th Team Members %th Team Members
%th Last Commit %th Last Commit
%th Edit %th Edit
%th.cred Danger Zone! %th.cred Danger Zone!
- @admin_projects.each do |project| - @projects.each do |project|
%tr %tr
%td= link_to project.name, [:admin, project] %td
%td= project.path - if project.namespace
= link_to project.namespace.human_name, [:admin, project]
&rarr;
= link_to project.name, [:admin, project]
%td
%span.monospace= project.path_with_namespace + ".git"
%td= project.users_projects.count %td= project.users_projects.count
%td= last_commit(project) %td= last_commit(project)
%td= link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn small" %td= link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn small"
%td.bgred= link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn small danger" %td.bgred= link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn small danger"
= paginate @admin_projects, theme: "admin" = paginate @projects, theme: "admin"

View file

@ -1,12 +0,0 @@
.project_new_holder
%h3.page_title
New Project
%hr
= render 'new_form'
%div.save-project-loader.hide
%center
= image_tag "ajax_loader.gif"
%h3 Creating project &amp; repository. Please wait a few minutes
:javascript
$(function(){ new Projects(); });

View file

@ -1,11 +1,11 @@
= render 'admin/shared/projects_head' = render 'admin/shared/projects_head'
%h3.page_title %h3.page_title
Project: #{@admin_project.name} Project: #{@project.name}
= link_to edit_admin_project_path(@admin_project), class: "btn right" do = link_to edit_admin_project_path(@project), class: "btn right" do
%i.icon-edit %i.icon-edit
Edit Edit
- if !@admin_project.has_post_receive_file? && @admin_project.has_commits? - if !@project.has_post_receive_file? && @project.has_commits?
%br %br
.alert.alert-error .alert.alert-error
%span %span
@ -25,36 +25,30 @@
%b %b
Name: Name:
%td %td
= @admin_project.name = @project.name
%tr
%td
%b
Code:
%td
= @admin_project.code
%tr %tr
%td %td
%b %b
Path: Path:
%td %td
= @admin_project.path %code= @project.path_to_repo
%tr %tr
%td %td
%b %b
Owner: Owner:
%td %td
= @admin_project.owner_name || '(deleted)' = @project.owner_name || '(deleted)'
%tr %tr
%td %td
%b %b
Post Receive File: Post Receive File:
%td %td
= check_box_tag :post_receive_file, 1, @admin_project.has_post_receive_file?, disabled: true = check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true
%br %br
%h3 %h3
Team Team
%small %small
(#{@admin_project.users_projects.count}) (#{@project.users_projects.count})
%br %br
%table.zebra-striped %table.zebra-striped
%thead %thead
@ -64,7 +58,7 @@
%th Repository Access %th Repository Access
%th %th
- @admin_project.users_projects.each do |tm| - @project.users_projects.each do |tm|
%tr %tr
%td %td
= link_to tm.user_name, admin_user_path(tm.user) = link_to tm.user_name, admin_user_path(tm.user)
@ -75,7 +69,7 @@
%br %br
%h3 Add new team member %h3 Add new team member
%br %br
= form_tag team_update_admin_project_path(@admin_project), class: "bulk_import", method: :put do = form_tag team_update_admin_project_path(@project), class: "bulk_import", method: :put do
%table.zebra-striped %table.zebra-striped
%thead %thead
%tr %tr

View file

@ -15,6 +15,11 @@
.input .input
= f.text_field :name = f.text_field :name
%span.help-inline * required %span.help-inline * required
.clearfix
= f.label :username
.input
= f.text_field :username
%span.help-inline * required
.clearfix .clearfix
= f.label :email = f.label :email
.input .input

View file

@ -11,7 +11,7 @@
%ul.unstyled %ul.unstyled
- groups.each do |group| - groups.each do |group|
%li.wll %li.wll
= link_to group_path(id: group.code), class: dom_class(group) do = link_to group_path(id: group.path), class: dom_class(group) do
%strong.group_name= truncate(group.name, length: 25) %strong.group_name= truncate(group.name, length: 25)
%span.arrow %span.arrow
&rarr; &rarr;

View file

@ -12,7 +12,11 @@
- projects.each do |project| - projects.each do |project|
%li.wll %li.wll
= link_to project_path(project), class: dom_class(project) do = link_to project_path(project), class: dom_class(project) do
%strong.project_name= truncate(project.name, length: 25) - if project.namespace
= project.namespace.human_name
\/
%strong.project_name
= truncate(project.name, length: 25)
%span.arrow %span.arrow
&rarr; &rarr;
%span.last_activity %span.last_activity

View file

@ -3,6 +3,11 @@
Projects Projects
%small %small
(#{projects.count}) (#{projects.count})
- if can? current_user, :manage_group, @group
%span.right
= link_to new_project_path(namespace_id: @group.id), class: "btn very_small info" do
%i.icon-plus
New Project
%ul.unstyled %ul.unstyled
- projects.each do |project| - projects.each do |project|
%li.wll %li.wll

View file

@ -9,4 +9,6 @@
= image_tag gravatar_icon(user.email, 16), class: "avatar s16" = image_tag gravatar_icon(user.email, 16), class: "avatar s16"
%strong= user.name %strong= user.name
%span.cgray= user.email %span.cgray= user.email
- if @group.owner == user
%span.btn.btn-small.disabled.right Owner

View file

@ -1,6 +1,6 @@
:javascript :javascript
$(function() { $(function() {
GitLab.GfmAutoComplete.Members.url = "#{ "/api/v2/projects/#{@project.code}/members" if @project }"; GitLab.GfmAutoComplete.Members.url = "#{ "/api/v2/projects/#{@project.path}/members" if @project }";
GitLab.GfmAutoComplete.Members.params.private_token = "#{current_user.private_token}"; GitLab.GfmAutoComplete.Members.params.private_token = "#{current_user.private_token}";
GitLab.GfmAutoComplete.Emoji.data = #{raw emoji_autocomplete_source}; GitLab.GfmAutoComplete.Emoji.data = #{raw emoji_autocomplete_source};

View file

@ -7,7 +7,7 @@
.container .container
%ul.main_menu %ul.main_menu
= nav_link(html_options: {class: "home #{project_tab_class}"}) do = nav_link(html_options: {class: "home #{project_tab_class}"}) do
= link_to @project.code, project_path(@project), title: "Project" = link_to @project.path, project_path(@project), title: "Project"
- if @project.repo_exists? - if @project.repo_exists?
- if can? current_user, :download_code, @project - if can? current_user, :download_code, @project

View file

@ -8,6 +8,7 @@
= link_to authbutton(provider, 32), omniauth_authorize_path(User, provider) = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)
%fieldset %fieldset
%legend %legend
Private token Private token
@ -44,11 +45,25 @@
.input= f.password_field :password .input= f.password_field :password
.clearfix .clearfix
= f.label :password_confirmation = f.label :password_confirmation
.input= f.password_field :password_confirmation .input
.actions = f.password_field :password_confirmation
= f.submit 'Save', class: "btn save-btn" .clearfix
.input
= f.submit 'Save password', class: "btn save-btn"
%fieldset
%legend
Username
%small.right
Changing your username can have unintended side effects!
= form_for @user, url: profile_update_path, method: :put do |f|
.padded
= f.label :username
.input
= f.text_field :username
.input
= f.submit 'Save username', class: "btn save-btn"

View file

@ -9,48 +9,45 @@
Project name is Project name is
.input .input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge" = f.text_field :name, placeholder: "Example Project", class: "xxlarge"
%fieldset %fieldset
%legend Advanced settings: %legend Advanced settings:
.clearfix .control-group
= f.label :path do = f.label :path do
Path Path
.input .controls
.input-prepend = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true
%strong
= text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true
.clearfix
= f.label :code do
URL
.input
.input-prepend
%span.add-on= web_app_url
= f.text_field :code, placeholder: "example"
- unless @project.new_record? || @project.heads.empty? .control-group
= f.label :namespace_id do
%span Namespace
.controls
= f.select :namespace_id, namespaces_options(@project.namespace_id), {}, {class: 'chosen'}
&nbsp;
%span.cred Be careful. Changing project namespace can have unintended side effects
- unless @project.heads.empty?
.clearfix .clearfix
= f.label :default_branch, "Default Branch" = f.label :default_branch, "Default Branch"
.input= f.select(:default_branch, @project.heads.map(&:name), {}, style: "width:210px;") .input= f.select(:default_branch, @project.heads.map(&:name), {}, style: "width:210px;")
- unless @project.new_record? %fieldset
%fieldset %legend Features:
%legend Features:
.clearfix .clearfix
= f.label :issues_enabled, "Issues" = f.label :issues_enabled, "Issues"
.input= f.check_box :issues_enabled .input= f.check_box :issues_enabled
.clearfix .clearfix
= f.label :merge_requests_enabled, "Merge Requests" = f.label :merge_requests_enabled, "Merge Requests"
.input= f.check_box :merge_requests_enabled .input= f.check_box :merge_requests_enabled
.clearfix .clearfix
= f.label :wall_enabled, "Wall" = f.label :wall_enabled, "Wall"
.input= f.check_box :wall_enabled .input= f.check_box :wall_enabled
.clearfix .clearfix
= f.label :wiki_enabled, "Wiki" = f.label :wiki_enabled, "Wiki"
.input= f.check_box :wiki_enabled .input= f.check_box :wiki_enabled
%br %br

View file

@ -9,21 +9,12 @@
= f.text_field :name, placeholder: "Example Project", class: "xxlarge" = f.text_field :name, placeholder: "Example Project", class: "xxlarge"
= f.submit 'Create project', class: "btn primary project-submit" = f.submit 'Create project', class: "btn primary project-submit"
- if current_user.several_namespaces?
.clearfix
= f.label :namespace_id do
%span.cgray Namespace
.input
= f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'chosen'}
%hr %hr
%div.adv_settings %p.padded
%h6 Advanced settings: All created project are private. You choose who can see project and commit to repository.
.clearfix
= f.label :path do
Git Clone
.input
.input-prepend
%span.add-on= Gitlab.config.ssh_path
= f.text_field :path, placeholder: "example_project", disabled: !@project.new_record?
%span.add-on= ".git"
.clearfix
= f.label :code do
URL
.input
.input-prepend
%span.add-on= web_app_url
= f.text_field :code, placeholder: "example"

View file

@ -1,6 +1,6 @@
- if @project.valid? - if @project.valid?
:plain :plain
location.href = "#{edit_project_path(@project, notice: 'Project was successfully updated.')}"; location.href = "#{edit_project_path(@project)}";
- else - else
:plain :plain
$('.project_edit_holder').show(); $('.project_edit_holder').show();

View file

@ -15,8 +15,12 @@
%span.options %span.options
= link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn very_small", target: "_blank" = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn very_small", target: "_blank"
.file_content.code .file_content.code
%div{class: current_user.dark_scheme ? "black" : ""} - unless @snippet.content.empty?
= raw @snippet.colorize(options: { linenos: 'True'}) %div{class: current_user.dark_scheme ? "black" : "white"}
= preserve do
= raw Pygments.highlight(@snippet.content, formatter: :gitlab)
- else
%h4.nothing_here_message Empty file
%div %div

View file

@ -18,7 +18,7 @@ Gitlab::Application.routes.draw do
project_root: Gitlab.config.git_base_path, project_root: Gitlab.config.git_base_path,
upload_pack: Gitlab.config.git_upload_pack, upload_pack: Gitlab.config.git_upload_pack,
receive_pack: Gitlab.config.git_receive_pack receive_pack: Gitlab.config.git_receive_pack
}), at: '/:path', constraints: { path: /[\w\.-]+\.git/ } }), at: '/:path', constraints: { path: /[-\/\w\.-]+\.git/ }
# #
# Help # Help
@ -49,7 +49,7 @@ Gitlab::Application.routes.draw do
delete :remove_project delete :remove_project
end end
end end
resources :projects, constraints: { id: /[^\/]+/ } do resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, except: [:new, :create] do
member do member do
get :team get :team
put :team_update put :team_update
@ -107,7 +107,7 @@ Gitlab::Application.routes.draw do
# #
# Project Area # Project Area
# #
resources :projects, constraints: { id: /[^\/]+/ }, except: [:new, :create, :index], path: "/" do resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, except: [:new, :create, :index], path: "/" do
member do member do
get "wall" get "wall"
get "graph" get "graph"

View file

@ -1,9 +1,10 @@
unless User.count > 0 unless User.count > 0
admin = User.create( admin = User.create(
:email => "admin@local.host", email: "admin@local.host",
:name => "Administrator", name: "Administrator",
:password => "5iveL!fe", username: 'root',
:password_confirmation => "5iveL!fe" password: "5iveL!fe",
password_confirmation: "5iveL!fe"
) )
admin.projects_limit = 10000 admin.projects_limit = 10000

View file

@ -1,5 +1,5 @@
Project.seed(:id, [ Project.seed(:id, [
{ id: 1, name: "Underscore.js", path: "underscore", code: "underscore", owner_id: 1 }, { id: 1, name: "Underscore.js", path: "underscore", owner_id: 1 },
{ id: 2, name: "Diaspora", path: "diaspora", code: "diaspora", owner_id: 1 }, { id: 2, name: "Diaspora", path: "diaspora", owner_id: 1 },
{ id: 3, name: "Ruby on Rails", path: "rails", code: "rails", owner_id: 1 } { id: 3, name: "Ruby on Rails", path: "rails", owner_id: 1 }
]) ])

View file

@ -1,11 +1,11 @@
User.seed(:id, [ User.seed(:id, [
{ :id => 2, :name => Faker::Internet.user_name, :email => Faker::Internet.email}, { id: 2, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
{ :id => 3, :name => Faker::Internet.user_name, :email => Faker::Internet.email}, { id: 3, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
{ :id => 4, :name => Faker::Internet.user_name, :email => Faker::Internet.email}, { id: 4, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
{ :id => 5, :name => Faker::Internet.user_name, :email => Faker::Internet.email}, { id: 5, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
{ :id => 6, :name => Faker::Internet.user_name, :email => Faker::Internet.email}, { id: 6, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
{ :id => 7, :name => Faker::Internet.user_name, :email => Faker::Internet.email}, { id: 7, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
{ :id => 8, :name => Faker::Internet.user_name, :email => Faker::Internet.email}, { id: 8, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
{ :id => 9, :name => Faker::Internet.user_name, :email => Faker::Internet.email} { id: 9, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email}
]) ])

View file

@ -1,8 +1,9 @@
admin = User.create( admin = User.create(
:email => "admin@local.host", email: "admin@local.host",
:name => "Administrator", name: "Administrator",
:password => "5iveL!fe", username: 'root',
:password_confirmation => "5iveL!fe" password: "5iveL!fe",
password_confirmation: "5iveL!fe"
) )
admin.projects_limit = 10000 admin.projects_limit = 10000

View file

@ -0,0 +1,13 @@
class ConvertGroupToNamespace < ActiveRecord::Migration
def up
rename_table 'groups', 'namespaces'
add_column :namespaces, :type, :string, null: true
# Migrate old groups
Namespace.update_all(type: 'Group')
end
def down
raise 'Rollback is not allowed'
end
end

View file

@ -0,0 +1,5 @@
class AddNamespaceIdToProject < ActiveRecord::Migration
def change
rename_column :projects, :group_id, :namespace_id
end
end

View file

@ -0,0 +1,5 @@
class AddUsernameToUser < ActiveRecord::Migration
def change
add_column :users, :username, :string, null: true
end
end

View file

@ -0,0 +1,11 @@
class RenameCodeToPath < ActiveRecord::Migration
def up
remove_column :projects, :code
rename_column :namespaces, :code, :path
end
def down
add_column :projects, :code, :string
rename_column :namespaces, :path, :code
end
end

View file

@ -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 => 20121120113838) do ActiveRecord::Schema.define(:version => 20121123164910) do
create_table "events", :force => true do |t| create_table "events", :force => true do |t|
t.string "target_type" t.string "target_type"
@ -25,14 +25,6 @@ ActiveRecord::Schema.define(:version => 20121120113838) do
t.integer "author_id" t.integer "author_id"
end end
create_table "groups", :force => true do |t|
t.string "name", :null => false
t.string "code", :null => false
t.integer "owner_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "issues", :force => true do |t| create_table "issues", :force => true do |t|
t.string "title" t.string "title"
t.integer "assignee_id" t.integer "assignee_id"
@ -88,6 +80,15 @@ ActiveRecord::Schema.define(:version => 20121120113838) do
t.datetime "updated_at", :null => false t.datetime "updated_at", :null => false
end end
create_table "namespaces", :force => true do |t|
t.string "name", :null => false
t.string "path", :null => false
t.integer "owner_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "type"
end
create_table "notes", :force => true do |t| create_table "notes", :force => true do |t|
t.text "note" t.text "note"
t.string "noteable_id" t.string "noteable_id"
@ -110,14 +111,13 @@ ActiveRecord::Schema.define(:version => 20121120113838) do
t.datetime "created_at", :null => false t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false t.datetime "updated_at", :null => false
t.boolean "private_flag", :default => true, :null => false t.boolean "private_flag", :default => true, :null => false
t.string "code"
t.integer "owner_id" t.integer "owner_id"
t.string "default_branch" t.string "default_branch"
t.boolean "issues_enabled", :default => true, :null => false t.boolean "issues_enabled", :default => true, :null => false
t.boolean "wall_enabled", :default => true, :null => false t.boolean "wall_enabled", :default => true, :null => false
t.boolean "merge_requests_enabled", :default => true, :null => false t.boolean "merge_requests_enabled", :default => true, :null => false
t.boolean "wiki_enabled", :default => true, :null => false t.boolean "wiki_enabled", :default => true, :null => false
t.integer "group_id" t.integer "namespace_id"
end end
create_table "protected_branches", :force => true do |t| create_table "protected_branches", :force => true do |t|
@ -194,6 +194,7 @@ ActiveRecord::Schema.define(:version => 20121120113838) do
t.datetime "locked_at" t.datetime "locked_at"
t.string "extern_uid" t.string "extern_uid"
t.string "provider" t.string "provider"
t.string "username"
end end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true add_index "users", ["email"], :name => "index_users_on_email", :unique => true

View file

@ -57,13 +57,14 @@ Feature: Project Issues
Then I should see "Release 0.3" in issues Then I should see "Release 0.3" in issues
And I should not see "Release 0.4" in issues And I should not see "Release 0.4" in issues
@javascript # TODO: find out solution for poltergeist/phantomjs or remove
Scenario: I clear search # @javascript
Given I click link "All" # Scenario: I clear search
And I fill in issue search with "Something" # Given I click link "All"
And I fill in issue search with "" # And I fill in issue search with "Something"
Then I should see "Release 0.4" in issues # And I fill in issue search with ""
And I should see "Release 0.3" in issues # Then I should see "Release 0.4" in issues
# And I should see "Release 0.3" in issues
@javascript @javascript
Scenario: I create Issue with pre-selected milestone Scenario: I create Issue with pre-selected milestone

View file

@ -9,7 +9,7 @@ class AdminGroups < Spinach::FeatureSteps
And 'submit form with new group info' do And 'submit form with new group info' do
fill_in 'group_name', :with => 'gitlab' fill_in 'group_name', :with => 'gitlab'
fill_in 'group_code', :with => 'gitlab' fill_in 'group_path', :with => 'gitlab'
click_button "Save group" click_button "Save group"
end end

View file

@ -4,8 +4,6 @@ class CreateProject < Spinach::FeatureSteps
And 'fill project form with valid data' do And 'fill project form with valid data' do
fill_in 'project_name', :with => 'NewProject' fill_in 'project_name', :with => 'NewProject'
fill_in 'project_code', :with => 'NPR'
fill_in 'project_path', :with => 'newproject'
click_button "Create project" click_button "Create project"
end end

View file

@ -73,7 +73,6 @@ class ProjectIssues < Spinach::FeatureSteps
end end
And 'I fill in issue search with ""' do And 'I fill in issue search with ""' do
page.execute_script("$('.issue_search').val('').keyup();");
fill_in 'issue_search', with: "" fill_in 'issue_search', with: ""
end end

View file

@ -5,7 +5,7 @@ require 'rspec'
require 'database_cleaner' require 'database_cleaner'
require 'spinach/capybara' require 'spinach/capybara'
%w(gitolite_stub stubbed_repository valid_commit).each do |f| %w(namespaces_stub gitolite_stub stubbed_repository valid_commit).each do |f|
require Rails.root.join('spec', 'support', f) require Rails.root.join('spec', 'support', f)
end end

View file

@ -6,7 +6,7 @@ module Gitlab
def user_project def user_project
if @project ||= current_user.projects.find_by_id(params[:id]) || if @project ||= current_user.projects.find_by_id(params[:id]) ||
current_user.projects.find_by_code(params[:id]) current_user.projects.find_by_path(params[:id])
else else
not_found! not_found!
end end

View file

@ -38,11 +38,7 @@ module Gitlab
# Example Request # Example Request
# POST /projects # POST /projects
post do post do
params[:code] ||= params[:name] attrs = attributes_for_keys [:name,
params[:path] ||= params[:name]
attrs = attributes_for_keys [:code,
:path,
:name,
:description, :description,
:default_branch, :default_branch,
:issues_enabled, :issues_enabled,

View file

@ -38,7 +38,7 @@ module Gitlab
# POST /users # POST /users
post do post do
authenticated_as_admin! authenticated_as_admin!
attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit] attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username]
user = User.new attrs, as: :admin user = User.new attrs, as: :admin
if user.save if user.save
present user, with: Entities::User present user, with: Entities::User

View file

@ -34,6 +34,7 @@ module Gitlab
extern_uid: uid, extern_uid: uid,
provider: provider, provider: provider,
name: name, name: name,
username: email.match(/^[^@]*/)[0],
email: email, email: email,
password: password, password: password,
password_confirmation: password, password_confirmation: password,

View file

@ -126,7 +126,7 @@ module Gitlab
end end
def update_project_config(project, conf) def update_project_config(project, conf)
repo_name = project.path repo_name = project.path_with_namespace
repo = if conf.has_repo?(repo_name) repo = if conf.has_repo?(repo_name)
conf.get_repo(repo_name) conf.get_repo(repo_name)

View file

@ -0,0 +1,41 @@
# ProjectMover class
#
# Used for moving project repositories from one subdir to another
module Gitlab
class ProjectMover
class ProjectMoveError < StandardError; end
attr_reader :project, :old_dir, :new_dir
def initialize(project, old_dir, new_dir)
@project = project
@old_dir = old_dir
@new_dir = new_dir
end
def execute
# Create new dir if missing
new_dir_path = File.join(Gitlab.config.git_base_path, new_dir)
Dir.mkdir(new_dir_path) unless File.exists?(new_dir_path)
old_path = File.join(Gitlab.config.git_base_path, old_dir, "#{project.path}.git")
new_path = File.join(new_dir_path, "#{project.path}.git")
if system("mv #{old_path} #{new_path}")
log_info "Project #{project.name} was moved from #{old_path} to #{new_path}"
true
else
message = "Project #{project.name} cannot be moved from #{old_path} to #{new_path}"
log_info "Error! #{message}"
raise ProjectMoveError.new(message)
false
end
end
protected
def log_info message
Gitlab::AppLogger.info message
end
end
end

View file

@ -0,0 +1,17 @@
namespace :gitlab do
desc "GITLAB | Enable usernames and namespaces for user projects"
task activate_namespaces: :environment do
User.find_each(batch_size: 500) do |user|
next if user.namespace
User.transaction do
username = user.email.match(/^[^@]*/)[0]
if user.update_attributes!(username: username)
print '.'.green
else
print 'F'.red
end
end
end
end
end

View file

@ -13,7 +13,7 @@ describe CommitsController do
describe "GET show" do describe "GET show" do
context "as atom feed" do context "as atom feed" do
it "should render as atom" do it "should render as atom" do
get :show, project_id: project.code, id: "master.atom" get :show, project_id: project.path, id: "master.atom"
response.should be_success response.should be_success
response.content_type.should == 'application/atom+xml' response.content_type.should == 'application/atom+xml'
end end

View file

@ -12,6 +12,7 @@ FactoryGirl.define do
factory :user, aliases: [:author, :assignee, :owner] do factory :user, aliases: [:author, :assignee, :owner] do
email { Faker::Internet.email } email { Faker::Internet.email }
name name
username { Faker::Internet.user_name }
password "123456" password "123456"
password_confirmation { password } password_confirmation { password }
@ -25,13 +26,19 @@ FactoryGirl.define do
factory :project do factory :project do
sequence(:name) { |n| "project#{n}" } sequence(:name) { |n| "project#{n}" }
path { name.downcase.gsub(/\s/, '_') } path { name.downcase.gsub(/\s/, '_') }
code { name.downcase.gsub(/\s/, '_') }
owner owner
end end
factory :group do factory :group do
sequence(:name) { |n| "group#{n}" } sequence(:name) { |n| "group#{n}" }
code { name.downcase.gsub(/\s/, '_') } path { name.downcase.gsub(/\s/, '_') }
owner
type 'Group'
end
factory :namespace do
sequence(:name) { |n| "group#{n}" }
path { name.downcase.gsub(/\s/, '_') }
owner owner
end end

View file

@ -169,9 +169,7 @@ describe Notify do
end end
describe 'project access changed' do describe 'project access changed' do
let(:project) { create(:project, let(:project) { create(:project) }
path: "Fuu",
code: "Fuu") }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:users_project) { create(:users_project, let(:users_project) { create(:users_project,
project: project, project: project,

View file

@ -1,13 +1,14 @@
# == Schema Information # == Schema Information
# #
# Table name: groups # Table name: namespaces
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) not null # name :string(255) not null
# code :string(255) not null # path :string(255) not null
# owner_id :integer not null # owner_id :integer not null
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# type :string(255)
# #
require 'spec_helper' require 'spec_helper'
@ -18,7 +19,7 @@ describe Group do
it { should have_many :projects } it { should have_many :projects }
it { should validate_presence_of :name } it { should validate_presence_of :name }
it { should validate_uniqueness_of(:name) } it { should validate_uniqueness_of(:name) }
it { should validate_presence_of :code } it { should validate_presence_of :path }
it { should validate_uniqueness_of(:code) } it { should validate_uniqueness_of(:path) }
it { should validate_presence_of :owner } it { should validate_presence_of :owner }
end end

View file

@ -0,0 +1,35 @@
# == Schema Information
#
# Table name: namespaces
#
# id :integer not null, primary key
# name :string(255) not null
# path :string(255) not null
# owner_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# type :string(255)
#
require 'spec_helper'
describe Namespace do
let!(:namespace) { create(:namespace) }
it { should have_many :projects }
it { should validate_presence_of :name }
it { should validate_uniqueness_of(:name) }
it { should validate_presence_of :path }
it { should validate_uniqueness_of(:path) }
it { should validate_presence_of :owner }
describe "Mass assignment" do
it { should allow_mass_assignment_of(:name) }
it { should allow_mass_assignment_of(:path) }
end
describe "Respond to" do
it { should respond_to(:human_name) }
it { should respond_to(:to_param) }
end
end

View file

@ -9,14 +9,13 @@
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# private_flag :boolean default(TRUE), not null # private_flag :boolean default(TRUE), not null
# code :string(255)
# owner_id :integer # owner_id :integer
# default_branch :string(255) # default_branch :string(255)
# issues_enabled :boolean default(TRUE), not null # issues_enabled :boolean default(TRUE), not null
# wall_enabled :boolean default(TRUE), not null # wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null # merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null
# group_id :integer # namespace_id :integer
# #
require 'spec_helper' require 'spec_helper'
@ -24,6 +23,7 @@ require 'spec_helper'
describe Project do describe Project do
describe "Associations" do describe "Associations" do
it { should belong_to(:group) } it { should belong_to(:group) }
it { should belong_to(:namespace) }
it { should belong_to(:owner).class_name('User') } it { should belong_to(:owner).class_name('User') }
it { should have_many(:users) } it { should have_many(:users) }
it { should have_many(:events).dependent(:destroy) } it { should have_many(:events).dependent(:destroy) }
@ -40,6 +40,7 @@ describe Project do
end end
describe "Mass assignment" do describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:namespace_id) }
it { should_not allow_mass_assignment_of(:owner_id) } it { should_not allow_mass_assignment_of(:owner_id) }
it { should_not allow_mass_assignment_of(:private_flag) } it { should_not allow_mass_assignment_of(:private_flag) }
end end
@ -58,9 +59,6 @@ describe Project do
it { should ensure_length_of(:description).is_within(0..2000) } it { should ensure_length_of(:description).is_within(0..2000) }
it { should validate_presence_of(:code) }
it { should validate_uniqueness_of(:code) }
it { should ensure_length_of(:code).is_within(1..255) }
# TODO: Formats # TODO: Formats
it { should validate_presence_of(:owner) } it { should validate_presence_of(:owner) }
@ -151,7 +149,7 @@ describe Project do
end end
it "returns the full web URL for this repo" do it "returns the full web URL for this repo" do
project = Project.new(code: "somewhere") project = Project.new(path: "somewhere")
project.web_url.should == "#{Gitlab.config.url}/somewhere" project.web_url.should == "#{Gitlab.config.url}/somewhere"
end end
@ -162,7 +160,7 @@ describe Project do
end end
it "should be invalid repo" do it "should be invalid repo" do
project = Project.new(name: "ok_name", path: "/INVALID_PATH/", code: "NEOK") project = Project.new(name: "ok_name", path: "/INVALID_PATH/", path: "NEOK")
project.valid_repo?.should be_false project.valid_repo?.should be_false
end end
end end

View file

@ -30,14 +30,17 @@
# locked_at :datetime # locked_at :datetime
# extern_uid :string(255) # extern_uid :string(255)
# provider :string(255) # provider :string(255)
# username :string(255)
# #
require 'spec_helper' require 'spec_helper'
describe User do describe User do
describe "Associations" do describe "Associations" do
it { should have_one(:namespace) }
it { should have_many(:users_projects).dependent(:destroy) } it { should have_many(:users_projects).dependent(:destroy) }
it { should have_many(:projects) } it { should have_many(:projects) }
it { should have_many(:groups) }
it { should have_many(:my_own_projects).class_name('Project') } it { should have_many(:my_own_projects).class_name('Project') }
it { should have_many(:keys).dependent(:destroy) } it { should have_many(:keys).dependent(:destroy) }
it { should have_many(:events).class_name('Event').dependent(:destroy) } it { should have_many(:events).class_name('Event').dependent(:destroy) }

View file

@ -13,7 +13,12 @@ describe UserObserver do
end end
context 'when a new user is created' do context 'when a new user is created' do
let(:user) { double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local') } let(:user) { double(:user, id: 42,
password: 'P@ssword!',
name: 'John',
email: 'u@mail.local',
username: 'root',
create_namespace: true) }
let(:notification) { double :notification } let(:notification) { double :notification }
it 'sends an email' do it 'sends an email' do

View file

@ -2,9 +2,7 @@ require 'spec_helper'
describe UsersProjectObserver do describe UsersProjectObserver do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, let(:project) { create(:project) }
code: "Fuu",
path: "Fuu" ) }
let(:users_project) { create(:users_project, let(:users_project) { create(:users_project,
project: project, project: project,
user: user )} user: user )}

View file

@ -2,9 +2,7 @@ require 'spec_helper'
describe "Admin::Hooks" do describe "Admin::Hooks" do
before do before do
@project = create(:project, @project = create(:project)
name: "LeGiT",
code: "LGT")
login_as :admin login_as :admin
@system_hook = create(:system_hook) @system_hook = create(:system_hook)

View file

@ -2,9 +2,7 @@ require 'spec_helper'
describe "Admin::Projects" do describe "Admin::Projects" do
before do before do
@project = create(:project, @project = create(:project)
name: "LeGiT",
code: "LGT")
login_as :admin login_as :admin
end end
@ -29,7 +27,7 @@ describe "Admin::Projects" do
end end
it "should have project info" do it "should have project info" do
page.should have_content(@project.code) page.should have_content(@project.path)
page.should have_content(@project.name) page.should have_content(@project.name)
end end
end end
@ -41,67 +39,27 @@ describe "Admin::Projects" do
end end
it "should have project edit page" do it "should have project edit page" do
page.should have_content("Project name") page.should have_content("Edit project")
page.should have_content("URL") page.should have_button("Save Project")
end end
describe "Update project" do describe "Update project" do
before do before do
fill_in "project_name", with: "Big Bang" fill_in "project_name", with: "Big Bang"
fill_in "project_code", with: "BB1"
click_button "Save Project" click_button "Save Project"
@project.reload @project.reload
end end
it "should show page with new data" do it "should show page with new data" do
page.should have_content("BB1")
page.should have_content("Big Bang") page.should have_content("Big Bang")
end end
it "should change project entry" do it "should change project entry" do
@project.name.should == "Big Bang" @project.name.should == "Big Bang"
@project.code.should == "BB1"
end end
end end
end end
describe "GET /admin/projects/new" do
before do
visit admin_projects_path
click_link "New Project"
end
it "should be correct path" do
current_path.should == new_admin_project_path
end
it "should have labels for new project" do
page.should have_content("Project name is")
page.should have_content("Git Clone")
page.should have_content("URL")
end
end
describe "POST /admin/projects" do
before do
visit new_admin_project_path
fill_in 'project_name', with: 'NewProject'
fill_in 'project_code', with: 'NPR'
fill_in 'project_path', with: 'gitlabhq_1'
expect { click_button "Create project" }.to change { Project.count }.by(1)
@project = Project.last
end
it "should be correct path" do
current_path.should == admin_project_path(@project)
end
it "should show project" do
page.should have_content(@project.name)
page.should have_content(@project.path)
end
end
describe "Add new team member" do describe "Add new team member" do
before do before do
@new_user = create(:user) @new_user = create(:user)

View file

@ -23,6 +23,7 @@ describe "Admin::Users" do
@password = "123ABC" @password = "123ABC"
visit new_admin_user_path visit new_admin_user_path
fill_in "user_name", with: "Big Bang" fill_in "user_name", with: "Big Bang"
fill_in "user_username", with: "bang"
fill_in "user_email", with: "bigbang@mail.com" fill_in "user_email", with: "bigbang@mail.com"
fill_in "user_password", with: @password fill_in "user_password", with: @password
fill_in "user_password_confirmation", with: @password fill_in "user_password_confirmation", with: @password

View file

@ -28,7 +28,7 @@ describe Gitlab::API do
describe "GET /projects/:id/issues" do describe "GET /projects/:id/issues" do
it "should return project issues" do it "should return project issues" do
get api("/projects/#{project.code}/issues", user) get api("/projects/#{project.path}/issues", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.first['title'].should == issue.title json_response.first['title'].should == issue.title
@ -37,7 +37,7 @@ describe Gitlab::API do
describe "GET /projects/:id/issues/:issue_id" do describe "GET /projects/:id/issues/:issue_id" do
it "should return a project issue by id" do it "should return a project issue by id" do
get api("/projects/#{project.code}/issues/#{issue.id}", user) get api("/projects/#{project.path}/issues/#{issue.id}", user)
response.status.should == 200 response.status.should == 200
json_response['title'].should == issue.title json_response['title'].should == issue.title
end end
@ -45,7 +45,7 @@ describe Gitlab::API do
describe "POST /projects/:id/issues" do describe "POST /projects/:id/issues" do
it "should create a new project issue" do it "should create a new project issue" do
post api("/projects/#{project.code}/issues", user), post api("/projects/#{project.path}/issues", user),
title: 'new issue', labels: 'label, label2' title: 'new issue', labels: 'label, label2'
response.status.should == 201 response.status.should == 201
json_response['title'].should == 'new issue' json_response['title'].should == 'new issue'
@ -56,7 +56,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/issues/:issue_id" do describe "PUT /projects/:id/issues/:issue_id" do
it "should update a project issue" do it "should update a project issue" do
put api("/projects/#{project.code}/issues/#{issue.id}", user), put api("/projects/#{project.path}/issues/#{issue.id}", user),
title: 'updated title', labels: 'label2', closed: 1 title: 'updated title', labels: 'label2', closed: 1
response.status.should == 200 response.status.should == 200
json_response['title'].should == 'updated title' json_response['title'].should == 'updated title'
@ -67,7 +67,7 @@ describe Gitlab::API do
describe "DELETE /projects/:id/issues/:issue_id" do describe "DELETE /projects/:id/issues/:issue_id" do
it "should delete a project issue" do it "should delete a project issue" do
delete api("/projects/#{project.code}/issues/#{issue.id}", user) delete api("/projects/#{project.path}/issues/#{issue.id}", user)
response.status.should == 405 response.status.should == 405
end end
end end

View file

@ -11,14 +11,14 @@ describe Gitlab::API do
describe "GET /projects/:id/merge_requests" do describe "GET /projects/:id/merge_requests" do
context "when unauthenticated" do context "when unauthenticated" do
it "should return authentication error" do it "should return authentication error" do
get api("/projects/#{project.code}/merge_requests") get api("/projects/#{project.path}/merge_requests")
response.status.should == 401 response.status.should == 401
end end
end end
context "when authenticated" do context "when authenticated" do
it "should return an array of merge_requests" do it "should return an array of merge_requests" do
get api("/projects/#{project.code}/merge_requests", user) get api("/projects/#{project.path}/merge_requests", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.first['title'].should == merge_request.title json_response.first['title'].should == merge_request.title
@ -28,7 +28,7 @@ describe Gitlab::API do
describe "GET /projects/:id/merge_request/:merge_request_id" do describe "GET /projects/:id/merge_request/:merge_request_id" do
it "should return merge_request" do it "should return merge_request" do
get api("/projects/#{project.code}/merge_request/#{merge_request.id}", user) get api("/projects/#{project.path}/merge_request/#{merge_request.id}", user)
response.status.should == 200 response.status.should == 200
json_response['title'].should == merge_request.title json_response['title'].should == merge_request.title
end end
@ -36,7 +36,7 @@ describe Gitlab::API do
describe "POST /projects/:id/merge_requests" do describe "POST /projects/:id/merge_requests" do
it "should return merge_request" do it "should return merge_request" do
post api("/projects/#{project.code}/merge_requests", user), post api("/projects/#{project.path}/merge_requests", user),
title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user
response.status.should == 201 response.status.should == 201
json_response['title'].should == 'Test merge_request' json_response['title'].should == 'Test merge_request'
@ -45,7 +45,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/merge_request/:merge_request_id" do describe "PUT /projects/:id/merge_request/:merge_request_id" do
it "should return merge_request" do it "should return merge_request" do
put api("/projects/#{project.code}/merge_request/#{merge_request.id}", user), title: "New title" put api("/projects/#{project.path}/merge_request/#{merge_request.id}", user), title: "New title"
response.status.should == 200 response.status.should == 200
json_response['title'].should == 'New title' json_response['title'].should == 'New title'
end end
@ -53,7 +53,7 @@ describe Gitlab::API do
describe "POST /projects/:id/merge_request/:merge_request_id/comments" do describe "POST /projects/:id/merge_request/:merge_request_id/comments" do
it "should return comment" do it "should return comment" do
post api("/projects/#{project.code}/merge_request/#{merge_request.id}/comments", user), note: "My comment" post api("/projects/#{project.path}/merge_request/#{merge_request.id}/comments", user), note: "My comment"
response.status.should == 201 response.status.should == 201
json_response['note'].should == 'My comment' json_response['note'].should == 'My comment'
end end

View file

@ -11,7 +11,7 @@ describe Gitlab::API do
describe "GET /projects/:id/milestones" do describe "GET /projects/:id/milestones" do
it "should return project milestones" do it "should return project milestones" do
get api("/projects/#{project.code}/milestones", user) get api("/projects/#{project.path}/milestones", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.first['title'].should == milestone.title json_response.first['title'].should == milestone.title
@ -20,7 +20,7 @@ describe Gitlab::API do
describe "GET /projects/:id/milestones/:milestone_id" do describe "GET /projects/:id/milestones/:milestone_id" do
it "should return a project milestone by id" do it "should return a project milestone by id" do
get api("/projects/#{project.code}/milestones/#{milestone.id}", user) get api("/projects/#{project.path}/milestones/#{milestone.id}", user)
response.status.should == 200 response.status.should == 200
json_response['title'].should == milestone.title json_response['title'].should == milestone.title
end end
@ -28,7 +28,7 @@ describe Gitlab::API do
describe "POST /projects/:id/milestones" do describe "POST /projects/:id/milestones" do
it "should create a new project milestone" do it "should create a new project milestone" do
post api("/projects/#{project.code}/milestones", user), post api("/projects/#{project.path}/milestones", user),
title: 'new milestone' title: 'new milestone'
response.status.should == 201 response.status.should == 201
json_response['title'].should == 'new milestone' json_response['title'].should == 'new milestone'
@ -38,7 +38,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/milestones/:milestone_id" do describe "PUT /projects/:id/milestones/:milestone_id" do
it "should update a project milestone" do it "should update a project milestone" do
put api("/projects/#{project.code}/milestones/#{milestone.id}", user), put api("/projects/#{project.path}/milestones/#{milestone.id}", user),
title: 'updated title' title: 'updated title'
response.status.should == 200 response.status.should == 200
json_response['title'].should == 'updated title' json_response['title'].should == 'updated title'

View file

@ -33,7 +33,7 @@ describe Gitlab::API do
end end
describe "POST /projects" do describe "POST /projects" do
it "should create new project without code and path" do it "should create new project without path" do
expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1) expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1)
end end
@ -53,8 +53,6 @@ describe Gitlab::API do
it "should assign attributes to project" do it "should assign attributes to project" do
project = attributes_for(:project, { project = attributes_for(:project, {
path: 'path',
code: 'code',
description: Faker::Lorem.sentence, description: Faker::Lorem.sentence,
default_branch: 'stable', default_branch: 'stable',
issues_enabled: false, issues_enabled: false,
@ -79,8 +77,8 @@ describe Gitlab::API do
json_response['owner']['email'].should == user.email json_response['owner']['email'].should == user.email
end end
it "should return a project by code name" do it "should return a project by path name" do
get api("/projects/#{project.code}", user) get api("/projects/#{project.path}", user)
response.status.should == 200 response.status.should == 200
json_response['name'].should == project.name json_response['name'].should == project.name
end end
@ -94,7 +92,7 @@ describe Gitlab::API do
describe "GET /projects/:id/repository/branches" do describe "GET /projects/:id/repository/branches" do
it "should return an array of project branches" do it "should return an array of project branches" do
get api("/projects/#{project.code}/repository/branches", user) get api("/projects/#{project.path}/repository/branches", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name
@ -103,7 +101,7 @@ describe Gitlab::API do
describe "GET /projects/:id/repository/branches/:branch" do describe "GET /projects/:id/repository/branches/:branch" do
it "should return the branch information for a single branch" do it "should return the branch information for a single branch" do
get api("/projects/#{project.code}/repository/branches/new_design", user) get api("/projects/#{project.path}/repository/branches/new_design", user)
response.status.should == 200 response.status.should == 200
json_response['name'].should == 'new_design' json_response['name'].should == 'new_design'
@ -113,7 +111,7 @@ describe Gitlab::API do
describe "GET /projects/:id/members" do describe "GET /projects/:id/members" do
it "should return project team members" do it "should return project team members" do
get api("/projects/#{project.code}/members", user) get api("/projects/#{project.path}/members", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.count.should == 2 json_response.count.should == 2
@ -123,7 +121,7 @@ describe Gitlab::API do
describe "GET /projects/:id/members/:user_id" do describe "GET /projects/:id/members/:user_id" do
it "should return project team member" do it "should return project team member" do
get api("/projects/#{project.code}/members/#{user.id}", user) get api("/projects/#{project.path}/members/#{user.id}", user)
response.status.should == 200 response.status.should == 200
json_response['email'].should == user.email json_response['email'].should == user.email
json_response['access_level'].should == UsersProject::MASTER json_response['access_level'].should == UsersProject::MASTER
@ -133,7 +131,7 @@ describe Gitlab::API do
describe "POST /projects/:id/members" do describe "POST /projects/:id/members" do
it "should add user to project team" do it "should add user to project team" do
expect { expect {
post api("/projects/#{project.code}/members", user), user_id: user2.id, post api("/projects/#{project.path}/members", user), user_id: user2.id,
access_level: UsersProject::DEVELOPER access_level: UsersProject::DEVELOPER
}.to change { UsersProject.count }.by(1) }.to change { UsersProject.count }.by(1)
@ -145,7 +143,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/members/:user_id" do describe "PUT /projects/:id/members/:user_id" do
it "should update project team member" do it "should update project team member" do
put api("/projects/#{project.code}/members/#{user3.id}", user), access_level: UsersProject::MASTER put api("/projects/#{project.path}/members/#{user3.id}", user), access_level: UsersProject::MASTER
response.status.should == 200 response.status.should == 200
json_response['email'].should == user3.email json_response['email'].should == user3.email
json_response['access_level'].should == UsersProject::MASTER json_response['access_level'].should == UsersProject::MASTER
@ -155,14 +153,14 @@ describe Gitlab::API do
describe "DELETE /projects/:id/members/:user_id" do describe "DELETE /projects/:id/members/:user_id" do
it "should remove user from project team" do it "should remove user from project team" do
expect { expect {
delete api("/projects/#{project.code}/members/#{user3.id}", user) delete api("/projects/#{project.path}/members/#{user3.id}", user)
}.to change { UsersProject.count }.by(-1) }.to change { UsersProject.count }.by(-1)
end end
end end
describe "GET /projects/:id/hooks" do describe "GET /projects/:id/hooks" do
it "should return project hooks" do it "should return project hooks" do
get api("/projects/#{project.code}/hooks", user) get api("/projects/#{project.path}/hooks", user)
response.status.should == 200 response.status.should == 200
@ -174,7 +172,7 @@ describe Gitlab::API do
describe "GET /projects/:id/hooks/:hook_id" do describe "GET /projects/:id/hooks/:hook_id" do
it "should return a project hook" do it "should return a project hook" do
get api("/projects/#{project.code}/hooks/#{hook.id}", user) get api("/projects/#{project.path}/hooks/#{hook.id}", user)
response.status.should == 200 response.status.should == 200
json_response['url'].should == hook.url json_response['url'].should == hook.url
end end
@ -183,7 +181,7 @@ describe Gitlab::API do
describe "POST /projects/:id/hooks" do describe "POST /projects/:id/hooks" do
it "should add hook to project" do it "should add hook to project" do
expect { expect {
post api("/projects/#{project.code}/hooks", user), post api("/projects/#{project.path}/hooks", user),
"url" => "http://example.com" "url" => "http://example.com"
}.to change {project.hooks.count}.by(1) }.to change {project.hooks.count}.by(1)
end end
@ -191,7 +189,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/hooks/:hook_id" do describe "PUT /projects/:id/hooks/:hook_id" do
it "should update an existing project hook" do it "should update an existing project hook" do
put api("/projects/#{project.code}/hooks/#{hook.id}", user), put api("/projects/#{project.path}/hooks/#{hook.id}", user),
url: 'http://example.org' url: 'http://example.org'
response.status.should == 200 response.status.should == 200
json_response['url'].should == 'http://example.org' json_response['url'].should == 'http://example.org'
@ -202,7 +200,7 @@ describe Gitlab::API do
describe "DELETE /projects/:id/hooks" do describe "DELETE /projects/:id/hooks" do
it "should delete hook from project" do it "should delete hook from project" do
expect { expect {
delete api("/projects/#{project.code}/hooks", user), delete api("/projects/#{project.path}/hooks", user),
hook_id: hook.id hook_id: hook.id
}.to change {project.hooks.count}.by(-1) }.to change {project.hooks.count}.by(-1)
end end
@ -210,7 +208,7 @@ describe Gitlab::API do
describe "GET /projects/:id/repository/tags" do describe "GET /projects/:id/repository/tags" do
it "should return an array of project tags" do it "should return an array of project tags" do
get api("/projects/#{project.code}/repository/tags", user) get api("/projects/#{project.path}/repository/tags", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name json_response.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name
@ -222,7 +220,7 @@ describe Gitlab::API do
before { project.add_access(user2, :read) } before { project.add_access(user2, :read) }
it "should return project commits" do it "should return project commits" do
get api("/projects/#{project.code}/repository/commits", user) get api("/projects/#{project.path}/repository/commits", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
@ -232,7 +230,7 @@ describe Gitlab::API do
context "unauthorized user" do context "unauthorized user" do
it "should not return project commits" do it "should not return project commits" do
get api("/projects/#{project.code}/repository/commits") get api("/projects/#{project.path}/repository/commits")
response.status.should == 401 response.status.should == 401
end end
end end
@ -240,7 +238,7 @@ describe Gitlab::API do
describe "GET /projects/:id/snippets" do describe "GET /projects/:id/snippets" do
it "should return an array of project snippets" do it "should return an array of project snippets" do
get api("/projects/#{project.code}/snippets", user) get api("/projects/#{project.path}/snippets", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.first['title'].should == snippet.title json_response.first['title'].should == snippet.title
@ -249,7 +247,7 @@ describe Gitlab::API do
describe "GET /projects/:id/snippets/:snippet_id" do describe "GET /projects/:id/snippets/:snippet_id" do
it "should return a project snippet" do it "should return a project snippet" do
get api("/projects/#{project.code}/snippets/#{snippet.id}", user) get api("/projects/#{project.path}/snippets/#{snippet.id}", user)
response.status.should == 200 response.status.should == 200
json_response['title'].should == snippet.title json_response['title'].should == snippet.title
end end
@ -257,7 +255,7 @@ describe Gitlab::API do
describe "POST /projects/:id/snippets" do describe "POST /projects/:id/snippets" do
it "should create a new project snippet" do it "should create a new project snippet" do
post api("/projects/#{project.code}/snippets", user), post api("/projects/#{project.path}/snippets", user),
title: 'api test', file_name: 'sample.rb', code: 'test' title: 'api test', file_name: 'sample.rb', code: 'test'
response.status.should == 201 response.status.should == 201
json_response['title'].should == 'api test' json_response['title'].should == 'api test'
@ -266,7 +264,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/snippets/:shippet_id" do describe "PUT /projects/:id/snippets/:shippet_id" do
it "should update an existing project snippet" do it "should update an existing project snippet" do
put api("/projects/#{project.code}/snippets/#{snippet.id}", user), put api("/projects/#{project.path}/snippets/#{snippet.id}", user),
code: 'updated code' code: 'updated code'
response.status.should == 200 response.status.should == 200
json_response['title'].should == 'example' json_response['title'].should == 'example'
@ -277,31 +275,31 @@ describe Gitlab::API do
describe "DELETE /projects/:id/snippets/:snippet_id" do describe "DELETE /projects/:id/snippets/:snippet_id" do
it "should delete existing project snippet" do it "should delete existing project snippet" do
expect { expect {
delete api("/projects/#{project.code}/snippets/#{snippet.id}", user) delete api("/projects/#{project.path}/snippets/#{snippet.id}", user)
}.to change { Snippet.count }.by(-1) }.to change { Snippet.count }.by(-1)
end end
end end
describe "GET /projects/:id/snippets/:snippet_id/raw" do describe "GET /projects/:id/snippets/:snippet_id/raw" do
it "should get a raw project snippet" do it "should get a raw project snippet" do
get api("/projects/#{project.code}/snippets/#{snippet.id}/raw", user) get api("/projects/#{project.path}/snippets/#{snippet.id}/raw", user)
response.status.should == 200 response.status.should == 200
end end
end end
describe "GET /projects/:id/:sha/blob" do describe "GET /projects/:id/:sha/blob" do
it "should get the raw file contents" do it "should get the raw file contents" do
get api("/projects/#{project.code}/repository/commits/master/blob?filepath=README.md", user) get api("/projects/#{project.path}/repository/commits/master/blob?filepath=README.md", user)
response.status.should == 200 response.status.should == 200
end end
it "should return 404 for invalid branch_name" do it "should return 404 for invalid branch_name" do
get api("/projects/#{project.code}/repository/commits/invalid_branch_name/blob?filepath=README.md", user) get api("/projects/#{project.path}/repository/commits/invalid_branch_name/blob?filepath=README.md", user)
response.status.should == 404 response.status.should == 404
end end
it "should return 404 for invalid file" do it "should return 404 for invalid file" do
get api("/projects/#{project.code}/repository/commits/master/blob?filepath=README.invalid", user) get api("/projects/#{project.path}/repository/commits/master/blob?filepath=README.invalid", user)
response.status.should == 404 response.status.should == 404
end end
end end

View file

@ -3,16 +3,6 @@ require 'spec_helper'
describe "Projects" do describe "Projects" do
before { login_as :user } before { login_as :user }
describe 'GET /project/new' do
it "should work autocomplete", :js => true do
visit new_project_path
fill_in 'project_name', with: 'Awesome'
find("#project_path").value.should == 'awesome'
find("#project_code").value.should == 'awesome'
end
end
describe "GET /projects/show" do describe "GET /projects/show" do
before do before do
@project = create(:project, owner: @user) @project = create(:project, owner: @user)
@ -53,7 +43,6 @@ describe "Projects" do
visit edit_project_path(@project) visit edit_project_path(@project)
fill_in 'project_name', with: 'Awesome' fill_in 'project_name', with: 'Awesome'
fill_in 'project_code', with: 'gitlabhq'
click_button "Save" click_button "Save"
@project = @project.reload @project = @project.reload
end end

View file

@ -78,14 +78,6 @@ describe Admin::ProjectsController, "routing" do
get("/admin/projects").should route_to('admin/projects#index') get("/admin/projects").should route_to('admin/projects#index')
end end
it "to #create" do
post("/admin/projects").should route_to('admin/projects#create')
end
it "to #new" do
get("/admin/projects/new").should route_to('admin/projects#new')
end
it "to #edit" do it "to #edit" do
get("/admin/projects/gitlab/edit").should route_to('admin/projects#edit', id: 'gitlab') get("/admin/projects/gitlab/edit").should route_to('admin/projects#edit', id: 'gitlab')
end end

View file

@ -0,0 +1,18 @@
require 'namespace'
require 'gitlab/project_mover'
class Namespace
def ensure_dir_exist
true
end
def move_dir
true
end
end
class Gitlab::ProjectMover
def execute
true
end
end