Commit e6edaa3b502090f461b58c439ea476da2d37f039
Exists in
master
and in
4 other branches
Merge remote-tracking branch 'upstream/master'
Showing
64 changed files
with
763 additions
and
198 deletions
Show diff stats
Gemfile
... | ... | @@ -14,7 +14,7 @@ gem "devise", "~> 2.1.0" |
14 | 14 | gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" |
15 | 15 | gem "gitolite", :git => "https://github.com/gitlabhq/gitolite-client.git", :ref => "9b715ca8bab6529f6c92204a25f84d12f25a6eb0" |
16 | 16 | gem "pygments.rb", :git => "https://github.com/gitlabhq/pygments.rb.git", :ref => "2cada028da5054616634a1d9ca6941b65b3ce188" |
17 | -gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "7edf27d0281e09561838122982c16b7e62181f44" | |
17 | +gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e" | |
18 | 18 | gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git" |
19 | 19 | gem 'grack', :git => "https://github.com/gitlabhq/grack.git" |
20 | 20 | gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git" | ... | ... |
Gemfile.lock
... | ... | @@ -42,8 +42,8 @@ GIT |
42 | 42 | |
43 | 43 | GIT |
44 | 44 | remote: https://github.com/gitlabhq/omniauth-ldap.git |
45 | - revision: 7edf27d0281e09561838122982c16b7e62181f44 | |
46 | - ref: 7edf27d0281e09561838122982c16b7e62181f44 | |
45 | + revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e | |
46 | + ref: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e | |
47 | 47 | specs: |
48 | 48 | omniauth-ldap (1.0.2) |
49 | 49 | net-ldap (~> 0.2.2) | ... | ... |
app/assets/javascripts/note.js
app/assets/javascripts/pager.js
app/assets/stylesheets/common.scss
... | ... | @@ -337,6 +337,15 @@ p.time { |
337 | 337 | padding: 15px 5px; |
338 | 338 | &:last-child { border:none } |
339 | 339 | .wll:hover { background:none } |
340 | + | |
341 | + .event_commits { | |
342 | + margin-top: 5px; | |
343 | + | |
344 | + li.commit { | |
345 | + padding:5px; | |
346 | + border:none; | |
347 | + } | |
348 | + } | |
340 | 349 | } |
341 | 350 | |
342 | 351 | .ico { | ... | ... |
app/assets/stylesheets/gitlab_bootstrap.scss
... | ... | @@ -18,7 +18,8 @@ a { |
18 | 18 | } |
19 | 19 | |
20 | 20 | &.lined { |
21 | - text-decoration:underlined; | |
21 | + text-decoration:underline; | |
22 | + &:hover { text-decoration:underline; } | |
22 | 23 | } |
23 | 24 | |
24 | 25 | &.gray { |
... | ... | @@ -74,10 +75,6 @@ h5 { |
74 | 75 | font-size:14px; |
75 | 76 | } |
76 | 77 | |
77 | -code { | |
78 | - background:#FCEEC1; | |
79 | - color:$style_color; | |
80 | -} | |
81 | 78 | |
82 | 79 | table { |
83 | 80 | width:100%; |
... | ... | @@ -381,7 +378,6 @@ form { |
381 | 378 | min-height: 20px; |
382 | 379 | border-bottom: 1px solid #eee; |
383 | 380 | border-bottom: 1px solid rgba(0, 0, 0, 0.05); |
384 | - cursor:pointer; | |
385 | 381 | &.smoke { |
386 | 382 | background-color:#f5f5f5; |
387 | 383 | } |
... | ... | @@ -516,7 +512,8 @@ form { |
516 | 512 | .row_title { |
517 | 513 | font-weight:bold; |
518 | 514 | color:#444; |
519 | - &:hover { | |
515 | + &:hover { | |
516 | + color:#444; | |
520 | 517 | text-decoration:underline; |
521 | 518 | } |
522 | 519 | } | ... | ... |
app/assets/stylesheets/notes.scss
... | ... | @@ -14,7 +14,8 @@ |
14 | 14 | border-bottom:1px solid #aaa; |
15 | 15 | } |
16 | 16 | |
17 | -.issue_notes { | |
17 | +.issue_notes, | |
18 | +.wiki_notes { | |
18 | 19 | .note_content { |
19 | 20 | float:left; |
20 | 21 | width:400px; |
... | ... | @@ -23,8 +24,8 @@ |
23 | 24 | |
24 | 25 | /* Note textare */ |
25 | 26 | #note_note { |
26 | - height:100px; | |
27 | - width:97%; | |
27 | + height:80px; | |
28 | + width:99%; | |
28 | 29 | font-size:14px; |
29 | 30 | } |
30 | 31 | |
... | ... | @@ -99,8 +100,25 @@ tr.line_notes_row { |
99 | 100 | td { |
100 | 101 | border-bottom:1px solid #ddd; |
101 | 102 | } |
102 | - .actions { | |
103 | + .note_actions { | |
103 | 104 | margin:0; |
105 | + padding-top: 10px; | |
106 | + | |
107 | + .buttons { | |
108 | + float:left; | |
109 | + width:300px; | |
110 | + } | |
111 | + .options { | |
112 | + .labels { | |
113 | + float:left; | |
114 | + padding-left:10px; | |
115 | + label { | |
116 | + padding: 6px 0; | |
117 | + margin: 0; | |
118 | + width:120px; | |
119 | + } | |
120 | + } | |
121 | + } | |
104 | 122 | } |
105 | 123 | } |
106 | 124 | ... | ... |
app/assets/stylesheets/sections/commits.scss
... | ... | @@ -194,4 +194,16 @@ |
194 | 194 | float:right; |
195 | 195 | @extend .cgray; |
196 | 196 | } |
197 | + | |
198 | + code { | |
199 | + background:#FCEEC1; | |
200 | + color:$style_color; | |
201 | + } | |
202 | + | |
203 | + .commit_short_id { | |
204 | + float:left; | |
205 | + @extend .lined; | |
206 | + min-width:65px; | |
207 | + font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; | |
208 | + } | |
197 | 209 | } | ... | ... |
app/assets/stylesheets/sections/issues.scss
app/contexts/notes_load.rb
... | ... | @@ -17,6 +17,8 @@ class NotesLoad < BaseContext |
17 | 17 | then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20) |
18 | 18 | when "merge_request" |
19 | 19 | then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20) |
20 | + when "wiki" | |
21 | + then project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20] | |
20 | 22 | end |
21 | 23 | |
22 | 24 | @notes = if last_id | ... | ... |
app/controllers/commits_controller.rb
... | ... | @@ -17,6 +17,7 @@ class CommitsController < ApplicationController |
17 | 17 | @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) |
18 | 18 | |
19 | 19 | @commits = @project.commits(@ref, params[:path], @limit, @offset) |
20 | + @commits = CommitDecorator.decorate(@commits) | |
20 | 21 | |
21 | 22 | respond_to do |format| |
22 | 23 | format.html # index.html.erb |
... | ... | @@ -51,6 +52,8 @@ class CommitsController < ApplicationController |
51 | 52 | @commit = result[:commit] |
52 | 53 | @diffs = result[:diffs] |
53 | 54 | @line_notes = [] |
55 | + | |
56 | + @commits = CommitDecorator.decorate(@commits) | |
54 | 57 | end |
55 | 58 | |
56 | 59 | def patch | ... | ... |
app/controllers/merge_requests_controller.rb
app/controllers/omniauth_callbacks_controller.rb
... | ... | @@ -3,13 +3,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController |
3 | 3 | # Extend the standard message generation to accept our custom exception |
4 | 4 | def failure_message |
5 | 5 | exception = env["omniauth.error"] |
6 | - if exception.class == OmniAuth::Error | |
7 | - error = exception.message | |
8 | - else | |
9 | - error = exception.error_reason if exception.respond_to?(:error_reason) | |
10 | - error ||= exception.error if exception.respond_to?(:error) | |
11 | - error ||= env["omniauth.error.type"].to_s | |
12 | - end | |
6 | + error = exception.error_reason if exception.respond_to?(:error_reason) | |
7 | + error ||= exception.error if exception.respond_to?(:error) | |
8 | + error ||= exception.message if exception.respond_to?(:message) | |
9 | + error ||= env["omniauth.error.type"].to_s | |
13 | 10 | error.to_s.humanize if error |
14 | 11 | end |
15 | 12 | ... | ... |
app/controllers/refs_controller.rb
... | ... | @@ -51,7 +51,8 @@ class RefsController < ApplicationController |
51 | 51 | @logs = contents.map do |content| |
52 | 52 | file = params[:path] ? File.join(params[:path], content.name) : content.name |
53 | 53 | last_commit = @project.commits(@commit.id, file, 1).last |
54 | - { | |
54 | + last_commit = CommitDecorator.decorate(last_commit) | |
55 | + { | |
55 | 56 | :file_name => content.name, |
56 | 57 | :commit => last_commit |
57 | 58 | } | ... | ... |
app/controllers/wikis_controller.rb
... | ... | @@ -13,16 +13,16 @@ class WikisController < ApplicationController |
13 | 13 | @wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last |
14 | 14 | end |
15 | 15 | |
16 | - unless @wiki | |
17 | - return render_404 unless can?(current_user, :write_wiki, @project) | |
18 | - end | |
16 | + @note = @project.notes.new(:noteable => @wiki) | |
19 | 17 | |
20 | - respond_to do |format| | |
21 | - if @wiki | |
22 | - format.html | |
23 | - else | |
18 | + if @wiki | |
19 | + render 'show' | |
20 | + else | |
21 | + if can?(current_user, :write_wiki, @project) | |
24 | 22 | @wiki = @project.wikis.new(:slug => params[:id]) |
25 | - format.html { render "edit" } | |
23 | + render 'edit' | |
24 | + else | |
25 | + render 'empty' | |
26 | 26 | end |
27 | 27 | end |
28 | 28 | end | ... | ... |
app/mailers/notify.rb
... | ... | @@ -46,6 +46,13 @@ class Notify < ActionMailer::Base |
46 | 46 | mail(:to => recipient.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project_name} ") |
47 | 47 | end |
48 | 48 | |
49 | + def note_wiki_email(recipient_id, note_id) | |
50 | + recipient = User.find(recipient_id) | |
51 | + @note = Note.find(note_id) | |
52 | + @wiki = @note.noteable | |
53 | + mail(:to => recipient.email, :subject => "gitlab | note for wiki | #{@note.project_name}") | |
54 | + end | |
55 | + | |
49 | 56 | def new_merge_request_email(merge_request_id) |
50 | 57 | @merge_request = MergeRequest.find(merge_request_id) |
51 | 58 | mail(:to => @merge_request.assignee_email, :subject => "gitlab | new merge request | #{@merge_request.title} ") | ... | ... |
app/models/commit.rb
... | ... | @@ -114,6 +114,10 @@ class Commit |
114 | 114 | @head = head |
115 | 115 | end |
116 | 116 | |
117 | + def short_id(length = 10) | |
118 | + id.to_s[0..length] | |
119 | + end | |
120 | + | |
117 | 121 | def safe_message |
118 | 122 | utf8 message |
119 | 123 | end |
... | ... | @@ -150,4 +154,8 @@ class Commit |
150 | 154 | def prev_commit_id |
151 | 155 | prev_commit.try :id |
152 | 156 | end |
157 | + | |
158 | + def parents_count | |
159 | + parents && parents.count || 0 | |
160 | + end | |
153 | 161 | end | ... | ... |
app/models/wiki.rb
app/observers/mailer_observer.rb
... | ... | @@ -34,6 +34,7 @@ class MailerObserver < ActiveRecord::Observer |
34 | 34 | case note.noteable_type |
35 | 35 | when "Commit"; Notify.note_commit_email(u.id, note.id).deliver |
36 | 36 | when "Issue"; Notify.note_issue_email(u.id, note.id).deliver |
37 | + when "Wiki"; Notify.note_wiki_email(u.id, note.id).deliver | |
37 | 38 | when "MergeRequest"; Notify.note_merge_request_email(u.id, note.id).deliver |
38 | 39 | when "Snippet"; true |
39 | 40 | else | ... | ... |
app/views/commits/_commit.html.haml
... | ... | @@ -2,16 +2,15 @@ |
2 | 2 | .browse_code_link_holder |
3 | 3 | %p |
4 | 4 | %strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), :class => "right" |
5 | - = link_to project_commit_path(@project, :id => commit.id) do | |
6 | - %p | |
7 | - %code.left= commit.id.to_s[0..10] | |
8 | - %strong.cgray= commit.author_name | |
9 | - – | |
10 | - = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 | |
11 | - %span.row_title= truncate(commit.safe_message, :length => 50) | |
5 | + %p | |
6 | + = link_to commit.short_id(8), project_commit_path(@project, :id => commit.id), :class => "commit_short_id" | |
7 | + %strong.cgray= commit.author_name | |
8 | + – | |
9 | + = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 | |
10 | + = link_to truncate(commit.title, :length => 50), project_commit_path(@project, :id => commit.id), :class => "row_title" | |
12 | 11 | |
13 | - %span.committed_ago | |
14 | - = time_ago_in_words(commit.committed_date) | |
15 | - ago | |
16 | - | |
12 | + %span.committed_ago | |
13 | + = time_ago_in_words(commit.committed_date) | |
14 | + ago | |
15 | + | |
17 | 16 | ... | ... |
app/views/commits/_commit_box.html.haml
app/views/commits/compare.html.haml
app/views/commits/index.atom.builder
... | ... | @@ -10,14 +10,14 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear |
10 | 10 | xml.entry do |
11 | 11 | xml.id project_commit_url(@project, :id => commit.id) |
12 | 12 | xml.link :href => project_commit_url(@project, :id => commit.id) |
13 | - xml.title truncate(commit.safe_message, :length => 80) | |
13 | + xml.title truncate(commit.title, :length => 80) | |
14 | 14 | xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") |
15 | 15 | xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email) |
16 | 16 | xml.author do |author| |
17 | 17 | xml.name commit.author_name |
18 | 18 | xml.email commit.author_email |
19 | 19 | end |
20 | - xml.summary commit.safe_message | |
20 | + xml.summary commit.description | |
21 | 21 | end |
22 | 22 | end |
23 | 23 | end | ... | ... |
app/views/dashboard/merge_requests.html.haml
app/views/errors/gitolite.html.haml
1 | 1 | .alert-message.block-message.error |
2 | 2 | %h3 Gitolite Error |
3 | - %hr | |
4 | 3 | %h4 Application cant get access to your gitolite system. |
5 | - %ol | |
6 | - %li | |
7 | - %p | |
8 | - Check 'config/gitlab.yml' for correct settings. | |
9 | - %li | |
10 | - %p | |
11 | - Make sure web server user has access to gitolite. | |
12 | - %a{:href => "https://github.com/gitlabhq/gitlabhq/wiki/Gitolite"} Setup tutorial | |
13 | - %li | |
14 | - %p | |
15 | - Try: | |
4 | + | |
5 | + | |
6 | + | |
7 | + | |
8 | +%h4 Tips for Administrator: | |
9 | + | |
10 | +%ul | |
11 | + %li | |
12 | + %p | |
13 | + Check git logs in admin area | |
14 | + %li | |
15 | + %p | |
16 | + Check config/gitlab.yml for correct settings. | |
17 | + %li | |
18 | + %p | |
19 | + Diagnostic tool: | |
16 | 20 | %pre |
17 | - = preserve do | |
18 | - sudo chmod -R 770 /home/git/repositories/ | |
19 | - sudo chown -R git:git /home/git/repositories/ | |
21 | + bundle exec rake gitlab:app:status RAILS_ENV=production | |
22 | + %li | |
23 | + %p | |
24 | + Permissions: | |
25 | + %pre | |
26 | + = preserve do | |
27 | + sudo chmod -R 770 /home/git/repositories/ | |
28 | + sudo chown -R git:git /home/git/repositories/ | |
29 | + sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive | |
30 | + | ... | ... |
app/views/events/_commit.html.haml
1 | +- commit = CommitDecorator.decorate(commit) | |
1 | 2 | %li.wll.commit |
2 | - = link_to project_commit_path(project, :id => commit.id) do | |
3 | - %p | |
4 | - %code.left= commit.id.to_s[0..10] | |
5 | - %strong.cgray= commit.author_name | |
6 | - – | |
7 | - = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 | |
8 | - %span.row_title= truncate(commit.safe_message, :length => 50) rescue "--broken encoding" | |
3 | + %p | |
4 | + = link_to commit.short_id(8), project_commit_path(project, :id => commit.id), :class => "commit_short_id" | |
5 | + %strong.cdark= commit.author_name | |
6 | + – | |
7 | + = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 | |
8 | + = truncate(commit.title, :length => 50) rescue "--broken encoding" | |
9 | 9 | ... | ... |
app/views/help/api.html.haml
1 | 1 | %h3 API |
2 | 2 | .back_link |
3 | - = link_to help_path do | |
3 | + = link_to help_path do | |
4 | 4 | ← to index |
5 | 5 | %hr |
6 | 6 | |
7 | 7 | %ol |
8 | - %li | |
8 | + %li | |
9 | 9 | %a{:href => "#README"} README |
10 | - %li | |
10 | + %li | |
11 | 11 | %a{:href => "#projects"} Projects |
12 | - %li | |
12 | + %li | |
13 | 13 | %a{:href => "#users"} Users |
14 | + %li | |
15 | + %a{:href => "#issues"} Issues | |
14 | 16 | |
15 | 17 | .file_holder#README |
16 | 18 | .file_title |
... | ... | @@ -39,3 +41,13 @@ |
39 | 41 | .file_content.wiki |
40 | 42 | = preserve do |
41 | 43 | = markdown File.read(Rails.root.join("doc", "api", "users.md")) |
44 | + | |
45 | +%br | |
46 | + | |
47 | +.file_holder#issues | |
48 | + .file_title | |
49 | + %i.icon-file | |
50 | + Issues | |
51 | + .file_content.wiki | |
52 | + = preserve do | |
53 | + = markdown File.read(Rails.root.join("doc", "api", "issues.md")) | ... | ... |
app/views/help/permissions.html.haml
... | ... | @@ -38,7 +38,6 @@ |
38 | 38 | %li Push to non-protected branches |
39 | 39 | %li Remove non-protected branches |
40 | 40 | %li Add tags |
41 | - %li Create new merge request | |
42 | 41 | %li Write a wiki |
43 | 42 | |
44 | 43 | .ui-box.span3 |
... | ... | @@ -55,7 +54,6 @@ |
55 | 54 | %li Push to non-protected branches |
56 | 55 | %li Remove non-protected branches |
57 | 56 | %li Add tags |
58 | - %li Create new merge request | |
59 | 57 | %li Write a wiki |
60 | 58 | %li Add new team members |
61 | 59 | %li Push to protected branches | ... | ... |
app/views/issues/_show.html.haml
... | ... | @@ -24,8 +24,7 @@ |
24 | 24 | - else |
25 | 25 | = image_tag "no_avatar.png", :class => "avatar" |
26 | 26 | |
27 | - = link_to project_issue_path(issue.project, issue) do | |
28 | - %p.row_title= truncate(issue.title, :length => 100) | |
27 | + %p= link_to truncate(issue.title, :length => 100), project_issue_path(issue.project, issue), :class => "row_title" | |
29 | 28 | |
30 | 29 | %span.update-author |
31 | 30 | %small.cdark= "##{issue.id}" | ... | ... |
app/views/issues/show.html.haml
... | ... | @@ -46,9 +46,7 @@ |
46 | 46 | - if @issue.milestone |
47 | 47 | - milestone = @issue.milestone |
48 | 48 | %cite.cgray and attached to milestone |
49 | - = link_to project_milestone_path(milestone.project, milestone) do | |
50 | - %strong | |
51 | - = truncate(milestone.title, :length => 20) | |
49 | + %strong= link_to truncate(milestone.title, :length => 20), project_milestone_path(milestone.project, milestone) | |
52 | 50 | |
53 | 51 | .right |
54 | 52 | - @issue.labels.each do |label| | ... | ... |
app/views/merge_requests/_merge_request.html.haml
... | ... | @@ -16,8 +16,7 @@ |
16 | 16 | = merge_request.target_branch |
17 | 17 | = image_tag gravatar_icon(merge_request.author_email), :class => "avatar" |
18 | 18 | |
19 | - = link_to project_merge_request_path(merge_request.project, merge_request) do | |
20 | - %p.row_title= truncate(merge_request.title, :length => 80) | |
19 | + %p= link_to truncate(merge_request.title, :length => 80), project_merge_request_path(merge_request.project, merge_request), :class => "row_title" | |
21 | 20 | |
22 | 21 | %span.update-author |
23 | 22 | %small.cdark= "##{merge_request.id}" | ... | ... |
app/views/milestones/_milestone.html.haml
... | ... | @@ -6,14 +6,13 @@ |
6 | 6 | = link_to 'Browse Issues', project_issues_path(milestone.project, :milestone_id => milestone.id), :class => "btn small grouped" |
7 | 7 | - if can? current_user, :admin_milestone, milestone.project |
8 | 8 | = link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), :class => "btn small edit-milestone-link grouped" |
9 | - = link_to project_milestone_path(milestone.project, milestone) do | |
10 | - %h4.row_title | |
11 | - = truncate(milestone.title, :length => 100) | |
12 | - %small | |
13 | - = milestone.expires_at | |
14 | - %br | |
15 | - .progress.progress-success.span3 | |
16 | - .bar{:style => "width: #{milestone.percent_complete}%;"} | |
9 | + %h4 | |
10 | + = link_to truncate(milestone.title, :length => 100), project_milestone_path(milestone.project, milestone), :class => "row_title" | |
11 | + %small | |
12 | + = milestone.expires_at | |
13 | + %br | |
14 | + .progress.progress-success.span3 | |
15 | + .bar{:style => "width: #{milestone.percent_complete}%;"} | |
17 | 16 | |
18 | 17 | |
19 | 18 | | ... | ... |
app/views/milestones/show.html.haml
... | ... | @@ -50,8 +50,8 @@ |
50 | 50 | %td |
51 | 51 | = link_to [@project, issue] do |
52 | 52 | %span.badge.badge-info ##{issue.id} |
53 | - – | |
54 | - = truncate issue.title, :length => 60 | |
53 | + – | |
54 | + = link_to truncate(issue.title, :length => 60), [@project, issue] | |
55 | 55 | %br |
56 | 56 | = paginate @issues, :theme => "gitlab" |
57 | 57 | ... | ... |
app/views/notes/_form.html.haml
app/views/notes/_per_line_form.html.haml
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | %tr.per_line_form |
3 | 3 | %td{:colspan => 3 } |
4 | 4 | = form_for [@project, @note], :remote => "true", :multipart => true do |f| |
5 | - %h3 Leave a note | |
5 | + %h3.page_title Leave a note | |
6 | 6 | %div.span10 |
7 | 7 | -if @note.errors.any? |
8 | 8 | .alert-message.block-message.error |
... | ... | @@ -13,19 +13,21 @@ |
13 | 13 | = f.hidden_field :noteable_type |
14 | 14 | = f.hidden_field :line_code |
15 | 15 | = f.text_area :note, :size => 255 |
16 | - %h5 Notify via email: | |
17 | - .clearfix | |
18 | - = label_tag :notify do | |
19 | - = check_box_tag :notify, 1, @note.noteable_type != "Commit" | |
20 | - %span Project team | |
16 | + .note_actions | |
17 | + .buttons | |
18 | + = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note" | |
19 | + = link_to "Cancel", "#", :class => "btn hide-button" | |
20 | + .options | |
21 | + %h6.left Notify via email: | |
22 | + .labels | |
23 | + = label_tag :notify do | |
24 | + = check_box_tag :notify, 1, @note.noteable_type != "Commit" | |
25 | + %span Project team | |
21 | 26 | |
22 | - - if @note.notify_only_author?(current_user) | |
23 | - = label_tag :notify_author do | |
24 | - = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" | |
25 | - %span Commit author | |
26 | - .actions | |
27 | - = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note" | |
28 | - = link_to "Close", "#", :class => "btn hide-button" | |
27 | + - if @note.notify_only_author?(current_user) | |
28 | + = label_tag :notify_author do | |
29 | + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" | |
30 | + %span Commit author | |
29 | 31 | |
30 | 32 | :javascript |
31 | 33 | $(function(){ | ... | ... |
... | ... | @@ -0,0 +1,24 @@ |
1 | +%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} | |
2 | + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} | |
3 | + %tr | |
4 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | |
5 | + %td{:align => "left", :style => "padding: 20px 0 0;"} | |
6 | + %h2{:style => "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} | |
7 | + New comment - | |
8 | + = link_to project_issue_url(@wiki.project, @wiki, :anchor => "note_#{@note.id}") do | |
9 | + = "Wiki ##{@wiki.title.to_s}" | |
10 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | |
11 | + %tr | |
12 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | |
13 | + %td{:style => "padding: 15px 0 15px;", :valign => "top"} | |
14 | + %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} | |
15 | + %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} | |
16 | + commented on Wiki page: | |
17 | + %br | |
18 | + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"} | |
19 | + %tr | |
20 | + %td{:valign => "top"} | |
21 | + %div{ :style => "background:#f5f5f5; padding:20px;border:1px solid #ddd" } | |
22 | + = markdown(@note.note) | |
23 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | |
24 | + | ... | ... |
app/views/projects/files.html.haml
app/views/refs/_tree_commit.html.haml
1 | 1 | - if tm |
2 | 2 | %strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm) |
3 | -= link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link" | |
3 | += link_to truncate(content_commit.title, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link" | ... | ... |
app/views/refs/blame.html.haml
... | ... | @@ -25,15 +25,15 @@ |
25 | 25 | %table |
26 | 26 | - @blame.each do |commit, lines| |
27 | 27 | - commit = Commit.new(commit) |
28 | + - commit = CommitDecorator.decorate(commit) | |
28 | 29 | %tr |
29 | 30 | %td.author |
30 | 31 | = image_tag gravatar_icon(commit.author_email, 16) |
31 | 32 | = commit.author_name |
32 | 33 | %td.blame_commit |
33 | 34 | |
34 | - = link_to project_commit_path(@project, :id => commit.id) do | |
35 | - %code= commit.id.to_s[0..10] | |
36 | - %span.row_title= truncate(commit.safe_message, :length => 30) rescue "--broken encoding" | |
35 | + %code= link_to commit.short_id, project_commit_path(@project, :id => commit.id) | |
36 | + = link_to truncate(commit.title, :length => 30), project_commit_path(@project, :id => commit.id), :class => "row_title" rescue "--broken encoding" | |
37 | 37 | %td.lines |
38 | 38 | = preserve do |
39 | 39 | %pre | ... | ... |
app/views/repositories/_branch.html.haml
1 | +- commit = Commit.new(branch.commit) | |
2 | +- commit = CommitDecorator.decorate(commit) | |
1 | 3 | %tr |
2 | 4 | %td |
3 | 5 | = link_to project_commits_path(@project, :ref => branch.name) do |
... | ... | @@ -5,14 +7,14 @@ |
5 | 7 | - if branch.name == @project.root_ref |
6 | 8 | %span.label default |
7 | 9 | %td |
8 | - = link_to project_commit_path(@project, :id => branch.commit.id) do | |
9 | - %code= branch.commit.id.to_s[0..10] | |
10 | + = link_to project_commit_path(@project, :id => commit.id) do | |
11 | + %code= commit.short_id | |
10 | 12 | |
11 | - = image_tag gravatar_icon(Commit.new(branch.commit).author_email), :class => "", :width => 16 | |
12 | - = truncate(Commit.new(branch.commit).safe_message, :length => 40) | |
13 | + = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 | |
14 | + = truncate(commit.title, :length => 40) | |
13 | 15 | %td |
14 | 16 | %span.update-author.right |
15 | - = time_ago_in_words(branch.commit.committed_date) | |
17 | + = time_ago_in_words(commit.committed_date) | |
16 | 18 | ago |
17 | 19 | %td |
18 | 20 | - if can? current_user, :download_code, @project | ... | ... |
app/views/repositories/_feed.html.haml
1 | 1 | - commit = update |
2 | +- commit = CommitDecorator.new(commit) | |
2 | 3 | %tr |
3 | 4 | %td |
4 | 5 | = link_to project_commits_path(@project, :ref => commit.head.name) do |
... | ... | @@ -10,9 +11,9 @@ |
10 | 11 | %td |
11 | 12 | %div |
12 | 13 | = link_to project_commits_path(@project, commit.id) do |
13 | - %code= commit.id.to_s[0..10] | |
14 | + %code= commit.short_id | |
14 | 15 | = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 |
15 | - = truncate(commit.safe_message, :length => 40) | |
16 | + = truncate(commit.title, :length => 40) | |
16 | 17 | %td |
17 | 18 | %span.right.cgray |
18 | 19 | = time_ago_in_words(commit.committed_date) | ... | ... |
app/views/repositories/tags.html.haml
... | ... | @@ -9,14 +9,15 @@ |
9 | 9 | %th |
10 | 10 | - @tags.each do |tag| |
11 | 11 | - commit = Commit.new(tag.commit) |
12 | + - commit = CommitDecorator.decorate(commit) | |
12 | 13 | %tr |
13 | 14 | %td |
14 | 15 | %strong= link_to tag.name, project_commits_path(@project, :ref => tag.name), :class => "" |
15 | 16 | %td |
16 | 17 | = link_to project_commit_path(@project, commit.id) do |
17 | - %code= commit.id.to_s[0..10] | |
18 | + %code= commit.short_id | |
18 | 19 | = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 |
19 | - = truncate(commit.safe_message, :length => 40) | |
20 | + = truncate(commit.title, :length => 40) | |
20 | 21 | %td |
21 | 22 | %span.update-author.right |
22 | 23 | = time_ago_in_words(commit.committed_date) | ... | ... |
app/views/wikis/_form.html.haml
... | ... | @@ -6,19 +6,21 @@ |
6 | 6 | - @wiki.errors.full_messages.each do |msg| |
7 | 7 | %li= msg |
8 | 8 | |
9 | - .alert-message.block-message.warning | |
10 | - %p | |
11 | - Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}. | |
12 | - %br | |
13 | - To add link to new page you can just type | |
14 | - %code [Link Title](page-slug) | |
15 | - .clearfix | |
16 | - = f.label :title | |
17 | - .input= f.text_field :title, :class => :xxlarge | |
18 | - = f.hidden_field :slug | |
19 | - .clearfix | |
20 | - = f.label :content | |
21 | - .input= f.text_area :content, :class => :xxlarge | |
9 | + .main_box | |
10 | + .top_box_content | |
11 | + = f.label :title | |
12 | + .input= f.text_field :title, :class => 'span8' | |
13 | + = f.hidden_field :slug | |
14 | + .middle_box_content | |
15 | + .input | |
16 | + %span.cgray | |
17 | + Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}. | |
18 | + To add link to new page you can just type | |
19 | + %code [Link Title](page-slug) | |
20 | + | |
21 | + .bottom_box_content | |
22 | + = f.label :content | |
23 | + .input= f.text_area :content, :class => 'span8' | |
22 | 24 | .actions |
23 | 25 | = f.submit 'Save', :class => "primary btn" |
24 | 26 | = link_to "Cancel", project_wiki_path(@project, :index), :class => "btn" | ... | ... |
app/views/wikis/edit.html.haml
app/views/wikis/history.html.haml
app/views/wikis/show.html.haml
... | ... | @@ -5,13 +5,18 @@ |
5 | 5 | = link_to history_project_wiki_path(@project, @wiki), :class => "btn small grouped" do |
6 | 6 | History |
7 | 7 | = link_to edit_project_wiki_path(@project, @wiki), :class => "btn small grouped" do |
8 | + %i.icon-edit | |
8 | 9 | Edit |
9 | -%hr | |
10 | -.wiki_content | |
11 | - = preserve do | |
12 | - = markdown @wiki.content | |
10 | +%br | |
11 | +.file_holder | |
12 | + .file_content.wiki | |
13 | + = preserve do | |
14 | + = markdown @wiki.content | |
13 | 15 | |
14 | 16 | %p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago |
15 | 17 | - if can? current_user, :admin_wiki, @project |
16 | 18 | = link_to project_wiki_path(@project, @wiki), :confirm => "Are you sure you want to delete this page?", :method => :delete do |
17 | 19 | Delete this page |
20 | + | |
21 | +%hr | |
22 | +.wiki_notes#notes= render "notes/notes", :tid => @wiki.id, :tt => "wiki" | ... | ... |
doc/api/README.md
... | ... | @@ -27,3 +27,4 @@ The API uses JSON to serialize data. You don't need to specify `.json` at the en |
27 | 27 | |
28 | 28 | + [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md) |
29 | 29 | + [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md) |
30 | ++ [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md) | ... | ... |
... | ... | @@ -0,0 +1,184 @@ |
1 | +## List issues | |
2 | + | |
3 | +Get all issues created by authenticed user. | |
4 | + | |
5 | +``` | |
6 | +GET /issues | |
7 | +``` | |
8 | + | |
9 | +```json | |
10 | +[ | |
11 | + { | |
12 | + "id": 43, | |
13 | + "project_id": 8, | |
14 | + "title": "4xx/5xx pages", | |
15 | + "description": "", | |
16 | + "labels": [ ], | |
17 | + "milestone": null, | |
18 | + "assignee": null, | |
19 | + "author": { | |
20 | + "id": 1, | |
21 | + "email": "john@example.com", | |
22 | + "name": "John Smith", | |
23 | + "blocked": false, | |
24 | + "created_at": "2012-05-23T08:00:58Z" | |
25 | + }, | |
26 | + "closed": true, | |
27 | + "updated_at": "2012-07-02T17:53:12Z", | |
28 | + "created_at": "2012-07-02T17:53:12Z" | |
29 | + }, | |
30 | + { | |
31 | + "id": 42, | |
32 | + "project_id": 8, | |
33 | + "title": "Add user settings", | |
34 | + "description": "", | |
35 | + "labels": [ | |
36 | + "feature" | |
37 | + ], | |
38 | + "milestone": { | |
39 | + "id": 1, | |
40 | + "title": "v1.0", | |
41 | + "description": "", | |
42 | + "due_date": "2012-07-20", | |
43 | + "closed": false, | |
44 | + "updated_at": "2012-07-04T13:42:48Z", | |
45 | + "created_at": "2012-07-04T13:42:48Z" | |
46 | + }, | |
47 | + "assignee": { | |
48 | + "id": 2, | |
49 | + "email": "jack@example.com", | |
50 | + "name": "Jack Smith", | |
51 | + "blocked": false, | |
52 | + "created_at": "2012-05-23T08:01:01Z" | |
53 | + }, | |
54 | + "author": { | |
55 | + "id": 1, | |
56 | + "email": "john@example.com", | |
57 | + "name": "John Smith", | |
58 | + "blocked": false, | |
59 | + "created_at": "2012-05-23T08:00:58Z" | |
60 | + }, | |
61 | + "closed": false, | |
62 | + "updated_at": "2012-07-12T13:43:19Z", | |
63 | + "created_at": "2012-06-28T12:58:06Z" | |
64 | + } | |
65 | +] | |
66 | +``` | |
67 | + | |
68 | +## List project issues | |
69 | + | |
70 | +Get a list of project issues. | |
71 | + | |
72 | +``` | |
73 | +GET /projects/:id/issues | |
74 | +``` | |
75 | + | |
76 | +Parameters: | |
77 | + | |
78 | ++ `id` (required) - The ID or code name of a project | |
79 | + | |
80 | +## Single issue | |
81 | + | |
82 | +Get a project issue. | |
83 | + | |
84 | +``` | |
85 | +GET /projects/:id/issues/:issue_id | |
86 | +``` | |
87 | + | |
88 | +Parameters: | |
89 | + | |
90 | ++ `id` (required) - The ID or code name of a project | |
91 | ++ `issue_id` (required) - The ID of a project issue | |
92 | + | |
93 | +```json | |
94 | +{ | |
95 | + "id": 42, | |
96 | + "project_id": 8, | |
97 | + "title": "Add user settings", | |
98 | + "description": "", | |
99 | + "labels": [ | |
100 | + "feature" | |
101 | + ], | |
102 | + "milestone": { | |
103 | + "id": 1, | |
104 | + "title": "v1.0", | |
105 | + "description": "", | |
106 | + "due_date": "2012-07-20", | |
107 | + "closed": false, | |
108 | + "updated_at": "2012-07-04T13:42:48Z", | |
109 | + "created_at": "2012-07-04T13:42:48Z" | |
110 | + }, | |
111 | + "assignee": { | |
112 | + "id": 2, | |
113 | + "email": "jack@example.com", | |
114 | + "name": "Jack Smith", | |
115 | + "blocked": false, | |
116 | + "created_at": "2012-05-23T08:01:01Z" | |
117 | + }, | |
118 | + "author": { | |
119 | + "id": 1, | |
120 | + "email": "john@example.com", | |
121 | + "name": "John Smith", | |
122 | + "blocked": false, | |
123 | + "created_at": "2012-05-23T08:00:58Z" | |
124 | + }, | |
125 | + "closed": false, | |
126 | + "updated_at": "2012-07-12T13:43:19Z", | |
127 | + "created_at": "2012-06-28T12:58:06Z" | |
128 | +} | |
129 | +``` | |
130 | + | |
131 | +## New issue | |
132 | + | |
133 | +Create a new project issue. | |
134 | + | |
135 | +``` | |
136 | +POST /projects/:id/issues | |
137 | +``` | |
138 | + | |
139 | +Parameters: | |
140 | + | |
141 | ++ `id` (required) - The ID or code name of a project | |
142 | ++ `title` (required) - The title of an issue | |
143 | ++ `description` (optional) - The description of an issue | |
144 | ++ `assignee_id` (optional) - The ID of a user to assign issue | |
145 | ++ `milestone_id` (optional) - The ID of a milestone to assign issue | |
146 | ++ `labels` (optional) - Comma-separated label names for an issue | |
147 | + | |
148 | +Will return created issue with status `201 Created` on success, or `404 Not found` on fail. | |
149 | + | |
150 | +## Edit issue | |
151 | + | |
152 | +Update an existing project issue. | |
153 | + | |
154 | +``` | |
155 | +PUT /projects/:id/issues/:issue_id | |
156 | +``` | |
157 | + | |
158 | +Parameters: | |
159 | + | |
160 | ++ `id` (required) - The ID or code name of a project | |
161 | ++ `issue_id` (required) - The ID of a project's issue | |
162 | ++ `title` (optional) - The title of an issue | |
163 | ++ `description` (optional) - The description of an issue | |
164 | ++ `assignee_id` (optional) - The ID of a user to assign issue | |
165 | ++ `milestone_id` (optional) - The ID of a milestone to assign issue | |
166 | ++ `labels` (optional) - Comma-separated label names for an issue | |
167 | ++ `closed` (optional) - The state of an issue (0 = false, 1 = true) | |
168 | + | |
169 | +Will return updated issue with status `200 OK` on success, or `404 Not found` on fail. | |
170 | + | |
171 | +## Delete issue | |
172 | + | |
173 | +Delete existing project issue. | |
174 | + | |
175 | +``` | |
176 | +DELETE /projects/:id/issues/:issue_id | |
177 | +``` | |
178 | + | |
179 | +Parameters: | |
180 | + | |
181 | ++ `id` (required) - The ID or code name of a project | |
182 | ++ `issue_id` (required) - The ID of a project's issue | |
183 | + | |
184 | +Status code `200` will be returned on success. | ... | ... |
doc/api/projects.md
1 | 1 | ## List projects |
2 | 2 | |
3 | -Get a list of authenticated users' projects. | |
3 | +Get a list of authenticated user's projects. | |
4 | 4 | |
5 | 5 | ``` |
6 | 6 | GET /projects |
... | ... | @@ -63,7 +63,7 @@ GET /projects/:id |
63 | 63 | |
64 | 64 | Parameters: |
65 | 65 | |
66 | -+ `id` (required) - The code name of a project | |
66 | ++ `id` (required) - The ID or code name of a project | |
67 | 67 | |
68 | 68 | ```json |
69 | 69 | { |
... | ... | @@ -91,7 +91,7 @@ Parameters: |
91 | 91 | |
92 | 92 | ## Project repository branches |
93 | 93 | |
94 | -Get a list of project repository branches. | |
94 | +Get a list of project repository branches sorted by name alphabetically. | |
95 | 95 | |
96 | 96 | ``` |
97 | 97 | GET /projects/:id/repository/branches |
... | ... | @@ -99,7 +99,7 @@ GET /projects/:id/repository/branches |
99 | 99 | |
100 | 100 | Parameters: |
101 | 101 | |
102 | -+ `id` (required) - The code name of a project | |
102 | ++ `id` (required) - The ID or code name of a project | |
103 | 103 | |
104 | 104 | ```json |
105 | 105 | [ |
... | ... | @@ -131,7 +131,7 @@ Parameters: |
131 | 131 | |
132 | 132 | ## Project repository tags |
133 | 133 | |
134 | -Get a list of project repository tags. | |
134 | +Get a list of project repository tags sorted by name in reverse alphabetical order. | |
135 | 135 | |
136 | 136 | ``` |
137 | 137 | GET /projects/:id/repository/tags |
... | ... | @@ -139,7 +139,7 @@ GET /projects/:id/repository/tags |
139 | 139 | |
140 | 140 | Parameters: |
141 | 141 | |
142 | -+ `id` (required) - The code name of a project | |
142 | ++ `id` (required) - The ID or code name of a project | |
143 | 143 | |
144 | 144 | ```json |
145 | 145 | [ |
... | ... | @@ -183,7 +183,7 @@ GET /projects/:id/snippets/:snippet_id |
183 | 183 | |
184 | 184 | Parameters: |
185 | 185 | |
186 | -+ `id` (required) - The code name of a project | |
186 | ++ `id` (required) - The ID or code name of a project | |
187 | 187 | + `snippet_id` (required) - The ID of a project's snippet |
188 | 188 | |
189 | 189 | ```json |
... | ... | @@ -214,7 +214,7 @@ GET /projects/:id/snippets/:snippet_id/raw |
214 | 214 | |
215 | 215 | Parameters: |
216 | 216 | |
217 | -+ `id` (required) - The code name of a project | |
217 | ++ `id` (required) - The ID or code name of a project | |
218 | 218 | + `snippet_id` (required) - The ID of a project's snippet |
219 | 219 | |
220 | 220 | ## New snippet |
... | ... | @@ -227,7 +227,7 @@ POST /projects/:id/snippets |
227 | 227 | |
228 | 228 | Parameters: |
229 | 229 | |
230 | -+ `id` (required) - The code name of a project | |
230 | ++ `id` (required) - The ID or code name of a project | |
231 | 231 | + `title` (required) - The title of a snippet |
232 | 232 | + `file_name` (required) - The name of a snippet file |
233 | 233 | + `lifetime` (optional) - The expiration date of a snippet |
... | ... | @@ -245,7 +245,7 @@ PUT /projects/:id/snippets/:snippet_id |
245 | 245 | |
246 | 246 | Parameters: |
247 | 247 | |
248 | -+ `id` (required) - The code name of a project | |
248 | ++ `id` (required) - The ID or code name of a project | |
249 | 249 | + `snippet_id` (required) - The ID of a project's snippet |
250 | 250 | + `title` (optional) - The title of a snippet |
251 | 251 | + `file_name` (optional) - The name of a snippet file |
... | ... | @@ -264,7 +264,7 @@ DELETE /projects/:id/snippets/:snippet_id |
264 | 264 | |
265 | 265 | Parameters: |
266 | 266 | |
267 | -+ `id` (required) - The code name of a project | |
267 | ++ `id` (required) - The ID or code name of a project | |
268 | 268 | + `snippet_id` (required) - The ID of a project's snippet |
269 | 269 | |
270 | 270 | Status code `200` will be returned on success. | ... | ... |
doc/installation.md
... | ... | @@ -119,6 +119,7 @@ Permissions: |
119 | 119 | |
120 | 120 | sudo chmod -R g+rwX /home/git/repositories/ |
121 | 121 | sudo chown -R git:git /home/git/repositories/ |
122 | + sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive | |
122 | 123 | |
123 | 124 | #### CHECK: Logout & login again to apply git group to your user |
124 | 125 | ... | ... |
features/step_definitions/project_commits_steps.rb
... | ... | @@ -16,11 +16,11 @@ Given /^I click atom feed link$/ do |
16 | 16 | end |
17 | 17 | |
18 | 18 | Then /^I see commits atom feed$/ do |
19 | - commit = @project.commit | |
19 | + commit = CommitDecorator.decorate(@project.commit) | |
20 | 20 | page.response_headers['Content-Type'].should have_content("application/atom+xml") |
21 | 21 | page.body.should have_selector("title", :text => "Recent commits to #{@project.name}") |
22 | 22 | page.body.should have_selector("author email", :text => commit.author_email) |
23 | - page.body.should have_selector("entry summary", :text => commit.message) | |
23 | + page.body.should have_selector("entry summary", :text => commit.description) | |
24 | 24 | end |
25 | 25 | |
26 | 26 | Given /^I click on commit link$/ do | ... | ... |
lib/api.rb
lib/api/entities.rb
... | ... | @@ -16,11 +16,7 @@ module Gitlab |
16 | 16 | expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at |
17 | 17 | end |
18 | 18 | |
19 | - class ProjectRepositoryBranches < Grape::Entity | |
20 | - expose :name, :commit | |
21 | - end | |
22 | - | |
23 | - class ProjectRepositoryTags < Grape::Entity | |
19 | + class RepoObject < Grape::Entity | |
24 | 20 | expose :name, :commit |
25 | 21 | end |
26 | 22 | |
... | ... | @@ -29,5 +25,19 @@ module Gitlab |
29 | 25 | expose :author, :using => Entities::UserBasic |
30 | 26 | expose :expires_at, :updated_at, :created_at |
31 | 27 | end |
28 | + | |
29 | + class Milestone < Grape::Entity | |
30 | + expose :id, :title, :description, :due_date, :closed, :updated_at, :created_at | |
31 | + end | |
32 | + | |
33 | + class Issue < Grape::Entity | |
34 | + expose :id | |
35 | + expose (:project_id) {|issue| issue.project.id} | |
36 | + expose :title, :description | |
37 | + expose :label_list, :as => :labels | |
38 | + expose :milestone, :using => Entities::Milestone | |
39 | + expose :assignee, :author, :using => Entities::UserBasic | |
40 | + expose :closed, :updated_at, :created_at | |
41 | + end | |
32 | 42 | end |
33 | 43 | end | ... | ... |
lib/api/helpers.rb
... | ... | @@ -4,6 +4,16 @@ module Gitlab |
4 | 4 | @current_user ||= User.find_by_authentication_token(params[:private_token]) |
5 | 5 | end |
6 | 6 | |
7 | + def user_project | |
8 | + if @project ||= current_user.projects.find_by_id(params[:id]) || | |
9 | + current_user.projects.find_by_code(params[:id]) | |
10 | + else | |
11 | + error!({'message' => '404 Not found'}, 404) | |
12 | + end | |
13 | + | |
14 | + @project | |
15 | + end | |
16 | + | |
7 | 17 | def authenticate! |
8 | 18 | error!({'message' => '401 Unauthorized'}, 401) unless current_user |
9 | 19 | end | ... | ... |
... | ... | @@ -0,0 +1,111 @@ |
1 | +module Gitlab | |
2 | + # Issues API | |
3 | + class Issues < Grape::API | |
4 | + before { authenticate! } | |
5 | + | |
6 | + resource :issues do | |
7 | + # Get currently authenticated user's issues | |
8 | + # | |
9 | + # Example Request: | |
10 | + # GET /issues | |
11 | + get do | |
12 | + present current_user.issues, :with => Entities::Issue | |
13 | + end | |
14 | + end | |
15 | + | |
16 | + resource :projects do | |
17 | + # Get a list of project issues | |
18 | + # | |
19 | + # Parameters: | |
20 | + # id (required) - The ID or code name of a project | |
21 | + # Example Request: | |
22 | + # GET /projects/:id/issues | |
23 | + get ":id/issues" do | |
24 | + present user_project.issues, :with => Entities::Issue | |
25 | + end | |
26 | + | |
27 | + # Get a single project issue | |
28 | + # | |
29 | + # Parameters: | |
30 | + # id (required) - The ID or code name of a project | |
31 | + # issue_id (required) - The ID of a project issue | |
32 | + # Example Request: | |
33 | + # GET /projects/:id/issues/:issue_id | |
34 | + get ":id/issues/:issue_id" do | |
35 | + @issue = user_project.issues.find(params[:issue_id]) | |
36 | + present @issue, :with => Entities::Issue | |
37 | + end | |
38 | + | |
39 | + # Create a new project issue | |
40 | + # | |
41 | + # Parameters: | |
42 | + # id (required) - The ID or code name of a project | |
43 | + # title (required) - The title of an issue | |
44 | + # description (optional) - The description of an issue | |
45 | + # assignee_id (optional) - The ID of a user to assign issue | |
46 | + # milestone_id (optional) - The ID of a milestone to assign issue | |
47 | + # labels (optional) - The labels of an issue | |
48 | + # Example Request: | |
49 | + # POST /projects/:id/issues | |
50 | + post ":id/issues" do | |
51 | + @issue = user_project.issues.new( | |
52 | + :title => params[:title], | |
53 | + :description => params[:description], | |
54 | + :assignee_id => params[:assignee_id], | |
55 | + :milestone_id => params[:milestone_id], | |
56 | + :label_list => params[:labels] | |
57 | + ) | |
58 | + @issue.author = current_user | |
59 | + | |
60 | + if @issue.save | |
61 | + present @issue, :with => Entities::Issue | |
62 | + else | |
63 | + error!({'message' => '404 Not found'}, 404) | |
64 | + end | |
65 | + end | |
66 | + | |
67 | + # Update an existing issue | |
68 | + # | |
69 | + # Parameters: | |
70 | + # id (required) - The ID or code name of a project | |
71 | + # issue_id (required) - The ID of a project issue | |
72 | + # title (optional) - The title of an issue | |
73 | + # description (optional) - The description of an issue | |
74 | + # assignee_id (optional) - The ID of a user to assign issue | |
75 | + # milestone_id (optional) - The ID of a milestone to assign issue | |
76 | + # labels (optional) - The labels of an issue | |
77 | + # closed (optional) - The state of an issue (0 = false, 1 = true) | |
78 | + # Example Request: | |
79 | + # PUT /projects/:id/issues/:issue_id | |
80 | + put ":id/issues/:issue_id" do | |
81 | + @issue = user_project.issues.find(params[:issue_id]) | |
82 | + parameters = { | |
83 | + :title => (params[:title] || @issue.title), | |
84 | + :description => (params[:description] || @issue.description), | |
85 | + :assignee_id => (params[:assignee_id] || @issue.assignee_id), | |
86 | + :milestone_id => (params[:milestone_id] || @issue.milestone_id), | |
87 | + :label_list => (params[:labels] || @issue.label_list), | |
88 | + :closed => (params[:closed] || @issue.closed) | |
89 | + } | |
90 | + | |
91 | + if @issue.update_attributes(parameters) | |
92 | + present @issue, :with => Entities::Issue | |
93 | + else | |
94 | + error!({'message' => '404 Not found'}, 404) | |
95 | + end | |
96 | + end | |
97 | + | |
98 | + # Delete a project issue | |
99 | + # | |
100 | + # Parameters: | |
101 | + # id (required) - The ID or code name of a project | |
102 | + # issue_id (required) - The ID of a project issue | |
103 | + # Example Request: | |
104 | + # DELETE /projects/:id/issues/:issue_id | |
105 | + delete ":id/issues/:issue_id" do | |
106 | + @issue = user_project.issues.find(params[:issue_id]) | |
107 | + @issue.destroy | |
108 | + end | |
109 | + end | |
110 | + end | |
111 | +end | ... | ... |
lib/api/projects.rb
... | ... | @@ -16,53 +16,49 @@ module Gitlab |
16 | 16 | # Get a single project |
17 | 17 | # |
18 | 18 | # Parameters: |
19 | - # id (required) - The code of a project | |
19 | + # id (required) - The ID or code name of a project | |
20 | 20 | # Example Request: |
21 | 21 | # GET /projects/:id |
22 | 22 | get ":id" do |
23 | - @project = current_user.projects.find_by_code(params[:id]) | |
24 | - present @project, :with => Entities::Project | |
23 | + present user_project, :with => Entities::Project | |
25 | 24 | end |
26 | 25 | |
27 | 26 | # Get a project repository branches |
28 | 27 | # |
29 | 28 | # Parameters: |
30 | - # id (required) - The code of a project | |
29 | + # id (required) - The ID or code name of a project | |
31 | 30 | # Example Request: |
32 | 31 | # GET /projects/:id/repository/branches |
33 | 32 | get ":id/repository/branches" do |
34 | - @project = current_user.projects.find_by_code(params[:id]) | |
35 | - present @project.repo.heads.sort_by(&:name), :with => Entities::ProjectRepositoryBranches | |
33 | + present user_project.repo.heads.sort_by(&:name), :with => Entities::RepoObject | |
36 | 34 | end |
37 | 35 | |
38 | 36 | # Get a project repository tags |
39 | 37 | # |
40 | 38 | # Parameters: |
41 | - # id (required) - The code of a project | |
39 | + # id (required) - The ID or code name of a project | |
42 | 40 | # Example Request: |
43 | 41 | # GET /projects/:id/repository/tags |
44 | 42 | get ":id/repository/tags" do |
45 | - @project = current_user.projects.find_by_code(params[:id]) | |
46 | - present @project.repo.tags.sort_by(&:name).reverse, :with => Entities::ProjectRepositoryTags | |
43 | + present user_project.repo.tags.sort_by(&:name).reverse, :with => Entities::RepoObject | |
47 | 44 | end |
48 | 45 | |
49 | 46 | # Get a project snippet |
50 | 47 | # |
51 | 48 | # Parameters: |
52 | - # id (required) - The code of a project | |
49 | + # id (required) - The ID or code name of a project | |
53 | 50 | # snippet_id (required) - The ID of a project snippet |
54 | 51 | # Example Request: |
55 | 52 | # GET /projects/:id/snippets/:snippet_id |
56 | 53 | get ":id/snippets/:snippet_id" do |
57 | - @project = current_user.projects.find_by_code(params[:id]) | |
58 | - @snippet = @project.snippets.find(params[:snippet_id]) | |
54 | + @snippet = user_project.snippets.find(params[:snippet_id]) | |
59 | 55 | present @snippet, :with => Entities::ProjectSnippet |
60 | 56 | end |
61 | 57 | |
62 | 58 | # Create a new project snippet |
63 | 59 | # |
64 | 60 | # Parameters: |
65 | - # id (required) - The code name of a project | |
61 | + # id (required) - The ID or code name of a project | |
66 | 62 | # title (required) - The title of a snippet |
67 | 63 | # file_name (required) - The name of a snippet file |
68 | 64 | # lifetime (optional) - The expiration date of a snippet |
... | ... | @@ -70,8 +66,7 @@ module Gitlab |
70 | 66 | # Example Request: |
71 | 67 | # POST /projects/:id/snippets |
72 | 68 | post ":id/snippets" do |
73 | - @project = current_user.projects.find_by_code(params[:id]) | |
74 | - @snippet = @project.snippets.new( | |
69 | + @snippet = user_project.snippets.new( | |
75 | 70 | :title => params[:title], |
76 | 71 | :file_name => params[:file_name], |
77 | 72 | :expires_at => params[:lifetime], |
... | ... | @@ -89,7 +84,7 @@ module Gitlab |
89 | 84 | # Update an existing project snippet |
90 | 85 | # |
91 | 86 | # Parameters: |
92 | - # id (required) - The code name of a project | |
87 | + # id (required) - The ID or code name of a project | |
93 | 88 | # snippet_id (required) - The ID of a project snippet |
94 | 89 | # title (optional) - The title of a snippet |
95 | 90 | # file_name (optional) - The name of a snippet file |
... | ... | @@ -98,8 +93,7 @@ module Gitlab |
98 | 93 | # Example Request: |
99 | 94 | # PUT /projects/:id/snippets/:snippet_id |
100 | 95 | put ":id/snippets/:snippet_id" do |
101 | - @project = current_user.projects.find_by_code(params[:id]) | |
102 | - @snippet = @project.snippets.find(params[:snippet_id]) | |
96 | + @snippet = user_project.snippets.find(params[:snippet_id]) | |
103 | 97 | parameters = { |
104 | 98 | :title => (params[:title] || @snippet.title), |
105 | 99 | :file_name => (params[:file_name] || @snippet.file_name), |
... | ... | @@ -117,26 +111,24 @@ module Gitlab |
117 | 111 | # Delete a project snippet |
118 | 112 | # |
119 | 113 | # Parameters: |
120 | - # id (required) - The code of a project | |
114 | + # id (required) - The ID or code name of a project | |
121 | 115 | # snippet_id (required) - The ID of a project snippet |
122 | 116 | # Example Request: |
123 | 117 | # DELETE /projects/:id/snippets/:snippet_id |
124 | 118 | delete ":id/snippets/:snippet_id" do |
125 | - @project = current_user.projects.find_by_code(params[:id]) | |
126 | - @snippet = @project.snippets.find(params[:snippet_id]) | |
119 | + @snippet = user_project.snippets.find(params[:snippet_id]) | |
127 | 120 | @snippet.destroy |
128 | 121 | end |
129 | 122 | |
130 | 123 | # Get a raw project snippet |
131 | 124 | # |
132 | 125 | # Parameters: |
133 | - # id (required) - The code of a project | |
126 | + # id (required) - The ID or code name of a project | |
134 | 127 | # snippet_id (required) - The ID of a project snippet |
135 | 128 | # Example Request: |
136 | 129 | # GET /projects/:id/snippets/:snippet_id/raw |
137 | 130 | get ":id/snippets/:snippet_id/raw" do |
138 | - @project = current_user.projects.find_by_code(params[:id]) | |
139 | - @snippet = @project.snippets.find(params[:snippet_id]) | |
131 | + @snippet = user_project.snippets.find(params[:snippet_id]) | |
140 | 132 | present @snippet.content |
141 | 133 | end |
142 | 134 | end | ... | ... |
lib/gitlab/logger.rb
lib/tasks/gitlab/backup.rake
... | ... | @@ -121,7 +121,7 @@ namespace :gitlab do |
121 | 121 | backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") |
122 | 122 | FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo) |
123 | 123 | puts "Dumping repositories:" |
124 | - project = Project.all.map { |n| [n.name,n.path_to_repo] } | |
124 | + project = Project.all.map { |n| [n.path,n.path_to_repo] } | |
125 | 125 | project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] |
126 | 126 | project.each do |project| |
127 | 127 | print "- Dumping repository #{project.first}... " |
... | ... | @@ -136,12 +136,18 @@ namespace :gitlab do |
136 | 136 | task :repo_restore => :environment do |
137 | 137 | backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") |
138 | 138 | puts "Restoring repositories:" |
139 | - project = Project.all.map { |n| [n.name,n.path_to_repo] } | |
139 | + project = Project.all.map { |n| [n.path,n.path_to_repo] } | |
140 | 140 | project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] |
141 | 141 | project.each do |project| |
142 | 142 | print "- Restoring repository #{project.first}... " |
143 | 143 | FileUtils.rm_rf(project.second) if File.dirname(project.second) # delet old stuff |
144 | 144 | if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1") |
145 | + permission_commands = [ | |
146 | + "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}", | |
147 | + "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}", | |
148 | + "sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive" | |
149 | + ] | |
150 | + permission_commands.each { |command| Kernel.system(command) } | |
145 | 151 | puts "[DONE]".green |
146 | 152 | else |
147 | 153 | puts "[FAILED]".red | ... | ... |
lib/tasks/gitlab/status.rake
... | ... | @@ -2,7 +2,7 @@ namespace :gitlab do |
2 | 2 | namespace :app do |
3 | 3 | desc "GITLAB | Check gitlab installation status" |
4 | 4 | task :status => :environment do |
5 | - puts "Starting diagnostic" | |
5 | + puts "Starting diagnostic".yellow | |
6 | 6 | git_base_path = Gitlab.config.git_base_path |
7 | 7 | |
8 | 8 | print "config/database.yml............" |
... | ... | @@ -56,7 +56,28 @@ namespace :gitlab do |
56 | 56 | return |
57 | 57 | end |
58 | 58 | |
59 | - puts "\nFinished" | |
59 | + if Project.count > 0 | |
60 | + puts "Validating projects repositories:".yellow | |
61 | + Project.find_each(:batch_size => 100) do |project| | |
62 | + print "#{project.name}....." | |
63 | + hook_file = File.join(project.path_to_repo, 'hooks','post-receive') | |
64 | + | |
65 | + unless File.exists?(hook_file) | |
66 | + puts "post-receive file missing".red | |
67 | + next | |
68 | + end | |
69 | + | |
70 | + | |
71 | + unless File.owned?(hook_file) | |
72 | + puts "post-receive file is not owner by gitlab".red | |
73 | + next | |
74 | + end | |
75 | + | |
76 | + puts "post-reveice file ok".green | |
77 | + end | |
78 | + end | |
79 | + | |
80 | + puts "\nFinished".blue | |
60 | 81 | end |
61 | 82 | end |
62 | 83 | end | ... | ... |
... | ... | @@ -0,0 +1,71 @@ |
1 | +require 'spec_helper' | |
2 | + | |
3 | +describe Gitlab::API do | |
4 | + let(:user) { Factory :user } | |
5 | + let!(:project) { Factory :project, :owner => user } | |
6 | + let!(:issue) { Factory :issue, :author => user, :assignee => user, :project => project } | |
7 | + before { project.add_access(user, :read) } | |
8 | + | |
9 | + describe "GET /issues" do | |
10 | + it "should return authentication error" do | |
11 | + get "#{api_prefix}/issues" | |
12 | + response.status.should == 401 | |
13 | + end | |
14 | + | |
15 | + describe "authenticated GET /issues" do | |
16 | + it "should return an array of issues" do | |
17 | + get "#{api_prefix}/issues?private_token=#{user.private_token}" | |
18 | + response.status.should == 200 | |
19 | + json_response.should be_an Array | |
20 | + json_response.first['title'].should == issue.title | |
21 | + end | |
22 | + end | |
23 | + end | |
24 | + | |
25 | + describe "GET /projects/:id/issues" do | |
26 | + it "should return project issues" do | |
27 | + get "#{api_prefix}/projects/#{project.code}/issues?private_token=#{user.private_token}" | |
28 | + response.status.should == 200 | |
29 | + json_response.should be_an Array | |
30 | + json_response.first['title'].should == issue.title | |
31 | + end | |
32 | + end | |
33 | + | |
34 | + describe "GET /projects/:id/issues/:issue_id" do | |
35 | + it "should return a project issue by id" do | |
36 | + get "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}" | |
37 | + response.status.should == 200 | |
38 | + json_response['title'].should == issue.title | |
39 | + end | |
40 | + end | |
41 | + | |
42 | + describe "POST /projects/:id/issues" do | |
43 | + it "should create a new project issue" do | |
44 | + post "#{api_prefix}/projects/#{project.code}/issues?private_token=#{user.private_token}", | |
45 | + :title => 'new issue', :labels => 'label, label2' | |
46 | + response.status.should == 201 | |
47 | + json_response['title'].should == 'new issue' | |
48 | + json_response['description'].should be_nil | |
49 | + json_response['labels'].should == ['label', 'label2'] | |
50 | + end | |
51 | + end | |
52 | + | |
53 | + describe "PUT /projects/:id/issues/:issue_id" do | |
54 | + it "should update a project issue" do | |
55 | + put "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}", | |
56 | + :title => 'updated title', :labels => 'label2', :closed => 1 | |
57 | + response.status.should == 200 | |
58 | + json_response['title'].should == 'updated title' | |
59 | + json_response['labels'].should == ['label2'] | |
60 | + json_response['closed'].should be_true | |
61 | + end | |
62 | + end | |
63 | + | |
64 | + describe "DELETE /projects/:id/issues/:issue_id" do | |
65 | + it "should delete a project issue" do | |
66 | + expect { | |
67 | + delete "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}" | |
68 | + }.to change { Issue.count }.by(-1) | |
69 | + end | |
70 | + end | |
71 | +end | ... | ... |
spec/api/projects_spec.rb
... | ... | @@ -25,11 +25,23 @@ describe Gitlab::API do |
25 | 25 | |
26 | 26 | describe "GET /projects/:id" do |
27 | 27 | it "should return a project by id" do |
28 | - get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}" | |
28 | + get "#{api_prefix}/projects/#{project.id}?private_token=#{user.private_token}" | |
29 | 29 | response.status.should == 200 |
30 | 30 | json_response['name'].should == project.name |
31 | 31 | json_response['owner']['email'].should == user.email |
32 | 32 | end |
33 | + | |
34 | + it "should return a project by code name" do | |
35 | + get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}" | |
36 | + response.status.should == 200 | |
37 | + json_response['name'].should == project.name | |
38 | + end | |
39 | + | |
40 | + it "should return a 404 error if not found" do | |
41 | + get "#{api_prefix}/projects/42?private_token=#{user.private_token}" | |
42 | + response.status.should == 404 | |
43 | + json_response['message'].should == '404 Not found' | |
44 | + end | |
33 | 45 | end |
34 | 46 | |
35 | 47 | describe "GET /projects/:id/repository/branches" do | ... | ... |
spec/requests/commits_spec.rb
... | ... | @@ -2,7 +2,7 @@ require 'spec_helper' |
2 | 2 | |
3 | 3 | describe "Commits" do |
4 | 4 | let(:project) { Factory :project } |
5 | - let!(:commit) { project.commit } | |
5 | + let!(:commit) { CommitDecorator.decorate(project.commit) } | |
6 | 6 | before do |
7 | 7 | login_as :user |
8 | 8 | project.add_access(@user, :read) |
... | ... | @@ -22,8 +22,8 @@ describe "Commits" do |
22 | 22 | end |
23 | 23 | |
24 | 24 | it "should list commits" do |
25 | - page.should have_content(commit.message) | |
26 | - page.should have_content(commit.id.to_s[0..5]) | |
25 | + page.should have_content(commit.description) | |
26 | + page.should have_content(commit.short_id(8)) | |
27 | 27 | end |
28 | 28 | |
29 | 29 | it "should render atom feed" do |
... | ... | @@ -32,7 +32,7 @@ describe "Commits" do |
32 | 32 | page.response_headers['Content-Type'].should have_content("application/atom+xml") |
33 | 33 | page.body.should have_selector("title", :text => "Recent commits to #{project.name}") |
34 | 34 | page.body.should have_selector("author email", :text => commit.author_email) |
35 | - page.body.should have_selector("entry summary", :text => commit.message) | |
35 | + page.body.should have_selector("entry summary", :text => commit.description) | |
36 | 36 | end |
37 | 37 | |
38 | 38 | it "should render atom feed via private token" do |
... | ... | @@ -42,7 +42,7 @@ describe "Commits" do |
42 | 42 | page.response_headers['Content-Type'].should have_content("application/atom+xml") |
43 | 43 | page.body.should have_selector("title", :text => "Recent commits to #{project.name}") |
44 | 44 | page.body.should have_selector("author email", :text => commit.author_email) |
45 | - page.body.should have_selector("entry summary", :text => commit.message) | |
45 | + page.body.should have_selector("entry summary", :text => commit.description) | |
46 | 46 | end |
47 | 47 | end |
48 | 48 | ... | ... |
... | ... | @@ -0,0 +1,29 @@ |
1 | +require 'spec_helper' | |
2 | + | |
3 | +describe "Wikis" do | |
4 | + let(:project) { Factory :project } | |
5 | + | |
6 | + before do | |
7 | + login_as :user | |
8 | + project.add_access(@user, :read, :write) | |
9 | + end | |
10 | + | |
11 | + describe "add new note", :js => true do | |
12 | + before do | |
13 | + visit project_wiki_path(project, :index) | |
14 | + | |
15 | + fill_in "Title", :with => 'Test title' | |
16 | + fill_in "Content", :with => '[link test](test)' | |
17 | + click_on "Save" | |
18 | + | |
19 | + page.should have_content("Test title") | |
20 | + | |
21 | + fill_in "note_note", :with => "Comment on wiki!" | |
22 | + click_button "Add Comment" | |
23 | + end | |
24 | + | |
25 | + it "should contain the new note" do | |
26 | + page.should have_content("Comment on wiki!") | |
27 | + end | |
28 | + end | |
29 | +end | ... | ... |