diff --git a/Capfile.example b/Capfile.example new file mode 100644 index 00000000..8863835d --- /dev/null +++ b/Capfile.example @@ -0,0 +1,4 @@ +load 'deploy' +load 'deploy/assets' +require 'bundler/capistrano' +load 'config/deploy' diff --git a/Gemfile b/Gemfile index cf1617c3..324e1ce2 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source "http://rubygems.org" +source "https://rubygems.org" def darwin_only(require_as) RUBY_PLATFORM.include?('darwin') && require_as @@ -103,6 +103,9 @@ gem 'settingslogic' gem "foreman" gem "git" +# Cache +gem "redis-rails" + group :assets do gem "sass-rails", "~> 3.2.5" gem "coffee-rails", "~> 3.2.2" diff --git a/Gemfile.lock b/Gemfile.lock index 89882492..36447188 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,7 +13,7 @@ GIT raphael-rails (2.1.0) GEM - remote: http://rubygems.org/ + remote: https://rubygems.org/ specs: actionmailer (3.2.12) actionpack (= 3.2.12) @@ -329,8 +329,24 @@ GEM json (~> 1.4) redcarpet (2.2.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 (~> 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) rspec (2.12.0) rspec-core (~> 2.12.0) @@ -504,6 +520,7 @@ DEPENDENCIES rb-fsevent rb-inotify redcarpet (~> 2.2.2) + redis-rails rspec-rails (= 2.12.2) sass-rails (~> 3.2.5) sdoc diff --git a/README.md b/README.md index 02b4722f..00a8a889 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,14 @@ ### GitLab allows you to * keep your code secure on your own server * manage repositories, users and access permissions - * communicate though issues, line-comments and wiki's - * perform code reviews with merge requests + * communicate through issues, line-comments and wiki pages + * perform code review with merge requests ### GitLab is * powered by Ruby on Rails * 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 @@ -34,28 +34,35 @@ ### Requirements -* Ubuntu/Debian* +* Ubuntu/Debian** * ruby 1.9.3+ * MySQL * git * gitlab-shell * 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 -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) ### 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 @@ -63,18 +70,18 @@ You can either follow the "ordinary" Installation guide to install it on a machi 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 -3. Start it manually in development mode + or start it manually bundle exec rails s bundle exec rake sidekiq:start ### Running the tests -* Seed the database with +* Seed the database bundle exec rake db:setup RAILS_ENV=test bundle exec rake db:seed_fu RAILS_ENV=test diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee index 5003f9b0..2603b9a9 100644 --- a/app/assets/javascripts/tree.js.coffee +++ b/app/assets/javascripts/tree.js.coffee @@ -11,12 +11,7 @@ $ -> # 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-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 ((window) -> History = window.History @@ -33,7 +28,12 @@ $ -> History.Adapter.bind window, 'statechange', -> state = History.getState() - window.ajaxGet(state.url) + $.ajax({ + url: state.url, + dataType: 'script', + beforeSend: -> $('.tree_progress').addClass("loading"), + complete: -> $('.tree_progress').removeClass("loading") + }) )(window) # See if there are lines selected diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index 4d1b6446..ce939bc2 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -34,13 +34,6 @@ padding: 15px; word-wrap: break-word; - pre { - background: none !important; - margin: 0; - border: none; - padding: 0; - } - .clearfix { margin: 0; } diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index 9e015eb2..00d2e88a 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -2,6 +2,7 @@ .cgray { color:gray } .cred { color:#D12F19 } .cgreen { color:#4a2 } +.cblue { color:#29A } .cblack { color:#111 } .cdark { color:#444 } .cwhite { color:#fff!important } diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index ada0780e..3abda7ee 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -120,3 +120,16 @@ ul.nav.nav-projects-tabs { .team_member_row form { margin: 0px; } + +.public-projects { + li { + margin-top: 8px; + margin-bottom: 5px; + border-bottom: 1px solid #eee; + + .description { + margin-left: 22px; + color: #aaa; + } + } +} diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c26d40c5..354a95e9 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -91,7 +91,7 @@ class MergeRequest < ActiveRecord::Base def validate_branches 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 diff --git a/app/models/repository.rb b/app/models/repository.rb index 3feb3180..934c1a6e 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1,4 +1,6 @@ class Repository + include Gitlab::Popen + # Repository directory name with namespace direcotry # Examples: # gitlab/gitolite @@ -147,4 +149,21 @@ class Repository file_path 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 diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 208ccf69..d0b3dd55 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -23,6 +23,7 @@ class GitPushService project.ensure_satellite_exists project.discover_default_branch + project.repository.expire_cache if push_to_branch?(ref, oldrev) project.update_merge_requests(oldrev, newrev, ref, @user) diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml index 7968b0e9..eb8c5194 100644 --- a/app/views/devise/sessions/_new_ldap.html.haml +++ b/app/views/devise/sessions/_new_ldap.html.haml @@ -1,6 +1,6 @@ = 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" - = 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"} %br/ = submit_tag "LDAP Sign in", :class => "btn-primary btn" diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index 719f6c37..febd72f6 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -1,15 +1,16 @@ - if event.proper? - %div.event-item - %span.cgray.pull-right - #{time_ago_in_words(event.created_at)} ago. + = cache event do + %div.event-item + %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? - = render "events/event/push", event: event - .clearfix - - elsif event.note? - = render "events/event/note", event: event - - else - = render "events/event/common", event: event + - if event.push? + = render "events/event/push", event: event + .clearfix + - elsif event.note? + = render "events/event/note", event: event + - else + = render "events/event/common", event: event diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml index d771f1e9..0c502ada 100644 --- a/app/views/help/api.html.haml +++ b/app/views/help/api.html.haml @@ -21,6 +21,8 @@ = link_to "Milestones", "#milestones", 'data-toggle' => 'tab' %li = link_to "Notes", "#notes", 'data-toggle' => 'tab' + %li + = link_to "System Hooks", "#system_hooks", 'data-toggle' => 'tab' .tab-content .tab-pane.active#README @@ -103,3 +105,12 @@ .file_content.wiki = preserve do = 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")) diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 879a19fd..78b29511 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -22,7 +22,7 @@ = mail_to Gitlab.config.gitlab.support_email, "support contact" %li Use the - = link_to "search bar", '#', onclick: "$("#search").focus();" + = link_to "search bar", '#', onclick: "$('#search').focus();" on the top of this page %li Ask in our diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml index fa368e9b..435250b6 100644 --- a/app/views/layouts/public.html.haml +++ b/app/views/layouts/public.html.haml @@ -10,7 +10,7 @@ = link_to root_path, class: "home" do %h1 GITLAB %span.separator - %h1.project_name Public Projects + %h1.project_name Public Projects .container .content .prepend-top-20 diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index b78c70be..a7930680 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -9,11 +9,19 @@ Project name is .input = f.text_field :name, placeholder: "Example Project", class: "xxlarge" + + - unless @repository.heads.empty? .clearfix = f.label :default_branch, "Default Branch" .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 %legend Features: diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 2c4f55eb..861930ca 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,8 +1,33 @@ = render "project_head" = render 'clone_panel' = 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 $(function(){ Pager.init(20); }); diff --git a/app/views/public/projects/index.html.haml b/app/views/public/projects/index.html.haml index 52e01c3d..b50484f6 100644 --- a/app/views/public/projects/index.html.haml +++ b/app/views/public/projects/index.html.haml @@ -1,18 +1,20 @@ %h3.page_title - Projects + Projects (#{@projects.total_count}) %small with read-only access %hr -%ul.unstyled - - @projects.each do |project| - %li.clearfix - %h5 - %i.icon-share - = project.name_with_namespace - .pull-right - %pre.dark.tiny git clone #{project.http_url_to_repo} +.public-projects + %ul.unstyled + - @projects.each do |project| + %li.clearfix + %h5 + %i.icon-share + = project.name_with_namespace + .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? - %h3.nothing_here_message No public projects - -= paginate @projects, theme: "admin" + = paginate @projects, theme: "admin" diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml index 29a2ed02..dc3a8440 100644 --- a/app/views/tree/_tree.html.haml +++ b/app/views/tree/_tree.html.haml @@ -11,9 +11,6 @@ - else = link_to title, '#' -.clear -%div.tree_progress - %div#tree-content-holder.tree-content-holder - if tree.is_blob? = render "tree/blob", blob: tree @@ -40,6 +37,8 @@ - if tree.readme = render "tree/readme", readme: tree.readme +%div.tree_progress + - unless tree.is_blob? :javascript // Load last commit log for each file in tree diff --git a/config/deploy.rb.example b/config/deploy.rb.example new file mode 100644 index 00000000..ddce4671 --- /dev/null +++ b/config/deploy.rb.example @@ -0,0 +1,72 @@ +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 diff --git a/config/environments/production.rb b/config/environments/production.rb index 52fb8877..6ae0324f 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -40,7 +40,7 @@ Gitlab::Application.configure do # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) # 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 # config.action_controller.asset_host = "http://assets.example.com" diff --git a/config/initializers/4_sidekiq.rb b/config/initializers/4_sidekiq.rb index 6abe6e74..c90d3762 100644 --- a/config/initializers/4_sidekiq.rb +++ b/config/initializers/4_sidekiq.rb @@ -4,19 +4,19 @@ config_file = Rails.root.join('config', 'resque.yml') resque_url = if File.exists?(config_file) YAML.load_file(config_file)[Rails.env] else - "localhost:6379" + "redis://localhost:6379" end Sidekiq.configure_server do |config| config.redis = { - url: "redis://#{resque_url}", + url: resque_url, namespace: 'resque:gitlab' } end Sidekiq.configure_client do |config| config.redis = { - url: "redis://#{resque_url}", + url: resque_url, namespace: 'resque:gitlab' } end diff --git a/config/resque.yml.example b/config/resque.yml.example index cd3d4874..3c7ad0e5 100644 --- a/config/resque.yml.example +++ b/config/resque.yml.example @@ -1,3 +1,3 @@ -development: localhost:6379 -test: localhost:6379 -production: redis.example.com:6379 +development: redis://localhost:6379 +test: redis://localhost:6379 +production: redis://redis.example.com:6379 diff --git a/config/routes.rb b/config/routes.rb index c8e7c8ee..b06fda8f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -166,7 +166,7 @@ Gitlab::Application.routes.draw do # # 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 get "wall" get "files" @@ -175,10 +175,10 @@ Gitlab::Application.routes.draw do resources :blob, only: [:show], constraints: {id: /.+/} resources :tree, only: [:show, :edit, :update], constraints: {id: /.+/} 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 :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", :via => [:get, :post], constraints: {from: /.+/, to: /.+/} diff --git a/doc/api/README.md b/doc/api/README.md index 2699434d..f6c4e41b 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -31,13 +31,10 @@ The API uses JSON to serialize data. You don't need to specify `.json` at the en ## Status codes -API requests return different status codes according to - -The API is designed to provide status codes according to the context and how the request -is handled. For example if a `GET` request is successful a status code `200 Ok` -is returned. The API is designed to be RESTful. - -The following list gives an overview of how the API functions are designed. +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. +status code `400 Bad Request` is returned if a required attribute is missing from the request. +The following list gives an overview of how the API functions generally behave. API request types: @@ -58,7 +55,7 @@ Return values: * `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 * `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 diff --git a/doc/api/groups.md b/doc/api/groups.md index 25b9741f..e9702ea2 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -44,3 +44,14 @@ Parameters: + `name` (required) - The name 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 diff --git a/doc/api/projects.md b/doc/api/projects.md index 326a62b0..d6a9a885 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -115,11 +115,9 @@ Parameters: + `merge_requests_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` class. Currently, 4 -levels are recoginized: +The project access levels are defined in the `user_project.rb` class. Currently, these levels are recoginized: ``` GUEST = 10 @@ -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. @@ -140,14 +161,12 @@ GET /projects/:id/members Parameters: + `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 a project team member. +Gets a project team member. ``` GET /projects/:id/members/:user_id @@ -175,7 +194,7 @@ Parameters: 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 -affect the membership. +affect the existing membership. ``` POST /projects/:id/members @@ -190,7 +209,7 @@ Parameters: ### 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 @@ -398,81 +417,90 @@ Returns values: + `404 Not Found` if project with id or the branch with `ref_name` not found -## Snippets -### List snippets +## Deploy Keys -Lists the snippets of a project. +### List deploy keys + +Get a list of a project's deploy keys. ``` -GET /projects/:id/snippets +GET /projects/:id/keys ``` Parameters: + `id` (required) - The ID of the project +```json +[ + { + "id": 1, + "title" : "Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=", + }, + { + "id": 3, + "title" : "Another Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" + } +] +``` -### List single snippet -Lists a single snippet of a project +### Single deploy key + +Get a single key. ``` -GET /projects/:id/snippets/:snippet_id +GET /projects/:id/keys/:key_id ``` Parameters: + `id` (required) - The ID of the project -+ `snippet_id` (required) - The ID of the snippet ++ `key_id` (required) - The ID of the deploy key + +```json +{ + "id": 1, + "title" : "Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" +} +``` -### Create snippet +### Add deploy key -Creates a new project snippet. +Creates a new deploy key for a project. ``` -POST /projects/:id/snippets +POST /projects/:id/keys ``` Parameters: + `id` (required) - The ID of the project -+ `title` (required) - The title of the new snippet -+ `file_name` (required) - The file name of the snippet -+ `code` (required) - The content of the snippet -+ `lifetime` (optional) - The expiration date of a snippet ++ `title` (required) - New deploy key's title ++ `key` (required) - New deploy key -### Update snippet +### Delete deploy key -Updates an existing project snippet. +Delete a deploy key from a project ``` -PUT /projects/:id/snippets/:snippet_id +DELETE /projects/:id/keys/:key_id ``` Parameters: + `id` (required) - The ID of the project -+ `snippet_id` (required) - The id of the project snippet -+ `title` (optional) - The new title of the project snippet -+ `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 - -Deletes a project snippet. This is an idempotent function call and returns `200 Ok` -even if the snippet with the id is not available. - -``` -DELETE /projects/:id/snippets/:snippet_id -``` - -Paramaters: - -+ `id` (required) - The ID of the project -+ `snippet_id` (required) - The ID of the snippet ++ `key_id` (required) - The ID of the deploy key diff --git a/doc/api/snippets.md b/doc/api/snippets.md index 4becc928..04ea367d 100644 --- a/doc/api/snippets.md +++ b/doc/api/snippets.md @@ -46,7 +46,7 @@ Parameters: ## 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 @@ -61,9 +61,9 @@ Parameters: + `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 @@ -96,7 +96,7 @@ Parameters: ## Snippet content -Get a raw project snippet. +Returns the raw project snippet as plain text. ``` GET /projects/:id/snippets/:snippet_id/raw diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md new file mode 100644 index 00000000..f6e11ed2 --- /dev/null +++ b/doc/api/system_hooks.md @@ -0,0 +1,47 @@ +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 diff --git a/doc/api/users.md b/doc/api/users.md index 6d5c9d78..dc31c10e 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -235,6 +235,23 @@ Parameters: + `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 Deletes key owned by currently authenticated user. This is an idempotent function and calling it on a key that is already diff --git a/doc/install/installation.md b/doc/install/installation.md index d0f586af..51a8dcfb 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -288,7 +288,7 @@ a different host, you can configure its connection string via the `config/resque.yml` file. # example - production: redis.example.tld:6379 + production: redis://redis.example.tld:6379 ## Custom SSH Connection diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index 2ca62988..7e9a7c29 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -27,6 +27,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps And 'I switch ref to "stable"' do page.select 'stable', :from => 'ref' + sleep 2 end And 'page should select "stable" in select box' do @@ -44,6 +45,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps fill_in 'q', :with => '98d6492' find('button').click end + sleep 2 end And 'page should have "v2.1.0" on graph' do diff --git a/lib/api.rb b/lib/api.rb index 3264f6a8..d241f9b7 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -33,5 +33,6 @@ module Gitlab mount MergeRequests mount Notes mount Internal + mount SystemHooks end end diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 5aaa5eb4..beb61519 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -56,6 +56,24 @@ module Gitlab not_found! 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 diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 5adf57b3..234a005a 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -8,6 +8,8 @@ module Gitlab def handle_merge_request_errors!(errors) if errors[:project_access].any? error!(errors[:project_access], 422) + elsif errors[:branch_conflict].any? + error!(errors[:branch_conflict], 422) end not_found! end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index b8efef31..b1d6357f 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -64,6 +64,38 @@ module Gitlab 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 # # Parameters: @@ -471,6 +503,49 @@ module Gitlab present tree.data 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 diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb new file mode 100644 index 00000000..665a1cdd --- /dev/null +++ b/lib/api/system_hooks.rb @@ -0,0 +1,60 @@ +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 diff --git a/lib/api/users.rb b/lib/api/users.rb index 5e0680de..6cc3a7e5 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -81,6 +81,26 @@ module Gitlab 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 # # Example Request: diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index fd0050cf..66b2f450 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -105,12 +105,6 @@ module ExtractsPath # Automatically renders `not_found!` if a valid tree path could not be # resolved (e.g., when a user inserts an invalid path or ref). 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) @ref, @path = extract_ref(path) diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake index 8d4950cf..5b74daf9 100644 --- a/lib/tasks/gitlab/setup.rake +++ b/lib/tasks/gitlab/setup.rake @@ -7,10 +7,12 @@ namespace :gitlab do def setup_db warn_user_is_not_gitlab - puts "This will create the necessary database tables and seed the database." - puts "You will lose any previous data stored in the database." - ask_to_continue - puts "" + unless ENV['force'] == 'yes' + puts "This will create the necessary database tables and seed the database." + puts "You will lose any previous data stored in the database." + ask_to_continue + puts "" + end Rake::Task["db:setup"].invoke Rake::Task["db:seed_fu"].invoke diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb index 1d5d99df..99cbcd13 100644 --- a/spec/controllers/commits_controller_spec.rb +++ b/spec/controllers/commits_controller_spec.rb @@ -13,7 +13,7 @@ describe CommitsController do describe "GET show" do context "as atom feed" 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.content_type.should == 'application/atom+xml' end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index df658a8c..e97ceb2c 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -100,4 +100,27 @@ describe Gitlab::API do 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 diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index 92ac5bef..90164083 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -105,13 +105,6 @@ describe Gitlab::API do response.status.should == 404 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 describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do @@ -180,12 +173,5 @@ describe Gitlab::API do response.status.should == 401 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 diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 994c8d5e..cddb7264 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -6,11 +6,14 @@ describe Gitlab::API do let(:user) { create(:user) } let(:user2) { create(:user) } let(:user3) { create(:user) } + let(:admin) { create(:admin) } let!(:project) { create(:project, namespace: user.namespace ) } let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } 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_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } + let(:key) { create(:key, project: project) } + before { project.team << [user, :reporter] } describe "GET /projects" do @@ -103,6 +106,46 @@ describe Gitlab::API do 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 it "should return a project by id" do get api("/projects/#{project.id}", user) @@ -591,4 +634,59 @@ describe Gitlab::API do response.status.should == 400 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 diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb new file mode 100644 index 00000000..9842ae91 --- /dev/null +++ b/spec/requests/api/system_hooks_spec.rb @@ -0,0 +1,69 @@ +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 diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 25ce2d2f..c2c9f846 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -167,6 +167,22 @@ describe Gitlab::API do 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 before { admin } diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 9cf5d913..98644149 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -56,7 +56,6 @@ end # projects POST /projects(.:format) projects#create # new_project GET /projects/new(.:format) projects#new # wall_project GET /:id/wall(.:format) projects#wall -# graph_project GET /:id/graph(.:format) projects#graph # files_project GET /:id/files(.:format) projects#files # edit_project GET /:id/edit(.:format) projects#edit # project GET /:id(.:format) projects#show @@ -75,10 +74,6 @@ describe ProjectsController, "routing" do get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') end - it "to #graph" do - get("/gitlabhq/graph/master").should route_to('graph#show', project_id: 'gitlabhq', id: 'master') - end - it "to #files" do get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq') end @@ -202,6 +197,7 @@ describe RefsController, "routing" 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/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 @@ -301,6 +297,10 @@ describe CommitsController, "routing" do let(:actions) { [:show] } let(:controller) { 'commits' } 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 # project_team_members GET /:project_id/team_members(.:format) team_members#index @@ -385,6 +385,7 @@ end describe BlameController, "routing" 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("/gitlab/gitlabhq/blame/master/files.scss").should route_to('blame#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') end end @@ -393,6 +394,7 @@ describe BlobController, "routing" 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/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 @@ -400,6 +402,7 @@ end describe TreeController, "routing" 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("/gitlab/gitlabhq/tree/master/files.scss").should route_to('tree#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') end end @@ -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') 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 diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index 106cfa6d..5fd8631a 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -43,6 +43,11 @@ class GitLabTestRepo < Repository def repo @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) end + + # patch repo size (in mb) + def size + 12.45 + end end module Gitlab