Commit 3374027e authored by Sebastian Ziebell's avatar Sebastian Ziebell

Merge branch 'master' into fixes/api, code clean up and tests fixed

Conflicts:
	doc/api/projects.md
	spec/requests/api/projects_spec.rb
parents 39114d25 9c2a6e20
load 'deploy'
load 'deploy/assets'
require 'bundler/capistrano'
load 'config/deploy'
source "http://rubygems.org" source "https://rubygems.org"
def darwin_only(require_as) def darwin_only(require_as)
RUBY_PLATFORM.include?('darwin') && require_as RUBY_PLATFORM.include?('darwin') && require_as
...@@ -103,6 +103,9 @@ gem 'settingslogic' ...@@ -103,6 +103,9 @@ gem 'settingslogic'
gem "foreman" gem "foreman"
gem "git" gem "git"
# Cache
gem "redis-rails"
group :assets do group :assets do
gem "sass-rails", "~> 3.2.5" gem "sass-rails", "~> 3.2.5"
gem "coffee-rails", "~> 3.2.2" gem "coffee-rails", "~> 3.2.2"
......
...@@ -13,7 +13,7 @@ GIT ...@@ -13,7 +13,7 @@ GIT
raphael-rails (2.1.0) raphael-rails (2.1.0)
GEM GEM
remote: http://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actionmailer (3.2.12) actionmailer (3.2.12)
actionpack (= 3.2.12) actionpack (= 3.2.12)
...@@ -329,8 +329,24 @@ GEM ...@@ -329,8 +329,24 @@ GEM
json (~> 1.4) json (~> 1.4)
redcarpet (2.2.2) redcarpet (2.2.2)
redis (3.0.2) redis (3.0.2)
redis-actionpack (3.2.3)
actionpack (~> 3.2.3)
redis-rack (~> 1.4.0)
redis-store (~> 1.1.0)
redis-activesupport (3.2.3)
activesupport (~> 3.2.3)
redis-store (~> 1.1.0)
redis-namespace (1.2.1) redis-namespace (1.2.1)
redis (~> 3.0.0) redis (~> 3.0.0)
redis-rack (1.4.2)
rack (~> 1.4.1)
redis-store (~> 1.1.0)
redis-rails (3.2.3)
redis-actionpack (~> 3.2.3)
redis-activesupport (~> 3.2.3)
redis-store (~> 1.1.0)
redis-store (1.1.3)
redis (>= 2.2.0)
request_store (1.0.5) request_store (1.0.5)
rspec (2.12.0) rspec (2.12.0)
rspec-core (~> 2.12.0) rspec-core (~> 2.12.0)
...@@ -504,6 +520,7 @@ DEPENDENCIES ...@@ -504,6 +520,7 @@ DEPENDENCIES
rb-fsevent rb-fsevent
rb-inotify rb-inotify
redcarpet (~> 2.2.2) redcarpet (~> 2.2.2)
redis-rails
rspec-rails (= 2.12.2) rspec-rails (= 2.12.2)
sass-rails (~> 3.2.5) sass-rails (~> 3.2.5)
sdoc sdoc
......
...@@ -5,14 +5,14 @@ ...@@ -5,14 +5,14 @@
### GitLab allows you to ### GitLab allows you to
* keep your code secure on your own server * keep your code secure on your own server
* manage repositories, users and access permissions * manage repositories, users and access permissions
* communicate though issues, line-comments and wiki's * communicate through issues, line-comments and wiki pages
* perform code reviews with merge requests * perform code review with merge requests
### GitLab is ### GitLab is
* powered by Ruby on Rails * powered by Ruby on Rails
* completely free and open source (MIT license) * completely free and open source (MIT license)
* used by 10.000 organization to keep their code secure * used by 10.000 organizations to keep their code secure
### Code status ### Code status
...@@ -34,28 +34,35 @@ ...@@ -34,28 +34,35 @@
### Requirements ### Requirements
* Ubuntu/Debian* * Ubuntu/Debian**
* ruby 1.9.3+ * ruby 1.9.3+
* MySQL * MySQL
* git * git
* gitlab-shell * gitlab-shell
* redis * redis
* More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md) ** More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md)
### Installation ### Installation
You can either follow the "ordinary" Installation guide to install it on a machine or use the Vagrant virtual machine. The Installation guide is recommended to set up a production server. The Vargrant virtual machine is recommended for development since it makes it much easier to set up all the dependencies for integration testing. #### For production
* [Installation guide for latest stable release](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) Follow the installation guide for production server.
* [Installation guide for the current master branch](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) * [Installation guide for latest stable release (4.2)](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) - **Recommended**
* [Installation guide for the current master branch (5.0)](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md)
#### For development
If you want to contribute, please first read our [Contributing Guidelines](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) and then we suggest you to use the Vagrant virtual machine project to get an environment working sandboxed and with all dependencies.
* [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) * [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm)
### Starting ### Starting
1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab with: 1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab
sudo service gitlab start sudo service gitlab start
...@@ -63,18 +70,18 @@ You can either follow the "ordinary" Installation guide to install it on a machi ...@@ -63,18 +70,18 @@ You can either follow the "ordinary" Installation guide to install it on a machi
sudo /etc/init.d/gitlab restart sudo /etc/init.d/gitlab restart
2. Start it with [Foreman](https://github.com/ddollar/foreman) in development model 2. Start it with [Foreman](https://github.com/ddollar/foreman) in development mode
bundle exec foreman start -p 3000 bundle exec foreman start -p 3000
3. Start it manually in development mode or start it manually
bundle exec rails s bundle exec rails s
bundle exec rake sidekiq:start bundle exec rake sidekiq:start
### Running the tests ### Running the tests
* Seed the database with * Seed the database
bundle exec rake db:setup RAILS_ENV=test bundle exec rake db:setup RAILS_ENV=test
bundle exec rake db:seed_fu RAILS_ENV=test bundle exec rake db:seed_fu RAILS_ENV=test
......
...@@ -11,12 +11,7 @@ $ -> ...@@ -11,12 +11,7 @@ $ ->
# Make the entire tree-item row clickable, but not if clicking another link (like a commit message) # Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
$("#tree-slider .tree-item").live 'click', (e) -> $("#tree-slider .tree-item").live 'click', (e) ->
$('.tree-item-file-name a', this).trigger('click') if (e.target.nodeName != "A") $('.tree-item-file-name a', this).trigger('click') if (e.target.nodeName != "A")
# Show/Hide the loading spinner
$('#tree-slider .tree-item-file-name a, .breadcrumb a, .project-refs-form').live
"ajax:beforeSend": -> $('.tree_progress').addClass("loading")
"ajax:complete": -> $('.tree_progress').removeClass("loading")
# Maintain forward/back history while browsing the file tree # Maintain forward/back history while browsing the file tree
((window) -> ((window) ->
History = window.History History = window.History
...@@ -33,7 +28,12 @@ $ -> ...@@ -33,7 +28,12 @@ $ ->
History.Adapter.bind window, 'statechange', -> History.Adapter.bind window, 'statechange', ->
state = History.getState() state = History.getState()
window.ajaxGet(state.url) $.ajax({
url: state.url,
dataType: 'script',
beforeSend: -> $('.tree_progress').addClass("loading"),
complete: -> $('.tree_progress').removeClass("loading")
})
)(window) )(window)
# See if there are lines selected # See if there are lines selected
......
...@@ -34,13 +34,6 @@ ...@@ -34,13 +34,6 @@
padding: 15px; padding: 15px;
word-wrap: break-word; word-wrap: break-word;
pre {
background: none !important;
margin: 0;
border: none;
padding: 0;
}
.clearfix { .clearfix {
margin: 0; margin: 0;
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
.cgray { color:gray } .cgray { color:gray }
.cred { color:#D12F19 } .cred { color:#D12F19 }
.cgreen { color:#4a2 } .cgreen { color:#4a2 }
.cblue { color:#29A }
.cblack { color:#111 } .cblack { color:#111 }
.cdark { color:#444 } .cdark { color:#444 }
.cwhite { color:#fff!important } .cwhite { color:#fff!important }
......
...@@ -120,3 +120,16 @@ ul.nav.nav-projects-tabs { ...@@ -120,3 +120,16 @@ ul.nav.nav-projects-tabs {
.team_member_row form { .team_member_row form {
margin: 0px; margin: 0px;
} }
.public-projects {
li {
margin-top: 8px;
margin-bottom: 5px;
border-bottom: 1px solid #eee;
.description {
margin-left: 22px;
color: #aaa;
}
}
}
...@@ -91,7 +91,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -91,7 +91,7 @@ class MergeRequest < ActiveRecord::Base
def validate_branches def validate_branches
if target_branch == source_branch if target_branch == source_branch
errors.add :base, "You can not use same branch for source and target branches" errors.add :branch_conflict, "You can not use same branch for source and target branches"
end end
end end
......
class Repository class Repository
include Gitlab::Popen
# Repository directory name with namespace direcotry # Repository directory name with namespace direcotry
# Examples: # Examples:
# gitlab/gitolite # gitlab/gitolite
...@@ -147,4 +149,21 @@ class Repository ...@@ -147,4 +149,21 @@ class Repository
file_path file_path
end end
# Return repo size in megabytes
# Cached in redis
def size
Rails.cache.fetch(cache_key(:size)) do
size = popen('du -s', path_to_repo).first.strip.to_i
(size.to_f / 1024).round(2)
end
end
def expire_cache
Rails.cache.delete(cache_key(:size))
end
def cache_key(type)
"#{type}:#{path_with_namespace}"
end
end end
...@@ -23,6 +23,7 @@ class GitPushService ...@@ -23,6 +23,7 @@ class GitPushService
project.ensure_satellite_exists project.ensure_satellite_exists
project.discover_default_branch project.discover_default_branch
project.repository.expire_cache
if push_to_branch?(ref, oldrev) if push_to_branch?(ref, oldrev)
project.update_merge_requests(oldrev, newrev, ref, @user) project.update_merge_requests(oldrev, newrev, ref, @user)
......
= form_tag(user_omniauth_callback_path(:ldap), :class => "login-box", :id => 'new_ldap_user' ) do = form_tag(user_omniauth_callback_path(:ldap), :class => "login-box", :id => 'new_ldap_user' ) do
= image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo"
= text_field_tag :username, nil, {:class => "text top", :placeholder => "LDAP Login"} = text_field_tag :username, nil, {:class => "text top", :placeholder => "LDAP Login", :autofocus => "autofocus"}
= password_field_tag :password, nil, {:class => "text bottom", :placeholder => "Password"} = password_field_tag :password, nil, {:class => "text bottom", :placeholder => "Password"}
%br/ %br/
= submit_tag "LDAP Sign in", :class => "btn-primary btn" = submit_tag "LDAP Sign in", :class => "btn-primary btn"
......
- if event.proper? - if event.proper?
%div.event-item = cache event do
%span.cgray.pull-right %div.event-item
#{time_ago_in_words(event.created_at)} ago. %span.cgray.pull-right
#{time_ago_in_words(event.created_at)} ago.
= image_tag gravatar_icon(event.author_email), class: "avatar s24" = image_tag gravatar_icon(event.author_email), class: "avatar s24"
- if event.push? - if event.push?
= render "events/event/push", event: event = render "events/event/push", event: event
.clearfix .clearfix
- elsif event.note? - elsif event.note?
= render "events/event/note", event: event = render "events/event/note", event: event
- else - else
= render "events/event/common", event: event = render "events/event/common", event: event
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
= link_to "Milestones", "#milestones", 'data-toggle' => 'tab' = link_to "Milestones", "#milestones", 'data-toggle' => 'tab'
%li %li
= link_to "Notes", "#notes", 'data-toggle' => 'tab' = link_to "Notes", "#notes", 'data-toggle' => 'tab'
%li
= link_to "System Hooks", "#system_hooks", 'data-toggle' => 'tab'
.tab-content .tab-content
.tab-pane.active#README .tab-pane.active#README
...@@ -103,3 +105,12 @@ ...@@ -103,3 +105,12 @@
.file_content.wiki .file_content.wiki
= preserve do = preserve do
= markdown File.read(Rails.root.join("doc", "api", "notes.md")) = markdown File.read(Rails.root.join("doc", "api", "notes.md"))
.tab-pane#system_hooks
.file_holder
.file_title
%i.icon-file
System Hooks
.file_content.wiki
= preserve do
= markdown File.read(Rails.root.join("doc", "api", "system_hooks.md"))
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
= mail_to Gitlab.config.gitlab.support_email, "support contact" = mail_to Gitlab.config.gitlab.support_email, "support contact"
%li %li
Use the Use the
= link_to "search bar", '#', onclick: "$("#search").focus();" = link_to "search bar", '#', onclick: "$('#search').focus();"
on the top of this page on the top of this page
%li %li
Ask in our Ask in our
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
= link_to root_path, class: "home" do = link_to root_path, class: "home" do
%h1 GITLAB %h1 GITLAB
%span.separator %span.separator
%h1.project_name Public Projects %h1.project_name Public Projects
.container .container
.content .content
.prepend-top-20 .prepend-top-20
......
...@@ -9,11 +9,19 @@ ...@@ -9,11 +9,19 @@
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"
- unless @repository.heads.empty? - unless @repository.heads.empty?
.clearfix .clearfix
= f.label :default_branch, "Default Branch" = f.label :default_branch, "Default Branch"
.input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;")
.clearfix
= f.label :description do
Project description
%span.light (optional)
.input
= f.text_area :description, placeholder: "awesome project", class: "xxlarge", rows: 3, maxlength: 250
%fieldset.features %fieldset.features
%legend Features: %legend Features:
......
= render "project_head" = render "project_head"
= render 'clone_panel' = render 'clone_panel'
= render "events/event_last_push", event: @last_push = render "events/event_last_push", event: @last_push
.content_list= render @events
.loading.hide
.row
.span9
.content_list= render @events
.loading.hide
.span3
.ui-box.white
.padded
%h3.page_title
= @project.name
- if @project.description.present?
%p.light= @project.description
%hr
%p
Access level:
- if @project.public
%span.cblue
%i.icon-share
Public
- else
%span.cgreen
%i.icon-lock
Private
%p Repo Size: #{@project.repository.size} MB
%p Created at: #{@project.created_at.stamp('Aug 22, 2013')}
%p Owner: #{link_to @project.owner_name, @project.owner}
:javascript :javascript
$(function(){ Pager.init(20); }); $(function(){ Pager.init(20); });
%h3.page_title %h3.page_title
Projects Projects (#{@projects.total_count})
%small with read-only access %small with read-only access
%hr %hr
%ul.unstyled .public-projects
- @projects.each do |project| %ul.unstyled
%li.clearfix - @projects.each do |project|
%h5 %li.clearfix
%i.icon-share %h5
= project.name_with_namespace %i.icon-share
.pull-right = project.name_with_namespace
%pre.dark.tiny git clone #{project.http_url_to_repo} .pull-right
%pre.dark.tiny git clone #{project.http_url_to_repo}
%p.description
= project.description
- unless @projects.present?
%h3.nothing_here_message No public projects
- unless @projects.present? = paginate @projects, theme: "admin"
%h3.nothing_here_message No public projects
= paginate @projects, theme: "admin"
...@@ -11,9 +11,6 @@ ...@@ -11,9 +11,6 @@
- else - else
= link_to title, '#' = link_to title, '#'
.clear
%div.tree_progress
%div#tree-content-holder.tree-content-holder %div#tree-content-holder.tree-content-holder
- if tree.is_blob? - if tree.is_blob?
= render "tree/blob", blob: tree = render "tree/blob", blob: tree
...@@ -40,6 +37,8 @@ ...@@ -40,6 +37,8 @@
- if tree.readme - if tree.readme
= render "tree/readme", readme: tree.readme = render "tree/readme", readme: tree.readme
%div.tree_progress
- unless tree.is_blob? - unless tree.is_blob?
:javascript :javascript
// Load last commit log for each file in tree // Load last commit log for each file in tree
......
set :domain, 'set application domain here'
set :db_adapter, 'mysql' # or postgres
set :mount_point, '/'
set :application, 'gitlabhq'
set :user, 'git'
set :rails_env, 'production'
set :deploy_to, "/home/#{user}/apps/#{application}"
set :bundle_without, %w[development test] + (%w[mysql postgres] - [db_adapter])
set :asset_env, "RAILS_GROUPS=assets RAILS_RELATIVE_URL_ROOT=#{mount_point.sub /\/+\Z/, ''}"
set :use_sudo, false
default_run_options[:pty] = true
# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`
set :scm, :git
set :repository, "git@#{domain}:#{application}.git"
set :deploy_via, :remote_cache
# Alternatively, you can deploy via copy, if you don't have gitlab in git
#set :scm, :none
#set :repository, '.'
#set :deploy_via, :copy
server domain, :app, :web, :db, primary: true
namespace :foreman do
desc 'Export the Procfile to Ubuntu upstart scripts'
task :export, roles: :app do
foreman_export = "foreman export upstart /etc/init -f Procfile -a #{application} -u #{user} -l #{shared_path}/log/foreman"
run "cd #{release_path} && #{sudo} #{fetch :bundle_cmd, 'bundle'} exec #{foreman_export}"
end
desc 'Start the application services'
task :start, roles: :app do
run "#{sudo} service #{application} start"
end
desc 'Stop the application services'
task :stop, roles: :app do
run "#{sudo} service #{application} stop"
end
desc 'Restart the application services'
task :restart, roles: :app do
run "#{sudo} service #{application} restart"
end
end
namespace :deploy do
desc 'Start the application services'
task :start, roles: :app do
foreman.start
end
desc 'Stop the application services'
task :stop, roles: :app do
foreman.stop
end
desc 'Restart the application services'
task :restart, roles: :app do
foreman.restart
end
end
after 'deploy:cold' do
run "cd #{release_path} && #{rake} gitlab:setup force=yes RAILS_ENV=#{rails_env}"
deploy.restart
end
after 'deploy:update', 'foreman:export' # Export foreman scripts
#after 'deploy:update', 'foreman:restart' # Restart application scripts
...@@ -40,7 +40,7 @@ Gitlab::Application.configure do ...@@ -40,7 +40,7 @@ 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 = :memory_store config.cache_store = :redis_store
# 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"
......
...@@ -4,19 +4,19 @@ config_file = Rails.root.join('config', 'resque.yml') ...@@ -4,19 +4,19 @@ config_file = Rails.root.join('config', 'resque.yml')
resque_url = if File.exists?(config_file) resque_url = if File.exists?(config_file)
YAML.load_file(config_file)[Rails.env] YAML.load_file(config_file)[Rails.env]
else else
"localhost:6379" "redis://localhost:6379"
end end
Sidekiq.configure_server do |config| Sidekiq.configure_server do |config|
config.redis = { config.redis = {
url: "redis://#{resque_url}", url: resque_url,
namespace: 'resque:gitlab' namespace: 'resque:gitlab'
} }
end end
Sidekiq.configure_client do |config| Sidekiq.configure_client do |config|
config.redis = { config.redis = {
url: "redis://#{resque_url}", url: resque_url,
namespace: 'resque:gitlab' namespace: 'resque:gitlab'
} }
end end
development: localhost:6379 development: redis://localhost:6379
test: localhost:6379 test: redis://localhost:6379
production: redis.example.com:6379 production: redis://redis.example.com:6379
...@@ -166,7 +166,7 @@ Gitlab::Application.routes.draw do ...@@ -166,7 +166,7 @@ Gitlab::Application.routes.draw do
# #
# Project Area # Project Area
# #
resources :projects, constraints: { id: /[a-zA-Z.0-9_\-\/]+/ }, except: [:new, :create, :index], path: "/" do resources :projects, constraints: { id: /(?:[a-zA-Z.0-9_\-]+\/)?[a-zA-Z.0-9_\-]+/ }, except: [:new, :create, :index], path: "/" do
member do member do
get "wall" get "wall"
get "files" get "files"
...@@ -175,10 +175,10 @@ Gitlab::Application.routes.draw do ...@@ -175,10 +175,10 @@ Gitlab::Application.routes.draw do
resources :blob, only: [:show], constraints: {id: /.+/} resources :blob, only: [:show], constraints: {id: /.+/}
resources :tree, only: [:show, :edit, :update], constraints: {id: /.+/} resources :tree, only: [:show, :edit, :update], constraints: {id: /.+/}
resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
resources :commits, only: [:show], constraints: {id: /.+/} resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/}
resources :compare, only: [:index, :create] resources :compare, only: [:index, :create]
resources :blame, only: [:show], constraints: {id: /.+/} resources :blame, only: [:show], constraints: {id: /.+/}
resources :graph, only: [:show], constraints: {id: /.+/} resources :graph, only: [:show], constraints: {id: /(?:[^.]|\.(?!json$))+/, format: /json/}
match "/compare/:from...:to" => "compare#show", as: "compare", match "/compare/:from...:to" => "compare#show", as: "compare",
:via => [:get, :post], constraints: {from: /.+/, to: /.+/} :via => [:get, :post], constraints: {from: /.+/, to: /.+/}
......
...@@ -31,13 +31,10 @@ The API uses JSON to serialize data. You don't need to specify `.json` at the en ...@@ -31,13 +31,10 @@ The API uses JSON to serialize data. You don't need to specify `.json` at the en
## Status codes ## Status codes
API requests return different status codes according to The API is designed to return different status codes according to context and action. In this way
if a request results in an error the caller is able to get insight into what went wrong, e.g.
The API is designed to provide status codes according to the context and how the request status code `400 Bad Request` is returned if a required attribute is missing from the request.
is handled. For example if a `GET` request is successful a status code `200 Ok` The following list gives an overview of how the API functions generally behave.
is returned. The API is designed to be RESTful.
The following list gives an overview of how the API functions are designed.
API request types: API request types:
...@@ -58,7 +55,7 @@ Return values: ...@@ -58,7 +55,7 @@ Return values:
* `403 Forbidden` - The request is not allowed, e.g. the user is not allowed to delete a project * `403 Forbidden` - The request is not allowed, e.g. the user is not allowed to delete a project
* `404 Not Found` - A resource could not be accessed, e.g. an ID for a resource could not be found * `404 Not Found` - A resource could not be accessed, e.g. an ID for a resource could not be found
* `405 Method Not Allowed` - The request is not supported * `405 Method Not Allowed` - The request is not supported
* `409 Conflict` - A conflicting resource already exists, a project with same name already exists * `409 Conflict` - A conflicting resource already exists, e.g. creating a project with a name that already exists
* `500 Server Error` - While handling the request something went wrong on the server side * `500 Server Error` - While handling the request something went wrong on the server side
......
...@@ -44,3 +44,14 @@ Parameters: ...@@ -44,3 +44,14 @@ Parameters:
+ `name` (required) - The name of the group + `name` (required) - The name of the group
+ `path` (required) - The path of the group + `path` (required) - The path of the group
## Transfer project to group
Transfer a project to the Group namespace. Available only for admin
```
POST /groups/:id/projects/:project_id
```
Parameters:
+ `id` (required) - The ID of a group
+ `project_id (required) - The ID of a project
...@@ -115,11 +115,9 @@ Parameters: ...@@ -115,11 +115,9 @@ Parameters:
+ `merge_requests_enabled` (optional) - enabled by default + `merge_requests_enabled` (optional) - enabled by default
+ `wiki_enabled` (optional) - enabled by default + `wiki_enabled` (optional) - enabled by default
**Project access levels**
## Project access levels The project access levels are defined in the `user_project.rb` class. Currently, these levels are recoginized:
The project access levels are defined in the `user_project` class. Currently, 4
levels are recoginized:
``` ```
GUEST = 10 GUEST = 10
...@@ -129,7 +127,30 @@ levels are recoginized: ...@@ -129,7 +127,30 @@ levels are recoginized:
``` ```
## List project team members ### Create project for user
Creates a new project owned by user. Available only for admins.
```
POST /projects/user/:user_id
```
Parameters:
+ `user_id` (required) - user_id of owner
+ `name` (required) - new project name
+ `description` (optional) - short project description
+ `default_branch` (optional) - 'master' by default
+ `issues_enabled` (optional) - enabled by default
+ `wall_enabled` (optional) - enabled by default
+ `merge_requests_enabled` (optional) - enabled by default
+ `wiki_enabled` (optional) - enabled by default
## Team members
### List project team members
Get a list of project team members. Get a list of project team members.
...@@ -140,14 +161,12 @@ GET /projects/:id/members ...@@ -140,14 +161,12 @@ GET /projects/:id/members
Parameters: Parameters:
+ `id` (required) - The ID or NAME of a project + `id` (required) - The ID or NAME of a project
+ `query` - Query string + `query` (optional) - Query string to search for members
## Team members
### Get project team member ### Get project team member
Get a project team member. Gets a project team member.
``` ```
GET /projects/:id/members/:user_id GET /projects/:id/members/:user_id
...@@ -175,7 +194,7 @@ Parameters: ...@@ -175,7 +194,7 @@ Parameters:
Adds a user to a project team. This is an idempotent method and can be called multiple times Adds a user to a project team. This is an idempotent method and can be called multiple times
with the same parameters. Adding team membership to a user that is already a member does not with the same parameters. Adding team membership to a user that is already a member does not
affect the membership. affect the existing membership.
``` ```
POST /projects/:id/members POST /projects/:id/members
...@@ -190,7 +209,7 @@ Parameters: ...@@ -190,7 +209,7 @@ Parameters:
### Edit project team member ### Edit project team member
Update project team member to specified access level. Updates project team member to a specified access level.
``` ```
PUT /projects/:id/members/:user_id PUT /projects/:id/members/:user_id
...@@ -398,81 +417,90 @@ Returns values: ...@@ -398,81 +417,90 @@ Returns values:
+ `404 Not Found` if project with id or the branch with `ref_name` not found + `404 Not Found` if project with id or the branch with `ref_name` not found
## Snippets
### List snippets ## Deploy Keys
### List deploy keys
Lists the snippets of a project. Get a list of a project's deploy keys.
``` ```
GET /projects/:id/snippets GET /projects/:id/keys
``` ```
Parameters: Parameters:
+ `id` (required) - The ID of the project + `id` (required) - The ID of the project
```json
### List single snippet [
{
Lists a single snippet of a project "id": 1,
"title" : "Public key"
``` "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4
GET /projects/:id/snippets/:snippet_id 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4
soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
},
{
"id": 3,
"title" : "Another Public key"
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4
596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4
soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
}
]
``` ```
Parameters:
+ `id` (required) - The ID of the project
+ `snippet_id` (required) - The ID of the snippet
### Single deploy key
### Create snippet Get a single key.
Creates a new project snippet.
``` ```
POST /projects/:id/snippets GET /projects/:id/keys/:key_id
``` ```
Parameters: Parameters:
+ `id` (required) - The ID of the project + `id` (required) - The ID of the project
+ `title` (required) - The title of the new snippet + `key_id` (required) - The ID of the deploy key
+ `file_name` (required) - The file name of the snippet
+ `code` (required) - The content of the snippet
+ `lifetime` (optional) - The expiration date of a snippet
```json
{
"id": 1,
"title" : "Public key"
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4
596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4
soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
}
```
### Update snippet
Updates an existing project snippet. ### Add deploy key
Creates a new deploy key for a project.
``` ```
PUT /projects/:id/snippets/:snippet_id POST /projects/:id/keys
``` ```
Parameters: Parameters:
+ `id` (required) - The ID of the project + `id` (required) - The ID of the project
+ `snippet_id` (required) - The id of the project snippet + `title` (required) - New deploy key's title
+ `title` (optional) - The new title of the project snippet + `key` (required) - New deploy key
+ `file_name` (optional) - The new file name of the project snippet
+ `lifetime` (optional) - The new expiration date of the snippet
+ `code` (optional) - The content of the snippet
## Delete snippet ### Delete deploy key
Deletes a project snippet. This is an idempotent function call and returns `200 Ok` Delete a deploy key from a project
even if the snippet with the id is not available.
``` ```
DELETE /projects/:id/snippets/:snippet_id DELETE /projects/:id/keys/:key_id
``` ```
Paramaters: Parameters:
+ `id` (required) - The ID of the project + `id` (required) - The ID of the project
+ `snippet_id` (required) - The ID of the snippet + `key_id` (required) - The ID of the deploy key
...@@ -46,7 +46,7 @@ Parameters: ...@@ -46,7 +46,7 @@ Parameters:
## Create new snippet ## Create new snippet
Creates a new project snippet. Creates a new project snippet. The user must have permission to create new snippets.
``` ```
POST /projects/:id/snippets POST /projects/:id/snippets
...@@ -61,9 +61,9 @@ Parameters: ...@@ -61,9 +61,9 @@ Parameters:
+ `code` (required) - The content of a snippet + `code` (required) - The content of a snippet
## Edit snippet ## Update snippet
Updates an existing project snippet. Updates an existing project snippet. The user must have permission to change an existing snippet.
``` ```
PUT /projects/:id/snippets/:snippet_id PUT /projects/:id/snippets/:snippet_id
...@@ -96,7 +96,7 @@ Parameters: ...@@ -96,7 +96,7 @@ Parameters:
## Snippet content ## Snippet content
Get a raw project snippet. Returns the raw project snippet as plain text.
``` ```
GET /projects/:id/snippets/:snippet_id/raw GET /projects/:id/snippets/:snippet_id/raw
......
All methods require admin authorization.
## List system hooks
Get list of system hooks
```
GET /hooks
```
Will return hooks with status `200 OK` on success, or `404 Not found` on fail.
## Add new system hook hook
```
POST /hooks
```
Parameters:
+ `url` (required) - The hook URL
Will return status `201 Created` on success, or `404 Not found` on fail.
## Test system hook
```
GET /hooks/:id
```
Parameters:
+ `id` (required) - The ID of hook
Will return hook with status `200 OK` on success, or `404 Not found` on fail.
## Delete system hook
```
DELETE /hooks/:id
```
Parameters:
+ `id` (required) - The ID of hook
Will return status `200 OK` on success, or `404 Not found` on fail.
\ No newline at end of file
...@@ -235,6 +235,23 @@ Parameters: ...@@ -235,6 +235,23 @@ Parameters:
+ `key` (required) - new SSH key + `key` (required) - new SSH key
## Add SSH key for user
Create new key owned by specified user. Available only for admin
```
POST /users/:id/keys
```
Parameters:
+ `id` (required) - id of specified user
+ `title` (required) - new SSH Key's title
+ `key` (required) - new SSH key
Will return created key with status `201 Created` on success, or `404 Not
found` on fail.
## Delete SSH key ## Delete SSH key
Deletes key owned by currently authenticated user. This is an idempotent function and calling it on a key that is already Deletes key owned by currently authenticated user. This is an idempotent function and calling it on a key that is already
......
...@@ -288,7 +288,7 @@ a different host, you can configure its connection string via the ...@@ -288,7 +288,7 @@ a different host, you can configure its connection string via the
`config/resque.yml` file. `config/resque.yml` file.
# example # example
production: redis.example.tld:6379 production: redis://redis.example.tld:6379
## Custom SSH Connection ## Custom SSH Connection
......
...@@ -27,6 +27,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps ...@@ -27,6 +27,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps
And 'I switch ref to "stable"' do And 'I switch ref to "stable"' do
page.select 'stable', :from => 'ref' page.select 'stable', :from => 'ref'
sleep 2
end end
And 'page should select "stable" in select box' do And 'page should select "stable" in select box' do
...@@ -44,6 +45,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps ...@@ -44,6 +45,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps
fill_in 'q', :with => '98d6492' fill_in 'q', :with => '98d6492'
find('button').click find('button').click
end end
sleep 2
end end
And 'page should have "v2.1.0" on graph' do And 'page should have "v2.1.0" on graph' do
......
...@@ -33,5 +33,6 @@ module Gitlab ...@@ -33,5 +33,6 @@ module Gitlab
mount MergeRequests mount MergeRequests
mount Notes mount Notes
mount Internal mount Internal
mount SystemHooks
end end
end end
...@@ -56,6 +56,24 @@ module Gitlab ...@@ -56,6 +56,24 @@ module Gitlab
not_found! not_found!
end end
end end
# Transfer a project to the Group namespace
#
# Parameters:
# id - group id
# project_id - project id
# Example Request:
# POST /groups/:id/projects/:project_id
post ":id/projects/:project_id" do
authenticated_as_admin!
@group = Group.find(params[:id])
project = Project.find(params[:project_id])
if project.transfer(@group)
present @group
else
not_found!
end
end
end end
end end
end end
...@@ -8,6 +8,8 @@ module Gitlab ...@@ -8,6 +8,8 @@ module Gitlab
def handle_merge_request_errors!(errors) def handle_merge_request_errors!(errors)
if errors[:project_access].any? if errors[:project_access].any?
error!(errors[:project_access], 422) error!(errors[:project_access], 422)
elsif errors[:branch_conflict].any?
error!(errors[:branch_conflict], 422)
end end
not_found! not_found!
end end
......
...@@ -64,6 +64,38 @@ module Gitlab ...@@ -64,6 +64,38 @@ module Gitlab
end end
end end
# Create new project for a specified user. Only available to admin users.
#
# Parameters:
# user_id (required) - The ID of a user
# name (required) - name for new project
# description (optional) - short project description
# default_branch (optional) - 'master' by default
# issues_enabled (optional) - enabled by default
# wall_enabled (optional) - enabled by default
# merge_requests_enabled (optional) - enabled by default
# wiki_enabled (optional) - enabled by default
# Example Request
# POST /projects/user/:user_id
post "user/:user_id" do
authenticated_as_admin!
user = User.find(params[:user_id])
attrs = attributes_for_keys [:name,
:description,
:default_branch,
:issues_enabled,
:wall_enabled,
:merge_requests_enabled,
:wiki_enabled]
@project = ::Projects::CreateContext.new(user, attrs).execute
if @project.saved?
present @project, with: Entities::Project
else
not_found!
end
end
# Get a project team members # Get a project team members
# #
# Parameters: # Parameters:
...@@ -471,6 +503,49 @@ module Gitlab ...@@ -471,6 +503,49 @@ module Gitlab
present tree.data present tree.data
end end
# Get a specific project's keys
#
# Example Request:
# GET /projects/:id/keys
get ":id/keys" do
present user_project.deploy_keys, with: Entities::SSHKey
end
# Get single key owned by currently authenticated user
#
# Example Request:
# GET /projects/:id/keys/:id
get ":id/keys/:key_id" do
key = user_project.deploy_keys.find params[:key_id]
present key, with: Entities::SSHKey
end
# Add new ssh key to currently authenticated user
#
# Parameters:
# key (required) - New SSH Key
# title (required) - New SSH Key's title
# Example Request:
# POST /projects/:id/keys
post ":id/keys" do
attrs = attributes_for_keys [:title, :key]
key = user_project.deploy_keys.new attrs
if key.save
present key, with: Entities::SSHKey
else
not_found!
end
end
# Delete existed ssh key of currently authenticated user
#
# Example Request:
# DELETE /projects/:id/keys/:id
delete ":id/keys/:key_id" do
key = user_project.deploy_keys.find params[:key_id]
key.delete
end
end end
end end
end end
module Gitlab
# Hooks API
class SystemHooks < Grape::API
before { authenticated_as_admin! }
resource :hooks do
# Get the list of system hooks
#
# Example Request:
# GET /hooks
get do
@hooks = SystemHook.all
present @hooks, with: Entities::Hook
end
# Create new system hook
#
# Parameters:
# url (required) - url for system hook
# Example Request
# POST /hooks
post do
attrs = attributes_for_keys [:url]
@hook = SystemHook.new attrs
if @hook.save
present @hook, with: Entities::Hook
else
not_found!
end
end
# Test a hook
#
# Example Request
# GET /hooks/:id
get ":id" do
@hook = SystemHook.find(params[:id])
data = {
event_name: "project_create",
name: "Ruby",
path: "ruby",
project_id: 1,
owner_name: "Someone",
owner_email: "example@gitlabhq.com"
}
@hook.execute(data)
data
end
# Delete a hook
#
# Example Request:
# DELETE /hooks/:id
delete ":id" do
@hook = SystemHook.find(params[:id])
@hook.destroy
end
end
end
end
\ No newline at end of file
...@@ -81,6 +81,26 @@ module Gitlab ...@@ -81,6 +81,26 @@ module Gitlab
end end
end end
# Add ssh key to a specified user. Only available to admin users.
#
# Parameters:
# id (required) - The ID of a user
# key (required) - New SSH Key
# title (required) - New SSH Key's title
# Example Request:
# POST /users/:id/keys
post ":id/keys" do
authenticated_as_admin!
user = User.find(params[:id])
attrs = attributes_for_keys [:title, :key]
key = user.keys.new attrs
if key.save
present key, with: Entities::SSHKey
else
not_found!
end
end
# Delete user. Available only for admin # Delete user. Available only for admin
# #
# Example Request: # Example Request:
......
...@@ -105,12 +105,6 @@ module ExtractsPath ...@@ -105,12 +105,6 @@ module ExtractsPath
# Automatically renders `not_found!` if a valid tree path could not be # Automatically renders `not_found!` if a valid tree path could not be
# resolved (e.g., when a user inserts an invalid path or ref). # resolved (e.g., when a user inserts an invalid path or ref).
def assign_ref_vars def assign_ref_vars
# Handle formats embedded in the id
if params[:id].ends_with?('.atom')
params[:id].gsub!(/\.atom$/, '')
request.format = :atom
end
path = CGI::unescape(request.fullpath.dup) path = CGI::unescape(request.fullpath.dup)
@ref, @path = extract_ref(path) @ref, @path = extract_ref(path)
......
...@@ -7,10 +7,12 @@ namespace :gitlab do ...@@ -7,10 +7,12 @@ namespace :gitlab do
def setup_db def setup_db
warn_user_is_not_gitlab warn_user_is_not_gitlab
puts "This will create the necessary database tables and seed the database." unless ENV['force'] == 'yes'
puts "You will lose any previous data stored in the database." puts "This will create the necessary database tables and seed the database."
ask_to_continue puts "You will lose any previous data stored in the database."
puts "" ask_to_continue
puts ""
end
Rake::Task["db:setup"].invoke Rake::Task["db:setup"].invoke
Rake::Task["db:seed_fu"].invoke Rake::Task["db:seed_fu"].invoke
......
...@@ -13,7 +13,7 @@ describe CommitsController do ...@@ -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.path, id: "master.atom" get :show, project_id: project.path, id: "master", format: "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
......
...@@ -100,4 +100,27 @@ describe Gitlab::API do ...@@ -100,4 +100,27 @@ describe Gitlab::API do
end end
end end
end end
describe "POST /groups/:id/projects/:project_id" do
let(:project) { create(:project) }
before(:each) do
project.stub!(:transfer).and_return(true)
Project.stub(:find).and_return(project)
end
context "when authenticated as user" do
it "should not transfer project to group" do
post api("/groups/#{group1.id}/projects/#{project.id}", user2)
response.status.should == 403
end
end
context "when authenticated as admin" do
it "should transfer project to group" do
project.should_receive(:transfer)
post api("/groups/#{group1.id}/projects/#{project.id}", admin)
end
end
end
end end
...@@ -105,13 +105,6 @@ describe Gitlab::API do ...@@ -105,13 +105,6 @@ describe Gitlab::API do
response.status.should == 404 response.status.should == 404
end end
end end
context "when notable is invalid" do
it "should return a 404 error" do
get api("/projects/#{project.id}/unknown/#{snippet.id}/notes", user)
response.status.should == 404
end
end
end end
describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
...@@ -180,12 +173,5 @@ describe Gitlab::API do ...@@ -180,12 +173,5 @@ describe Gitlab::API do
response.status.should == 401 response.status.should == 401
end end
end end
context "when noteable is invalid" do
it "should return a 404 error" do
post api("/projects/#{project.id}/invalid/#{snippet.id}/notes", user)
response.status.should == 404
end
end
end end
end end
...@@ -6,11 +6,14 @@ describe Gitlab::API do ...@@ -6,11 +6,14 @@ describe Gitlab::API do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:user2) { create(:user) }
let(:user3) { create(:user) } let(:user3) { create(:user) }
let(:admin) { create(:admin) }
let!(:project) { create(:project, namespace: user.namespace ) } let!(:project) { create(:project, namespace: user.namespace ) }
let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } let!(:hook) { create(:project_hook, project: project, url: "http://example.com") }
let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') }
let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) }
let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) }
let(:key) { create(:key, project: project) }
before { project.team << [user, :reporter] } before { project.team << [user, :reporter] }
describe "GET /projects" do describe "GET /projects" do
...@@ -103,6 +106,46 @@ describe Gitlab::API do ...@@ -103,6 +106,46 @@ describe Gitlab::API do
end end
end end
describe "POST /projects/user/:id" do
before { admin }
it "should create new project without path" do
expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
end
it "should not create new project without name" do
expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count}
end
it "should respond with 201 on success" do
post api("/projects/user/#{user.id}", admin), name: 'foo'
response.status.should == 201
end
it "should respond with 404 on failure" do
post api("/projects/user/#{user.id}", admin)
response.status.should == 404
end
it "should assign attributes to project" do
project = attributes_for(:project, {
description: Faker::Lorem.sentence,
default_branch: 'stable',
issues_enabled: false,
wall_enabled: false,
merge_requests_enabled: false,
wiki_enabled: false
})
post api("/projects/user/#{user.id}", admin), project
project.each_pair do |k,v|
next if k == :path
json_response[k.to_s].should == v
end
end
end
describe "GET /projects/:id" do describe "GET /projects/:id" do
it "should return a project by id" do it "should return a project by id" do
get api("/projects/#{project.id}", user) get api("/projects/#{project.id}", user)
...@@ -591,4 +634,59 @@ describe Gitlab::API do ...@@ -591,4 +634,59 @@ describe Gitlab::API do
response.status.should == 400 response.status.should == 400
end end
end end
describe "GET /projects/:id/keys" do
it "should return array of ssh keys" do
project.deploy_keys << key
project.save
get api("/projects/#{project.id}/keys", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == key.title
end
end
describe "GET /projects/:id/keys/:key_id" do
it "should return a single key" do
project.deploy_keys << key
project.save
get api("/projects/#{project.id}/keys/#{key.id}", user)
response.status.should == 200
json_response['title'].should == key.title
end
it "should return 404 Not Found with invalid ID" do
get api("/projects/#{project.id}/keys/404", user)
response.status.should == 404
end
end
describe "POST /projects/:id/keys" do
it "should not create an invalid ssh key" do
post api("/projects/#{project.id}/keys", user), { title: "invalid key" }
response.status.should == 404
end
it "should create new ssh key" do
key_attrs = attributes_for :key
expect {
post api("/projects/#{project.id}/keys", user), key_attrs
}.to change{ project.deploy_keys.count }.by(1)
end
end
describe "DELETE /projects/:id/keys/:key_id" do
it "should delete existing key" do
project.deploy_keys << key
project.save
expect {
delete api("/projects/#{project.id}/keys/#{key.id}", user)
}.to change{ project.deploy_keys.count }.by(-1)
end
it "should return 404 Not Found with invalid ID" do
delete api("/projects/#{project.id}/keys/404", user)
response.status.should == 404
end
end
end end
require 'spec_helper'
describe Gitlab::API do
include ApiHelpers
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let!(:hook) { create(:system_hook, url: "http://example.com") }
before { stub_request(:post, hook.url) }
describe "GET /hooks" do
context "when not an admin" do
it "should return forbidden error" do
get api("/hooks", user)
response.status.should == 403
end
end
context "when authenticated as admin" do
it "should return an array of hooks" do
get api("/hooks", admin)
response.status.should == 200
json_response.should be_an Array
json_response.first['url'].should == hook.url
end
end
end
describe "POST /hooks" do
it "should create new hook" do
expect {
post api("/hooks", admin), url: 'http://example.com'
}.to change { SystemHook.count }.by(1)
end
it "should respond with 404 on failure" do
post api("/hooks", admin)
response.status.should == 404
end
it "should not create new hook without url" do
expect {
post api("/hooks", admin)
}.to_not change { SystemHook.count }
end
end
describe "GET /hooks/:id" do
it "should return hook by id" do
get api("/hooks/#{hook.id}", admin)
response.status.should == 200
json_response['event_name'].should == 'project_create'
end
it "should return 404 on failure" do
get api("/hooks/404", admin)
response.status.should == 404
end
end
describe "DELETE /hooks/:id" do
it "should delete a hook" do
expect {
delete api("/hooks/#{hook.id}", admin)
}.to change { SystemHook.count }.by(-1)
end
end
end
\ No newline at end of file
...@@ -167,6 +167,22 @@ describe Gitlab::API do ...@@ -167,6 +167,22 @@ describe Gitlab::API do
end end
end end
describe "POST /users/:id/keys" do
before { admin }
it "should not create invalid ssh key" do
post api("/users/#{user.id}/keys", admin), { title: "invalid key" }
response.status.should == 404
end
it "should create ssh key" do
key_attrs = attributes_for :key
expect {
post api("/users/#{user.id}/keys", admin), key_attrs
}.to change{ user.keys.count }.by(1)
end
end
describe "DELETE /users/:id" do describe "DELETE /users/:id" do
before { admin } before { admin }
......
...@@ -56,7 +56,6 @@ end ...@@ -56,7 +56,6 @@ end
# projects POST /projects(.:format) projects#create # projects POST /projects(.:format) projects#create
# new_project GET /projects/new(.:format) projects#new # new_project GET /projects/new(.:format) projects#new
# wall_project GET /:id/wall(.:format) projects#wall # wall_project GET /:id/wall(.:format) projects#wall
# graph_project GET /:id/graph(.:format) projects#graph
# files_project GET /:id/files(.:format) projects#files # files_project GET /:id/files(.:format) projects#files
# edit_project GET /:id/edit(.:format) projects#edit # edit_project GET /:id/edit(.:format) projects#edit
# project GET /:id(.:format) projects#show # project GET /:id(.:format) projects#show
...@@ -75,10 +74,6 @@ describe ProjectsController, "routing" do ...@@ -75,10 +74,6 @@ describe ProjectsController, "routing" do
get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq')
end end
it "to #graph" do
get("/gitlabhq/graph/master").should route_to('graph#show', project_id: 'gitlabhq', id: 'master')
end
it "to #files" do it "to #files" do
get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq') get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq')
end end
...@@ -202,6 +197,7 @@ describe RefsController, "routing" do ...@@ -202,6 +197,7 @@ describe RefsController, "routing" do
it "to #logs_tree" do it "to #logs_tree" do
get("/gitlabhq/refs/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable') get("/gitlabhq/refs/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable')
get("/gitlabhq/refs/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') get("/gitlabhq/refs/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz')
get("/gitlab/gitlabhq/refs/stable/logs_tree/files.scss").should route_to('refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'files.scss')
end end
end end
...@@ -301,6 +297,10 @@ describe CommitsController, "routing" do ...@@ -301,6 +297,10 @@ describe CommitsController, "routing" do
let(:actions) { [:show] } let(:actions) { [:show] }
let(:controller) { 'commits' } let(:controller) { 'commits' }
end end
it "to #show" do
get("/gitlab/gitlabhq/commits/master.atom").should route_to('commits#show', project_id: 'gitlab/gitlabhq', id: "master", format: "atom")
end
end end
# project_team_members GET /:project_id/team_members(.:format) team_members#index # project_team_members GET /:project_id/team_members(.:format) team_members#index
...@@ -385,6 +385,7 @@ end ...@@ -385,6 +385,7 @@ end
describe BlameController, "routing" do describe BlameController, "routing" do
it "to #show" do it "to #show" do
get("/gitlabhq/blame/master/app/models/project.rb").should route_to('blame#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') get("/gitlabhq/blame/master/app/models/project.rb").should route_to('blame#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
get("/gitlab/gitlabhq/blame/master/files.scss").should route_to('blame#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end end
end end
...@@ -393,6 +394,7 @@ describe BlobController, "routing" do ...@@ -393,6 +394,7 @@ describe BlobController, "routing" do
it "to #show" do it "to #show" do
get("/gitlabhq/blob/master/app/models/project.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') get("/gitlabhq/blob/master/app/models/project.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
get("/gitlabhq/blob/master/app/models/compare.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/compare.rb') get("/gitlabhq/blob/master/app/models/compare.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/compare.rb')
get("/gitlab/gitlabhq/blob/master/files.scss").should route_to('blob#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end end
end end
...@@ -400,6 +402,7 @@ end ...@@ -400,6 +402,7 @@ end
describe TreeController, "routing" do describe TreeController, "routing" do
it "to #show" do it "to #show" do
get("/gitlabhq/tree/master/app/models/project.rb").should route_to('tree#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') get("/gitlabhq/tree/master/app/models/project.rb").should route_to('tree#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
get("/gitlab/gitlabhq/tree/master/files.scss").should route_to('tree#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end end
end end
...@@ -420,3 +423,10 @@ describe CompareController, "routing" do ...@@ -420,3 +423,10 @@ describe CompareController, "routing" do
get("/gitlabhq/compare/issue/1234...stable").should route_to('compare#show', project_id: 'gitlabhq', from: 'issue/1234', to: 'stable') get("/gitlabhq/compare/issue/1234...stable").should route_to('compare#show', project_id: 'gitlabhq', from: 'issue/1234', to: 'stable')
end end
end end
describe GraphController, "routing" do
it "to #show" do
get("/gitlabhq/graph/master").should route_to('graph#show', project_id: 'gitlabhq', id: 'master')
get("/gitlabhq/graph/master.json").should route_to('graph#show', project_id: 'gitlabhq', id: 'master', format: "json")
end
end
...@@ -43,6 +43,11 @@ class GitLabTestRepo < Repository ...@@ -43,6 +43,11 @@ class GitLabTestRepo < Repository
def repo def repo
@repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq'))
end end
# patch repo size (in mb)
def size
12.45
end
end end
module Gitlab module Gitlab
......
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