Commit 3374027e3a4e4eb040e59294a9ced9d7886a71e2
Exists in
master
and in
4 other branches
Merge branch 'master' into fixes/api, code clean up and tests fixed
Conflicts: doc/api/projects.md spec/requests/api/projects_spec.rb
Showing
49 changed files
with
819 additions
and
162 deletions
Show diff stats
Gemfile
1 | -source "http://rubygems.org" | 1 | +source "https://rubygems.org" |
2 | 2 | ||
3 | def darwin_only(require_as) | 3 | def darwin_only(require_as) |
4 | RUBY_PLATFORM.include?('darwin') && require_as | 4 | RUBY_PLATFORM.include?('darwin') && require_as |
@@ -103,6 +103,9 @@ gem 'settingslogic' | @@ -103,6 +103,9 @@ gem 'settingslogic' | ||
103 | gem "foreman" | 103 | gem "foreman" |
104 | gem "git" | 104 | gem "git" |
105 | 105 | ||
106 | +# Cache | ||
107 | +gem "redis-rails" | ||
108 | + | ||
106 | group :assets do | 109 | group :assets do |
107 | gem "sass-rails", "~> 3.2.5" | 110 | gem "sass-rails", "~> 3.2.5" |
108 | gem "coffee-rails", "~> 3.2.2" | 111 | gem "coffee-rails", "~> 3.2.2" |
Gemfile.lock
@@ -13,7 +13,7 @@ GIT | @@ -13,7 +13,7 @@ GIT | ||
13 | raphael-rails (2.1.0) | 13 | raphael-rails (2.1.0) |
14 | 14 | ||
15 | GEM | 15 | GEM |
16 | - remote: http://rubygems.org/ | 16 | + remote: https://rubygems.org/ |
17 | specs: | 17 | specs: |
18 | actionmailer (3.2.12) | 18 | actionmailer (3.2.12) |
19 | actionpack (= 3.2.12) | 19 | actionpack (= 3.2.12) |
@@ -329,8 +329,24 @@ GEM | @@ -329,8 +329,24 @@ GEM | ||
329 | json (~> 1.4) | 329 | json (~> 1.4) |
330 | redcarpet (2.2.2) | 330 | redcarpet (2.2.2) |
331 | redis (3.0.2) | 331 | redis (3.0.2) |
332 | + redis-actionpack (3.2.3) | ||
333 | + actionpack (~> 3.2.3) | ||
334 | + redis-rack (~> 1.4.0) | ||
335 | + redis-store (~> 1.1.0) | ||
336 | + redis-activesupport (3.2.3) | ||
337 | + activesupport (~> 3.2.3) | ||
338 | + redis-store (~> 1.1.0) | ||
332 | redis-namespace (1.2.1) | 339 | redis-namespace (1.2.1) |
333 | redis (~> 3.0.0) | 340 | redis (~> 3.0.0) |
341 | + redis-rack (1.4.2) | ||
342 | + rack (~> 1.4.1) | ||
343 | + redis-store (~> 1.1.0) | ||
344 | + redis-rails (3.2.3) | ||
345 | + redis-actionpack (~> 3.2.3) | ||
346 | + redis-activesupport (~> 3.2.3) | ||
347 | + redis-store (~> 1.1.0) | ||
348 | + redis-store (1.1.3) | ||
349 | + redis (>= 2.2.0) | ||
334 | request_store (1.0.5) | 350 | request_store (1.0.5) |
335 | rspec (2.12.0) | 351 | rspec (2.12.0) |
336 | rspec-core (~> 2.12.0) | 352 | rspec-core (~> 2.12.0) |
@@ -504,6 +520,7 @@ DEPENDENCIES | @@ -504,6 +520,7 @@ DEPENDENCIES | ||
504 | rb-fsevent | 520 | rb-fsevent |
505 | rb-inotify | 521 | rb-inotify |
506 | redcarpet (~> 2.2.2) | 522 | redcarpet (~> 2.2.2) |
523 | + redis-rails | ||
507 | rspec-rails (= 2.12.2) | 524 | rspec-rails (= 2.12.2) |
508 | sass-rails (~> 3.2.5) | 525 | sass-rails (~> 3.2.5) |
509 | sdoc | 526 | sdoc |
README.md
@@ -5,14 +5,14 @@ | @@ -5,14 +5,14 @@ | ||
5 | ### GitLab allows you to | 5 | ### GitLab allows you to |
6 | * keep your code secure on your own server | 6 | * keep your code secure on your own server |
7 | * manage repositories, users and access permissions | 7 | * manage repositories, users and access permissions |
8 | - * communicate though issues, line-comments and wiki's | ||
9 | - * perform code reviews with merge requests | 8 | + * communicate through issues, line-comments and wiki pages |
9 | + * perform code review with merge requests | ||
10 | 10 | ||
11 | ### GitLab is | 11 | ### GitLab is |
12 | 12 | ||
13 | * powered by Ruby on Rails | 13 | * powered by Ruby on Rails |
14 | * completely free and open source (MIT license) | 14 | * completely free and open source (MIT license) |
15 | -* used by 10.000 organization to keep their code secure | 15 | +* used by 10.000 organizations to keep their code secure |
16 | 16 | ||
17 | ### Code status | 17 | ### Code status |
18 | 18 | ||
@@ -34,28 +34,35 @@ | @@ -34,28 +34,35 @@ | ||
34 | 34 | ||
35 | ### Requirements | 35 | ### Requirements |
36 | 36 | ||
37 | -* Ubuntu/Debian* | 37 | +* Ubuntu/Debian** |
38 | * ruby 1.9.3+ | 38 | * ruby 1.9.3+ |
39 | * MySQL | 39 | * MySQL |
40 | * git | 40 | * git |
41 | * gitlab-shell | 41 | * gitlab-shell |
42 | * redis | 42 | * redis |
43 | 43 | ||
44 | -* More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md) | 44 | +** More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md) |
45 | 45 | ||
46 | ### Installation | 46 | ### Installation |
47 | 47 | ||
48 | -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. | 48 | +#### For production |
49 | 49 | ||
50 | -* [Installation guide for latest stable release](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) | 50 | +Follow the installation guide for production server. |
51 | 51 | ||
52 | -* [Installation guide for the current master branch](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) | 52 | +* [Installation guide for latest stable release (4.2)](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) - **Recommended** |
53 | + | ||
54 | +* [Installation guide for the current master branch (5.0)](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) | ||
55 | + | ||
56 | + | ||
57 | +#### For development | ||
58 | + | ||
59 | +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. | ||
53 | 60 | ||
54 | * [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) | 61 | * [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) |
55 | 62 | ||
56 | ### Starting | 63 | ### Starting |
57 | 64 | ||
58 | -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: | 65 | +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 |
59 | 66 | ||
60 | sudo service gitlab start | 67 | sudo service gitlab start |
61 | 68 | ||
@@ -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 | ||
63 | 70 | ||
64 | sudo /etc/init.d/gitlab restart | 71 | sudo /etc/init.d/gitlab restart |
65 | 72 | ||
66 | -2. Start it with [Foreman](https://github.com/ddollar/foreman) in development model | 73 | +2. Start it with [Foreman](https://github.com/ddollar/foreman) in development mode |
67 | 74 | ||
68 | bundle exec foreman start -p 3000 | 75 | bundle exec foreman start -p 3000 |
69 | 76 | ||
70 | -3. Start it manually in development mode | 77 | + or start it manually |
71 | 78 | ||
72 | bundle exec rails s | 79 | bundle exec rails s |
73 | bundle exec rake sidekiq:start | 80 | bundle exec rake sidekiq:start |
74 | 81 | ||
75 | ### Running the tests | 82 | ### Running the tests |
76 | 83 | ||
77 | -* Seed the database with | 84 | +* Seed the database |
78 | 85 | ||
79 | bundle exec rake db:setup RAILS_ENV=test | 86 | bundle exec rake db:setup RAILS_ENV=test |
80 | bundle exec rake db:seed_fu RAILS_ENV=test | 87 | bundle exec rake db:seed_fu RAILS_ENV=test |
app/assets/javascripts/tree.js.coffee
@@ -11,12 +11,7 @@ $ -> | @@ -11,12 +11,7 @@ $ -> | ||
11 | # Make the entire tree-item row clickable, but not if clicking another link (like a commit message) | 11 | # Make the entire tree-item row clickable, but not if clicking another link (like a commit message) |
12 | $("#tree-slider .tree-item").live 'click', (e) -> | 12 | $("#tree-slider .tree-item").live 'click', (e) -> |
13 | $('.tree-item-file-name a', this).trigger('click') if (e.target.nodeName != "A") | 13 | $('.tree-item-file-name a', this).trigger('click') if (e.target.nodeName != "A") |
14 | - | ||
15 | - # Show/Hide the loading spinner | ||
16 | - $('#tree-slider .tree-item-file-name a, .breadcrumb a, .project-refs-form').live | ||
17 | - "ajax:beforeSend": -> $('.tree_progress').addClass("loading") | ||
18 | - "ajax:complete": -> $('.tree_progress').removeClass("loading") | ||
19 | - | 14 | + |
20 | # Maintain forward/back history while browsing the file tree | 15 | # Maintain forward/back history while browsing the file tree |
21 | ((window) -> | 16 | ((window) -> |
22 | History = window.History | 17 | History = window.History |
@@ -33,7 +28,12 @@ $ -> | @@ -33,7 +28,12 @@ $ -> | ||
33 | 28 | ||
34 | History.Adapter.bind window, 'statechange', -> | 29 | History.Adapter.bind window, 'statechange', -> |
35 | state = History.getState() | 30 | state = History.getState() |
36 | - window.ajaxGet(state.url) | 31 | + $.ajax({ |
32 | + url: state.url, | ||
33 | + dataType: 'script', | ||
34 | + beforeSend: -> $('.tree_progress').addClass("loading"), | ||
35 | + complete: -> $('.tree_progress').removeClass("loading") | ||
36 | + }) | ||
37 | )(window) | 37 | )(window) |
38 | 38 | ||
39 | # See if there are lines selected | 39 | # See if there are lines selected |
app/assets/stylesheets/gitlab_bootstrap/blocks.scss
@@ -34,13 +34,6 @@ | @@ -34,13 +34,6 @@ | ||
34 | padding: 15px; | 34 | padding: 15px; |
35 | word-wrap: break-word; | 35 | word-wrap: break-word; |
36 | 36 | ||
37 | - pre { | ||
38 | - background: none !important; | ||
39 | - margin: 0; | ||
40 | - border: none; | ||
41 | - padding: 0; | ||
42 | - } | ||
43 | - | ||
44 | .clearfix { | 37 | .clearfix { |
45 | margin: 0; | 38 | margin: 0; |
46 | } | 39 | } |
app/assets/stylesheets/gitlab_bootstrap/common.scss
@@ -2,6 +2,7 @@ | @@ -2,6 +2,7 @@ | ||
2 | .cgray { color:gray } | 2 | .cgray { color:gray } |
3 | .cred { color:#D12F19 } | 3 | .cred { color:#D12F19 } |
4 | .cgreen { color:#4a2 } | 4 | .cgreen { color:#4a2 } |
5 | +.cblue { color:#29A } | ||
5 | .cblack { color:#111 } | 6 | .cblack { color:#111 } |
6 | .cdark { color:#444 } | 7 | .cdark { color:#444 } |
7 | .cwhite { color:#fff!important } | 8 | .cwhite { color:#fff!important } |
app/assets/stylesheets/sections/projects.scss
@@ -120,3 +120,16 @@ ul.nav.nav-projects-tabs { | @@ -120,3 +120,16 @@ ul.nav.nav-projects-tabs { | ||
120 | .team_member_row form { | 120 | .team_member_row form { |
121 | margin: 0px; | 121 | margin: 0px; |
122 | } | 122 | } |
123 | + | ||
124 | +.public-projects { | ||
125 | + li { | ||
126 | + margin-top: 8px; | ||
127 | + margin-bottom: 5px; | ||
128 | + border-bottom: 1px solid #eee; | ||
129 | + | ||
130 | + .description { | ||
131 | + margin-left: 22px; | ||
132 | + color: #aaa; | ||
133 | + } | ||
134 | + } | ||
135 | +} |
app/models/merge_request.rb
@@ -91,7 +91,7 @@ class MergeRequest < ActiveRecord::Base | @@ -91,7 +91,7 @@ class MergeRequest < ActiveRecord::Base | ||
91 | 91 | ||
92 | def validate_branches | 92 | def validate_branches |
93 | if target_branch == source_branch | 93 | if target_branch == source_branch |
94 | - errors.add :base, "You can not use same branch for source and target branches" | 94 | + errors.add :branch_conflict, "You can not use same branch for source and target branches" |
95 | end | 95 | end |
96 | end | 96 | end |
97 | 97 |
app/models/repository.rb
1 | class Repository | 1 | class Repository |
2 | + include Gitlab::Popen | ||
3 | + | ||
2 | # Repository directory name with namespace direcotry | 4 | # Repository directory name with namespace direcotry |
3 | # Examples: | 5 | # Examples: |
4 | # gitlab/gitolite | 6 | # gitlab/gitolite |
@@ -147,4 +149,21 @@ class Repository | @@ -147,4 +149,21 @@ class Repository | ||
147 | 149 | ||
148 | file_path | 150 | file_path |
149 | end | 151 | end |
152 | + | ||
153 | + # Return repo size in megabytes | ||
154 | + # Cached in redis | ||
155 | + def size | ||
156 | + Rails.cache.fetch(cache_key(:size)) do | ||
157 | + size = popen('du -s', path_to_repo).first.strip.to_i | ||
158 | + (size.to_f / 1024).round(2) | ||
159 | + end | ||
160 | + end | ||
161 | + | ||
162 | + def expire_cache | ||
163 | + Rails.cache.delete(cache_key(:size)) | ||
164 | + end | ||
165 | + | ||
166 | + def cache_key(type) | ||
167 | + "#{type}:#{path_with_namespace}" | ||
168 | + end | ||
150 | end | 169 | end |
app/services/git_push_service.rb
@@ -23,6 +23,7 @@ class GitPushService | @@ -23,6 +23,7 @@ class GitPushService | ||
23 | 23 | ||
24 | project.ensure_satellite_exists | 24 | project.ensure_satellite_exists |
25 | project.discover_default_branch | 25 | project.discover_default_branch |
26 | + project.repository.expire_cache | ||
26 | 27 | ||
27 | if push_to_branch?(ref, oldrev) | 28 | if push_to_branch?(ref, oldrev) |
28 | project.update_merge_requests(oldrev, newrev, ref, @user) | 29 | project.update_merge_requests(oldrev, newrev, ref, @user) |
app/views/devise/sessions/_new_ldap.html.haml
1 | = form_tag(user_omniauth_callback_path(:ldap), :class => "login-box", :id => 'new_ldap_user' ) do | 1 | = form_tag(user_omniauth_callback_path(:ldap), :class => "login-box", :id => 'new_ldap_user' ) do |
2 | = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" | 2 | = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" |
3 | - = text_field_tag :username, nil, {:class => "text top", :placeholder => "LDAP Login"} | 3 | + = text_field_tag :username, nil, {:class => "text top", :placeholder => "LDAP Login", :autofocus => "autofocus"} |
4 | = password_field_tag :password, nil, {:class => "text bottom", :placeholder => "Password"} | 4 | = password_field_tag :password, nil, {:class => "text bottom", :placeholder => "Password"} |
5 | %br/ | 5 | %br/ |
6 | = submit_tag "LDAP Sign in", :class => "btn-primary btn" | 6 | = submit_tag "LDAP Sign in", :class => "btn-primary btn" |
app/views/events/_event.html.haml
1 | - if event.proper? | 1 | - if event.proper? |
2 | - %div.event-item | ||
3 | - %span.cgray.pull-right | ||
4 | - #{time_ago_in_words(event.created_at)} ago. | 2 | + = cache event do |
3 | + %div.event-item | ||
4 | + %span.cgray.pull-right | ||
5 | + #{time_ago_in_words(event.created_at)} ago. | ||
5 | 6 | ||
6 | - = image_tag gravatar_icon(event.author_email), class: "avatar s24" | 7 | + = image_tag gravatar_icon(event.author_email), class: "avatar s24" |
7 | 8 | ||
8 | - - if event.push? | ||
9 | - = render "events/event/push", event: event | ||
10 | - .clearfix | ||
11 | - - elsif event.note? | ||
12 | - = render "events/event/note", event: event | ||
13 | - - else | ||
14 | - = render "events/event/common", event: event | 9 | + - if event.push? |
10 | + = render "events/event/push", event: event | ||
11 | + .clearfix | ||
12 | + - elsif event.note? | ||
13 | + = render "events/event/note", event: event | ||
14 | + - else | ||
15 | + = render "events/event/common", event: event | ||
15 | 16 |
app/views/help/api.html.haml
@@ -21,6 +21,8 @@ | @@ -21,6 +21,8 @@ | ||
21 | = link_to "Milestones", "#milestones", 'data-toggle' => 'tab' | 21 | = link_to "Milestones", "#milestones", 'data-toggle' => 'tab' |
22 | %li | 22 | %li |
23 | = link_to "Notes", "#notes", 'data-toggle' => 'tab' | 23 | = link_to "Notes", "#notes", 'data-toggle' => 'tab' |
24 | + %li | ||
25 | + = link_to "System Hooks", "#system_hooks", 'data-toggle' => 'tab' | ||
24 | 26 | ||
25 | .tab-content | 27 | .tab-content |
26 | .tab-pane.active#README | 28 | .tab-pane.active#README |
@@ -103,3 +105,12 @@ | @@ -103,3 +105,12 @@ | ||
103 | .file_content.wiki | 105 | .file_content.wiki |
104 | = preserve do | 106 | = preserve do |
105 | = markdown File.read(Rails.root.join("doc", "api", "notes.md")) | 107 | = markdown File.read(Rails.root.join("doc", "api", "notes.md")) |
108 | + | ||
109 | + .tab-pane#system_hooks | ||
110 | + .file_holder | ||
111 | + .file_title | ||
112 | + %i.icon-file | ||
113 | + System Hooks | ||
114 | + .file_content.wiki | ||
115 | + = preserve do | ||
116 | + = markdown File.read(Rails.root.join("doc", "api", "system_hooks.md")) |
app/views/help/index.html.haml
@@ -22,7 +22,7 @@ | @@ -22,7 +22,7 @@ | ||
22 | = mail_to Gitlab.config.gitlab.support_email, "support contact" | 22 | = mail_to Gitlab.config.gitlab.support_email, "support contact" |
23 | %li | 23 | %li |
24 | Use the | 24 | Use the |
25 | - = link_to "search bar", '#', onclick: "$("#search").focus();" | 25 | + = link_to "search bar", '#', onclick: "$('#search').focus();" |
26 | on the top of this page | 26 | on the top of this page |
27 | %li | 27 | %li |
28 | Ask in our | 28 | Ask in our |
app/views/layouts/public.html.haml
@@ -10,7 +10,7 @@ | @@ -10,7 +10,7 @@ | ||
10 | = link_to root_path, class: "home" do | 10 | = link_to root_path, class: "home" do |
11 | %h1 GITLAB | 11 | %h1 GITLAB |
12 | %span.separator | 12 | %span.separator |
13 | - %h1.project_name Public Projects | 13 | + %h1.project_name Public Projects |
14 | .container | 14 | .container |
15 | .content | 15 | .content |
16 | .prepend-top-20 | 16 | .prepend-top-20 |
app/views/projects/_form.html.haml
@@ -9,11 +9,19 @@ | @@ -9,11 +9,19 @@ | ||
9 | Project name is | 9 | Project name is |
10 | .input | 10 | .input |
11 | = f.text_field :name, placeholder: "Example Project", class: "xxlarge" | 11 | = f.text_field :name, placeholder: "Example Project", class: "xxlarge" |
12 | + | ||
13 | + | ||
12 | - unless @repository.heads.empty? | 14 | - unless @repository.heads.empty? |
13 | .clearfix | 15 | .clearfix |
14 | = f.label :default_branch, "Default Branch" | 16 | = f.label :default_branch, "Default Branch" |
15 | .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") | 17 | .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") |
16 | 18 | ||
19 | + .clearfix | ||
20 | + = f.label :description do | ||
21 | + Project description | ||
22 | + %span.light (optional) | ||
23 | + .input | ||
24 | + = f.text_area :description, placeholder: "awesome project", class: "xxlarge", rows: 3, maxlength: 250 | ||
17 | 25 | ||
18 | %fieldset.features | 26 | %fieldset.features |
19 | %legend Features: | 27 | %legend Features: |
app/views/projects/show.html.haml
1 | = render "project_head" | 1 | = render "project_head" |
2 | = render 'clone_panel' | 2 | = render 'clone_panel' |
3 | = render "events/event_last_push", event: @last_push | 3 | = render "events/event_last_push", event: @last_push |
4 | -.content_list= render @events | ||
5 | -.loading.hide | ||
6 | 4 | ||
5 | +.row | ||
6 | + .span9 | ||
7 | + .content_list= render @events | ||
8 | + .loading.hide | ||
9 | + .span3 | ||
10 | + .ui-box.white | ||
11 | + .padded | ||
12 | + %h3.page_title | ||
13 | + = @project.name | ||
14 | + - if @project.description.present? | ||
15 | + %p.light= @project.description | ||
16 | + | ||
17 | + %hr | ||
18 | + %p | ||
19 | + Access level: | ||
20 | + - if @project.public | ||
21 | + %span.cblue | ||
22 | + %i.icon-share | ||
23 | + Public | ||
24 | + - else | ||
25 | + %span.cgreen | ||
26 | + %i.icon-lock | ||
27 | + Private | ||
28 | + | ||
29 | + %p Repo Size: #{@project.repository.size} MB | ||
30 | + %p Created at: #{@project.created_at.stamp('Aug 22, 2013')} | ||
31 | + %p Owner: #{link_to @project.owner_name, @project.owner} | ||
7 | :javascript | 32 | :javascript |
8 | $(function(){ Pager.init(20); }); | 33 | $(function(){ Pager.init(20); }); |
app/views/public/projects/index.html.haml
1 | %h3.page_title | 1 | %h3.page_title |
2 | - Projects | 2 | + Projects (#{@projects.total_count}) |
3 | %small with read-only access | 3 | %small with read-only access |
4 | %hr | 4 | %hr |
5 | 5 | ||
6 | -%ul.unstyled | ||
7 | - - @projects.each do |project| | ||
8 | - %li.clearfix | ||
9 | - %h5 | ||
10 | - %i.icon-share | ||
11 | - = project.name_with_namespace | ||
12 | - .pull-right | ||
13 | - %pre.dark.tiny git clone #{project.http_url_to_repo} | 6 | +.public-projects |
7 | + %ul.unstyled | ||
8 | + - @projects.each do |project| | ||
9 | + %li.clearfix | ||
10 | + %h5 | ||
11 | + %i.icon-share | ||
12 | + = project.name_with_namespace | ||
13 | + .pull-right | ||
14 | + %pre.dark.tiny git clone #{project.http_url_to_repo} | ||
15 | + %p.description | ||
16 | + = project.description | ||
17 | + - unless @projects.present? | ||
18 | + %h3.nothing_here_message No public projects | ||
14 | 19 | ||
15 | - - unless @projects.present? | ||
16 | - %h3.nothing_here_message No public projects | ||
17 | - | ||
18 | -= paginate @projects, theme: "admin" | 20 | + = paginate @projects, theme: "admin" |
app/views/tree/_tree.html.haml
@@ -11,9 +11,6 @@ | @@ -11,9 +11,6 @@ | ||
11 | - else | 11 | - else |
12 | = link_to title, '#' | 12 | = link_to title, '#' |
13 | 13 | ||
14 | -.clear | ||
15 | -%div.tree_progress | ||
16 | - | ||
17 | %div#tree-content-holder.tree-content-holder | 14 | %div#tree-content-holder.tree-content-holder |
18 | - if tree.is_blob? | 15 | - if tree.is_blob? |
19 | = render "tree/blob", blob: tree | 16 | = render "tree/blob", blob: tree |
@@ -40,6 +37,8 @@ | @@ -40,6 +37,8 @@ | ||
40 | - if tree.readme | 37 | - if tree.readme |
41 | = render "tree/readme", readme: tree.readme | 38 | = render "tree/readme", readme: tree.readme |
42 | 39 | ||
40 | +%div.tree_progress | ||
41 | + | ||
43 | - unless tree.is_blob? | 42 | - unless tree.is_blob? |
44 | :javascript | 43 | :javascript |
45 | // Load last commit log for each file in tree | 44 | // Load last commit log for each file in tree |
@@ -0,0 +1,72 @@ | @@ -0,0 +1,72 @@ | ||
1 | +set :domain, 'set application domain here' | ||
2 | +set :db_adapter, 'mysql' # or postgres | ||
3 | +set :mount_point, '/' | ||
4 | +set :application, 'gitlabhq' | ||
5 | +set :user, 'git' | ||
6 | +set :rails_env, 'production' | ||
7 | +set :deploy_to, "/home/#{user}/apps/#{application}" | ||
8 | +set :bundle_without, %w[development test] + (%w[mysql postgres] - [db_adapter]) | ||
9 | +set :asset_env, "RAILS_GROUPS=assets RAILS_RELATIVE_URL_ROOT=#{mount_point.sub /\/+\Z/, ''}" | ||
10 | + | ||
11 | +set :use_sudo, false | ||
12 | +default_run_options[:pty] = true | ||
13 | + | ||
14 | +# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none` | ||
15 | +set :scm, :git | ||
16 | +set :repository, "git@#{domain}:#{application}.git" | ||
17 | +set :deploy_via, :remote_cache | ||
18 | + | ||
19 | +# Alternatively, you can deploy via copy, if you don't have gitlab in git | ||
20 | +#set :scm, :none | ||
21 | +#set :repository, '.' | ||
22 | +#set :deploy_via, :copy | ||
23 | + | ||
24 | +server domain, :app, :web, :db, primary: true | ||
25 | + | ||
26 | +namespace :foreman do | ||
27 | + desc 'Export the Procfile to Ubuntu upstart scripts' | ||
28 | + task :export, roles: :app do | ||
29 | + foreman_export = "foreman export upstart /etc/init -f Procfile -a #{application} -u #{user} -l #{shared_path}/log/foreman" | ||
30 | + run "cd #{release_path} && #{sudo} #{fetch :bundle_cmd, 'bundle'} exec #{foreman_export}" | ||
31 | + end | ||
32 | + | ||
33 | + desc 'Start the application services' | ||
34 | + task :start, roles: :app do | ||
35 | + run "#{sudo} service #{application} start" | ||
36 | + end | ||
37 | + | ||
38 | + desc 'Stop the application services' | ||
39 | + task :stop, roles: :app do | ||
40 | + run "#{sudo} service #{application} stop" | ||
41 | + end | ||
42 | + | ||
43 | + desc 'Restart the application services' | ||
44 | + task :restart, roles: :app do | ||
45 | + run "#{sudo} service #{application} restart" | ||
46 | + end | ||
47 | +end | ||
48 | + | ||
49 | +namespace :deploy do | ||
50 | + desc 'Start the application services' | ||
51 | + task :start, roles: :app do | ||
52 | + foreman.start | ||
53 | + end | ||
54 | + | ||
55 | + desc 'Stop the application services' | ||
56 | + task :stop, roles: :app do | ||
57 | + foreman.stop | ||
58 | + end | ||
59 | + | ||
60 | + desc 'Restart the application services' | ||
61 | + task :restart, roles: :app do | ||
62 | + foreman.restart | ||
63 | + end | ||
64 | +end | ||
65 | + | ||
66 | +after 'deploy:cold' do | ||
67 | + run "cd #{release_path} && #{rake} gitlab:setup force=yes RAILS_ENV=#{rails_env}" | ||
68 | + deploy.restart | ||
69 | +end | ||
70 | + | ||
71 | +after 'deploy:update', 'foreman:export' # Export foreman scripts | ||
72 | +#after 'deploy:update', 'foreman:restart' # Restart application scripts |
config/environments/production.rb
@@ -40,7 +40,7 @@ Gitlab::Application.configure do | @@ -40,7 +40,7 @@ Gitlab::Application.configure do | ||
40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) | 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) |
41 | 41 | ||
42 | # Use a different cache store in production | 42 | # Use a different cache store in production |
43 | - config.cache_store = :memory_store | 43 | + config.cache_store = :redis_store |
44 | 44 | ||
45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server | 45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server |
46 | # config.action_controller.asset_host = "http://assets.example.com" | 46 | # config.action_controller.asset_host = "http://assets.example.com" |
config/initializers/4_sidekiq.rb
@@ -4,19 +4,19 @@ config_file = Rails.root.join('config', 'resque.yml') | @@ -4,19 +4,19 @@ config_file = Rails.root.join('config', 'resque.yml') | ||
4 | resque_url = if File.exists?(config_file) | 4 | resque_url = if File.exists?(config_file) |
5 | YAML.load_file(config_file)[Rails.env] | 5 | YAML.load_file(config_file)[Rails.env] |
6 | else | 6 | else |
7 | - "localhost:6379" | 7 | + "redis://localhost:6379" |
8 | end | 8 | end |
9 | 9 | ||
10 | Sidekiq.configure_server do |config| | 10 | Sidekiq.configure_server do |config| |
11 | config.redis = { | 11 | config.redis = { |
12 | - url: "redis://#{resque_url}", | 12 | + url: resque_url, |
13 | namespace: 'resque:gitlab' | 13 | namespace: 'resque:gitlab' |
14 | } | 14 | } |
15 | end | 15 | end |
16 | 16 | ||
17 | Sidekiq.configure_client do |config| | 17 | Sidekiq.configure_client do |config| |
18 | config.redis = { | 18 | config.redis = { |
19 | - url: "redis://#{resque_url}", | 19 | + url: resque_url, |
20 | namespace: 'resque:gitlab' | 20 | namespace: 'resque:gitlab' |
21 | } | 21 | } |
22 | end | 22 | end |
config/resque.yml.example
config/routes.rb
@@ -166,7 +166,7 @@ Gitlab::Application.routes.draw do | @@ -166,7 +166,7 @@ Gitlab::Application.routes.draw do | ||
166 | # | 166 | # |
167 | # Project Area | 167 | # Project Area |
168 | # | 168 | # |
169 | - resources :projects, constraints: { id: /[a-zA-Z.0-9_\-\/]+/ }, except: [:new, :create, :index], path: "/" do | 169 | + resources :projects, constraints: { id: /(?:[a-zA-Z.0-9_\-]+\/)?[a-zA-Z.0-9_\-]+/ }, except: [:new, :create, :index], path: "/" do |
170 | member do | 170 | member do |
171 | get "wall" | 171 | get "wall" |
172 | get "files" | 172 | get "files" |
@@ -175,10 +175,10 @@ Gitlab::Application.routes.draw do | @@ -175,10 +175,10 @@ Gitlab::Application.routes.draw do | ||
175 | resources :blob, only: [:show], constraints: {id: /.+/} | 175 | resources :blob, only: [:show], constraints: {id: /.+/} |
176 | resources :tree, only: [:show, :edit, :update], constraints: {id: /.+/} | 176 | resources :tree, only: [:show, :edit, :update], constraints: {id: /.+/} |
177 | resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} | 177 | resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} |
178 | - resources :commits, only: [:show], constraints: {id: /.+/} | 178 | + resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/} |
179 | resources :compare, only: [:index, :create] | 179 | resources :compare, only: [:index, :create] |
180 | resources :blame, only: [:show], constraints: {id: /.+/} | 180 | resources :blame, only: [:show], constraints: {id: /.+/} |
181 | - resources :graph, only: [:show], constraints: {id: /.+/} | 181 | + resources :graph, only: [:show], constraints: {id: /(?:[^.]|\.(?!json$))+/, format: /json/} |
182 | match "/compare/:from...:to" => "compare#show", as: "compare", | 182 | match "/compare/:from...:to" => "compare#show", as: "compare", |
183 | :via => [:get, :post], constraints: {from: /.+/, to: /.+/} | 183 | :via => [:get, :post], constraints: {from: /.+/, to: /.+/} |
184 | 184 |
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 | @@ -31,13 +31,10 @@ The API uses JSON to serialize data. You don't need to specify `.json` at the en | ||
31 | 31 | ||
32 | ## Status codes | 32 | ## Status codes |
33 | 33 | ||
34 | -API requests return different status codes according to | ||
35 | - | ||
36 | -The API is designed to provide status codes according to the context and how the request | ||
37 | -is handled. For example if a `GET` request is successful a status code `200 Ok` | ||
38 | -is returned. The API is designed to be RESTful. | ||
39 | - | ||
40 | -The following list gives an overview of how the API functions are designed. | 34 | +The API is designed to return different status codes according to context and action. In this way |
35 | +if a request results in an error the caller is able to get insight into what went wrong, e.g. | ||
36 | +status code `400 Bad Request` is returned if a required attribute is missing from the request. | ||
37 | +The following list gives an overview of how the API functions generally behave. | ||
41 | 38 | ||
42 | API request types: | 39 | API request types: |
43 | 40 | ||
@@ -58,7 +55,7 @@ Return values: | @@ -58,7 +55,7 @@ Return values: | ||
58 | * `403 Forbidden` - The request is not allowed, e.g. the user is not allowed to delete a project | 55 | * `403 Forbidden` - The request is not allowed, e.g. the user is not allowed to delete a project |
59 | * `404 Not Found` - A resource could not be accessed, e.g. an ID for a resource could not be found | 56 | * `404 Not Found` - A resource could not be accessed, e.g. an ID for a resource could not be found |
60 | * `405 Method Not Allowed` - The request is not supported | 57 | * `405 Method Not Allowed` - The request is not supported |
61 | -* `409 Conflict` - A conflicting resource already exists, a project with same name already exists | 58 | +* `409 Conflict` - A conflicting resource already exists, e.g. creating a project with a name that already exists |
62 | * `500 Server Error` - While handling the request something went wrong on the server side | 59 | * `500 Server Error` - While handling the request something went wrong on the server side |
63 | 60 | ||
64 | 61 |
doc/api/groups.md
@@ -44,3 +44,14 @@ Parameters: | @@ -44,3 +44,14 @@ Parameters: | ||
44 | + `name` (required) - The name of the group | 44 | + `name` (required) - The name of the group |
45 | + `path` (required) - The path of the group | 45 | + `path` (required) - The path of the group |
46 | 46 | ||
47 | +## Transfer project to group | ||
48 | + | ||
49 | +Transfer a project to the Group namespace. Available only for admin | ||
50 | + | ||
51 | +``` | ||
52 | +POST /groups/:id/projects/:project_id | ||
53 | +``` | ||
54 | + | ||
55 | +Parameters: | ||
56 | ++ `id` (required) - The ID of a group | ||
57 | ++ `project_id (required) - The ID of a project |
doc/api/projects.md
@@ -115,11 +115,9 @@ Parameters: | @@ -115,11 +115,9 @@ Parameters: | ||
115 | + `merge_requests_enabled` (optional) - enabled by default | 115 | + `merge_requests_enabled` (optional) - enabled by default |
116 | + `wiki_enabled` (optional) - enabled by default | 116 | + `wiki_enabled` (optional) - enabled by default |
117 | 117 | ||
118 | +**Project access levels** | ||
118 | 119 | ||
119 | -## Project access levels | ||
120 | - | ||
121 | -The project access levels are defined in the `user_project` class. Currently, 4 | ||
122 | -levels are recoginized: | 120 | +The project access levels are defined in the `user_project.rb` class. Currently, these levels are recoginized: |
123 | 121 | ||
124 | ``` | 122 | ``` |
125 | GUEST = 10 | 123 | GUEST = 10 |
@@ -129,7 +127,30 @@ levels are recoginized: | @@ -129,7 +127,30 @@ levels are recoginized: | ||
129 | ``` | 127 | ``` |
130 | 128 | ||
131 | 129 | ||
132 | -## List project team members | 130 | +### Create project for user |
131 | + | ||
132 | +Creates a new project owned by user. Available only for admins. | ||
133 | + | ||
134 | +``` | ||
135 | +POST /projects/user/:user_id | ||
136 | +``` | ||
137 | + | ||
138 | +Parameters: | ||
139 | + | ||
140 | ++ `user_id` (required) - user_id of owner | ||
141 | ++ `name` (required) - new project name | ||
142 | ++ `description` (optional) - short project description | ||
143 | ++ `default_branch` (optional) - 'master' by default | ||
144 | ++ `issues_enabled` (optional) - enabled by default | ||
145 | ++ `wall_enabled` (optional) - enabled by default | ||
146 | ++ `merge_requests_enabled` (optional) - enabled by default | ||
147 | ++ `wiki_enabled` (optional) - enabled by default | ||
148 | + | ||
149 | + | ||
150 | + | ||
151 | +## Team members | ||
152 | + | ||
153 | +### List project team members | ||
133 | 154 | ||
134 | Get a list of project team members. | 155 | Get a list of project team members. |
135 | 156 | ||
@@ -140,14 +161,12 @@ GET /projects/:id/members | @@ -140,14 +161,12 @@ GET /projects/:id/members | ||
140 | Parameters: | 161 | Parameters: |
141 | 162 | ||
142 | + `id` (required) - The ID or NAME of a project | 163 | + `id` (required) - The ID or NAME of a project |
143 | -+ `query` - Query string | ||
144 | - | 164 | ++ `query` (optional) - Query string to search for members |
145 | 165 | ||
146 | -## Team members | ||
147 | 166 | ||
148 | ### Get project team member | 167 | ### Get project team member |
149 | 168 | ||
150 | -Get a project team member. | 169 | +Gets a project team member. |
151 | 170 | ||
152 | ``` | 171 | ``` |
153 | GET /projects/:id/members/:user_id | 172 | GET /projects/:id/members/:user_id |
@@ -175,7 +194,7 @@ Parameters: | @@ -175,7 +194,7 @@ Parameters: | ||
175 | 194 | ||
176 | Adds a user to a project team. This is an idempotent method and can be called multiple times | 195 | Adds a user to a project team. This is an idempotent method and can be called multiple times |
177 | with the same parameters. Adding team membership to a user that is already a member does not | 196 | with the same parameters. Adding team membership to a user that is already a member does not |
178 | -affect the membership. | 197 | +affect the existing membership. |
179 | 198 | ||
180 | ``` | 199 | ``` |
181 | POST /projects/:id/members | 200 | POST /projects/:id/members |
@@ -190,7 +209,7 @@ Parameters: | @@ -190,7 +209,7 @@ Parameters: | ||
190 | 209 | ||
191 | ### Edit project team member | 210 | ### Edit project team member |
192 | 211 | ||
193 | -Update project team member to specified access level. | 212 | +Updates project team member to a specified access level. |
194 | 213 | ||
195 | ``` | 214 | ``` |
196 | PUT /projects/:id/members/:user_id | 215 | PUT /projects/:id/members/:user_id |
@@ -398,81 +417,90 @@ Returns values: | @@ -398,81 +417,90 @@ Returns values: | ||
398 | + `404 Not Found` if project with id or the branch with `ref_name` not found | 417 | + `404 Not Found` if project with id or the branch with `ref_name` not found |
399 | 418 | ||
400 | 419 | ||
401 | -## Snippets | ||
402 | 420 | ||
403 | -### List snippets | 421 | +## Deploy Keys |
422 | + | ||
423 | +### List deploy keys | ||
404 | 424 | ||
405 | -Lists the snippets of a project. | 425 | +Get a list of a project's deploy keys. |
406 | 426 | ||
407 | ``` | 427 | ``` |
408 | -GET /projects/:id/snippets | 428 | +GET /projects/:id/keys |
409 | ``` | 429 | ``` |
410 | 430 | ||
411 | Parameters: | 431 | Parameters: |
412 | 432 | ||
413 | + `id` (required) - The ID of the project | 433 | + `id` (required) - The ID of the project |
414 | 434 | ||
415 | - | ||
416 | -### List single snippet | ||
417 | - | ||
418 | -Lists a single snippet of a project | ||
419 | - | ||
420 | -``` | ||
421 | -GET /projects/:id/snippets/:snippet_id | 435 | +```json |
436 | +[ | ||
437 | + { | ||
438 | + "id": 1, | ||
439 | + "title" : "Public key" | ||
440 | + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 | ||
441 | + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 | ||
442 | + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=", | ||
443 | + }, | ||
444 | + { | ||
445 | + "id": 3, | ||
446 | + "title" : "Another Public key" | ||
447 | + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 | ||
448 | + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 | ||
449 | + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" | ||
450 | + } | ||
451 | +] | ||
422 | ``` | 452 | ``` |
423 | 453 | ||
424 | -Parameters: | ||
425 | - | ||
426 | -+ `id` (required) - The ID of the project | ||
427 | -+ `snippet_id` (required) - The ID of the snippet | ||
428 | 454 | ||
455 | +### Single deploy key | ||
429 | 456 | ||
430 | -### Create snippet | ||
431 | - | ||
432 | -Creates a new project snippet. | 457 | +Get a single key. |
433 | 458 | ||
434 | ``` | 459 | ``` |
435 | -POST /projects/:id/snippets | 460 | +GET /projects/:id/keys/:key_id |
436 | ``` | 461 | ``` |
437 | 462 | ||
438 | Parameters: | 463 | Parameters: |
439 | 464 | ||
440 | + `id` (required) - The ID of the project | 465 | + `id` (required) - The ID of the project |
441 | -+ `title` (required) - The title of the new snippet | ||
442 | -+ `file_name` (required) - The file name of the snippet | ||
443 | -+ `code` (required) - The content of the snippet | ||
444 | -+ `lifetime` (optional) - The expiration date of a snippet | 466 | ++ `key_id` (required) - The ID of the deploy key |
445 | 467 | ||
468 | +```json | ||
469 | +{ | ||
470 | + "id": 1, | ||
471 | + "title" : "Public key" | ||
472 | + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 | ||
473 | + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 | ||
474 | + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" | ||
475 | +} | ||
476 | +``` | ||
446 | 477 | ||
447 | -### Update snippet | ||
448 | 478 | ||
449 | -Updates an existing project snippet. | 479 | +### Add deploy key |
480 | + | ||
481 | +Creates a new deploy key for a project. | ||
450 | 482 | ||
451 | ``` | 483 | ``` |
452 | -PUT /projects/:id/snippets/:snippet_id | 484 | +POST /projects/:id/keys |
453 | ``` | 485 | ``` |
454 | 486 | ||
455 | Parameters: | 487 | Parameters: |
456 | 488 | ||
457 | + `id` (required) - The ID of the project | 489 | + `id` (required) - The ID of the project |
458 | -+ `snippet_id` (required) - The id of the project snippet | ||
459 | -+ `title` (optional) - The new title of the project snippet | ||
460 | -+ `file_name` (optional) - The new file name of the project snippet | ||
461 | -+ `lifetime` (optional) - The new expiration date of the snippet | ||
462 | -+ `code` (optional) - The content of the snippet | 490 | ++ `title` (required) - New deploy key's title |
491 | ++ `key` (required) - New deploy key | ||
463 | 492 | ||
464 | 493 | ||
465 | -## Delete snippet | 494 | +### Delete deploy key |
466 | 495 | ||
467 | -Deletes a project snippet. This is an idempotent function call and returns `200 Ok` | ||
468 | -even if the snippet with the id is not available. | 496 | +Delete a deploy key from a project |
469 | 497 | ||
470 | ``` | 498 | ``` |
471 | -DELETE /projects/:id/snippets/:snippet_id | 499 | +DELETE /projects/:id/keys/:key_id |
472 | ``` | 500 | ``` |
473 | 501 | ||
474 | -Paramaters: | 502 | +Parameters: |
475 | 503 | ||
476 | + `id` (required) - The ID of the project | 504 | + `id` (required) - The ID of the project |
477 | -+ `snippet_id` (required) - The ID of the snippet | 505 | ++ `key_id` (required) - The ID of the deploy key |
478 | 506 |
doc/api/snippets.md
@@ -46,7 +46,7 @@ Parameters: | @@ -46,7 +46,7 @@ Parameters: | ||
46 | 46 | ||
47 | ## Create new snippet | 47 | ## Create new snippet |
48 | 48 | ||
49 | -Creates a new project snippet. | 49 | +Creates a new project snippet. The user must have permission to create new snippets. |
50 | 50 | ||
51 | ``` | 51 | ``` |
52 | POST /projects/:id/snippets | 52 | POST /projects/:id/snippets |
@@ -61,9 +61,9 @@ Parameters: | @@ -61,9 +61,9 @@ Parameters: | ||
61 | + `code` (required) - The content of a snippet | 61 | + `code` (required) - The content of a snippet |
62 | 62 | ||
63 | 63 | ||
64 | -## Edit snippet | 64 | +## Update snippet |
65 | 65 | ||
66 | -Updates an existing project snippet. | 66 | +Updates an existing project snippet. The user must have permission to change an existing snippet. |
67 | 67 | ||
68 | ``` | 68 | ``` |
69 | PUT /projects/:id/snippets/:snippet_id | 69 | PUT /projects/:id/snippets/:snippet_id |
@@ -96,7 +96,7 @@ Parameters: | @@ -96,7 +96,7 @@ Parameters: | ||
96 | 96 | ||
97 | ## Snippet content | 97 | ## Snippet content |
98 | 98 | ||
99 | -Get a raw project snippet. | 99 | +Returns the raw project snippet as plain text. |
100 | 100 | ||
101 | ``` | 101 | ``` |
102 | GET /projects/:id/snippets/:snippet_id/raw | 102 | GET /projects/:id/snippets/:snippet_id/raw |
@@ -0,0 +1,47 @@ | @@ -0,0 +1,47 @@ | ||
1 | +All methods require admin authorization. | ||
2 | + | ||
3 | +## List system hooks | ||
4 | + | ||
5 | +Get list of system hooks | ||
6 | + | ||
7 | +``` | ||
8 | +GET /hooks | ||
9 | +``` | ||
10 | + | ||
11 | +Will return hooks with status `200 OK` on success, or `404 Not found` on fail. | ||
12 | + | ||
13 | +## Add new system hook hook | ||
14 | + | ||
15 | +``` | ||
16 | +POST /hooks | ||
17 | +``` | ||
18 | + | ||
19 | +Parameters: | ||
20 | + | ||
21 | ++ `url` (required) - The hook URL | ||
22 | + | ||
23 | +Will return status `201 Created` on success, or `404 Not found` on fail. | ||
24 | + | ||
25 | +## Test system hook | ||
26 | + | ||
27 | +``` | ||
28 | +GET /hooks/:id | ||
29 | +``` | ||
30 | + | ||
31 | +Parameters: | ||
32 | + | ||
33 | ++ `id` (required) - The ID of hook | ||
34 | + | ||
35 | +Will return hook with status `200 OK` on success, or `404 Not found` on fail. | ||
36 | + | ||
37 | +## Delete system hook | ||
38 | + | ||
39 | +``` | ||
40 | +DELETE /hooks/:id | ||
41 | +``` | ||
42 | + | ||
43 | +Parameters: | ||
44 | + | ||
45 | ++ `id` (required) - The ID of hook | ||
46 | + | ||
47 | +Will return status `200 OK` on success, or `404 Not found` on fail. | ||
0 | \ No newline at end of file | 48 | \ No newline at end of file |
doc/api/users.md
@@ -235,6 +235,23 @@ Parameters: | @@ -235,6 +235,23 @@ Parameters: | ||
235 | + `key` (required) - new SSH key | 235 | + `key` (required) - new SSH key |
236 | 236 | ||
237 | 237 | ||
238 | +## Add SSH key for user | ||
239 | + | ||
240 | +Create new key owned by specified user. Available only for admin | ||
241 | + | ||
242 | +``` | ||
243 | +POST /users/:id/keys | ||
244 | +``` | ||
245 | + | ||
246 | +Parameters: | ||
247 | + | ||
248 | ++ `id` (required) - id of specified user | ||
249 | ++ `title` (required) - new SSH Key's title | ||
250 | ++ `key` (required) - new SSH key | ||
251 | + | ||
252 | +Will return created key with status `201 Created` on success, or `404 Not | ||
253 | +found` on fail. | ||
254 | + | ||
238 | ## Delete SSH key | 255 | ## Delete SSH key |
239 | 256 | ||
240 | Deletes key owned by currently authenticated user. This is an idempotent function and calling it on a key that is already | 257 | Deletes key owned by currently authenticated user. This is an idempotent function and calling it on a key that is already |
doc/install/installation.md
@@ -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 | ||
288 | `config/resque.yml` file. | 288 | `config/resque.yml` file. |
289 | 289 | ||
290 | # example | 290 | # example |
291 | - production: redis.example.tld:6379 | 291 | + production: redis://redis.example.tld:6379 |
292 | 292 | ||
293 | ## Custom SSH Connection | 293 | ## Custom SSH Connection |
294 | 294 |
features/steps/project/project_network_graph.rb
@@ -27,6 +27,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps | @@ -27,6 +27,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps | ||
27 | 27 | ||
28 | And 'I switch ref to "stable"' do | 28 | And 'I switch ref to "stable"' do |
29 | page.select 'stable', :from => 'ref' | 29 | page.select 'stable', :from => 'ref' |
30 | + sleep 2 | ||
30 | end | 31 | end |
31 | 32 | ||
32 | And 'page should select "stable" in select box' do | 33 | 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 | ||
44 | fill_in 'q', :with => '98d6492' | 45 | fill_in 'q', :with => '98d6492' |
45 | find('button').click | 46 | find('button').click |
46 | end | 47 | end |
48 | + sleep 2 | ||
47 | end | 49 | end |
48 | 50 | ||
49 | And 'page should have "v2.1.0" on graph' do | 51 | And 'page should have "v2.1.0" on graph' do |
lib/api.rb
lib/api/groups.rb
@@ -56,6 +56,24 @@ module Gitlab | @@ -56,6 +56,24 @@ module Gitlab | ||
56 | not_found! | 56 | not_found! |
57 | end | 57 | end |
58 | end | 58 | end |
59 | + | ||
60 | + # Transfer a project to the Group namespace | ||
61 | + # | ||
62 | + # Parameters: | ||
63 | + # id - group id | ||
64 | + # project_id - project id | ||
65 | + # Example Request: | ||
66 | + # POST /groups/:id/projects/:project_id | ||
67 | + post ":id/projects/:project_id" do | ||
68 | + authenticated_as_admin! | ||
69 | + @group = Group.find(params[:id]) | ||
70 | + project = Project.find(params[:project_id]) | ||
71 | + if project.transfer(@group) | ||
72 | + present @group | ||
73 | + else | ||
74 | + not_found! | ||
75 | + end | ||
76 | + end | ||
59 | end | 77 | end |
60 | end | 78 | end |
61 | end | 79 | end |
lib/api/merge_requests.rb
@@ -8,6 +8,8 @@ module Gitlab | @@ -8,6 +8,8 @@ module Gitlab | ||
8 | def handle_merge_request_errors!(errors) | 8 | def handle_merge_request_errors!(errors) |
9 | if errors[:project_access].any? | 9 | if errors[:project_access].any? |
10 | error!(errors[:project_access], 422) | 10 | error!(errors[:project_access], 422) |
11 | + elsif errors[:branch_conflict].any? | ||
12 | + error!(errors[:branch_conflict], 422) | ||
11 | end | 13 | end |
12 | not_found! | 14 | not_found! |
13 | end | 15 | end |
lib/api/projects.rb
@@ -64,6 +64,38 @@ module Gitlab | @@ -64,6 +64,38 @@ module Gitlab | ||
64 | end | 64 | end |
65 | end | 65 | end |
66 | 66 | ||
67 | + # Create new project for a specified user. Only available to admin users. | ||
68 | + # | ||
69 | + # Parameters: | ||
70 | + # user_id (required) - The ID of a user | ||
71 | + # name (required) - name for new project | ||
72 | + # description (optional) - short project description | ||
73 | + # default_branch (optional) - 'master' by default | ||
74 | + # issues_enabled (optional) - enabled by default | ||
75 | + # wall_enabled (optional) - enabled by default | ||
76 | + # merge_requests_enabled (optional) - enabled by default | ||
77 | + # wiki_enabled (optional) - enabled by default | ||
78 | + # Example Request | ||
79 | + # POST /projects/user/:user_id | ||
80 | + post "user/:user_id" do | ||
81 | + authenticated_as_admin! | ||
82 | + user = User.find(params[:user_id]) | ||
83 | + attrs = attributes_for_keys [:name, | ||
84 | + :description, | ||
85 | + :default_branch, | ||
86 | + :issues_enabled, | ||
87 | + :wall_enabled, | ||
88 | + :merge_requests_enabled, | ||
89 | + :wiki_enabled] | ||
90 | + @project = ::Projects::CreateContext.new(user, attrs).execute | ||
91 | + if @project.saved? | ||
92 | + present @project, with: Entities::Project | ||
93 | + else | ||
94 | + not_found! | ||
95 | + end | ||
96 | + end | ||
97 | + | ||
98 | + | ||
67 | # Get a project team members | 99 | # Get a project team members |
68 | # | 100 | # |
69 | # Parameters: | 101 | # Parameters: |
@@ -471,6 +503,49 @@ module Gitlab | @@ -471,6 +503,49 @@ module Gitlab | ||
471 | present tree.data | 503 | present tree.data |
472 | end | 504 | end |
473 | 505 | ||
506 | + # Get a specific project's keys | ||
507 | + # | ||
508 | + # Example Request: | ||
509 | + # GET /projects/:id/keys | ||
510 | + get ":id/keys" do | ||
511 | + present user_project.deploy_keys, with: Entities::SSHKey | ||
512 | + end | ||
513 | + | ||
514 | + # Get single key owned by currently authenticated user | ||
515 | + # | ||
516 | + # Example Request: | ||
517 | + # GET /projects/:id/keys/:id | ||
518 | + get ":id/keys/:key_id" do | ||
519 | + key = user_project.deploy_keys.find params[:key_id] | ||
520 | + present key, with: Entities::SSHKey | ||
521 | + end | ||
522 | + | ||
523 | + # Add new ssh key to currently authenticated user | ||
524 | + # | ||
525 | + # Parameters: | ||
526 | + # key (required) - New SSH Key | ||
527 | + # title (required) - New SSH Key's title | ||
528 | + # Example Request: | ||
529 | + # POST /projects/:id/keys | ||
530 | + post ":id/keys" do | ||
531 | + attrs = attributes_for_keys [:title, :key] | ||
532 | + key = user_project.deploy_keys.new attrs | ||
533 | + if key.save | ||
534 | + present key, with: Entities::SSHKey | ||
535 | + else | ||
536 | + not_found! | ||
537 | + end | ||
538 | + end | ||
539 | + | ||
540 | + # Delete existed ssh key of currently authenticated user | ||
541 | + # | ||
542 | + # Example Request: | ||
543 | + # DELETE /projects/:id/keys/:id | ||
544 | + delete ":id/keys/:key_id" do | ||
545 | + key = user_project.deploy_keys.find params[:key_id] | ||
546 | + key.delete | ||
547 | + end | ||
548 | + | ||
474 | end | 549 | end |
475 | end | 550 | end |
476 | end | 551 | end |
@@ -0,0 +1,60 @@ | @@ -0,0 +1,60 @@ | ||
1 | +module Gitlab | ||
2 | + # Hooks API | ||
3 | + class SystemHooks < Grape::API | ||
4 | + before { authenticated_as_admin! } | ||
5 | + | ||
6 | + resource :hooks do | ||
7 | + # Get the list of system hooks | ||
8 | + # | ||
9 | + # Example Request: | ||
10 | + # GET /hooks | ||
11 | + get do | ||
12 | + @hooks = SystemHook.all | ||
13 | + present @hooks, with: Entities::Hook | ||
14 | + end | ||
15 | + | ||
16 | + # Create new system hook | ||
17 | + # | ||
18 | + # Parameters: | ||
19 | + # url (required) - url for system hook | ||
20 | + # Example Request | ||
21 | + # POST /hooks | ||
22 | + post do | ||
23 | + attrs = attributes_for_keys [:url] | ||
24 | + @hook = SystemHook.new attrs | ||
25 | + if @hook.save | ||
26 | + present @hook, with: Entities::Hook | ||
27 | + else | ||
28 | + not_found! | ||
29 | + end | ||
30 | + end | ||
31 | + | ||
32 | + # Test a hook | ||
33 | + # | ||
34 | + # Example Request | ||
35 | + # GET /hooks/:id | ||
36 | + get ":id" do | ||
37 | + @hook = SystemHook.find(params[:id]) | ||
38 | + data = { | ||
39 | + event_name: "project_create", | ||
40 | + name: "Ruby", | ||
41 | + path: "ruby", | ||
42 | + project_id: 1, | ||
43 | + owner_name: "Someone", | ||
44 | + owner_email: "example@gitlabhq.com" | ||
45 | + } | ||
46 | + @hook.execute(data) | ||
47 | + data | ||
48 | + end | ||
49 | + | ||
50 | + # Delete a hook | ||
51 | + # | ||
52 | + # Example Request: | ||
53 | + # DELETE /hooks/:id | ||
54 | + delete ":id" do | ||
55 | + @hook = SystemHook.find(params[:id]) | ||
56 | + @hook.destroy | ||
57 | + end | ||
58 | + end | ||
59 | + end | ||
60 | +end | ||
0 | \ No newline at end of file | 61 | \ No newline at end of file |
lib/api/users.rb
@@ -81,6 +81,26 @@ module Gitlab | @@ -81,6 +81,26 @@ module Gitlab | ||
81 | end | 81 | end |
82 | end | 82 | end |
83 | 83 | ||
84 | + # Add ssh key to a specified user. Only available to admin users. | ||
85 | + # | ||
86 | + # Parameters: | ||
87 | + # id (required) - The ID of a user | ||
88 | + # key (required) - New SSH Key | ||
89 | + # title (required) - New SSH Key's title | ||
90 | + # Example Request: | ||
91 | + # POST /users/:id/keys | ||
92 | + post ":id/keys" do | ||
93 | + authenticated_as_admin! | ||
94 | + user = User.find(params[:id]) | ||
95 | + attrs = attributes_for_keys [:title, :key] | ||
96 | + key = user.keys.new attrs | ||
97 | + if key.save | ||
98 | + present key, with: Entities::SSHKey | ||
99 | + else | ||
100 | + not_found! | ||
101 | + end | ||
102 | + end | ||
103 | + | ||
84 | # Delete user. Available only for admin | 104 | # Delete user. Available only for admin |
85 | # | 105 | # |
86 | # Example Request: | 106 | # Example Request: |
lib/extracts_path.rb
@@ -105,12 +105,6 @@ module ExtractsPath | @@ -105,12 +105,6 @@ module ExtractsPath | ||
105 | # Automatically renders `not_found!` if a valid tree path could not be | 105 | # Automatically renders `not_found!` if a valid tree path could not be |
106 | # resolved (e.g., when a user inserts an invalid path or ref). | 106 | # resolved (e.g., when a user inserts an invalid path or ref). |
107 | def assign_ref_vars | 107 | def assign_ref_vars |
108 | - # Handle formats embedded in the id | ||
109 | - if params[:id].ends_with?('.atom') | ||
110 | - params[:id].gsub!(/\.atom$/, '') | ||
111 | - request.format = :atom | ||
112 | - end | ||
113 | - | ||
114 | path = CGI::unescape(request.fullpath.dup) | 108 | path = CGI::unescape(request.fullpath.dup) |
115 | 109 | ||
116 | @ref, @path = extract_ref(path) | 110 | @ref, @path = extract_ref(path) |
lib/tasks/gitlab/setup.rake
@@ -7,10 +7,12 @@ namespace :gitlab do | @@ -7,10 +7,12 @@ namespace :gitlab do | ||
7 | def setup_db | 7 | def setup_db |
8 | warn_user_is_not_gitlab | 8 | warn_user_is_not_gitlab |
9 | 9 | ||
10 | - puts "This will create the necessary database tables and seed the database." | ||
11 | - puts "You will lose any previous data stored in the database." | ||
12 | - ask_to_continue | ||
13 | - puts "" | 10 | + unless ENV['force'] == 'yes' |
11 | + puts "This will create the necessary database tables and seed the database." | ||
12 | + puts "You will lose any previous data stored in the database." | ||
13 | + ask_to_continue | ||
14 | + puts "" | ||
15 | + end | ||
14 | 16 | ||
15 | Rake::Task["db:setup"].invoke | 17 | Rake::Task["db:setup"].invoke |
16 | Rake::Task["db:seed_fu"].invoke | 18 | Rake::Task["db:seed_fu"].invoke |
spec/controllers/commits_controller_spec.rb
@@ -13,7 +13,7 @@ describe CommitsController do | @@ -13,7 +13,7 @@ describe CommitsController do | ||
13 | describe "GET show" do | 13 | describe "GET show" do |
14 | context "as atom feed" do | 14 | context "as atom feed" do |
15 | it "should render as atom" do | 15 | it "should render as atom" do |
16 | - get :show, project_id: project.path, id: "master.atom" | 16 | + get :show, project_id: project.path, id: "master", format: "atom" |
17 | response.should be_success | 17 | response.should be_success |
18 | response.content_type.should == 'application/atom+xml' | 18 | response.content_type.should == 'application/atom+xml' |
19 | end | 19 | end |
spec/requests/api/groups_spec.rb
@@ -100,4 +100,27 @@ describe Gitlab::API do | @@ -100,4 +100,27 @@ describe Gitlab::API do | ||
100 | end | 100 | end |
101 | end | 101 | end |
102 | end | 102 | end |
103 | + | ||
104 | + describe "POST /groups/:id/projects/:project_id" do | ||
105 | + let(:project) { create(:project) } | ||
106 | + before(:each) do | ||
107 | + project.stub!(:transfer).and_return(true) | ||
108 | + Project.stub(:find).and_return(project) | ||
109 | + end | ||
110 | + | ||
111 | + | ||
112 | + context "when authenticated as user" do | ||
113 | + it "should not transfer project to group" do | ||
114 | + post api("/groups/#{group1.id}/projects/#{project.id}", user2) | ||
115 | + response.status.should == 403 | ||
116 | + end | ||
117 | + end | ||
118 | + | ||
119 | + context "when authenticated as admin" do | ||
120 | + it "should transfer project to group" do | ||
121 | + project.should_receive(:transfer) | ||
122 | + post api("/groups/#{group1.id}/projects/#{project.id}", admin) | ||
123 | + end | ||
124 | + end | ||
125 | + end | ||
103 | end | 126 | end |
spec/requests/api/notes_spec.rb
@@ -105,13 +105,6 @@ describe Gitlab::API do | @@ -105,13 +105,6 @@ describe Gitlab::API do | ||
105 | response.status.should == 404 | 105 | response.status.should == 404 |
106 | end | 106 | end |
107 | end | 107 | end |
108 | - | ||
109 | - context "when notable is invalid" do | ||
110 | - it "should return a 404 error" do | ||
111 | - get api("/projects/#{project.id}/unknown/#{snippet.id}/notes", user) | ||
112 | - response.status.should == 404 | ||
113 | - end | ||
114 | - end | ||
115 | end | 108 | end |
116 | 109 | ||
117 | describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do | 110 | 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 | ||
180 | response.status.should == 401 | 173 | response.status.should == 401 |
181 | end | 174 | end |
182 | end | 175 | end |
183 | - | ||
184 | - context "when noteable is invalid" do | ||
185 | - it "should return a 404 error" do | ||
186 | - post api("/projects/#{project.id}/invalid/#{snippet.id}/notes", user) | ||
187 | - response.status.should == 404 | ||
188 | - end | ||
189 | - end | ||
190 | end | 176 | end |
191 | end | 177 | end |
spec/requests/api/projects_spec.rb
@@ -6,11 +6,14 @@ describe Gitlab::API do | @@ -6,11 +6,14 @@ describe Gitlab::API do | ||
6 | let(:user) { create(:user) } | 6 | let(:user) { create(:user) } |
7 | let(:user2) { create(:user) } | 7 | let(:user2) { create(:user) } |
8 | let(:user3) { create(:user) } | 8 | let(:user3) { create(:user) } |
9 | + let(:admin) { create(:admin) } | ||
9 | let!(:project) { create(:project, namespace: user.namespace ) } | 10 | let!(:project) { create(:project, namespace: user.namespace ) } |
10 | let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } | 11 | let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } |
11 | let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } | 12 | let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } |
12 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } | 13 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } |
13 | let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } | 14 | let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } |
15 | + let(:key) { create(:key, project: project) } | ||
16 | + | ||
14 | before { project.team << [user, :reporter] } | 17 | before { project.team << [user, :reporter] } |
15 | 18 | ||
16 | describe "GET /projects" do | 19 | describe "GET /projects" do |
@@ -103,6 +106,46 @@ describe Gitlab::API do | @@ -103,6 +106,46 @@ describe Gitlab::API do | ||
103 | end | 106 | end |
104 | end | 107 | end |
105 | 108 | ||
109 | + describe "POST /projects/user/:id" do | ||
110 | + before { admin } | ||
111 | + | ||
112 | + it "should create new project without path" do | ||
113 | + expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1) | ||
114 | + end | ||
115 | + | ||
116 | + it "should not create new project without name" do | ||
117 | + expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count} | ||
118 | + end | ||
119 | + | ||
120 | + it "should respond with 201 on success" do | ||
121 | + post api("/projects/user/#{user.id}", admin), name: 'foo' | ||
122 | + response.status.should == 201 | ||
123 | + end | ||
124 | + | ||
125 | + it "should respond with 404 on failure" do | ||
126 | + post api("/projects/user/#{user.id}", admin) | ||
127 | + response.status.should == 404 | ||
128 | + end | ||
129 | + | ||
130 | + it "should assign attributes to project" do | ||
131 | + project = attributes_for(:project, { | ||
132 | + description: Faker::Lorem.sentence, | ||
133 | + default_branch: 'stable', | ||
134 | + issues_enabled: false, | ||
135 | + wall_enabled: false, | ||
136 | + merge_requests_enabled: false, | ||
137 | + wiki_enabled: false | ||
138 | + }) | ||
139 | + | ||
140 | + post api("/projects/user/#{user.id}", admin), project | ||
141 | + | ||
142 | + project.each_pair do |k,v| | ||
143 | + next if k == :path | ||
144 | + json_response[k.to_s].should == v | ||
145 | + end | ||
146 | + end | ||
147 | + end | ||
148 | + | ||
106 | describe "GET /projects/:id" do | 149 | describe "GET /projects/:id" do |
107 | it "should return a project by id" do | 150 | it "should return a project by id" do |
108 | get api("/projects/#{project.id}", user) | 151 | get api("/projects/#{project.id}", user) |
@@ -591,4 +634,59 @@ describe Gitlab::API do | @@ -591,4 +634,59 @@ describe Gitlab::API do | ||
591 | response.status.should == 400 | 634 | response.status.should == 400 |
592 | end | 635 | end |
593 | end | 636 | end |
637 | + | ||
638 | + describe "GET /projects/:id/keys" do | ||
639 | + it "should return array of ssh keys" do | ||
640 | + project.deploy_keys << key | ||
641 | + project.save | ||
642 | + get api("/projects/#{project.id}/keys", user) | ||
643 | + response.status.should == 200 | ||
644 | + json_response.should be_an Array | ||
645 | + json_response.first['title'].should == key.title | ||
646 | + end | ||
647 | + end | ||
648 | + | ||
649 | + describe "GET /projects/:id/keys/:key_id" do | ||
650 | + it "should return a single key" do | ||
651 | + project.deploy_keys << key | ||
652 | + project.save | ||
653 | + get api("/projects/#{project.id}/keys/#{key.id}", user) | ||
654 | + response.status.should == 200 | ||
655 | + json_response['title'].should == key.title | ||
656 | + end | ||
657 | + | ||
658 | + it "should return 404 Not Found with invalid ID" do | ||
659 | + get api("/projects/#{project.id}/keys/404", user) | ||
660 | + response.status.should == 404 | ||
661 | + end | ||
662 | + end | ||
663 | + | ||
664 | + describe "POST /projects/:id/keys" do | ||
665 | + it "should not create an invalid ssh key" do | ||
666 | + post api("/projects/#{project.id}/keys", user), { title: "invalid key" } | ||
667 | + response.status.should == 404 | ||
668 | + end | ||
669 | + | ||
670 | + it "should create new ssh key" do | ||
671 | + key_attrs = attributes_for :key | ||
672 | + expect { | ||
673 | + post api("/projects/#{project.id}/keys", user), key_attrs | ||
674 | + }.to change{ project.deploy_keys.count }.by(1) | ||
675 | + end | ||
676 | + end | ||
677 | + | ||
678 | + describe "DELETE /projects/:id/keys/:key_id" do | ||
679 | + it "should delete existing key" do | ||
680 | + project.deploy_keys << key | ||
681 | + project.save | ||
682 | + expect { | ||
683 | + delete api("/projects/#{project.id}/keys/#{key.id}", user) | ||
684 | + }.to change{ project.deploy_keys.count }.by(-1) | ||
685 | + end | ||
686 | + | ||
687 | + it "should return 404 Not Found with invalid ID" do | ||
688 | + delete api("/projects/#{project.id}/keys/404", user) | ||
689 | + response.status.should == 404 | ||
690 | + end | ||
691 | + end | ||
594 | end | 692 | end |
@@ -0,0 +1,69 @@ | @@ -0,0 +1,69 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe Gitlab::API do | ||
4 | + include ApiHelpers | ||
5 | + | ||
6 | + let(:user) { create(:user) } | ||
7 | + let(:admin) { create(:admin) } | ||
8 | + let!(:hook) { create(:system_hook, url: "http://example.com") } | ||
9 | + | ||
10 | + before { stub_request(:post, hook.url) } | ||
11 | + | ||
12 | + describe "GET /hooks" do | ||
13 | + context "when not an admin" do | ||
14 | + it "should return forbidden error" do | ||
15 | + get api("/hooks", user) | ||
16 | + response.status.should == 403 | ||
17 | + end | ||
18 | + end | ||
19 | + | ||
20 | + context "when authenticated as admin" do | ||
21 | + it "should return an array of hooks" do | ||
22 | + get api("/hooks", admin) | ||
23 | + response.status.should == 200 | ||
24 | + json_response.should be_an Array | ||
25 | + json_response.first['url'].should == hook.url | ||
26 | + end | ||
27 | + end | ||
28 | + end | ||
29 | + | ||
30 | + describe "POST /hooks" do | ||
31 | + it "should create new hook" do | ||
32 | + expect { | ||
33 | + post api("/hooks", admin), url: 'http://example.com' | ||
34 | + }.to change { SystemHook.count }.by(1) | ||
35 | + end | ||
36 | + | ||
37 | + it "should respond with 404 on failure" do | ||
38 | + post api("/hooks", admin) | ||
39 | + response.status.should == 404 | ||
40 | + end | ||
41 | + | ||
42 | + it "should not create new hook without url" do | ||
43 | + expect { | ||
44 | + post api("/hooks", admin) | ||
45 | + }.to_not change { SystemHook.count } | ||
46 | + end | ||
47 | + end | ||
48 | + | ||
49 | + describe "GET /hooks/:id" do | ||
50 | + it "should return hook by id" do | ||
51 | + get api("/hooks/#{hook.id}", admin) | ||
52 | + response.status.should == 200 | ||
53 | + json_response['event_name'].should == 'project_create' | ||
54 | + end | ||
55 | + | ||
56 | + it "should return 404 on failure" do | ||
57 | + get api("/hooks/404", admin) | ||
58 | + response.status.should == 404 | ||
59 | + end | ||
60 | + end | ||
61 | + | ||
62 | + describe "DELETE /hooks/:id" do | ||
63 | + it "should delete a hook" do | ||
64 | + expect { | ||
65 | + delete api("/hooks/#{hook.id}", admin) | ||
66 | + }.to change { SystemHook.count }.by(-1) | ||
67 | + end | ||
68 | + end | ||
69 | +end | ||
0 | \ No newline at end of file | 70 | \ No newline at end of file |
spec/requests/api/users_spec.rb
@@ -167,6 +167,22 @@ describe Gitlab::API do | @@ -167,6 +167,22 @@ describe Gitlab::API do | ||
167 | end | 167 | end |
168 | end | 168 | end |
169 | 169 | ||
170 | + describe "POST /users/:id/keys" do | ||
171 | + before { admin } | ||
172 | + | ||
173 | + it "should not create invalid ssh key" do | ||
174 | + post api("/users/#{user.id}/keys", admin), { title: "invalid key" } | ||
175 | + response.status.should == 404 | ||
176 | + end | ||
177 | + | ||
178 | + it "should create ssh key" do | ||
179 | + key_attrs = attributes_for :key | ||
180 | + expect { | ||
181 | + post api("/users/#{user.id}/keys", admin), key_attrs | ||
182 | + }.to change{ user.keys.count }.by(1) | ||
183 | + end | ||
184 | + end | ||
185 | + | ||
170 | describe "DELETE /users/:id" do | 186 | describe "DELETE /users/:id" do |
171 | before { admin } | 187 | before { admin } |
172 | 188 |
spec/routing/project_routing_spec.rb
@@ -56,7 +56,6 @@ end | @@ -56,7 +56,6 @@ end | ||
56 | # projects POST /projects(.:format) projects#create | 56 | # projects POST /projects(.:format) projects#create |
57 | # new_project GET /projects/new(.:format) projects#new | 57 | # new_project GET /projects/new(.:format) projects#new |
58 | # wall_project GET /:id/wall(.:format) projects#wall | 58 | # wall_project GET /:id/wall(.:format) projects#wall |
59 | -# graph_project GET /:id/graph(.:format) projects#graph | ||
60 | # files_project GET /:id/files(.:format) projects#files | 59 | # files_project GET /:id/files(.:format) projects#files |
61 | # edit_project GET /:id/edit(.:format) projects#edit | 60 | # edit_project GET /:id/edit(.:format) projects#edit |
62 | # project GET /:id(.:format) projects#show | 61 | # project GET /:id(.:format) projects#show |
@@ -75,10 +74,6 @@ describe ProjectsController, "routing" do | @@ -75,10 +74,6 @@ describe ProjectsController, "routing" do | ||
75 | get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') | 74 | get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') |
76 | end | 75 | end |
77 | 76 | ||
78 | - it "to #graph" do | ||
79 | - get("/gitlabhq/graph/master").should route_to('graph#show', project_id: 'gitlabhq', id: 'master') | ||
80 | - end | ||
81 | - | ||
82 | it "to #files" do | 77 | it "to #files" do |
83 | get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq') | 78 | get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq') |
84 | end | 79 | end |
@@ -202,6 +197,7 @@ describe RefsController, "routing" do | @@ -202,6 +197,7 @@ describe RefsController, "routing" do | ||
202 | it "to #logs_tree" do | 197 | it "to #logs_tree" do |
203 | get("/gitlabhq/refs/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable') | 198 | get("/gitlabhq/refs/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable') |
204 | get("/gitlabhq/refs/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') | 199 | get("/gitlabhq/refs/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') |
200 | + get("/gitlab/gitlabhq/refs/stable/logs_tree/files.scss").should route_to('refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'files.scss') | ||
205 | end | 201 | end |
206 | end | 202 | end |
207 | 203 | ||
@@ -301,6 +297,10 @@ describe CommitsController, "routing" do | @@ -301,6 +297,10 @@ describe CommitsController, "routing" do | ||
301 | let(:actions) { [:show] } | 297 | let(:actions) { [:show] } |
302 | let(:controller) { 'commits' } | 298 | let(:controller) { 'commits' } |
303 | end | 299 | end |
300 | + | ||
301 | + it "to #show" do | ||
302 | + get("/gitlab/gitlabhq/commits/master.atom").should route_to('commits#show', project_id: 'gitlab/gitlabhq', id: "master", format: "atom") | ||
303 | + end | ||
304 | end | 304 | end |
305 | 305 | ||
306 | # project_team_members GET /:project_id/team_members(.:format) team_members#index | 306 | # project_team_members GET /:project_id/team_members(.:format) team_members#index |
@@ -385,6 +385,7 @@ end | @@ -385,6 +385,7 @@ end | ||
385 | describe BlameController, "routing" do | 385 | describe BlameController, "routing" do |
386 | it "to #show" do | 386 | it "to #show" do |
387 | get("/gitlabhq/blame/master/app/models/project.rb").should route_to('blame#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') | 387 | get("/gitlabhq/blame/master/app/models/project.rb").should route_to('blame#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') |
388 | + get("/gitlab/gitlabhq/blame/master/files.scss").should route_to('blame#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') | ||
388 | end | 389 | end |
389 | end | 390 | end |
390 | 391 | ||
@@ -393,6 +394,7 @@ describe BlobController, "routing" do | @@ -393,6 +394,7 @@ describe BlobController, "routing" do | ||
393 | it "to #show" do | 394 | it "to #show" do |
394 | get("/gitlabhq/blob/master/app/models/project.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') | 395 | get("/gitlabhq/blob/master/app/models/project.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') |
395 | get("/gitlabhq/blob/master/app/models/compare.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/compare.rb') | 396 | get("/gitlabhq/blob/master/app/models/compare.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/compare.rb') |
397 | + get("/gitlab/gitlabhq/blob/master/files.scss").should route_to('blob#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') | ||
396 | end | 398 | end |
397 | end | 399 | end |
398 | 400 | ||
@@ -400,6 +402,7 @@ end | @@ -400,6 +402,7 @@ end | ||
400 | describe TreeController, "routing" do | 402 | describe TreeController, "routing" do |
401 | it "to #show" do | 403 | it "to #show" do |
402 | get("/gitlabhq/tree/master/app/models/project.rb").should route_to('tree#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') | 404 | get("/gitlabhq/tree/master/app/models/project.rb").should route_to('tree#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') |
405 | + get("/gitlab/gitlabhq/tree/master/files.scss").should route_to('tree#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') | ||
403 | end | 406 | end |
404 | end | 407 | end |
405 | 408 | ||
@@ -420,3 +423,10 @@ describe CompareController, "routing" do | @@ -420,3 +423,10 @@ describe CompareController, "routing" do | ||
420 | get("/gitlabhq/compare/issue/1234...stable").should route_to('compare#show', project_id: 'gitlabhq', from: 'issue/1234', to: 'stable') | 423 | get("/gitlabhq/compare/issue/1234...stable").should route_to('compare#show', project_id: 'gitlabhq', from: 'issue/1234', to: 'stable') |
421 | end | 424 | end |
422 | end | 425 | end |
426 | + | ||
427 | +describe GraphController, "routing" do | ||
428 | + it "to #show" do | ||
429 | + get("/gitlabhq/graph/master").should route_to('graph#show', project_id: 'gitlabhq', id: 'master') | ||
430 | + get("/gitlabhq/graph/master.json").should route_to('graph#show', project_id: 'gitlabhq', id: 'master', format: "json") | ||
431 | + end | ||
432 | +end |
spec/support/stubbed_repository.rb
@@ -43,6 +43,11 @@ class GitLabTestRepo < Repository | @@ -43,6 +43,11 @@ class GitLabTestRepo < Repository | ||
43 | def repo | 43 | def repo |
44 | @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) | 44 | @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) |
45 | end | 45 | end |
46 | + | ||
47 | + # patch repo size (in mb) | ||
48 | + def size | ||
49 | + 12.45 | ||
50 | + end | ||
46 | end | 51 | end |
47 | 52 | ||
48 | module Gitlab | 53 | module Gitlab |