Commit eefb27f5ae0edf0c005eb8ce6da56cbd17c9aa8a
Exists in
master
and in
4 other branches
Merge branch 'master' into fixes/api
Conflicts: spec/requests/api/projects_spec.rb
Showing
135 changed files
with
1141 additions
and
884 deletions
Show diff stats
.gitignore
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | .rbx/ | 2 | .rbx/ |
3 | db/*.sqlite3 | 3 | db/*.sqlite3 |
4 | db/*.sqlite3-journal | 4 | db/*.sqlite3-journal |
5 | -log/*.log | 5 | +log/*.log* |
6 | tmp/ | 6 | tmp/ |
7 | .sass-cache/ | 7 | .sass-cache/ |
8 | coverage/* | 8 | coverage/* |
@@ -20,6 +20,7 @@ config/database.yml | @@ -20,6 +20,7 @@ config/database.yml | ||
20 | config/initializers/omniauth.rb | 20 | config/initializers/omniauth.rb |
21 | config/unicorn.rb | 21 | config/unicorn.rb |
22 | config/resque.yml | 22 | config/resque.yml |
23 | +config/aws.yml | ||
23 | db/data.yml | 24 | db/data.yml |
24 | .idea | 25 | .idea |
25 | .DS_Store | 26 | .DS_Store |
Gemfile
@@ -70,6 +70,9 @@ gem "github-markup", "~> 0.7.4", require: 'github/markup' | @@ -70,6 +70,9 @@ gem "github-markup", "~> 0.7.4", require: 'github/markup' | ||
70 | # Servers | 70 | # Servers |
71 | gem "unicorn", "~> 4.4.0" | 71 | gem "unicorn", "~> 4.4.0" |
72 | 72 | ||
73 | +# State machine | ||
74 | +gem "state_machine" | ||
75 | + | ||
73 | # Issue tags | 76 | # Issue tags |
74 | gem "acts-as-taggable-on", "2.3.3" | 77 | gem "acts-as-taggable-on", "2.3.3" |
75 | 78 |
Gemfile.lock
@@ -425,6 +425,7 @@ GEM | @@ -425,6 +425,7 @@ GEM | ||
425 | rack (~> 1.0) | 425 | rack (~> 1.0) |
426 | tilt (~> 1.1, != 1.3.0) | 426 | tilt (~> 1.1, != 1.3.0) |
427 | stamp (0.3.0) | 427 | stamp (0.3.0) |
428 | + state_machine (1.1.2) | ||
428 | temple (0.5.5) | 429 | temple (0.5.5) |
429 | test_after_commit (0.0.1) | 430 | test_after_commit (0.0.1) |
430 | therubyracer (0.10.2) | 431 | therubyracer (0.10.2) |
@@ -536,6 +537,7 @@ DEPENDENCIES | @@ -536,6 +537,7 @@ DEPENDENCIES | ||
536 | slim | 537 | slim |
537 | spinach-rails | 538 | spinach-rails |
538 | stamp | 539 | stamp |
540 | + state_machine | ||
539 | test_after_commit | 541 | test_after_commit |
540 | therubyracer | 542 | therubyracer |
541 | thin | 543 | thin |
app/assets/javascripts/main.js.coffee
@@ -49,6 +49,10 @@ $ -> | @@ -49,6 +49,10 @@ $ -> | ||
49 | # Bottom tooltip | 49 | # Bottom tooltip |
50 | $('.has_bottom_tooltip').tooltip(placement: 'bottom') | 50 | $('.has_bottom_tooltip').tooltip(placement: 'bottom') |
51 | 51 | ||
52 | + # Form submitter | ||
53 | + $('.trigger-submit').on 'change', -> | ||
54 | + $(@).parents('form').submit() | ||
55 | + | ||
52 | # Flash | 56 | # Flash |
53 | if (flash = $("#flash-container")).length > 0 | 57 | if (flash = $("#flash-container")).length > 0 |
54 | flash.click -> $(@).slideUp("slow") | 58 | flash.click -> $(@).slideUp("slow") |
app/assets/javascripts/merge_requests.js.coffee
@@ -27,7 +27,7 @@ class MergeRequest | @@ -27,7 +27,7 @@ class MergeRequest | ||
27 | this.$el.find(selector) | 27 | this.$el.find(selector) |
28 | 28 | ||
29 | initMergeWidget: -> | 29 | initMergeWidget: -> |
30 | - this.showState( @opts.current_state ) | 30 | + this.showState( @opts.current_status ) |
31 | 31 | ||
32 | if this.$('.automerge_widget').length and @opts.check_enable | 32 | if this.$('.automerge_widget').length and @opts.check_enable |
33 | $.get @opts.url_to_automerge_check, (data) => | 33 | $.get @opts.url_to_automerge_check, (data) => |
app/assets/stylesheets/gitlab_bootstrap/mixins.scss
@@ -63,7 +63,7 @@ | @@ -63,7 +63,7 @@ | ||
63 | color: $style_color; | 63 | color: $style_color; |
64 | text-shadow: 0 1px 1px #FFF; | 64 | text-shadow: 0 1px 1px #FFF; |
65 | font-family: 'Yanone', sans-serif; | 65 | font-family: 'Yanone', sans-serif; |
66 | - font-size: 26px; | ||
67 | - line-height: 42px; | 66 | + font-size: 24px; |
67 | + line-height: 36px; | ||
68 | font-weight: normal; | 68 | font-weight: normal; |
69 | } | 69 | } |
app/assets/stylesheets/sections/commits.scss
@@ -29,7 +29,7 @@ | @@ -29,7 +29,7 @@ | ||
29 | a{ | 29 | a{ |
30 | color: $style_color; | 30 | color: $style_color; |
31 | } | 31 | } |
32 | - | 32 | + |
33 | > span { | 33 | > span { |
34 | font-family: $monospace_font; | 34 | font-family: $monospace_font; |
35 | font-size: 14px; | 35 | font-size: 14px; |
@@ -124,7 +124,7 @@ | @@ -124,7 +124,7 @@ | ||
124 | .wrap{ | 124 | .wrap{ |
125 | display: inline-block; | 125 | display: inline-block; |
126 | } | 126 | } |
127 | - | 127 | + |
128 | .frame { | 128 | .frame { |
129 | display: inline-block; | 129 | display: inline-block; |
130 | background-color: #fff; | 130 | background-color: #fff; |
@@ -149,7 +149,7 @@ | @@ -149,7 +149,7 @@ | ||
149 | 149 | ||
150 | .view.swipe{ | 150 | .view.swipe{ |
151 | position: relative; | 151 | position: relative; |
152 | - | 152 | + |
153 | .swipe-frame{ | 153 | .swipe-frame{ |
154 | display: block; | 154 | display: block; |
155 | margin: auto; | 155 | margin: auto; |
@@ -228,7 +228,7 @@ | @@ -228,7 +228,7 @@ | ||
228 | bottom: 0px; | 228 | bottom: 0px; |
229 | left: 50%; | 229 | left: 50%; |
230 | margin-left: -150px; | 230 | margin-left: -150px; |
231 | - | 231 | + |
232 | .drag-track{ | 232 | .drag-track{ |
233 | display: block; | 233 | display: block; |
234 | position: absolute; | 234 | position: absolute; |
@@ -237,7 +237,7 @@ | @@ -237,7 +237,7 @@ | ||
237 | width: 276px; | 237 | width: 276px; |
238 | background: url('onion_skin_sprites.gif') -4px -20px repeat-x; | 238 | background: url('onion_skin_sprites.gif') -4px -20px repeat-x; |
239 | } | 239 | } |
240 | - | 240 | + |
241 | .dragger { | 241 | .dragger { |
242 | display: block; | 242 | display: block; |
243 | position: absolute; | 243 | position: absolute; |
@@ -248,7 +248,7 @@ | @@ -248,7 +248,7 @@ | ||
248 | background: url('onion_skin_sprites.gif') 0px -34px repeat-x; | 248 | background: url('onion_skin_sprites.gif') 0px -34px repeat-x; |
249 | cursor: pointer; | 249 | cursor: pointer; |
250 | } | 250 | } |
251 | - | 251 | + |
252 | .transparent { | 252 | .transparent { |
253 | display: block; | 253 | display: block; |
254 | position: absolute; | 254 | position: absolute; |
@@ -258,7 +258,7 @@ | @@ -258,7 +258,7 @@ | ||
258 | width: 10px; | 258 | width: 10px; |
259 | background: url('onion_skin_sprites.gif') -2px 0px no-repeat; | 259 | background: url('onion_skin_sprites.gif') -2px 0px no-repeat; |
260 | } | 260 | } |
261 | - | 261 | + |
262 | .opaque { | 262 | .opaque { |
263 | display: block; | 263 | display: block; |
264 | position: absolute; | 264 | position: absolute; |
@@ -275,19 +275,19 @@ | @@ -275,19 +275,19 @@ | ||
275 | 275 | ||
276 | padding: 10px; | 276 | padding: 10px; |
277 | text-align: center; | 277 | text-align: center; |
278 | - | 278 | + |
279 | background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); | 279 | background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); |
280 | background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); | 280 | background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); |
281 | background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); | 281 | background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); |
282 | background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); | 282 | background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); |
283 | - | 283 | + |
284 | ul, li{ | 284 | ul, li{ |
285 | list-style: none; | 285 | list-style: none; |
286 | margin: 0; | 286 | margin: 0; |
287 | padding: 0; | 287 | padding: 0; |
288 | display: inline-block; | 288 | display: inline-block; |
289 | } | 289 | } |
290 | - | 290 | + |
291 | li{ | 291 | li{ |
292 | color: grey; | 292 | color: grey; |
293 | border-left: 1px solid #c1c1c1; | 293 | border-left: 1px solid #c1c1c1; |
@@ -322,12 +322,12 @@ | @@ -322,12 +322,12 @@ | ||
322 | } | 322 | } |
323 | .commit-author, .commit-committer{ | 323 | .commit-author, .commit-committer{ |
324 | display: block; | 324 | display: block; |
325 | - color: #999; | ||
326 | - font-weight: normal; | 325 | + color: #999; |
326 | + font-weight: normal; | ||
327 | font-style: italic; | 327 | font-style: italic; |
328 | } | 328 | } |
329 | .commit-author strong, .commit-committer strong{ | 329 | .commit-author strong, .commit-committer strong{ |
330 | - font-weight: bold; | 330 | + font-weight: bold; |
331 | font-style: normal; | 331 | font-style: normal; |
332 | } | 332 | } |
333 | 333 | ||
@@ -337,7 +337,6 @@ | @@ -337,7 +337,6 @@ | ||
337 | */ | 337 | */ |
338 | .commit { | 338 | .commit { |
339 | .browse_code_link_holder { | 339 | .browse_code_link_holder { |
340 | - @extend .span2; | ||
341 | float: right; | 340 | float: right; |
342 | } | 341 | } |
343 | 342 |
app/assets/stylesheets/sections/header.scss
@@ -5,15 +5,16 @@ | @@ -5,15 +5,16 @@ | ||
5 | header { | 5 | header { |
6 | &.navbar-gitlab { | 6 | &.navbar-gitlab { |
7 | .navbar-inner { | 7 | .navbar-inner { |
8 | - height: 45px; | ||
9 | - padding: 5px; | 8 | + height: 40px; |
9 | + padding: 3px; | ||
10 | background: #F1F1F1; | 10 | background: #F1F1F1; |
11 | + filter: none; | ||
11 | 12 | ||
12 | .nav > li > a { | 13 | .nav > li > a { |
13 | color: $style_color; | 14 | color: $style_color; |
14 | text-shadow: 0 1px 0 #fff; | 15 | text-shadow: 0 1px 0 #fff; |
15 | - font-size: 18px; | ||
16 | - padding: 12px; | 16 | + font-size: 16px; |
17 | + padding: 10px; | ||
17 | } | 18 | } |
18 | 19 | ||
19 | /** NAV block with links and profile **/ | 20 | /** NAV block with links and profile **/ |
@@ -25,7 +26,6 @@ header { | @@ -25,7 +26,6 @@ header { | ||
25 | } | 26 | } |
26 | 27 | ||
27 | z-index: 10; | 28 | z-index: 10; |
28 | - /*height: 60px;*/ | ||
29 | 29 | ||
30 | /** | 30 | /** |
31 | * | 31 | * |
@@ -34,7 +34,7 @@ header { | @@ -34,7 +34,7 @@ header { | ||
34 | */ | 34 | */ |
35 | .app_logo { | 35 | .app_logo { |
36 | float: left; | 36 | float: left; |
37 | - margin-right: 15px; | 37 | + margin-right: 9px; |
38 | position: relative; | 38 | position: relative; |
39 | top: -5px; | 39 | top: -5px; |
40 | padding-top: 5px; | 40 | padding-top: 5px; |
@@ -42,10 +42,10 @@ header { | @@ -42,10 +42,10 @@ header { | ||
42 | a { | 42 | a { |
43 | float: left; | 43 | float: left; |
44 | padding: 0px; | 44 | padding: 0px; |
45 | - margin: 0 10px; | 45 | + margin: 0 6px; |
46 | 46 | ||
47 | h1 { | 47 | h1 { |
48 | - background: url('logo_dark.png') no-repeat 0px 2px; | 48 | + background: url('logo_dark.png') no-repeat center 1px; |
49 | float: left; | 49 | float: left; |
50 | height: 40px; | 50 | height: 40px; |
51 | width: 40px; | 51 | width: 40px; |
@@ -79,7 +79,6 @@ header { | @@ -79,7 +79,6 @@ header { | ||
79 | .search { | 79 | .search { |
80 | margin-right: 45px; | 80 | margin-right: 45px; |
81 | margin-left: 10px; | 81 | margin-left: 10px; |
82 | - margin-top: 2px; | ||
83 | 82 | ||
84 | .search-input { | 83 | .search-input { |
85 | @extend .span2; | 84 | @extend .span2; |
@@ -105,7 +104,7 @@ header { | @@ -105,7 +104,7 @@ header { | ||
105 | .account-box { | 104 | .account-box { |
106 | position: absolute; | 105 | position: absolute; |
107 | right: 0; | 106 | right: 0; |
108 | - top: 6px; | 107 | + top: 4px; |
109 | z-index: 10000; | 108 | z-index: 10000; |
110 | width: 128px; | 109 | width: 128px; |
111 | font-size: 11px; | 110 | font-size: 11px; |
@@ -228,6 +227,7 @@ header { | @@ -228,6 +227,7 @@ header { | ||
228 | .search-input { | 227 | .search-input { |
229 | background-color: #D2D5DA; | 228 | background-color: #D2D5DA; |
230 | background-color: rgba(255, 255, 255, 0.5); | 229 | background-color: rgba(255, 255, 255, 0.5); |
230 | + border: 1px solid #AAA; | ||
231 | 231 | ||
232 | &:focus { | 232 | &:focus { |
233 | background-color: white; | 233 | background-color: white; |
@@ -240,13 +240,16 @@ header { | @@ -240,13 +240,16 @@ header { | ||
240 | .app_logo { | 240 | .app_logo { |
241 | a { | 241 | a { |
242 | h1 { | 242 | h1 { |
243 | - background: url('logo_white.png') no-repeat center center; | 243 | + background: url('logo_white.png') no-repeat center 1px; |
244 | color: #fff; | 244 | color: #fff; |
245 | text-shadow: 0 1px 1px #111; | 245 | text-shadow: 0 1px 1px #111; |
246 | } | 246 | } |
247 | } | 247 | } |
248 | } | 248 | } |
249 | .project_name { | 249 | .project_name { |
250 | + a { | ||
251 | + color: #FFF; | ||
252 | + } | ||
250 | color: #fff; | 253 | color: #fff; |
251 | text-shadow: 0 1px 1px #111; | 254 | text-shadow: 0 1px 1px #111; |
252 | } | 255 | } |
@@ -261,11 +264,11 @@ header { | @@ -261,11 +264,11 @@ header { | ||
261 | 264 | ||
262 | .separator { | 265 | .separator { |
263 | float: left; | 266 | float: left; |
264 | - height: 60px; | 267 | + height: 46px; |
265 | width: 1px; | 268 | width: 1px; |
266 | background: white; | 269 | background: white; |
267 | border-left: 1px solid #DDD; | 270 | border-left: 1px solid #DDD; |
268 | - margin-top: -10px; | 271 | + margin-top: -3px; |
269 | margin-left: 10px; | 272 | margin-left: 10px; |
270 | margin-right: 10px; | 273 | margin-right: 10px; |
271 | } | 274 | } |
app/assets/stylesheets/sections/projects.scss
app/assets/stylesheets/themes/ui_mars.scss
@@ -8,66 +8,27 @@ | @@ -8,66 +8,27 @@ | ||
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | .ui_mars { | 10 | .ui_mars { |
11 | - | ||
12 | /* | 11 | /* |
13 | * Application Header | 12 | * Application Header |
14 | * | 13 | * |
15 | */ | 14 | */ |
16 | header { | 15 | header { |
17 | - | 16 | + @extend .header-dark; |
18 | &.navbar-gitlab { | 17 | &.navbar-gitlab { |
19 | .navbar-inner { | 18 | .navbar-inner { |
20 | - background: #474D57 url('bg-header.png') repeat-x bottom; | ||
21 | - border-bottom: 1px solid #444; | ||
22 | - | ||
23 | - .nav > li > a { | ||
24 | - color: #eee; | ||
25 | - text-shadow: 0 1px 0 #444; | 19 | + background: #474D57; |
20 | + border-bottom: 1px solid #373D47; | ||
21 | + .app_logo { | ||
22 | + &:hover { | ||
23 | + background-color: #373D47; | ||
24 | + } | ||
26 | } | 25 | } |
27 | } | 26 | } |
28 | } | 27 | } |
29 | 28 | ||
30 | - .search { | ||
31 | - float: right; | ||
32 | - margin-right: 45px; | ||
33 | - .search-input { | ||
34 | - border: 1px solid rgba(0, 0, 0, 0.7); | ||
35 | - background-color: #D2D5DA; | ||
36 | - background-color: rgba(255, 255, 255, 0.5); | ||
37 | - | ||
38 | - &:focus { | ||
39 | - background-color: white; | ||
40 | - } | ||
41 | - } | ||
42 | - } | ||
43 | - .search-input::-webkit-input-placeholder { | ||
44 | - color: #666; | ||
45 | - } | ||
46 | - .app_logo { | ||
47 | - a { | ||
48 | - h1 { | ||
49 | - background: url('logo_white.png') no-repeat center center; | ||
50 | - color: #eee; | ||
51 | - text-shadow: 0 1px 1px #111; | ||
52 | - } | ||
53 | - } | ||
54 | - &:hover { | ||
55 | - background-color: #41464e; | ||
56 | - } | ||
57 | - } | ||
58 | - .project_name { | ||
59 | - color: #eee; | ||
60 | - text-shadow: 0 1px 1px #111; | 29 | + .separator { |
30 | + background: #31363E; | ||
31 | + border-left: 1px solid #666; | ||
61 | } | 32 | } |
62 | } | 33 | } |
63 | - | ||
64 | - .separator { | ||
65 | - background: #31363E; | ||
66 | - border-left: 1px solid #666; | ||
67 | - } | ||
68 | - | ||
69 | - /* | ||
70 | - * End of Application Header | ||
71 | - * | ||
72 | - */ | ||
73 | } | 34 | } |
app/contexts/merge_requests_load_context.rb
@@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext | @@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext | ||
14 | end | 14 | end |
15 | 15 | ||
16 | merge_requests = merge_requests.page(params[:page]).per(20) | 16 | merge_requests = merge_requests.page(params[:page]).per(20) |
17 | - merge_requests = merge_requests.includes(:author, :project).order("closed, created_at desc") | 17 | + merge_requests = merge_requests.includes(:author, :project).order("state, created_at desc") |
18 | 18 | ||
19 | # Filter by specific assignee_id (or lack thereof)? | 19 | # Filter by specific assignee_id (or lack thereof)? |
20 | if params[:assignee_id].present? | 20 | if params[:assignee_id].present? |
app/contexts/projects/create_context.rb
@@ -38,6 +38,8 @@ module Projects | @@ -38,6 +38,8 @@ module Projects | ||
38 | if @project.valid? && @project.import_url.present? | 38 | if @project.valid? && @project.import_url.present? |
39 | shell = Gitlab::Shell.new | 39 | shell = Gitlab::Shell.new |
40 | if shell.import_repository(@project.path_with_namespace, @project.import_url) | 40 | if shell.import_repository(@project.path_with_namespace, @project.import_url) |
41 | + # We should create satellite for imported repo | ||
42 | + @project.satellite.create unless @project.satellite.exists? | ||
41 | true | 43 | true |
42 | else | 44 | else |
43 | @project.errors.add(:import_url, 'cannot clone repo') | 45 | @project.errors.add(:import_url, 'cannot clone repo') |
app/controllers/dashboard_controller.rb
@@ -5,7 +5,7 @@ class DashboardController < ApplicationController | @@ -5,7 +5,7 @@ class DashboardController < ApplicationController | ||
5 | before_filter :event_filter, only: :show | 5 | before_filter :event_filter, only: :show |
6 | 6 | ||
7 | def show | 7 | def show |
8 | - @groups = current_user.authorized_groups | 8 | + @groups = current_user.authorized_groups.sort_by(&:human_name) |
9 | @has_authorized_projects = @projects.count > 0 | 9 | @has_authorized_projects = @projects.count > 0 |
10 | @teams = current_user.authorized_teams | 10 | @teams = current_user.authorized_teams |
11 | @projects_count = @projects.count | 11 | @projects_count = @projects.count |
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +class FilesController < ApplicationController | ||
2 | + def download | ||
3 | + note = Note.find(params[:id]) | ||
4 | + | ||
5 | + if can?(current_user, :read_project, note.project) | ||
6 | + uploader = note.attachment | ||
7 | + send_file uploader.file.path, disposition: 'attachment' | ||
8 | + else | ||
9 | + not_found! | ||
10 | + end | ||
11 | + end | ||
12 | +end | ||
13 | + |
app/controllers/merge_requests_controller.rb
@@ -73,14 +73,14 @@ class MergeRequestsController < ProjectResourceController | @@ -73,14 +73,14 @@ class MergeRequestsController < ProjectResourceController | ||
73 | if @merge_request.unchecked? | 73 | if @merge_request.unchecked? |
74 | @merge_request.check_if_can_be_merged | 74 | @merge_request.check_if_can_be_merged |
75 | end | 75 | end |
76 | - render json: {state: @merge_request.human_state} | 76 | + render json: {merge_status: @merge_request.human_merge_status} |
77 | rescue Gitlab::SatelliteNotExistError | 77 | rescue Gitlab::SatelliteNotExistError |
78 | - render json: {state: :no_satellite} | 78 | + render json: {merge_status: :no_satellite} |
79 | end | 79 | end |
80 | 80 | ||
81 | def automerge | 81 | def automerge |
82 | return access_denied! unless can?(current_user, :accept_mr, @project) | 82 | return access_denied! unless can?(current_user, :accept_mr, @project) |
83 | - if @merge_request.open? && @merge_request.can_be_merged? | 83 | + if @merge_request.opened? && @merge_request.can_be_merged? |
84 | @merge_request.should_remove_source_branch = params[:should_remove_source_branch] | 84 | @merge_request.should_remove_source_branch = params[:should_remove_source_branch] |
85 | @merge_request.automerge!(current_user) | 85 | @merge_request.automerge!(current_user) |
86 | @status = true | 86 | @status = true |
app/controllers/milestones_controller.rb
@@ -12,7 +12,7 @@ class MilestonesController < ProjectResourceController | @@ -12,7 +12,7 @@ class MilestonesController < ProjectResourceController | ||
12 | 12 | ||
13 | def index | 13 | def index |
14 | @milestones = case params[:f] | 14 | @milestones = case params[:f] |
15 | - when 'all'; @project.milestones.order("closed, due_date DESC") | 15 | + when 'all'; @project.milestones.order("state, due_date DESC") |
16 | when 'closed'; @project.milestones.closed.order("due_date DESC") | 16 | when 'closed'; @project.milestones.closed.order("due_date DESC") |
17 | else @project.milestones.active.order("due_date ASC") | 17 | else @project.milestones.active.order("due_date ASC") |
18 | end | 18 | end |
app/controllers/profiles_controller.rb
@@ -51,7 +51,9 @@ class ProfilesController < ApplicationController | @@ -51,7 +51,9 @@ class ProfilesController < ApplicationController | ||
51 | end | 51 | end |
52 | 52 | ||
53 | def update_username | 53 | def update_username |
54 | - @user.update_attributes(username: params[:user][:username]) | 54 | + if @user.can_change_username? |
55 | + @user.update_attributes(username: params[:user][:username]) | ||
56 | + end | ||
55 | 57 | ||
56 | respond_to do |format| | 58 | respond_to do |format| |
57 | format.js | 59 | format.js |
app/controllers/team_members_controller.rb
@@ -4,7 +4,11 @@ class TeamMembersController < ProjectResourceController | @@ -4,7 +4,11 @@ class TeamMembersController < ProjectResourceController | ||
4 | before_filter :authorize_admin_project!, except: [:index, :show] | 4 | before_filter :authorize_admin_project!, except: [:index, :show] |
5 | 5 | ||
6 | def index | 6 | def index |
7 | - @teams = UserTeam.scoped | 7 | + @team = @project.users_projects.scoped |
8 | + @team = @team.send(params[:type]) if %w(masters developers reporters guests).include?(params[:type]) | ||
9 | + @team = @team.sort_by(&:project_access).reverse.group_by(&:project_access) | ||
10 | + | ||
11 | + @assigned_teams = @project.user_team_project_relationships | ||
8 | end | 12 | end |
9 | 13 | ||
10 | def show | 14 | def show |
app/controllers/teams/members_controller.rb
@@ -27,7 +27,13 @@ class Teams::MembersController < Teams::ApplicationController | @@ -27,7 +27,13 @@ class Teams::MembersController < Teams::ApplicationController | ||
27 | end | 27 | end |
28 | 28 | ||
29 | def update | 29 | def update |
30 | - options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]} | 30 | + member_params = params[:team_member] |
31 | + | ||
32 | + options = { | ||
33 | + default_projects_access: member_params[:permission], | ||
34 | + group_admin: member_params[:group_admin] | ||
35 | + } | ||
36 | + | ||
31 | if user_team.update_membership(team_member, options) | 37 | if user_team.update_membership(team_member, options) |
32 | redirect_to team_members_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users." | 38 | redirect_to team_members_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users." |
33 | else | 39 | else |
@@ -45,5 +51,4 @@ class Teams::MembersController < Teams::ApplicationController | @@ -45,5 +51,4 @@ class Teams::MembersController < Teams::ApplicationController | ||
45 | def team_member | 51 | def team_member |
46 | @member ||= user_team.members.find_by_username(params[:id]) | 52 | @member ||= user_team.members.find_by_username(params[:id]) |
47 | end | 53 | end |
48 | - | ||
49 | end | 54 | end |
app/controllers/teams_controller.rb
@@ -9,13 +9,11 @@ class TeamsController < ApplicationController | @@ -9,13 +9,11 @@ class TeamsController < ApplicationController | ||
9 | layout 'user_team', except: [:new, :create] | 9 | layout 'user_team', except: [:new, :create] |
10 | 10 | ||
11 | def show | 11 | def show |
12 | - user_team | ||
13 | projects | 12 | projects |
14 | @events = Event.in_projects(user_team.project_ids).limit(20).offset(params[:offset] || 0) | 13 | @events = Event.in_projects(user_team.project_ids).limit(20).offset(params[:offset] || 0) |
15 | end | 14 | end |
16 | 15 | ||
17 | def edit | 16 | def edit |
18 | - user_team | ||
19 | end | 17 | end |
20 | 18 | ||
21 | def update | 19 | def update |
@@ -41,6 +39,9 @@ class TeamsController < ApplicationController | @@ -41,6 +39,9 @@ class TeamsController < ApplicationController | ||
41 | @team.path = @team.name.dup.parameterize if @team.name | 39 | @team.path = @team.name.dup.parameterize if @team.name |
42 | 40 | ||
43 | if @team.save | 41 | if @team.save |
42 | + # Add current user as Master to the team | ||
43 | + @team.add_members([current_user.id], UsersProject::MASTER, true) | ||
44 | + | ||
44 | redirect_to team_path(@team) | 45 | redirect_to team_path(@team) |
45 | else | 46 | else |
46 | render action: :new | 47 | render action: :new |
app/helpers/application_helper.rb
@@ -73,8 +73,8 @@ module ApplicationHelper | @@ -73,8 +73,8 @@ module ApplicationHelper | ||
73 | 73 | ||
74 | def search_autocomplete_source | 74 | def search_autocomplete_source |
75 | projects = current_user.authorized_projects.map { |p| { label: "project: #{p.name_with_namespace}", url: project_path(p) } } | 75 | projects = current_user.authorized_projects.map { |p| { label: "project: #{p.name_with_namespace}", url: project_path(p) } } |
76 | - groups = current_user.authorized_groups.map { |group| { label: "group: #{group.name}", url: group_path(group) } } | ||
77 | - teams = current_user.authorized_teams.map { |team| { label: "team: #{team.name}", url: team_path(team) } } | 76 | + groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } } |
77 | + teams = current_user.authorized_teams.map { |team| { label: "team: #{simple_sanitize(team.name)}", url: team_path(team) } } | ||
78 | 78 | ||
79 | default_nav = [ | 79 | default_nav = [ |
80 | { label: "My Profile", url: profile_path }, | 80 | { label: "My Profile", url: profile_path }, |
@@ -159,8 +159,13 @@ module ApplicationHelper | @@ -159,8 +159,13 @@ module ApplicationHelper | ||
159 | alt: "Sign in with #{provider.to_s.titleize}") | 159 | alt: "Sign in with #{provider.to_s.titleize}") |
160 | end | 160 | end |
161 | 161 | ||
162 | + def simple_sanitize str | ||
163 | + sanitize(str, tags: %w(a span)) | ||
164 | + end | ||
165 | + | ||
162 | def image_url(source) | 166 | def image_url(source) |
163 | root_url + path_to_image(source) | 167 | root_url + path_to_image(source) |
164 | end | 168 | end |
169 | + | ||
165 | alias_method :url_to_image, :image_url | 170 | alias_method :url_to_image, :image_url |
166 | end | 171 | end |
app/helpers/dashboard_helper.rb
app/helpers/issues_helper.rb
@@ -6,7 +6,7 @@ module IssuesHelper | @@ -6,7 +6,7 @@ module IssuesHelper | ||
6 | 6 | ||
7 | def issue_css_classes issue | 7 | def issue_css_classes issue |
8 | classes = "issue" | 8 | classes = "issue" |
9 | - classes << " closed" if issue.closed | 9 | + classes << " closed" if issue.closed? |
10 | classes << " today" if issue.today? | 10 | classes << " today" if issue.today? |
11 | classes | 11 | classes |
12 | end | 12 | end |
app/helpers/merge_requests_helper.rb
@@ -12,7 +12,7 @@ module MergeRequestsHelper | @@ -12,7 +12,7 @@ module MergeRequestsHelper | ||
12 | 12 | ||
13 | def mr_css_classes mr | 13 | def mr_css_classes mr |
14 | classes = "merge_request" | 14 | classes = "merge_request" |
15 | - classes << " closed" if mr.closed | 15 | + classes << " closed" if mr.closed? |
16 | classes << " merged" if mr.merged? | 16 | classes << " merged" if mr.merged? |
17 | classes | 17 | classes |
18 | end | 18 | end |
app/helpers/namespaces_helper.rb
@@ -10,8 +10,8 @@ module NamespacesHelper | @@ -10,8 +10,8 @@ module NamespacesHelper | ||
10 | 10 | ||
11 | 11 | ||
12 | global_opts = ["Global", [['/', Namespace.global_id]] ] | 12 | global_opts = ["Global", [['/', Namespace.global_id]] ] |
13 | - group_opts = ["Groups", groups.map {|g| [g.human_name, g.id]} ] | ||
14 | - users_opts = [ "Users", users.map {|u| [u.human_name, u.id]} ] | 13 | + group_opts = ["Groups", groups.sort_by(&:human_name).map {|g| [g.human_name, g.id]} ] |
14 | + users_opts = [ "Users", users.sort_by(&:human_name).map {|u| [u.human_name, u.id]} ] | ||
15 | 15 | ||
16 | options = [] | 16 | options = [] |
17 | options << global_opts if current_user.admin | 17 | options << global_opts if current_user.admin |
app/helpers/projects_helper.rb
1 | module ProjectsHelper | 1 | module ProjectsHelper |
2 | - def grouper_project_members(project) | ||
3 | - @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) | ||
4 | - end | ||
5 | - | ||
6 | - def grouper_project_teams(project) | ||
7 | - @project.user_team_project_relationships.sort_by(&:greatest_access).reverse.group_by(&:greatest_access) | ||
8 | - end | ||
9 | - | ||
10 | def remove_from_project_team_message(project, user) | 2 | def remove_from_project_team_message(project, user) |
11 | "You are going to remove #{user.name} from #{project.name} project team. Are you sure?" | 3 | "You are going to remove #{user.name} from #{project.name} project team. Are you sure?" |
12 | end | 4 | end |
@@ -56,7 +48,7 @@ module ProjectsHelper | @@ -56,7 +48,7 @@ module ProjectsHelper | ||
56 | def project_title project | 48 | def project_title project |
57 | if project.group | 49 | if project.group |
58 | content_tag :span do | 50 | content_tag :span do |
59 | - link_to(project.group.name, group_path(project.group)) + " / " + project.name | 51 | + link_to(simple_sanitize(project.group.name), group_path(project.group)) + " / " + project.name |
60 | end | 52 | end |
61 | else | 53 | else |
62 | project.name | 54 | project.name |
app/models/ability.rb
@@ -123,7 +123,7 @@ class Ability | @@ -123,7 +123,7 @@ class Ability | ||
123 | def user_team_abilities user, team | 123 | def user_team_abilities user, team |
124 | rules = [] | 124 | rules = [] |
125 | 125 | ||
126 | - # Only group owner and administrators can manage group | 126 | + # Only group owner and administrators can manage team |
127 | if team.owner == user || team.admin?(user) || user.admin? | 127 | if team.owner == user || team.admin?(user) || user.admin? |
128 | rules << [ :manage_user_team ] | 128 | rules << [ :manage_user_team ] |
129 | end | 129 | end |
app/models/concerns/issuable.rb
@@ -17,10 +17,9 @@ module Issuable | @@ -17,10 +17,9 @@ module Issuable | ||
17 | validates :project, presence: true | 17 | validates :project, presence: true |
18 | validates :author, presence: true | 18 | validates :author, presence: true |
19 | validates :title, presence: true, length: { within: 0..255 } | 19 | validates :title, presence: true, length: { within: 0..255 } |
20 | - validates :closed, inclusion: { in: [true, false] } | ||
21 | 20 | ||
22 | - scope :opened, -> { where(closed: false) } | ||
23 | - scope :closed, -> { where(closed: true) } | 21 | + scope :opened, -> { with_state(:opened) } |
22 | + scope :closed, -> { with_state(:closed) } | ||
24 | scope :of_group, ->(group) { where(project_id: group.project_ids) } | 23 | scope :of_group, ->(group) { where(project_id: group.project_ids) } |
25 | scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } | 24 | scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } |
26 | scope :assigned, ->(u) { where(assignee_id: u.id)} | 25 | scope :assigned, ->(u) { where(assignee_id: u.id)} |
@@ -62,14 +61,6 @@ module Issuable | @@ -62,14 +61,6 @@ module Issuable | ||
62 | assignee_id_changed? | 61 | assignee_id_changed? |
63 | end | 62 | end |
64 | 63 | ||
65 | - def is_being_closed? | ||
66 | - closed_changed? && closed | ||
67 | - end | ||
68 | - | ||
69 | - def is_being_reopened? | ||
70 | - closed_changed? && !closed | ||
71 | - end | ||
72 | - | ||
73 | # | 64 | # |
74 | # Votes | 65 | # Votes |
75 | # | 66 | # |
app/models/event.rb
@@ -130,10 +130,6 @@ class Event < ActiveRecord::Base | @@ -130,10 +130,6 @@ class Event < ActiveRecord::Base | ||
130 | target if target_type == "MergeRequest" | 130 | target if target_type == "MergeRequest" |
131 | end | 131 | end |
132 | 132 | ||
133 | - def author | ||
134 | - @author ||= User.find(author_id) | ||
135 | - end | ||
136 | - | ||
137 | def action_name | 133 | def action_name |
138 | if closed? | 134 | if closed? |
139 | "closed" | 135 | "closed" |
app/models/issue.rb
@@ -9,7 +9,7 @@ | @@ -9,7 +9,7 @@ | ||
9 | # project_id :integer | 9 | # project_id :integer |
10 | # created_at :datetime not null | 10 | # created_at :datetime not null |
11 | # updated_at :datetime not null | 11 | # updated_at :datetime not null |
12 | -# closed :boolean default(FALSE), not null | 12 | +# state :string default(FALSE), not null |
13 | # position :integer default(0) | 13 | # position :integer default(0) |
14 | # branch_name :string(255) | 14 | # branch_name :string(255) |
15 | # description :text | 15 | # description :text |
@@ -19,12 +19,35 @@ | @@ -19,12 +19,35 @@ | ||
19 | class Issue < ActiveRecord::Base | 19 | class Issue < ActiveRecord::Base |
20 | include Issuable | 20 | include Issuable |
21 | 21 | ||
22 | - attr_accessible :title, :assignee_id, :closed, :position, :description, | ||
23 | - :milestone_id, :label_list, :author_id_of_changes | 22 | + attr_accessible :title, :assignee_id, :position, :description, |
23 | + :milestone_id, :label_list, :author_id_of_changes, | ||
24 | + :state_event | ||
24 | 25 | ||
25 | acts_as_taggable_on :labels | 26 | acts_as_taggable_on :labels |
26 | 27 | ||
27 | - def self.open_for(user) | ||
28 | - opened.assigned(user) | 28 | + class << self |
29 | + def cared(user) | ||
30 | + where('assignee_id = :user', user: user.id) | ||
31 | + end | ||
32 | + | ||
33 | + def open_for(user) | ||
34 | + opened.assigned(user) | ||
35 | + end | ||
36 | + end | ||
37 | + | ||
38 | + state_machine :state, initial: :opened do | ||
39 | + event :close do | ||
40 | + transition [:reopened, :opened] => :closed | ||
41 | + end | ||
42 | + | ||
43 | + event :reopen do | ||
44 | + transition closed: :reopened | ||
45 | + end | ||
46 | + | ||
47 | + state :opened | ||
48 | + | ||
49 | + state :reopened | ||
50 | + | ||
51 | + state :closed | ||
29 | end | 52 | end |
30 | end | 53 | end |
app/models/key.rb
@@ -35,7 +35,7 @@ class Key < ActiveRecord::Base | @@ -35,7 +35,7 @@ class Key < ActiveRecord::Base | ||
35 | 35 | ||
36 | def fingerprintable_key | 36 | def fingerprintable_key |
37 | return true unless key # Don't test if there is no key. | 37 | return true unless key # Don't test if there is no key. |
38 | - # `ssh-keygen -lf /dev/stdin <<< "#{key}"` errors with: redirection unexpected | 38 | + |
39 | file = Tempfile.new('key_file') | 39 | file = Tempfile.new('key_file') |
40 | begin | 40 | begin |
41 | file.puts key | 41 | file.puts key |
@@ -45,7 +45,7 @@ class Key < ActiveRecord::Base | @@ -45,7 +45,7 @@ class Key < ActiveRecord::Base | ||
45 | file.close | 45 | file.close |
46 | file.unlink # deletes the temp file | 46 | file.unlink # deletes the temp file |
47 | end | 47 | end |
48 | - errors.add(:key, "can't be fingerprinted") if fingerprint_output.match("failed") | 48 | + errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0 |
49 | end | 49 | end |
50 | 50 | ||
51 | def set_identifier | 51 | def set_identifier |
app/models/merge_request.rb
@@ -9,15 +9,14 @@ | @@ -9,15 +9,14 @@ | ||
9 | # author_id :integer | 9 | # author_id :integer |
10 | # assignee_id :integer | 10 | # assignee_id :integer |
11 | # title :string(255) | 11 | # title :string(255) |
12 | -# closed :boolean default(FALSE), not null | 12 | +# state :string(255) not null |
13 | # created_at :datetime not null | 13 | # created_at :datetime not null |
14 | # updated_at :datetime not null | 14 | # updated_at :datetime not null |
15 | # st_commits :text(2147483647) | 15 | # st_commits :text(2147483647) |
16 | # st_diffs :text(2147483647) | 16 | # st_diffs :text(2147483647) |
17 | -# merged :boolean default(FALSE), not null | ||
18 | -# state :integer default(1), not null | ||
19 | -# milestone_id :integer | 17 | +# merge_status :integer default(1), not null |
20 | # | 18 | # |
19 | +# milestone_id :integer | ||
21 | 20 | ||
22 | require Rails.root.join("app/models/commit") | 21 | require Rails.root.join("app/models/commit") |
23 | require Rails.root.join("lib/static_model") | 22 | require Rails.root.join("lib/static_model") |
@@ -25,11 +24,33 @@ require Rails.root.join("lib/static_model") | @@ -25,11 +24,33 @@ require Rails.root.join("lib/static_model") | ||
25 | class MergeRequest < ActiveRecord::Base | 24 | class MergeRequest < ActiveRecord::Base |
26 | include Issuable | 25 | include Issuable |
27 | 26 | ||
28 | - attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id, | ||
29 | - :author_id_of_changes | 27 | + attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id, |
28 | + :author_id_of_changes, :state_event | ||
30 | 29 | ||
31 | attr_accessor :should_remove_source_branch | 30 | attr_accessor :should_remove_source_branch |
32 | 31 | ||
32 | + state_machine :state, initial: :opened do | ||
33 | + event :close do | ||
34 | + transition [:reopened, :opened] => :closed | ||
35 | + end | ||
36 | + | ||
37 | + event :merge do | ||
38 | + transition [:reopened, :opened] => :merged | ||
39 | + end | ||
40 | + | ||
41 | + event :reopen do | ||
42 | + transition closed: :reopened | ||
43 | + end | ||
44 | + | ||
45 | + state :opened | ||
46 | + | ||
47 | + state :reopened | ||
48 | + | ||
49 | + state :closed | ||
50 | + | ||
51 | + state :merged | ||
52 | + end | ||
53 | + | ||
33 | BROKEN_DIFF = "--broken-diff" | 54 | BROKEN_DIFF = "--broken-diff" |
34 | 55 | ||
35 | UNCHECKED = 1 | 56 | UNCHECKED = 1 |
@@ -43,21 +64,33 @@ class MergeRequest < ActiveRecord::Base | @@ -43,21 +64,33 @@ class MergeRequest < ActiveRecord::Base | ||
43 | validates :target_branch, presence: true | 64 | validates :target_branch, presence: true |
44 | validate :validate_branches | 65 | validate :validate_branches |
45 | 66 | ||
46 | - def self.find_all_by_branch(branch_name) | ||
47 | - where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) | ||
48 | - end | 67 | + scope :merged, -> { with_state(:merged) } |
49 | 68 | ||
50 | - def self.find_all_by_milestone(milestone) | ||
51 | - where("milestone_id = :milestone_id", milestone_id: milestone) | 69 | + class << self |
70 | + def find_all_by_branch(branch_name) | ||
71 | + where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) | ||
72 | + end | ||
73 | + | ||
74 | + def cared(user) | ||
75 | + where('assignee_id = :user OR author_id = :user', user: user.id) | ||
76 | + end | ||
77 | + | ||
78 | + def find_all_by_branch(branch_name) | ||
79 | + where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) | ||
80 | + end | ||
81 | + | ||
82 | + def find_all_by_milestone(milestone) | ||
83 | + where("milestone_id = :milestone_id", milestone_id: milestone) | ||
84 | + end | ||
52 | end | 85 | end |
53 | 86 | ||
54 | - def human_state | ||
55 | - states = { | 87 | + def human_merge_status |
88 | + merge_statuses = { | ||
56 | CAN_BE_MERGED => "can_be_merged", | 89 | CAN_BE_MERGED => "can_be_merged", |
57 | CANNOT_BE_MERGED => "cannot_be_merged", | 90 | CANNOT_BE_MERGED => "cannot_be_merged", |
58 | UNCHECKED => "unchecked" | 91 | UNCHECKED => "unchecked" |
59 | } | 92 | } |
60 | - states[self.state] | 93 | + merge_statuses[self.merge_status] |
61 | end | 94 | end |
62 | 95 | ||
63 | def validate_branches | 96 | def validate_branches |
@@ -72,20 +105,20 @@ class MergeRequest < ActiveRecord::Base | @@ -72,20 +105,20 @@ class MergeRequest < ActiveRecord::Base | ||
72 | end | 105 | end |
73 | 106 | ||
74 | def unchecked? | 107 | def unchecked? |
75 | - state == UNCHECKED | 108 | + merge_status == UNCHECKED |
76 | end | 109 | end |
77 | 110 | ||
78 | def mark_as_unchecked | 111 | def mark_as_unchecked |
79 | - self.state = UNCHECKED | 112 | + self.merge_status = UNCHECKED |
80 | self.save | 113 | self.save |
81 | end | 114 | end |
82 | 115 | ||
83 | def can_be_merged? | 116 | def can_be_merged? |
84 | - state == CAN_BE_MERGED | 117 | + merge_status == CAN_BE_MERGED |
85 | end | 118 | end |
86 | 119 | ||
87 | def check_if_can_be_merged | 120 | def check_if_can_be_merged |
88 | - self.state = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? | 121 | + self.merge_status = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? |
89 | CAN_BE_MERGED | 122 | CAN_BE_MERGED |
90 | else | 123 | else |
91 | CANNOT_BE_MERGED | 124 | CANNOT_BE_MERGED |
@@ -98,7 +131,7 @@ class MergeRequest < ActiveRecord::Base | @@ -98,7 +131,7 @@ class MergeRequest < ActiveRecord::Base | ||
98 | end | 131 | end |
99 | 132 | ||
100 | def reloaded_diffs | 133 | def reloaded_diffs |
101 | - if open? && unmerged_diffs.any? | 134 | + if opened? && unmerged_diffs.any? |
102 | self.st_diffs = unmerged_diffs | 135 | self.st_diffs = unmerged_diffs |
103 | self.save | 136 | self.save |
104 | end | 137 | end |
@@ -128,10 +161,6 @@ class MergeRequest < ActiveRecord::Base | @@ -128,10 +161,6 @@ class MergeRequest < ActiveRecord::Base | ||
128 | commits.first | 161 | commits.first |
129 | end | 162 | end |
130 | 163 | ||
131 | - def merged? | ||
132 | - merged && merge_event | ||
133 | - end | ||
134 | - | ||
135 | def merge_event | 164 | def merge_event |
136 | self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last | 165 | self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last |
137 | end | 166 | end |
@@ -146,26 +175,16 @@ class MergeRequest < ActiveRecord::Base | @@ -146,26 +175,16 @@ class MergeRequest < ActiveRecord::Base | ||
146 | 175 | ||
147 | def probably_merged? | 176 | def probably_merged? |
148 | unmerged_commits.empty? && | 177 | unmerged_commits.empty? && |
149 | - commits.any? && open? | ||
150 | - end | ||
151 | - | ||
152 | - def open? | ||
153 | - !closed | ||
154 | - end | ||
155 | - | ||
156 | - def mark_as_merged! | ||
157 | - self.merged = true | ||
158 | - self.closed = true | ||
159 | - save | 178 | + commits.any? && opened? |
160 | end | 179 | end |
161 | 180 | ||
162 | def mark_as_unmergable | 181 | def mark_as_unmergable |
163 | - self.state = CANNOT_BE_MERGED | 182 | + self.merge_status = CANNOT_BE_MERGED |
164 | self.save | 183 | self.save |
165 | end | 184 | end |
166 | 185 | ||
167 | def reloaded_commits | 186 | def reloaded_commits |
168 | - if open? && unmerged_commits.any? | 187 | + if opened? && unmerged_commits.any? |
169 | self.st_commits = unmerged_commits | 188 | self.st_commits = unmerged_commits |
170 | save | 189 | save |
171 | end | 190 | end |
@@ -181,7 +200,8 @@ class MergeRequest < ActiveRecord::Base | @@ -181,7 +200,8 @@ class MergeRequest < ActiveRecord::Base | ||
181 | end | 200 | end |
182 | 201 | ||
183 | def merge!(user_id) | 202 | def merge!(user_id) |
184 | - self.mark_as_merged! | 203 | + self.merge |
204 | + | ||
185 | Event.create( | 205 | Event.create( |
186 | project: self.project, | 206 | project: self.project, |
187 | action: Event::MERGED, | 207 | action: Event::MERGED, |
app/models/milestone.rb
@@ -13,19 +13,32 @@ | @@ -13,19 +13,32 @@ | ||
13 | # | 13 | # |
14 | 14 | ||
15 | class Milestone < ActiveRecord::Base | 15 | class Milestone < ActiveRecord::Base |
16 | - attr_accessible :title, :description, :due_date, :closed, :author_id_of_changes | 16 | + attr_accessible :title, :description, :due_date, :state_event, :author_id_of_changes |
17 | attr_accessor :author_id_of_changes | 17 | attr_accessor :author_id_of_changes |
18 | 18 | ||
19 | belongs_to :project | 19 | belongs_to :project |
20 | has_many :issues | 20 | has_many :issues |
21 | has_many :merge_requests | 21 | has_many :merge_requests |
22 | 22 | ||
23 | - scope :active, -> { where(closed: false) } | ||
24 | - scope :closed, -> { where(closed: true) } | 23 | + scope :active, -> { with_state(:active) } |
24 | + scope :closed, -> { with_state(:closed) } | ||
25 | 25 | ||
26 | validates :title, presence: true | 26 | validates :title, presence: true |
27 | validates :project, presence: true | 27 | validates :project, presence: true |
28 | - validates :closed, inclusion: { in: [true, false] } | 28 | + |
29 | + state_machine :state, initial: :active do | ||
30 | + event :close do | ||
31 | + transition active: :closed | ||
32 | + end | ||
33 | + | ||
34 | + event :activate do | ||
35 | + transition closed: :active | ||
36 | + end | ||
37 | + | ||
38 | + state :closed | ||
39 | + | ||
40 | + state :active | ||
41 | + end | ||
29 | 42 | ||
30 | def expired? | 43 | def expired? |
31 | if due_date | 44 | if due_date |
@@ -68,17 +81,13 @@ class Milestone < ActiveRecord::Base | @@ -68,17 +81,13 @@ class Milestone < ActiveRecord::Base | ||
68 | end | 81 | end |
69 | 82 | ||
70 | def can_be_closed? | 83 | def can_be_closed? |
71 | - open? && issues.opened.count.zero? | 84 | + active? && issues.opened.count.zero? |
72 | end | 85 | end |
73 | 86 | ||
74 | def is_empty? | 87 | def is_empty? |
75 | total_items_count.zero? | 88 | total_items_count.zero? |
76 | end | 89 | end |
77 | 90 | ||
78 | - def open? | ||
79 | - !closed | ||
80 | - end | ||
81 | - | ||
82 | def author_id | 91 | def author_id |
83 | author_id_of_changes | 92 | author_id_of_changes |
84 | end | 93 | end |
app/models/namespace.rb
@@ -17,11 +17,15 @@ class Namespace < ActiveRecord::Base | @@ -17,11 +17,15 @@ class Namespace < ActiveRecord::Base | ||
17 | has_many :projects, dependent: :destroy | 17 | has_many :projects, dependent: :destroy |
18 | belongs_to :owner, class_name: "User" | 18 | belongs_to :owner, class_name: "User" |
19 | 19 | ||
20 | - validates :name, presence: true, uniqueness: true | 20 | + validates :owner, presence: true |
21 | + validates :name, presence: true, uniqueness: true, | ||
22 | + length: { within: 0..255 }, | ||
23 | + format: { with: Gitlab::Regex.name_regex, | ||
24 | + message: "only letters, digits, spaces & '_' '-' '.' allowed." } | ||
25 | + | ||
21 | validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, | 26 | validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, |
22 | format: { with: Gitlab::Regex.path_regex, | 27 | format: { with: Gitlab::Regex.path_regex, |
23 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } | 28 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } |
24 | - validates :owner, presence: true | ||
25 | 29 | ||
26 | delegate :name, to: :owner, allow_nil: true, prefix: true | 30 | delegate :name, to: :owner, allow_nil: true, prefix: true |
27 | 31 |
app/models/project.rb
@@ -43,7 +43,7 @@ class Project < ActiveRecord::Base | @@ -43,7 +43,7 @@ class Project < ActiveRecord::Base | ||
43 | 43 | ||
44 | has_many :events, dependent: :destroy | 44 | has_many :events, dependent: :destroy |
45 | has_many :merge_requests, dependent: :destroy | 45 | has_many :merge_requests, dependent: :destroy |
46 | - has_many :issues, dependent: :destroy, order: "closed, created_at DESC" | 46 | + has_many :issues, dependent: :destroy, order: "state, created_at DESC" |
47 | has_many :milestones, dependent: :destroy | 47 | has_many :milestones, dependent: :destroy |
48 | has_many :users_projects, dependent: :destroy | 48 | has_many :users_projects, dependent: :destroy |
49 | has_many :notes, dependent: :destroy | 49 | has_many :notes, dependent: :destroy |
@@ -146,7 +146,7 @@ class Project < ActiveRecord::Base | @@ -146,7 +146,7 @@ class Project < ActiveRecord::Base | ||
146 | end | 146 | end |
147 | 147 | ||
148 | def saved? | 148 | def saved? |
149 | - id && valid? | 149 | + id && persisted? |
150 | end | 150 | end |
151 | 151 | ||
152 | def import? | 152 | def import? |
app/models/repository.rb
@@ -132,16 +132,16 @@ class Repository | @@ -132,16 +132,16 @@ class Repository | ||
132 | return nil unless commit | 132 | return nil unless commit |
133 | 133 | ||
134 | # Build file path | 134 | # Build file path |
135 | - file_name = self.path_with_namespace + "-" + commit.id.to_s + ".tar.gz" | 135 | + file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz" |
136 | storage_path = Rails.root.join("tmp", "repositories") | 136 | storage_path = Rails.root.join("tmp", "repositories") |
137 | - file_path = File.join(storage_path, file_name) | 137 | + file_path = File.join(storage_path, self.path_with_namespace, file_name) |
138 | 138 | ||
139 | # Put files into a directory before archiving | 139 | # Put files into a directory before archiving |
140 | prefix = self.path_with_namespace + "/" | 140 | prefix = self.path_with_namespace + "/" |
141 | 141 | ||
142 | # Create file if not exists | 142 | # Create file if not exists |
143 | unless File.exists?(file_path) | 143 | unless File.exists?(file_path) |
144 | - FileUtils.mkdir_p storage_path | 144 | + FileUtils.mkdir_p File.dirname(file_path) |
145 | file = self.repo.archive_to_file(ref, prefix, file_path) | 145 | file = self.repo.archive_to_file(ref, prefix, file_path) |
146 | end | 146 | end |
147 | 147 |
app/models/user.rb
@@ -234,8 +234,12 @@ class User < ActiveRecord::Base | @@ -234,8 +234,12 @@ class User < ActiveRecord::Base | ||
234 | keys.count == 0 | 234 | keys.count == 0 |
235 | end | 235 | end |
236 | 236 | ||
237 | + def can_change_username? | ||
238 | + Gitlab.config.gitlab.username_changing_enabled | ||
239 | + end | ||
240 | + | ||
237 | def can_create_project? | 241 | def can_create_project? |
238 | - projects_limit > personal_projects.count | 242 | + projects_limit > owned_projects.count |
239 | end | 243 | end |
240 | 244 | ||
241 | def can_create_group? | 245 | def can_create_group? |
@@ -263,7 +267,7 @@ class User < ActiveRecord::Base | @@ -263,7 +267,7 @@ class User < ActiveRecord::Base | ||
263 | end | 267 | end |
264 | 268 | ||
265 | def cared_merge_requests | 269 | def cared_merge_requests |
266 | - MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id) | 270 | + MergeRequest.cared(self) |
267 | end | 271 | end |
268 | 272 | ||
269 | # Remove user from all projects and | 273 | # Remove user from all projects and |
app/models/user_team.rb
@@ -21,8 +21,11 @@ class UserTeam < ActiveRecord::Base | @@ -21,8 +21,11 @@ class UserTeam < ActiveRecord::Base | ||
21 | has_many :projects, through: :user_team_project_relationships | 21 | has_many :projects, through: :user_team_project_relationships |
22 | has_many :members, through: :user_team_user_relationships, source: :user | 22 | has_many :members, through: :user_team_user_relationships, source: :user |
23 | 23 | ||
24 | - validates :name, presence: true, uniqueness: true | ||
25 | validates :owner, presence: true | 24 | validates :owner, presence: true |
25 | + validates :name, presence: true, uniqueness: true, | ||
26 | + length: { within: 0..255 }, | ||
27 | + format: { with: Gitlab::Regex.name_regex, | ||
28 | + message: "only letters, digits, spaces & '_' '-' '.' allowed." } | ||
26 | validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, | 29 | validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, |
27 | format: { with: Gitlab::Regex.path_regex, | 30 | format: { with: Gitlab::Regex.path_regex, |
28 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } | 31 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } |
app/models/user_team_project_relationship.rb
@@ -26,6 +26,10 @@ class UserTeamProjectRelationship < ActiveRecord::Base | @@ -26,6 +26,10 @@ class UserTeamProjectRelationship < ActiveRecord::Base | ||
26 | user_team.name | 26 | user_team.name |
27 | end | 27 | end |
28 | 28 | ||
29 | + def human_max_access | ||
30 | + UserTeam.access_roles.key(greatest_access) | ||
31 | + end | ||
32 | + | ||
29 | private | 33 | private |
30 | 34 | ||
31 | def check_greatest_access | 35 | def check_greatest_access |
app/observers/activity_observer.rb
@@ -20,15 +20,23 @@ class ActivityObserver < ActiveRecord::Observer | @@ -20,15 +20,23 @@ class ActivityObserver < ActiveRecord::Observer | ||
20 | end | 20 | end |
21 | end | 21 | end |
22 | 22 | ||
23 | - def after_save(record) | ||
24 | - if record.changed.include?("closed") && record.author_id_of_changes | 23 | + def after_close(record, transition) |
25 | Event.create( | 24 | Event.create( |
26 | project: record.project, | 25 | project: record.project, |
27 | target_id: record.id, | 26 | target_id: record.id, |
28 | target_type: record.class.name, | 27 | target_type: record.class.name, |
29 | - action: (record.closed ? Event::CLOSED : Event::REOPENED), | 28 | + action: Event::CLOSED, |
29 | + author_id: record.author_id_of_changes | ||
30 | + ) | ||
31 | + end | ||
32 | + | ||
33 | + def after_reopen(record, transition) | ||
34 | + Event.create( | ||
35 | + project: record.project, | ||
36 | + target_id: record.id, | ||
37 | + target_type: record.class.name, | ||
38 | + action: Event::REOPENED, | ||
30 | author_id: record.author_id_of_changes | 39 | author_id: record.author_id_of_changes |
31 | ) | 40 | ) |
32 | - end | ||
33 | end | 41 | end |
34 | end | 42 | end |
app/observers/issue_observer.rb
@@ -7,22 +7,31 @@ class IssueObserver < ActiveRecord::Observer | @@ -7,22 +7,31 @@ class IssueObserver < ActiveRecord::Observer | ||
7 | end | 7 | end |
8 | end | 8 | end |
9 | 9 | ||
10 | - def after_update(issue) | 10 | + def after_close(issue, transition) |
11 | send_reassigned_email(issue) if issue.is_being_reassigned? | 11 | send_reassigned_email(issue) if issue.is_being_reassigned? |
12 | 12 | ||
13 | - status = nil | ||
14 | - status = 'closed' if issue.is_being_closed? | ||
15 | - status = 'reopened' if issue.is_being_reopened? | ||
16 | - if status | ||
17 | - Note.create_status_change_note(issue, current_user, status) | ||
18 | - [issue.author, issue.assignee].compact.each do |recipient| | ||
19 | - Notify.delay.issue_status_changed_email(recipient.id, issue.id, status, current_user.id) | ||
20 | - end | ||
21 | - end | 13 | + create_note(issue) |
14 | + end | ||
15 | + | ||
16 | + def after_reopen(issue, transition) | ||
17 | + send_reassigned_email(issue) if issue.is_being_reassigned? | ||
18 | + | ||
19 | + create_note(issue) | ||
20 | + end | ||
21 | + | ||
22 | + def after_update(issue) | ||
23 | + send_reassigned_email(issue) if issue.is_being_reassigned? | ||
22 | end | 24 | end |
23 | 25 | ||
24 | protected | 26 | protected |
25 | 27 | ||
28 | + def create_note(issue) | ||
29 | + Note.create_status_change_note(issue, current_user, issue.state) | ||
30 | + [issue.author, issue.assignee].compact.each do |recipient| | ||
31 | + Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) | ||
32 | + end | ||
33 | + end | ||
34 | + | ||
26 | def send_reassigned_email(issue) | 35 | def send_reassigned_email(issue) |
27 | recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } | 36 | recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } |
28 | 37 |
app/observers/merge_request_observer.rb
@@ -7,15 +7,20 @@ class MergeRequestObserver < ActiveRecord::Observer | @@ -7,15 +7,20 @@ class MergeRequestObserver < ActiveRecord::Observer | ||
7 | end | 7 | end |
8 | end | 8 | end |
9 | 9 | ||
10 | - def after_update(merge_request) | 10 | + def after_close(merge_request, transition) |
11 | send_reassigned_email(merge_request) if merge_request.is_being_reassigned? | 11 | send_reassigned_email(merge_request) if merge_request.is_being_reassigned? |
12 | 12 | ||
13 | - status = nil | ||
14 | - status = 'closed' if merge_request.is_being_closed? | ||
15 | - status = 'reopened' if merge_request.is_being_reopened? | ||
16 | - if status | ||
17 | - Note.create_status_change_note(merge_request, current_user, status) | ||
18 | - end | 13 | + Note.create_status_change_note(merge_request, current_user, merge_request.state) |
14 | + end | ||
15 | + | ||
16 | + def after_reopen(merge_request, transition) | ||
17 | + send_reassigned_email(merge_request) if merge_request.is_being_reassigned? | ||
18 | + | ||
19 | + Note.create_status_change_note(merge_request, current_user, merge_request.state) | ||
20 | + end | ||
21 | + | ||
22 | + def after_update(merge_request) | ||
23 | + send_reassigned_email(merge_request) if merge_request.is_being_reassigned? | ||
19 | end | 24 | end |
20 | 25 | ||
21 | protected | 26 | protected |
app/uploaders/attachment_uploader.rb
@@ -19,4 +19,12 @@ class AttachmentUploader < CarrierWave::Uploader::Base | @@ -19,4 +19,12 @@ class AttachmentUploader < CarrierWave::Uploader::Base | ||
19 | rescue | 19 | rescue |
20 | false | 20 | false |
21 | end | 21 | end |
22 | + | ||
23 | + def secure_url | ||
24 | + if self.class.storage == CarrierWave::Storage::File | ||
25 | + "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}" | ||
26 | + else | ||
27 | + url | ||
28 | + end | ||
29 | + end | ||
22 | end | 30 | end |
app/views/admin/groups/index.html.haml
@@ -28,7 +28,7 @@ | @@ -28,7 +28,7 @@ | ||
28 | %td= group.path | 28 | %td= group.path |
29 | %td= group.projects.count | 29 | %td= group.projects.count |
30 | %td | 30 | %td |
31 | - = link_to group.owner_name, admin_user_path(group.owner_id) | 31 | + = link_to group.owner_name, admin_user_path(group.owner) |
32 | %td.bgred | 32 | %td.bgred |
33 | = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small" | 33 | = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small" |
34 | = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" | 34 | = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" |
app/views/admin/teams/index.html.haml
@@ -30,7 +30,7 @@ | @@ -30,7 +30,7 @@ | ||
30 | %td= team.projects.count | 30 | %td= team.projects.count |
31 | %td= team.members.count | 31 | %td= team.members.count |
32 | %td | 32 | %td |
33 | - = link_to team.owner.name, admin_user_path(team.owner_id) | 33 | + = link_to team.owner.name, admin_user_path(team.owner) |
34 | %td.bgred | 34 | %td.bgred |
35 | = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small" | 35 | = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small" |
36 | = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" | 36 | = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" |
app/views/commits/_commit.html.haml
@@ -6,9 +6,9 @@ | @@ -6,9 +6,9 @@ | ||
6 | = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" | 6 | = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" |
7 | = commit.author_link avatar: true, size: 24 | 7 | = commit.author_link avatar: true, size: 24 |
8 | | 8 | |
9 | - = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title" | 9 | + = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title" |
10 | 10 | ||
11 | - %span.committed_ago | 11 | + %time.committed_ago{ datetime: commit.committed_date, title: commit.committed_date.stamp("Aug 21, 2011 9:23pm") } |
12 | = time_ago_in_words(commit.committed_date) | 12 | = time_ago_in_words(commit.committed_date) |
13 | ago | 13 | ago |
14 | | 14 | |
app/views/events/event/_note.html.haml
@@ -26,7 +26,7 @@ | @@ -26,7 +26,7 @@ | ||
26 | = markdown truncate(event.target.note, length: 70) | 26 | = markdown truncate(event.target.note, length: 70) |
27 | - note = event.target | 27 | - note = event.target |
28 | - if note.attachment.url | 28 | - if note.attachment.url |
29 | - = link_to note.attachment.url, target: "_blank", class: 'note-file-attach' do | 29 | + = link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do |
30 | - if note.attachment.image? | 30 | - if note.attachment.image? |
31 | = image_tag note.attachment.url, class: 'note-image-attach' | 31 | = image_tag note.attachment.url, class: 'note-image-attach' |
32 | - else | 32 | - else |
app/views/groups/_filter.html.haml
@@ -26,6 +26,8 @@ | @@ -26,6 +26,8 @@ | ||
26 | = link_to group_filter_path(entity, project_id: project.id) do | 26 | = link_to group_filter_path(entity, project_id: project.id) do |
27 | = project.name_with_namespace | 27 | = project.name_with_namespace |
28 | %small.pull-right= entities_per_project(project, entity) | 28 | %small.pull-right= entities_per_project(project, entity) |
29 | + - if @projects.blank? | ||
30 | + %p.nothing_here_message This group has no projects yet | ||
29 | 31 | ||
30 | %fieldset | 32 | %fieldset |
31 | %hr | 33 | %hr |
app/views/groups/_people_filter.html.haml
@@ -7,6 +7,8 @@ | @@ -7,6 +7,8 @@ | ||
7 | = link_to people_group_path(@group, project_id: project.id) do | 7 | = link_to people_group_path(@group, project_id: project.id) do |
8 | = project.name_with_namespace | 8 | = project.name_with_namespace |
9 | %small.pull-right= project.users.count | 9 | %small.pull-right= project.users.count |
10 | + - if @projects.blank? | ||
11 | + %p.nothing_here_message This group has no projects yet | ||
10 | 12 | ||
11 | %fieldset | 13 | %fieldset |
12 | %hr | 14 | %hr |
app/views/groups/edit.html.haml
@@ -30,6 +30,8 @@ | @@ -30,6 +30,8 @@ | ||
30 | = link_to 'Team', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" | 30 | = link_to 'Team', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" |
31 | = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" | 31 | = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" |
32 | = link_to 'Remove', project, confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" | 32 | = link_to 'Remove', project, confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" |
33 | + - if @group.projects.blank? | ||
34 | + %p.nothing_here_message This group has no projects yet | ||
33 | 35 | ||
34 | .span5 | 36 | .span5 |
35 | .ui-box | 37 | .ui-box |
app/views/help/index.html.haml
app/views/issues/_show.html.haml
@@ -8,10 +8,10 @@ | @@ -8,10 +8,10 @@ | ||
8 | %i.icon-comment | 8 | %i.icon-comment |
9 | = issue.notes.count | 9 | = issue.notes.count |
10 | - if can? current_user, :modify_issue, issue | 10 | - if can? current_user, :modify_issue, issue |
11 | - - if issue.closed | ||
12 | - = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {closed: false }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true | 11 | + - if issue.closed? |
12 | + = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true | ||
13 | - else | 13 | - else |
14 | - = link_to 'Close', project_issue_path(issue.project, issue, issue: {closed: true }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true | 14 | + = link_to 'Close', project_issue_path(issue.project, issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true |
15 | = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do | 15 | = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do |
16 | %i.icon-edit | 16 | %i.icon-edit |
17 | Edit | 17 | Edit |
app/views/issues/show.html.haml
@@ -7,10 +7,10 @@ | @@ -7,10 +7,10 @@ | ||
7 | 7 | ||
8 | %span.pull-right | 8 | %span.pull-right |
9 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user | 9 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user |
10 | - - if @issue.closed | ||
11 | - = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn grouped reopen_issue" | 10 | + - if @issue.closed? |
11 | + = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" | ||
12 | - else | 12 | - else |
13 | - = link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" | 13 | + = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" |
14 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user | 14 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user |
15 | = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do | 15 | = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do |
16 | %i.icon-edit | 16 | %i.icon-edit |
@@ -27,7 +27,7 @@ | @@ -27,7 +27,7 @@ | ||
27 | .ui-box.ui-box-show | 27 | .ui-box.ui-box-show |
28 | .ui-box-head | 28 | .ui-box-head |
29 | %h4.box-title | 29 | %h4.box-title |
30 | - - if @issue.closed | 30 | + - if @issue.closed? |
31 | .error.status_info Closed | 31 | .error.status_info Closed |
32 | = gfm escape_once(@issue.title) | 32 | = gfm escape_once(@issue.title) |
33 | 33 |
app/views/merge_requests/_show.html.haml
@@ -29,10 +29,10 @@ | @@ -29,10 +29,10 @@ | ||
29 | $(function(){ | 29 | $(function(){ |
30 | merge_request = new MergeRequest({ | 30 | merge_request = new MergeRequest({ |
31 | url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", | 31 | url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", |
32 | - check_enable: #{@merge_request.state == MergeRequest::UNCHECKED ? "true" : "false"}, | 32 | + check_enable: #{@merge_request.merge_status == MergeRequest::UNCHECKED ? "true" : "false"}, |
33 | url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", | 33 | url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", |
34 | ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, | 34 | ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, |
35 | - current_state: "#{@merge_request.human_state}", | 35 | + current_status: "#{@merge_request.human_merge_status}", |
36 | action: "#{controller.action_name}" | 36 | action: "#{controller.action_name}" |
37 | }); | 37 | }); |
38 | }); | 38 | }); |
app/views/merge_requests/show/_mr_accept.html.haml
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | %strong Only masters can accept MR | 3 | %strong Only masters can accept MR |
4 | 4 | ||
5 | 5 | ||
6 | -- if @merge_request.open? && @commits.any? && can?(current_user, :accept_mr, @project) | 6 | +- if @merge_request.opened? && @commits.any? && can?(current_user, :accept_mr, @project) |
7 | .automerge_widget.can_be_merged{style: "display:none"} | 7 | .automerge_widget.can_be_merged{style: "display:none"} |
8 | .alert.alert-success | 8 | .alert.alert-success |
9 | %span | 9 | %span |
app/views/merge_requests/show/_mr_box.html.haml
1 | .ui-box.ui-box-show | 1 | .ui-box.ui-box-show |
2 | .ui-box-head | 2 | .ui-box-head |
3 | %h4.box-title | 3 | %h4.box-title |
4 | - - if @merge_request.merged | 4 | + - if @merge_request.merged? |
5 | .error.status_info | 5 | .error.status_info |
6 | %i.icon-ok | 6 | %i.icon-ok |
7 | Merged | 7 | Merged |
8 | - - elsif @merge_request.closed | 8 | + - elsif @merge_request.closed? |
9 | .error.status_info Closed | 9 | .error.status_info Closed |
10 | = gfm escape_once(@merge_request.title) | 10 | = gfm escape_once(@merge_request.title) |
11 | 11 | ||
@@ -21,14 +21,14 @@ | @@ -21,14 +21,14 @@ | ||
21 | %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone) | 21 | %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone) |
22 | 22 | ||
23 | 23 | ||
24 | - - if @merge_request.closed | 24 | + - if @merge_request.closed? |
25 | .ui-box-bottom | 25 | .ui-box-bottom |
26 | - - if @merge_request.merged? | ||
27 | - %span | ||
28 | - Merged by #{link_to_member(@project, @merge_request.merge_event.author)} | ||
29 | - %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago. | ||
30 | - - elsif @merge_request.closed_event | ||
31 | - %span | ||
32 | - Closed by #{link_to_member(@project, @merge_request.closed_event.author)} | ||
33 | - %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago. | 26 | + %span |
27 | + Closed by #{link_to_member(@project, @merge_request.closed_event.author)} | ||
28 | + %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago. | ||
29 | + - if @merge_request.merged? | ||
30 | + .ui-box-bottom | ||
31 | + %span | ||
32 | + Merged by #{link_to_member(@project, @merge_request.merge_event.author)} | ||
33 | + %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago. | ||
34 | 34 |
app/views/merge_requests/show/_mr_ci.html.haml
app/views/merge_requests/show/_mr_title.html.haml
@@ -7,7 +7,7 @@ | @@ -7,7 +7,7 @@ | ||
7 | 7 | ||
8 | %span.pull-right | 8 | %span.pull-right |
9 | - if can?(current_user, :modify_merge_request, @merge_request) | 9 | - if can?(current_user, :modify_merge_request, @merge_request) |
10 | - - if @merge_request.open? | 10 | + - if @merge_request.opened? |
11 | .left.btn-group | 11 | .left.btn-group |
12 | %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} } | 12 | %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} } |
13 | %i.icon-download-alt | 13 | %i.icon-download-alt |
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | %li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch) | 17 | %li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch) |
18 | %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff) | 18 | %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff) |
19 | 19 | ||
20 | - = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {closed: true }, status_only: true), method: :put, class: "btn grouped btn-close", title: "Close merge request" | 20 | + = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn grouped btn-close", title: "Close merge request" |
21 | 21 | ||
22 | = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn grouped" do | 22 | = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn grouped" do |
23 | %i.icon-edit | 23 | %i.icon-edit |
app/views/milestones/_milestone.html.haml
1 | -%li{class: "milestone milestone-#{milestone.closed ? 'closed' : 'open'}", id: dom_id(milestone) } | 1 | +%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone) } |
2 | .pull-right | 2 | .pull-right |
3 | - - if can?(current_user, :admin_milestone, milestone.project) and milestone.open? | 3 | + - if can?(current_user, :admin_milestone, milestone.project) and milestone.active? |
4 | = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do | 4 | = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do |
5 | %i.icon-edit | 5 | %i.icon-edit |
6 | Edit | 6 | Edit |
7 | %h4 | 7 | %h4 |
8 | = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone) | 8 | = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone) |
9 | - - if milestone.expired? and not milestone.closed | 9 | + - if milestone.expired? and not milestone.closed? |
10 | %span.cred (Expired) | 10 | %span.cred (Expired) |
11 | %small | 11 | %small |
12 | = milestone.expires_at | 12 | = milestone.expires_at |
app/views/milestones/show.html.haml
@@ -9,7 +9,7 @@ | @@ -9,7 +9,7 @@ | ||
9 | ← To milestones list | 9 | ← To milestones list |
10 | .span6 | 10 | .span6 |
11 | .pull-right | 11 | .pull-right |
12 | - - unless @milestone.closed | 12 | + - unless @milestone.closed? |
13 | = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do | 13 | = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do |
14 | %i.icon-plus | 14 | %i.icon-plus |
15 | New Issue | 15 | New Issue |
@@ -25,12 +25,12 @@ | @@ -25,12 +25,12 @@ | ||
25 | %hr | 25 | %hr |
26 | %p | 26 | %p |
27 | %span All issues for this milestone are closed. You may close milestone now. | 27 | %span All issues for this milestone are closed. You may close milestone now. |
28 | - = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn btn-small btn-remove" | 28 | + = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-remove" |
29 | 29 | ||
30 | .ui-box.ui-box-show | 30 | .ui-box.ui-box-show |
31 | .ui-box-head | 31 | .ui-box-head |
32 | %h4.box-title | 32 | %h4.box-title |
33 | - - if @milestone.closed | 33 | + - if @milestone.closed? |
34 | .error.status_info Closed | 34 | .error.status_info Closed |
35 | - elsif @milestone.expired? | 35 | - elsif @milestone.expired? |
36 | .error.status_info Expired | 36 | .error.status_info Expired |
@@ -63,7 +63,7 @@ | @@ -63,7 +63,7 @@ | ||
63 | %li=link_to('All Issues', '#') | 63 | %li=link_to('All Issues', '#') |
64 | %ul.well-list | 64 | %ul.well-list |
65 | - @issues.each do |issue| | 65 | - @issues.each do |issue| |
66 | - %li{data: {closed: issue.closed}} | 66 | + %li{data: {closed: issue.closed?}} |
67 | = link_to [@project, issue] do | 67 | = link_to [@project, issue] do |
68 | %span.badge.badge-info ##{issue.id} | 68 | %span.badge.badge-info ##{issue.id} |
69 | – | 69 | – |
@@ -77,7 +77,7 @@ | @@ -77,7 +77,7 @@ | ||
77 | %li=link_to('All Merge Requests', '#') | 77 | %li=link_to('All Merge Requests', '#') |
78 | %ul.well-list | 78 | %ul.well-list |
79 | - @merge_requests.each do |merge_request| | 79 | - @merge_requests.each do |merge_request| |
80 | - %li{data: {closed: merge_request.closed}} | 80 | + %li{data: {closed: merge_request.closed?}} |
81 | = link_to [@project, merge_request] do | 81 | = link_to [@project, merge_request] do |
82 | %span.badge.badge-info ##{merge_request.id} | 82 | %span.badge.badge-info ##{merge_request.id} |
83 | – | 83 | – |
app/views/notes/_note.html.haml
@@ -31,7 +31,7 @@ | @@ -31,7 +31,7 @@ | ||
31 | - if note.attachment.image? | 31 | - if note.attachment.image? |
32 | = image_tag note.attachment.url, class: 'note-image-attach' | 32 | = image_tag note.attachment.url, class: 'note-image-attach' |
33 | .attachment.pull-right | 33 | .attachment.pull-right |
34 | - = link_to note.attachment.url, target: "_blank" do | 34 | + = link_to note.attachment.secure_url, target: "_blank" do |
35 | %i.icon-paper-clip | 35 | %i.icon-paper-clip |
36 | = note.attachment_identifier | 36 | = note.attachment_identifier |
37 | .clear | 37 | .clear |
app/views/profiles/account.html.haml
@@ -53,29 +53,30 @@ | @@ -53,29 +53,30 @@ | ||
53 | 53 | ||
54 | 54 | ||
55 | 55 | ||
56 | -%fieldset.update-username | ||
57 | - %legend | ||
58 | - Username | ||
59 | - %small.cred.pull-right | ||
60 | - Changing your username can have unintended side effects! | ||
61 | - = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f| | ||
62 | - .padded | ||
63 | - = f.label :username | ||
64 | - .input | ||
65 | - = f.text_field :username, required: true | ||
66 | - | ||
67 | - %span.loading-gif.hide= image_tag "ajax_loader.gif" | ||
68 | - %span.update-success.cgreen.hide | ||
69 | - %i.icon-ok | ||
70 | - Saved | ||
71 | - %span.update-failed.cred.hide | ||
72 | - %i.icon-remove | ||
73 | - Failed | ||
74 | - %ul.cred | ||
75 | - %li It will change web url for personal projects. | ||
76 | - %li It will change the git path to repositories for personal projects. | ||
77 | - .input | ||
78 | - = f.submit 'Save username', class: "btn btn-save" | 56 | +- if current_user.can_change_username? |
57 | + %fieldset.update-username | ||
58 | + %legend | ||
59 | + Username | ||
60 | + %small.cred.pull-right | ||
61 | + Changing your username can have unintended side effects! | ||
62 | + = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f| | ||
63 | + .padded | ||
64 | + = f.label :username | ||
65 | + .input | ||
66 | + = f.text_field :username, required: true | ||
67 | + | ||
68 | + %span.loading-gif.hide= image_tag "ajax_loader.gif" | ||
69 | + %span.update-success.cgreen.hide | ||
70 | + %i.icon-ok | ||
71 | + Saved | ||
72 | + %span.update-failed.cred.hide | ||
73 | + %i.icon-remove | ||
74 | + Failed | ||
75 | + %ul.cred | ||
76 | + %li It will change web url for personal projects. | ||
77 | + %li It will change the git path to repositories for personal projects. | ||
78 | + .input | ||
79 | + = f.submit 'Save username', class: "btn btn-save" | ||
79 | 80 | ||
80 | - if Gitlab.config.gitlab.signup_enabled | 81 | - if Gitlab.config.gitlab.signup_enabled |
81 | %fieldset.remove-account | 82 | %fieldset.remove-account |
@@ -83,4 +84,4 @@ | @@ -83,4 +84,4 @@ | ||
83 | Remove account | 84 | Remove account |
84 | %small.cred.pull-right | 85 | %small.cred.pull-right |
85 | Before removing the account you must remove all projects! | 86 | Before removing the account you must remove all projects! |
86 | - = link_to 'Delete account', user_registration_path, confirm: "REMOVE #{current_user.name}? Are you sure?", method: :delete, class: "btn btn-remove delete-key btn-small pull-right" | ||
87 | \ No newline at end of file | 87 | \ No newline at end of file |
88 | + = link_to 'Delete account', user_registration_path, confirm: "REMOVE #{current_user.name}? Are you sure?", method: :delete, class: "btn btn-remove delete-key btn-small pull-right" |
app/views/profiles/show.html.haml
@@ -77,7 +77,7 @@ | @@ -77,7 +77,7 @@ | ||
77 | %legend | 77 | %legend |
78 | Personal projects: | 78 | Personal projects: |
79 | %small.pull-right | 79 | %small.pull-right |
80 | - %span= current_user.personal_projects.count | 80 | + %span= current_user.owned_projects.count |
81 | of | 81 | of |
82 | %span= current_user.projects_limit | 82 | %span= current_user.projects_limit |
83 | .padded | 83 | .padded |
app/views/projects/_new_form.html.haml
@@ -28,7 +28,7 @@ | @@ -28,7 +28,7 @@ | ||
28 | .input | 28 | .input |
29 | = f.text_field :import_url, class: 'xlarge', placeholder: 'https://github.com/randx/six.git' | 29 | = f.text_field :import_url, class: 'xlarge', placeholder: 'https://github.com/randx/six.git' |
30 | .light | 30 | .light |
31 | - URL should be clonable | 31 | + URL must be clonable |
32 | 32 | ||
33 | %p.padded | 33 | %p.padded |
34 | New projects are private by default. You choose who can see the project and commit to repository. | 34 | New projects are private by default. You choose who can see the project and commit to repository. |
app/views/projects/files.html.haml
@@ -9,7 +9,7 @@ | @@ -9,7 +9,7 @@ | ||
9 | - @notes.each do |note| | 9 | - @notes.each do |note| |
10 | %tr | 10 | %tr |
11 | %td | 11 | %td |
12 | - %a{href: note.attachment.url} | 12 | + = link_to note.attachment.secure_url, target: "_blank" do |
13 | = image_tag gravatar_icon(note.author_email), class: "avatar s24" | 13 | = image_tag gravatar_icon(note.author_email), class: "avatar s24" |
14 | = note.attachment_identifier | 14 | = note.attachment_identifier |
15 | %td | 15 | %td |
@@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
1 | +%li{id: dom_id(team), class: "user_team_row team_#{team.id}"} | ||
2 | + .pull-right | ||
3 | + - if can?(current_user, :admin_team_member, @project) | ||
4 | + = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove btn-tiny" do | ||
5 | + %i.icon-minus.icon-white | ||
6 | + | ||
7 | + %strong= link_to team.name, team_path(team), title: team.name, class: "dark" | ||
8 | + %br | ||
9 | + %small.cgray Members: #{team.members.count} | ||
10 | + %small.cgray Max access: #{team_relation.human_max_access} |
app/views/team_members/_show.html.haml
@@ -1,28 +0,0 @@ | @@ -1,28 +0,0 @@ | ||
1 | -- user = member.user | ||
2 | -- allow_admin = can? current_user, :admin_project, @project | ||
3 | -%li{id: dom_id(user), class: "team_member_row user_#{user.id}"} | ||
4 | - .row | ||
5 | - .span6 | ||
6 | - = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do | ||
7 | - = image_tag gravatar_icon(user.email, 40), class: "avatar s32" | ||
8 | - = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do | ||
9 | - %strong= truncate(user.name, lenght: 40) | ||
10 | - %br | ||
11 | - %small.cgray= user.email | ||
12 | - | ||
13 | - .span5.pull-right | ||
14 | - - if allow_admin | ||
15 | - .left | ||
16 | - = form_for(member, as: :team_member, url: project_team_member_path(@project, member.user)) do |f| | ||
17 | - = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2" | ||
18 | - .pull-right | ||
19 | - - if current_user == user | ||
20 | - %span.btn.disabled This is you! | ||
21 | - - if @project.namespace_owner == user | ||
22 | - %span.btn.disabled Owner | ||
23 | - - elsif user.blocked | ||
24 | - %span.btn.disabled.blocked Blocked | ||
25 | - - elsif allow_admin | ||
26 | - = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove" do | ||
27 | - %i.icon-minus.icon-white | ||
28 | - |
app/views/team_members/_show_team.html.haml
@@ -1,15 +0,0 @@ | @@ -1,15 +0,0 @@ | ||
1 | -- team = team_rel.user_team | ||
2 | -- allow_admin = can? current_user, :admin_team_member, @project | ||
3 | -%li{id: dom_id(team), class: "user_team_row team_#{team.id}"} | ||
4 | - .row | ||
5 | - .span6 | ||
6 | - %strong= link_to team.name, team_path(team), title: team.name, class: "dark" | ||
7 | - %br | ||
8 | - %small.cgray Members: #{team.members.count} | ||
9 | - | ||
10 | - .span5.pull-right | ||
11 | - .pull-right | ||
12 | - - if allow_admin | ||
13 | - .left | ||
14 | - = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove small" do | ||
15 | - %i.icon-minus.icon-white |
app/views/team_members/_team.html.haml
1 | -- grouper_project_members(@project).each do |access, members| | 1 | +- team.each do |access, members| |
2 | .ui-box | 2 | .ui-box |
3 | %h5.title | 3 | %h5.title |
4 | = Project.access_options.key(access).pluralize | 4 | = Project.access_options.key(access).pluralize |
5 | %small= members.size | 5 | %small= members.size |
6 | %ul.well-list | 6 | %ul.well-list |
7 | - - members.sort_by(&:user_name).each do |up| | ||
8 | - = render(partial: 'team_members/show', locals: {member: up}) | ||
9 | - | ||
10 | - | ||
11 | -:javascript | ||
12 | - $(function(){ | ||
13 | - $('.repo-access-select, .project-access-select').live("change", function() { | ||
14 | - $(this.form).submit(); | ||
15 | - }); | ||
16 | - }) | 7 | + - members.sort_by(&:user_name).each do |team_member| |
8 | + = render 'team_members/team_member', member: team_member |
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +- user = member.user | ||
2 | +- allow_admin = can? current_user, :admin_project, @project | ||
3 | +%li{id: dom_id(user), class: "team_member_row user_#{user.id}"} | ||
4 | + .row | ||
5 | + .span4 | ||
6 | + = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do | ||
7 | + = image_tag gravatar_icon(user.email, 40), class: "avatar s32" | ||
8 | + = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do | ||
9 | + %strong= truncate(user.name, lenght: 40) | ||
10 | + %br | ||
11 | + %small.cgray= user.email | ||
12 | + | ||
13 | + .span4.pull-right | ||
14 | + - if allow_admin | ||
15 | + .left | ||
16 | + = form_for(member, as: :team_member, url: project_team_member_path(@project, member.user)) do |f| | ||
17 | + = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2 trigger-submit" | ||
18 | + .pull-right | ||
19 | + - if current_user == user | ||
20 | + %span.label This is you! | ||
21 | + - if @project.namespace_owner == user | ||
22 | + %span.label Owner | ||
23 | + - elsif user.blocked | ||
24 | + %span.label Blocked | ||
25 | + - elsif allow_admin | ||
26 | + = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove" do | ||
27 | + %i.icon-minus.icon-white | ||
28 | + |
app/views/team_members/_teams.html.haml
@@ -1,16 +0,0 @@ | @@ -1,16 +0,0 @@ | ||
1 | -- grouper_project_teams(@project).each do |access, teams| | ||
2 | - .ui-box | ||
3 | - %h5.title | ||
4 | - = UserTeam.access_roles.key(access).pluralize | ||
5 | - %small= teams.size | ||
6 | - %ul.well-list | ||
7 | - - teams.sort_by(&:team_name).each do |tofr| | ||
8 | - = render(partial: 'team_members/show_team', locals: {team_rel: tofr}) | ||
9 | - | ||
10 | - | ||
11 | -:javascript | ||
12 | - $(function(){ | ||
13 | - $('.repo-access-select, .project-access-select').live("change", function() { | ||
14 | - $(this.form).submit(); | ||
15 | - }); | ||
16 | - }) |
app/views/team_members/index.html.haml
@@ -18,16 +18,39 @@ | @@ -18,16 +18,39 @@ | ||
18 | %hr | 18 | %hr |
19 | 19 | ||
20 | .clearfix | 20 | .clearfix |
21 | -%div.team-table | ||
22 | - = render partial: "team_members/team", locals: {project: @project} | 21 | +.row |
22 | + .span3 | ||
23 | + %ul.nav.nav-pills.nav-stacked | ||
24 | + %li{class: ("active" if !params[:type])} | ||
25 | + = link_to project_team_members_path(type: nil) do | ||
26 | + All | ||
27 | + %li{class: ("active" if params[:type] == 'masters')} | ||
28 | + = link_to project_team_members_path(type: 'masters') do | ||
29 | + Masters | ||
30 | + %span.pull-right= @project.users_projects.masters.count | ||
31 | + %li{class: ("active" if params[:type] == 'developers')} | ||
32 | + = link_to project_team_members_path(type: 'developers') do | ||
33 | + Developers | ||
34 | + %span.pull-right= @project.users_projects.developers.count | ||
35 | + %li{class: ("active" if params[:type] == 'reporters')} | ||
36 | + = link_to project_team_members_path(type: 'reporters') do | ||
37 | + Reporters | ||
38 | + %span.pull-right= @project.users_projects.reporters.count | ||
39 | + %li{class: ("active" if params[:type] == 'guests')} | ||
40 | + = link_to project_team_members_path(type: 'guests') do | ||
41 | + Guests | ||
42 | + %span.pull-right= @project.users_projects.guests.count | ||
23 | 43 | ||
44 | + - if @assigned_teams.present? | ||
45 | + %h5 | ||
46 | + Assigned teams | ||
47 | + (#{@project.user_teams.count}) | ||
48 | + %div | ||
49 | + = render "team_members/assigned_teams", assigned_teams: @assigned_teams | ||
50 | + | ||
51 | + .span9 | ||
52 | + %div.team-table | ||
53 | + = render "team_members/team", team: @team | ||
24 | 54 | ||
25 | -%h3.page_title | ||
26 | - Assigned teams | ||
27 | - (#{@project.user_teams.count}) | ||
28 | 55 | ||
29 | -%hr | ||
30 | 56 | ||
31 | -.clearfix | ||
32 | -%div.team-table | ||
33 | - = render partial: "team_members/teams", locals: {project: @project} |
app/views/teams/edit.html.haml
1 | %h3.page_title= "Edit Team #{@team.name}" | 1 | %h3.page_title= "Edit Team #{@team.name}" |
2 | %hr | 2 | %hr |
3 | -= form_for @team, url: team_path(@team) do |f| | ||
4 | - - if @team.errors.any? | ||
5 | - .alert.alert-error | ||
6 | - %span= @team.errors.full_messages.first | ||
7 | - .clearfix | ||
8 | - = f.label :name do | ||
9 | - Team name is | ||
10 | - .input | ||
11 | - = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" | 3 | +.row |
4 | + .span7 | ||
5 | + = form_for @team, url: team_path(@team) do |f| | ||
6 | + - if @team.errors.any? | ||
7 | + .alert.alert-error | ||
8 | + %span= @team.errors.full_messages.first | ||
9 | + .clearfix | ||
10 | + = f.label :name do | ||
11 | + Team name is | ||
12 | + .input | ||
13 | + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xlarge left" | ||
14 | + | ||
15 | + .clearfix | ||
16 | + = f.label :path do | ||
17 | + Team path is | ||
18 | + .input | ||
19 | + = f.text_field :path, placeholder: "opensource", class: "xlarge left" | ||
20 | + .form-actions | ||
21 | + = f.submit 'Save team changes', class: "btn btn-save" | ||
22 | + .span5 | ||
23 | + .ui-box | ||
24 | + %h5.title Remove team | ||
25 | + .padded.bgred | ||
26 | + %p | ||
27 | + Removed team can not be restored! | ||
28 | + = link_to 'Remove team', team_path(@team), method: :delete, confirm: "You are sure?", class: "btn btn-remove btn-small" | ||
12 | 29 | ||
13 | - .clearfix | ||
14 | - = f.label :path do | ||
15 | - Team path is | ||
16 | - .input | ||
17 | - = f.text_field :path, placeholder: "opensource", class: "xxlarge left" | ||
18 | - .form-actions | ||
19 | - = f.submit 'Save team changes', class: "btn btn-primary" | ||
20 | - = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn btn-remove pull-right" |
app/views/teams/members/_show.html.haml
@@ -10,22 +10,21 @@ | @@ -10,22 +10,21 @@ | ||
10 | %br | 10 | %br |
11 | %small.cgray= user.email | 11 | %small.cgray= user.email |
12 | 12 | ||
13 | - .span6.pull-right | 13 | + .span4 |
14 | - if allow_admin | 14 | - if allow_admin |
15 | - .left.span2 | ||
16 | - = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f| | ||
17 | - = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium project-access-select span2" | ||
18 | - .left.span2 | ||
19 | - %span | ||
20 | - = check_box_tag :group_admin, true, @team.admin?(user) | ||
21 | - Admin access | ||
22 | - .pull-right | ||
23 | - - if current_user == user | ||
24 | - %span.btn.disabled This is you! | ||
25 | - - if @team.owner == user | ||
26 | - %span.btn.disabled.btn-success Owner | ||
27 | - - elsif user.blocked | ||
28 | - %span.btn.disabled.blocked Blocked | ||
29 | - - elsif allow_admin | ||
30 | - = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do | ||
31 | - %i.icon-minus.icon-white | 15 | + = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f| |
16 | + = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium trigger-submit" | ||
17 | + %br | ||
18 | + = label_tag do | ||
19 | + = f.check_box :group_admin, class: 'trigger-submit' | ||
20 | + %span Admin access | ||
21 | + .pull-right | ||
22 | + - if current_user == user | ||
23 | + %span.btn.disabled This is you! | ||
24 | + - if @team.owner == user | ||
25 | + %span.btn.disabled Owner | ||
26 | + - elsif user.blocked | ||
27 | + %span.btn.disabled.blocked Blocked | ||
28 | + - elsif allow_admin | ||
29 | + = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do | ||
30 | + %i.icon-minus.icon-white |
app/views/teams/new.html.haml
@@ -17,3 +17,17 @@ | @@ -17,3 +17,17 @@ | ||
17 | %li All created teams are public (users can view who enter into team and which project are assigned for this team) | 17 | %li All created teams are public (users can view who enter into team and which project are assigned for this team) |
18 | %li People within a team see only projects they have access to | 18 | %li People within a team see only projects they have access to |
19 | %li You will be able to assign existing projects for team | 19 | %li You will be able to assign existing projects for team |
20 | + %hr | ||
21 | + | ||
22 | + - if current_user.can_create_group? | ||
23 | + .clearfix | ||
24 | + .input.light | ||
25 | + Need a group for several dependent projects? | ||
26 | + = link_to new_group_path, class: "btn btn-tiny" do | ||
27 | + Create a group | ||
28 | + - if current_user.can_create_project? | ||
29 | + .clearfix | ||
30 | + .input.light | ||
31 | + Want to create a project? | ||
32 | + = link_to new_project_path, class: "btn btn-tiny" do | ||
33 | + Create a project |
app/workers/post_receive.rb
@@ -21,14 +21,18 @@ class PostReceive | @@ -21,14 +21,18 @@ class PostReceive | ||
21 | return false | 21 | return false |
22 | end | 22 | end |
23 | 23 | ||
24 | - # Ignore push from non-gitlab users | ||
25 | - user = if identifier.nil? | ||
26 | - raise identifier.inspect | 24 | + user = if identifier.blank? |
25 | + # Local push from gitlab | ||
27 | email = project.repository.commit(newrev).author.email rescue nil | 26 | email = project.repository.commit(newrev).author.email rescue nil |
28 | User.find_by_email(email) if email | 27 | User.find_by_email(email) if email |
29 | - elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) | ||
30 | - User.find_by_email(identifier) | ||
31 | - elsif identifier =~ /key/ | 28 | + |
29 | + elsif identifier =~ /\Auser-\d+\Z/ | ||
30 | + # git push over http | ||
31 | + user_id = identifier.gsub("user-", "") | ||
32 | + User.find_by_id(user_id) | ||
33 | + | ||
34 | + elsif identifier =~ /\Akey-\d+\Z/ | ||
35 | + # git push over ssh | ||
32 | key_id = identifier.gsub("key-", "") | 36 | key_id = identifier.gsub("key-", "") |
33 | Key.find_by_id(key_id).try(:user) | 37 | Key.find_by_id(key_id).try(:user) |
34 | end | 38 | end |
config/gitlab.yml.example
@@ -7,121 +7,132 @@ | @@ -7,121 +7,132 @@ | ||
7 | # 2. Replace gitlab -> host with your domain | 7 | # 2. Replace gitlab -> host with your domain |
8 | # 3. Replace gitlab -> email_from | 8 | # 3. Replace gitlab -> email_from |
9 | 9 | ||
10 | -# | ||
11 | -# 1. GitLab app settings | ||
12 | -# ========================== | ||
13 | - | ||
14 | -## GitLab settings | ||
15 | -gitlab: | ||
16 | - ## Web server settings | ||
17 | - host: localhost | ||
18 | - port: 80 | ||
19 | - https: false | ||
20 | - # Uncomment and customize to run in non-root path | ||
21 | - # Note that ENV['RAILS_RELATIVE_URL_ROOT'] in config/unicorn.rb may need to be changed | ||
22 | - # relative_url_root: /gitlab | ||
23 | - | ||
24 | - # Uncomment and customize if you can't use the default user to run GitLab (default: 'git') | ||
25 | - # user: git | ||
26 | - | ||
27 | - ## Email settings | ||
28 | - # Email address used in the "From" field in mails sent by GitLab | ||
29 | - email_from: gitlab@localhost | ||
30 | - | ||
31 | - # Email address of your support contact (default: same as email_from) | ||
32 | - support_email: support@localhost | ||
33 | - | ||
34 | - ## Project settings | ||
35 | - default_projects_limit: 10 | ||
36 | - # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. | ||
37 | - | ||
38 | -## Gravatar | ||
39 | -gravatar: | ||
40 | - enabled: true # Use user avatar images from Gravatar.com (default: true) | ||
41 | - # plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm | ||
42 | - # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm | ||
43 | - | ||
44 | - | ||
45 | - | ||
46 | -# | ||
47 | -# 2. Auth settings | ||
48 | -# ========================== | ||
49 | - | ||
50 | -## LDAP settings | ||
51 | -ldap: | ||
52 | - enabled: false | ||
53 | - host: '_your_ldap_server' | ||
54 | - base: '_the_base_where_you_search_for_users' | ||
55 | - port: 636 | ||
56 | - uid: 'sAMAccountName' | ||
57 | - method: 'ssl' # "ssl" or "plain" | ||
58 | - bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' | ||
59 | - password: '_the_password_of_the_bind_user' | ||
60 | - | ||
61 | -## Omniauth settings | ||
62 | -omniauth: | ||
63 | - # Enable ability for users | ||
64 | - # Allow logging in via Twitter, Google, etc. using Omniauth providers | ||
65 | - enabled: false | ||
66 | - | 10 | +production: &base |
11 | + # | ||
12 | + # 1. GitLab app settings | ||
13 | + # ========================== | ||
14 | + | ||
15 | + ## GitLab settings | ||
16 | + gitlab: | ||
17 | + ## Web server settings | ||
18 | + host: localhost | ||
19 | + port: 80 | ||
20 | + https: false | ||
21 | + # Uncomment and customize to run in non-root path | ||
22 | + # Note that ENV['RAILS_RELATIVE_URL_ROOT'] in config/unicorn.rb may need to be changed | ||
23 | + # relative_url_root: /gitlab | ||
24 | + | ||
25 | + # Uncomment and customize if you can't use the default user to run GitLab (default: 'git') | ||
26 | + # user: git | ||
27 | + | ||
28 | + ## Email settings | ||
29 | + # Email address used in the "From" field in mails sent by GitLab | ||
30 | + email_from: gitlab@localhost | ||
31 | + | ||
32 | + # Email address of your support contact (default: same as email_from) | ||
33 | + support_email: support@localhost | ||
34 | + | ||
35 | + ## Project settings | ||
36 | + default_projects_limit: 10 | ||
37 | + # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. | ||
38 | + # username_changing_enabled: false # default: true - User can change her username/namespace | ||
39 | + | ||
40 | + ## Gravatar | ||
41 | + gravatar: | ||
42 | + enabled: true # Use user avatar images from Gravatar.com (default: true) | ||
43 | + # plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm | ||
44 | + # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm | ||
45 | + | ||
46 | + | ||
47 | + | ||
48 | + # | ||
49 | + # 2. Auth settings | ||
50 | + # ========================== | ||
51 | + | ||
52 | + ## LDAP settings | ||
53 | + ldap: | ||
54 | + enabled: false | ||
55 | + host: '_your_ldap_server' | ||
56 | + base: '_the_base_where_you_search_for_users' | ||
57 | + port: 636 | ||
58 | + uid: 'sAMAccountName' | ||
59 | + method: 'ssl' # "ssl" or "plain" | ||
60 | + bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' | ||
61 | + password: '_the_password_of_the_bind_user' | ||
62 | + | ||
63 | + ## Omniauth settings | ||
64 | + omniauth: | ||
65 | + # Enable ability for users | ||
66 | + # Allow logging in via Twitter, Google, etc. using Omniauth providers | ||
67 | + enabled: false | ||
68 | + | ||
69 | + # CAUTION! | ||
70 | + # This allows users to login without having a user account first (default: false) | ||
71 | + # User accounts will be created automatically when authentication was successful. | ||
72 | + allow_single_sign_on: false | ||
73 | + # Locks down those users until they have been cleared by the admin (default: true) | ||
74 | + block_auto_created_users: true | ||
75 | + | ||
76 | + ## Auth providers | ||
77 | + # Uncomment the lines and fill in the data of the auth provider you want to use | ||
78 | + # If your favorite auth provider is not listed you can user others: | ||
79 | + # see https://github.com/gitlabhq/gitlabhq/wiki/Using-Custom-Omniauth-Providers | ||
80 | + # The 'app_id' and 'app_secret' parameters are always passed as the first two | ||
81 | + # arguments, followed by optional 'args' which can be either a hash or an array. | ||
82 | + providers: | ||
83 | + # - { name: 'google_oauth2', app_id: 'YOUR APP ID', | ||
84 | + # app_secret: 'YOUR APP SECRET', | ||
85 | + # args: { access_type: 'offline', approval_prompt: '' } } | ||
86 | + # - { name: 'twitter', app_id: 'YOUR APP ID', | ||
87 | + # app_secret: 'YOUR APP SECRET'} | ||
88 | + # - { name: 'github', app_id: 'YOUR APP ID', | ||
89 | + # app_secret: 'YOUR APP SECRET' } | ||
90 | + | ||
91 | + | ||
92 | + | ||
93 | + # | ||
94 | + # 3. Advanced settings | ||
95 | + # ========================== | ||
96 | + | ||
97 | + # GitLab Satellites | ||
98 | + satellites: | ||
99 | + # Relative paths are relative to Rails.root (default: tmp/repo_satellites/) | ||
100 | + path: /home/git/gitlab-satellites/ | ||
101 | + | ||
102 | + ## Backup settings | ||
103 | + backup: | ||
104 | + path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) | ||
105 | + # keep_time: 604800 # default: 0 (forever) (in seconds) | ||
106 | + | ||
107 | + ## GitLab Shell settings | ||
108 | + gitlab_shell: | ||
109 | + # REPOS_PATH MUST NOT BE A SYMLINK!!! | ||
110 | + repos_path: /home/git/repositories/ | ||
111 | + hooks_path: /home/git/gitlab-shell/hooks/ | ||
112 | + | ||
113 | + # Git over HTTP | ||
114 | + upload_pack: true | ||
115 | + receive_pack: true | ||
116 | + | ||
117 | + # If you use non-standart ssh port you need to specify it | ||
118 | + # ssh_port: 22 | ||
119 | + | ||
120 | + ## Git settings | ||
67 | # CAUTION! | 121 | # CAUTION! |
68 | - # This allows users to login without having a user account first (default: false) | ||
69 | - # User accounts will be created automatically when authentication was successful. | ||
70 | - allow_single_sign_on: false | ||
71 | - # Locks down those users until they have been cleared by the admin (default: true) | ||
72 | - block_auto_created_users: true | ||
73 | - | ||
74 | - ## Auth providers | ||
75 | - # Uncomment the lines and fill in the data of the auth provider you want to use | ||
76 | - # If your favorite auth provider is not listed you can user others: | ||
77 | - # see https://github.com/gitlabhq/gitlabhq/wiki/Using-Custom-Omniauth-Providers | ||
78 | - # The 'app_id' and 'app_secret' parameters are always passed as the first two | ||
79 | - # arguments, followed by optional 'args' which can be either a hash or an array. | ||
80 | - providers: | ||
81 | - # - { name: 'google_oauth2', app_id: 'YOUR APP ID', | ||
82 | - # app_secret: 'YOUR APP SECRET', | ||
83 | - # args: { access_type: 'offline', approval_prompt: '' } } | ||
84 | - # - { name: 'twitter', app_id: 'YOUR APP ID', | ||
85 | - # app_secret: 'YOUR APP SECRET'} | ||
86 | - # - { name: 'github', app_id: 'YOUR APP ID', | ||
87 | - # app_secret: 'YOUR APP SECRET' } | ||
88 | - | ||
89 | - | ||
90 | - | ||
91 | -# | ||
92 | -# 3. Advanced settings | ||
93 | -# ========================== | ||
94 | - | ||
95 | -# GitLab Satellites | ||
96 | -satellites: | ||
97 | - # Relative paths are relative to Rails.root (default: tmp/repo_satellites/) | ||
98 | - path: /home/git/gitlab-satellites/ | ||
99 | - | ||
100 | -## Backup settings | ||
101 | -backup: | ||
102 | - path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) | ||
103 | - # keep_time: 604800 # default: 0 (forever) (in seconds) | ||
104 | - | ||
105 | -## GitLab Shell settings | ||
106 | -gitlab_shell: | ||
107 | - # REPOS_PATH MUST NOT BE A SYMLINK!!! | ||
108 | - repos_path: /home/git/repositories/ | ||
109 | - hooks_path: /home/git/gitlab-shell/hooks/ | ||
110 | - | ||
111 | - # Git over HTTP | ||
112 | - upload_pack: true | ||
113 | - receive_pack: true | ||
114 | - | ||
115 | - # If you use non-standart ssh port you need to specify it | ||
116 | - # ssh_port: 22 | ||
117 | - | ||
118 | -## Git settings | ||
119 | -# CAUTION! | ||
120 | -# Use the default values unless you really know what you are doing | ||
121 | -git: | ||
122 | - bin_path: /usr/bin/git | ||
123 | - # Max size of git object like commit, in bytes | ||
124 | - # This value can be increased if you have a very large commits | ||
125 | - max_size: 5242880 # 5.megabytes | ||
126 | - # Git timeout to read commit, in seconds | ||
127 | - timeout: 10 | 122 | + # Use the default values unless you really know what you are doing |
123 | + git: | ||
124 | + bin_path: /usr/bin/git | ||
125 | + # Max size of git object like commit, in bytes | ||
126 | + # This value can be increased if you have a very large commits | ||
127 | + max_size: 5242880 # 5.megabytes | ||
128 | + # Git timeout to read commit, in seconds | ||
129 | + timeout: 10 | ||
130 | + | ||
131 | +development: | ||
132 | + <<: *base | ||
133 | + | ||
134 | +test: | ||
135 | + <<: *base | ||
136 | + | ||
137 | +staging: | ||
138 | + <<: *base |
config/initializers/1_settings.rb
1 | class Settings < Settingslogic | 1 | class Settings < Settingslogic |
2 | source "#{Rails.root}/config/gitlab.yml" | 2 | source "#{Rails.root}/config/gitlab.yml" |
3 | + namespace Rails.env | ||
3 | 4 | ||
4 | class << self | 5 | class << self |
5 | def gitlab_on_non_standard_port? | 6 | def gitlab_on_non_standard_port? |
@@ -56,6 +57,7 @@ Settings.gitlab['support_email'] ||= Settings.gitlab.email_from | @@ -56,6 +57,7 @@ Settings.gitlab['support_email'] ||= Settings.gitlab.email_from | ||
56 | Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url) | 57 | Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url) |
57 | Settings.gitlab['user'] ||= 'git' | 58 | Settings.gitlab['user'] ||= 'git' |
58 | Settings.gitlab['signup_enabled'] ||= false | 59 | Settings.gitlab['signup_enabled'] ||= false |
60 | +Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? | ||
59 | 61 | ||
60 | # | 62 | # |
61 | # Gravatar | 63 | # Gravatar |
config/initializers/2_app.rb
1 | module Gitlab | 1 | module Gitlab |
2 | - Version = File.read(Rails.root.join("VERSION")) | ||
3 | - Revision = `git log --pretty=format:'%h' -n 1` | 2 | + VERSION = File.read(Rails.root.join("VERSION")).strip |
3 | + REVISION = `git log --pretty=format:'%h' -n 1` | ||
4 | 4 | ||
5 | def self.config | 5 | def self.config |
6 | Settings | 6 | Settings |
config/routes.rb
@@ -47,6 +47,11 @@ Gitlab::Application.routes.draw do | @@ -47,6 +47,11 @@ Gitlab::Application.routes.draw do | ||
47 | end | 47 | end |
48 | 48 | ||
49 | # | 49 | # |
50 | + # Attachments serving | ||
51 | + # | ||
52 | + get 'files/:type/:id/:filename' => 'files#download', constraints: { id: /\d+/, type: /[a-z]+/, filename: /[a-zA-Z.0-9_\-\+]+/ } | ||
53 | + | ||
54 | + # | ||
50 | # Admin Area | 55 | # Admin Area |
51 | # | 56 | # |
52 | namespace :admin do | 57 | namespace :admin do |
db/fixtures/development/02_source_code.rb
db/fixtures/development/09_issues.rb
@@ -16,7 +16,7 @@ Gitlab::Seeder.quiet do | @@ -16,7 +16,7 @@ Gitlab::Seeder.quiet do | ||
16 | project_id: project.id, | 16 | project_id: project.id, |
17 | author_id: user_id, | 17 | author_id: user_id, |
18 | assignee_id: user_id, | 18 | assignee_id: user_id, |
19 | - closed: [true, false].sample, | 19 | + state: ['opened', 'closed'].sample, |
20 | milestone: project.milestones.sample, | 20 | milestone: project.milestones.sample, |
21 | title: Faker::Lorem.sentence(6) | 21 | title: Faker::Lorem.sentence(6) |
22 | }]) | 22 | }]) |
db/fixtures/development/10_merge_requests.rb
@@ -17,7 +17,7 @@ Gitlab::Seeder.quiet do | @@ -17,7 +17,7 @@ Gitlab::Seeder.quiet do | ||
17 | project_id: project.id, | 17 | project_id: project.id, |
18 | author_id: user_id, | 18 | author_id: user_id, |
19 | assignee_id: user_id, | 19 | assignee_id: user_id, |
20 | - closed: [true, false].sample, | 20 | + state: ['opened', 'closed'].sample, |
21 | milestone: project.milestones.sample, | 21 | milestone: project.milestones.sample, |
22 | title: Faker::Lorem.sentence(6) | 22 | title: Faker::Lorem.sentence(6) |
23 | }]) | 23 | }]) |
db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb
0 → 100644
db/migrate/20130218141258_convert_closed_to_state_in_issue.rb
0 → 100644
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +class ConvertClosedToStateInIssue < ActiveRecord::Migration | ||
2 | + def up | ||
3 | + Issue.transaction do | ||
4 | + Issue.where(closed: true).update_all("state = 'closed'") | ||
5 | + Issue.where(closed: false).update_all("state = 'opened'") | ||
6 | + end | ||
7 | + end | ||
8 | + | ||
9 | + def down | ||
10 | + Issue.transaction do | ||
11 | + Issue.where(state: :closed).update_all("closed = 1") | ||
12 | + end | ||
13 | + end | ||
14 | +end |
db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb
0 → 100644
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
1 | +class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration | ||
2 | + def up | ||
3 | + MergeRequest.transaction do | ||
4 | + MergeRequest.where("closed = 1 AND merged = 1").update_all("state = 'merged'") | ||
5 | + MergeRequest.where("closed = 1 AND merged = 0").update_all("state = 'closed'") | ||
6 | + MergeRequest.where("closed = 0").update_all("state = 'opened'") | ||
7 | + end | ||
8 | + end | ||
9 | + | ||
10 | + def down | ||
11 | + MergeRequest.transaction do | ||
12 | + MergeRequest.where(state: :closed).update_all("closed = 1") | ||
13 | + MergeRequest.where(state: :merged).update_all("closed = 1, merged = 1") | ||
14 | + end | ||
15 | + end | ||
16 | +end |
db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb
0 → 100644
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +class ConvertClosedToStateInMilestone < ActiveRecord::Migration | ||
2 | + def up | ||
3 | + Milestone.transaction do | ||
4 | + Milestone.where(closed: false).update_all("state = 'opened'") | ||
5 | + Milestone.where(closed: false).update_all("state = 'active'") | ||
6 | + end | ||
7 | + end | ||
8 | + | ||
9 | + def down | ||
10 | + Milestone.transaction do | ||
11 | + Milestone.where(state: :closed).update_all("closed = 1") | ||
12 | + end | ||
13 | + end | ||
14 | +end |
db/migrate/20130218141444_remove_merged_from_merge_request.rb
0 → 100644
db/migrate/20130218141536_remove_closed_from_merge_request.rb
0 → 100644
db/migrate/20130218141554_remove_closed_from_milestone.rb
0 → 100644
db/schema.rb
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | # | 11 | # |
12 | # It's strongly recommended to check this file into your version control system. | 12 | # It's strongly recommended to check this file into your version control system. |
13 | 13 | ||
14 | -ActiveRecord::Schema.define(:version => 20130131070232) do | 14 | +ActiveRecord::Schema.define(:version => 20130218141554) do |
15 | 15 | ||
16 | create_table "events", :force => true do |t| | 16 | create_table "events", :force => true do |t| |
17 | t.string "target_type" | 17 | t.string "target_type" |
@@ -37,18 +37,17 @@ ActiveRecord::Schema.define(:version => 20130131070232) do | @@ -37,18 +37,17 @@ ActiveRecord::Schema.define(:version => 20130131070232) do | ||
37 | t.integer "assignee_id" | 37 | t.integer "assignee_id" |
38 | t.integer "author_id" | 38 | t.integer "author_id" |
39 | t.integer "project_id" | 39 | t.integer "project_id" |
40 | - t.datetime "created_at", :null => false | ||
41 | - t.datetime "updated_at", :null => false | ||
42 | - t.boolean "closed", :default => false, :null => false | 40 | + t.datetime "created_at", :null => false |
41 | + t.datetime "updated_at", :null => false | ||
43 | t.integer "position", :default => 0 | 42 | t.integer "position", :default => 0 |
44 | t.string "branch_name" | 43 | t.string "branch_name" |
45 | t.text "description" | 44 | t.text "description" |
46 | t.integer "milestone_id" | 45 | t.integer "milestone_id" |
46 | + t.string "state" | ||
47 | end | 47 | end |
48 | 48 | ||
49 | add_index "issues", ["assignee_id"], :name => "index_issues_on_assignee_id" | 49 | add_index "issues", ["assignee_id"], :name => "index_issues_on_assignee_id" |
50 | add_index "issues", ["author_id"], :name => "index_issues_on_author_id" | 50 | add_index "issues", ["author_id"], :name => "index_issues_on_author_id" |
51 | - add_index "issues", ["closed"], :name => "index_issues_on_closed" | ||
52 | add_index "issues", ["created_at"], :name => "index_issues_on_created_at" | 51 | add_index "issues", ["created_at"], :name => "index_issues_on_created_at" |
53 | add_index "issues", ["milestone_id"], :name => "index_issues_on_milestone_id" | 52 | add_index "issues", ["milestone_id"], :name => "index_issues_on_milestone_id" |
54 | add_index "issues", ["project_id"], :name => "index_issues_on_project_id" | 53 | add_index "issues", ["project_id"], :name => "index_issues_on_project_id" |
@@ -69,25 +68,23 @@ ActiveRecord::Schema.define(:version => 20130131070232) do | @@ -69,25 +68,23 @@ ActiveRecord::Schema.define(:version => 20130131070232) do | ||
69 | add_index "keys", ["user_id"], :name => "index_keys_on_user_id" | 68 | add_index "keys", ["user_id"], :name => "index_keys_on_user_id" |
70 | 69 | ||
71 | create_table "merge_requests", :force => true do |t| | 70 | create_table "merge_requests", :force => true do |t| |
72 | - t.string "target_branch", :null => false | ||
73 | - t.string "source_branch", :null => false | ||
74 | - t.integer "project_id", :null => false | 71 | + t.string "target_branch", :null => false |
72 | + t.string "source_branch", :null => false | ||
73 | + t.integer "project_id", :null => false | ||
75 | t.integer "author_id" | 74 | t.integer "author_id" |
76 | t.integer "assignee_id" | 75 | t.integer "assignee_id" |
77 | t.string "title" | 76 | t.string "title" |
78 | - t.boolean "closed", :default => false, :null => false | ||
79 | - t.datetime "created_at", :null => false | ||
80 | - t.datetime "updated_at", :null => false | 77 | + t.datetime "created_at", :null => false |
78 | + t.datetime "updated_at", :null => false | ||
81 | t.text "st_commits", :limit => 2147483647 | 79 | t.text "st_commits", :limit => 2147483647 |
82 | t.text "st_diffs", :limit => 2147483647 | 80 | t.text "st_diffs", :limit => 2147483647 |
83 | - t.boolean "merged", :default => false, :null => false | ||
84 | - t.integer "state", :default => 1, :null => false | 81 | + t.integer "merge_status", :default => 1, :null => false |
85 | t.integer "milestone_id" | 82 | t.integer "milestone_id" |
83 | + t.string "state" | ||
86 | end | 84 | end |
87 | 85 | ||
88 | add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" | 86 | add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" |
89 | add_index "merge_requests", ["author_id"], :name => "index_merge_requests_on_author_id" | 87 | add_index "merge_requests", ["author_id"], :name => "index_merge_requests_on_author_id" |
90 | - add_index "merge_requests", ["closed"], :name => "index_merge_requests_on_closed" | ||
91 | add_index "merge_requests", ["created_at"], :name => "index_merge_requests_on_created_at" | 88 | add_index "merge_requests", ["created_at"], :name => "index_merge_requests_on_created_at" |
92 | add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id" | 89 | add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id" |
93 | add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" | 90 | add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" |
@@ -96,13 +93,13 @@ ActiveRecord::Schema.define(:version => 20130131070232) do | @@ -96,13 +93,13 @@ ActiveRecord::Schema.define(:version => 20130131070232) do | ||
96 | add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title" | 93 | add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title" |
97 | 94 | ||
98 | create_table "milestones", :force => true do |t| | 95 | create_table "milestones", :force => true do |t| |
99 | - t.string "title", :null => false | ||
100 | - t.integer "project_id", :null => false | 96 | + t.string "title", :null => false |
97 | + t.integer "project_id", :null => false | ||
101 | t.text "description" | 98 | t.text "description" |
102 | t.date "due_date" | 99 | t.date "due_date" |
103 | - t.boolean "closed", :default => false, :null => false | ||
104 | - t.datetime "created_at", :null => false | ||
105 | - t.datetime "updated_at", :null => false | 100 | + t.datetime "created_at", :null => false |
101 | + t.datetime "updated_at", :null => false | ||
102 | + t.string "state" | ||
106 | end | 103 | end |
107 | 104 | ||
108 | add_index "milestones", ["due_date"], :name => "index_milestones_on_due_date" | 105 | add_index "milestones", ["due_date"], :name => "index_milestones_on_due_date" |
doc/api/milestones.md
@@ -34,7 +34,6 @@ POST /projects/:id/milestones | @@ -34,7 +34,6 @@ POST /projects/:id/milestones | ||
34 | Parameters: | 34 | Parameters: |
35 | 35 | ||
36 | + `id` (required) - The ID of a project | 36 | + `id` (required) - The ID of a project |
37 | -+ `milestone_id` (required) - The ID of a project milestone | ||
38 | + `title` (required) - The title of an milestone | 37 | + `title` (required) - The title of an milestone |
39 | + `description` (optional) - The description of the milestone | 38 | + `description` (optional) - The description of the milestone |
40 | + `due_date` (optional) - The due date of the milestone | 39 | + `due_date` (optional) - The due date of the milestone |
doc/api/projects.md
@@ -23,7 +23,7 @@ GET /projects | @@ -23,7 +23,7 @@ GET /projects | ||
23 | "blocked": false, | 23 | "blocked": false, |
24 | "created_at": "2012-05-23T08:00:58Z" | 24 | "created_at": "2012-05-23T08:00:58Z" |
25 | }, | 25 | }, |
26 | - "private": true, | 26 | + "public": true, |
27 | "path": "rails", | 27 | "path": "rails", |
28 | "path_with_namespace": "rails/rails", | 28 | "path_with_namespace": "rails/rails", |
29 | "issues_enabled": false, | 29 | "issues_enabled": false, |
@@ -45,7 +45,7 @@ GET /projects | @@ -45,7 +45,7 @@ GET /projects | ||
45 | "blocked": false, | 45 | "blocked": false, |
46 | "created_at": "2012-05-23T08:00:58Z" | 46 | "created_at": "2012-05-23T08:00:58Z" |
47 | }, | 47 | }, |
48 | - "private": true, | 48 | + "public": true, |
49 | "path": "gitlab", | 49 | "path": "gitlab", |
50 | "path_with_namespace": "randx/gitlab", | 50 | "path_with_namespace": "randx/gitlab", |
51 | "issues_enabled": true, | 51 | "issues_enabled": true, |
@@ -89,7 +89,7 @@ Parameters: | @@ -89,7 +89,7 @@ Parameters: | ||
89 | "blocked": false, | 89 | "blocked": false, |
90 | "created_at": "2012-05-23T08:00:58Z" | 90 | "created_at": "2012-05-23T08:00:58Z" |
91 | }, | 91 | }, |
92 | - "private": true, | 92 | + "public": true, |
93 | "path": "gitlab", | 93 | "path": "gitlab", |
94 | "path_with_namespace": "randx/gitlab", | 94 | "path_with_namespace": "randx/gitlab", |
95 | "issues_enabled": true, | 95 | "issues_enabled": true, |
doc/install/databases.md
@@ -27,7 +27,7 @@ GitLab supports the following databases: | @@ -27,7 +27,7 @@ GitLab supports the following databases: | ||
27 | mysql> \q | 27 | mysql> \q |
28 | 28 | ||
29 | # Try connecting to the new database with the new user | 29 | # Try connecting to the new database with the new user |
30 | - sudo -u gitlab -H mysql -u gitlab -p -D gitlabhq_production | 30 | + sudo -u git -H mysql -u gitlab -p -D gitlabhq_production |
31 | 31 | ||
32 | ## PostgreSQL | 32 | ## PostgreSQL |
33 | 33 | ||
@@ -47,5 +47,5 @@ GitLab supports the following databases: | @@ -47,5 +47,5 @@ GitLab supports the following databases: | ||
47 | template1=# \q | 47 | template1=# \q |
48 | 48 | ||
49 | # Try connecting to the new database with the new user | 49 | # Try connecting to the new database with the new user |
50 | - sudo -u gitlab -H psql -d gitlabhq_production | 50 | + sudo -u git -H psql -d gitlabhq_production |
51 | 51 |
doc/install/installation.md
1 | This installation guide was created for Debian/Ubuntu and tested on it. | 1 | This installation guide was created for Debian/Ubuntu and tested on it. |
2 | 2 | ||
3 | -Please read `doc/install/requirements.md` for hardware and platform requirements. | 3 | +Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements. |
4 | 4 | ||
5 | 5 | ||
6 | **Important Note:** | 6 | **Important Note:** |
@@ -8,12 +8,13 @@ The following steps have been known to work. | @@ -8,12 +8,13 @@ The following steps have been known to work. | ||
8 | If you deviate from this guide, do it with caution and make sure you don't | 8 | If you deviate from this guide, do it with caution and make sure you don't |
9 | violate any assumptions GitLab makes about its environment. | 9 | violate any assumptions GitLab makes about its environment. |
10 | For things like AWS installation scripts, init scripts or config files for | 10 | For things like AWS installation scripts, init scripts or config files for |
11 | -alternative web server have a look at the "Advanced Setup Tips" section. | 11 | +alternative web server have a look at the [`Advanced Setup |
12 | +Tips`](./installation.md#advanced-setup-tips) section. | ||
12 | 13 | ||
13 | 14 | ||
14 | **Important Note:** | 15 | **Important Note:** |
15 | If you find a bug/error in this guide please submit an issue or pull request | 16 | If you find a bug/error in this guide please submit an issue or pull request |
16 | -following the contribution guide (see `CONTRIBUTING.md`). | 17 | +following the [`contribution guide`](../../CONTRIBUTING.md). |
17 | 18 | ||
18 | - - - | 19 | - - - |
19 | 20 | ||
@@ -24,7 +25,7 @@ The GitLab installation consists of setting up the following components: | @@ -24,7 +25,7 @@ The GitLab installation consists of setting up the following components: | ||
24 | 1. Packages / Dependencies | 25 | 1. Packages / Dependencies |
25 | 2. Ruby | 26 | 2. Ruby |
26 | 3. System Users | 27 | 3. System Users |
27 | -4. Gitolite | 28 | +4. GitLab shell |
28 | 5. Database | 29 | 5. Database |
29 | 6. GitLab | 30 | 6. GitLab |
30 | 7. Nginx | 31 | 7. Nginx |
@@ -32,16 +33,13 @@ The GitLab installation consists of setting up the following components: | @@ -32,16 +33,13 @@ The GitLab installation consists of setting up the following components: | ||
32 | 33 | ||
33 | # 1. Packages / Dependencies | 34 | # 1. Packages / Dependencies |
34 | 35 | ||
35 | -`sudo` is not installed on Debian by default. If you don't have it you'll need | ||
36 | -to install it first. | 36 | +`sudo` is not installed on Debian by default. Make sure your system is |
37 | +up-to-date and install it. | ||
37 | 38 | ||
38 | # run as root | 39 | # run as root |
39 | - apt-get update && apt-get upgrade && apt-get install sudo | ||
40 | - | ||
41 | -Make sure your system is up-to-date: | ||
42 | - | ||
43 | - sudo apt-get update | ||
44 | - sudo apt-get upgrade | 40 | + apt-get update |
41 | + apt-get upgrade | ||
42 | + apt-get install sudo | ||
45 | 43 | ||
46 | **Note:** | 44 | **Note:** |
47 | Vim is an editor that is used here whenever there are files that need to be | 45 | Vim is an editor that is used here whenever there are files that need to be |
@@ -96,25 +94,24 @@ Create a `git` user for Gitlab: | @@ -96,25 +94,24 @@ Create a `git` user for Gitlab: | ||
96 | 94 | ||
97 | # 4. GitLab shell | 95 | # 4. GitLab shell |
98 | 96 | ||
99 | - # login as git | 97 | + # Login as git |
100 | sudo su git | 98 | sudo su git |
101 | 99 | ||
102 | - # go to home directory | 100 | + # Go to home directory |
103 | cd /home/git | 101 | cd /home/git |
104 | 102 | ||
105 | - # clone gitlab shell | 103 | + # Clone gitlab shell |
106 | git clone https://github.com/gitlabhq/gitlab-shell.git | 104 | git clone https://github.com/gitlabhq/gitlab-shell.git |
107 | 105 | ||
108 | - # setup | 106 | + # Setup |
109 | cd gitlab-shell | 107 | cd gitlab-shell |
110 | cp config.yml.example config.yml | 108 | cp config.yml.example config.yml |
111 | ./bin/install | 109 | ./bin/install |
112 | 110 | ||
113 | 111 | ||
114 | - | ||
115 | # 5. Database | 112 | # 5. Database |
116 | 113 | ||
117 | -To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md) . | 114 | +To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md). |
118 | 115 | ||
119 | 116 | ||
120 | # 6. GitLab | 117 | # 6. GitLab |
@@ -154,9 +151,13 @@ do so with caution! | @@ -154,9 +151,13 @@ do so with caution! | ||
154 | sudo chmod -R u+rwX log/ | 151 | sudo chmod -R u+rwX log/ |
155 | sudo chmod -R u+rwX tmp/ | 152 | sudo chmod -R u+rwX tmp/ |
156 | 153 | ||
157 | - # Make directory for satellites | 154 | + # Create directory for satellites |
158 | sudo -u git -H mkdir /home/git/gitlab-satellites | 155 | sudo -u git -H mkdir /home/git/gitlab-satellites |
159 | 156 | ||
157 | + # Create directory for pids and make sure GitLab can write to it | ||
158 | + sudo -u git -H mkdir tmp/pids/ | ||
159 | + sudo chmod -R u+rwX tmp/pids/ | ||
160 | + | ||
160 | # Copy the example Unicorn config | 161 | # Copy the example Unicorn config |
161 | sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb | 162 | sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb |
162 | 163 | ||
@@ -187,7 +188,9 @@ Make sure to update username/password in config/database.yml. | @@ -187,7 +188,9 @@ Make sure to update username/password in config/database.yml. | ||
187 | 188 | ||
188 | 189 | ||
189 | ## Initialise Database and Activate Advanced Features | 190 | ## Initialise Database and Activate Advanced Features |
190 | - | 191 | + |
192 | + sudo -u git -H bundle exec rake db:setup RAILS_ENV=production | ||
193 | + sudo -u git -H bundle exec rake db:seed_fu RAILS_ENV=production | ||
191 | sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production | 194 | sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production |
192 | 195 | ||
193 | 196 | ||
@@ -205,7 +208,7 @@ Make GitLab start on boot: | @@ -205,7 +208,7 @@ Make GitLab start on boot: | ||
205 | 208 | ||
206 | ## Check Application Status | 209 | ## Check Application Status |
207 | 210 | ||
208 | -Check if GitLab and its environment is configured correctly: | 211 | +Check if GitLab and its environment are configured correctly: |
209 | 212 | ||
210 | sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production | 213 | sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production |
211 | 214 | ||
@@ -227,7 +230,7 @@ However there are still a few steps left. | @@ -227,7 +230,7 @@ However there are still a few steps left. | ||
227 | 230 | ||
228 | **Note:** | 231 | **Note:** |
229 | If you can't or don't want to use Nginx as your web server, have a look at the | 232 | If you can't or don't want to use Nginx as your web server, have a look at the |
230 | -"Advanced Setup Tips" section. | 233 | +[`Advanced Setup Tips`](./installation.md#advanced-setup-tips) section. |
231 | 234 | ||
232 | ## Installation | 235 | ## Installation |
233 | sudo apt-get install nginx | 236 | sudo apt-get install nginx |
@@ -244,11 +247,11 @@ Make sure to edit the config file to match your setup: | @@ -244,11 +247,11 @@ Make sure to edit the config file to match your setup: | ||
244 | # Change **YOUR_SERVER_IP** and **YOUR_SERVER_FQDN** | 247 | # Change **YOUR_SERVER_IP** and **YOUR_SERVER_FQDN** |
245 | # to the IP address and fully-qualified domain name | 248 | # to the IP address and fully-qualified domain name |
246 | # of your host serving GitLab | 249 | # of your host serving GitLab |
247 | - sudo vim /etc/nginx/sites-enabled/gitlab | 250 | + sudo vim /etc/nginx/sites-available/gitlab |
248 | 251 | ||
249 | ## Restart | 252 | ## Restart |
250 | 253 | ||
251 | - sudo /etc/init.d/nginx restart | 254 | + sudo service nginx restart |
252 | 255 | ||
253 | 256 | ||
254 | # Done! | 257 | # Done! |
@@ -282,7 +285,7 @@ a different host, you can configure its connection string via the | @@ -282,7 +285,7 @@ a different host, you can configure its connection string via the | ||
282 | 285 | ||
283 | ## Custom SSH Connection | 286 | ## Custom SSH Connection |
284 | 287 | ||
285 | -If you are running SSH on a non-standard port, you must change the gitlab user'S SSH config. | 288 | +If you are running SSH on a non-standard port, you must change the gitlab user's SSH config. |
286 | 289 | ||
287 | # Add to /home/git/.ssh/config | 290 | # Add to /home/git/.ssh/config |
288 | host localhost # Give your setup a name (here: override localhost) | 291 | host localhost # Give your setup a name (here: override localhost) |
features/steps/profile/profile_ssh_keys.rb
@@ -43,6 +43,6 @@ class ProfileSshKeys < Spinach::FeatureSteps | @@ -43,6 +43,6 @@ class ProfileSshKeys < Spinach::FeatureSteps | ||
43 | end | 43 | end |
44 | 44 | ||
45 | And 'I have ssh key "ssh-rsa Work"' do | 45 | And 'I have ssh key "ssh-rsa Work"' do |
46 | - create(:key, :user => @user, :title => "ssh-rsa Work", :key => "jfKLJDFKSFJSHFJssh-rsa Work") | 46 | + create(:key, :user => @user, :title => "ssh-rsa Work", :key => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+L3TbFegm3k8QjejSwemk4HhlRh+DuN679Pc5ckqE/MPhVtE/+kZQDYCTB284GiT2aIoGzmZ8ee9TkaoejAsBwlA+Wz2Q3vhz65X6sMgalRwpdJx8kSEUYV8ZPV3MZvPo8KdNg993o4jL6G36GDW4BPIyO6FPZhfsawdf6liVD0Xo5kibIK7B9VoE178cdLQtLpS2YolRwf5yy6XR6hbbBGQR+6xrGOdP16eGZDb1CE2bMvvJijjloFqPscGktWOqW+nfh5txwFfBzlfARDTBsS8WZtg3Yoj1kn33kPsWRlgHfNutFRAIynDuDdQzQq8tTtVwm+Yi75RfcPHW8y3P Work") |
47 | end | 47 | end |
48 | end | 48 | end |
features/steps/project/project_issues.rb
@@ -122,10 +122,9 @@ class ProjectIssues < Spinach::FeatureSteps | @@ -122,10 +122,9 @@ class ProjectIssues < Spinach::FeatureSteps | ||
122 | 122 | ||
123 | And 'project "Shop" have "Release 0.3" closed issue' do | 123 | And 'project "Shop" have "Release 0.3" closed issue' do |
124 | project = Project.find_by_name("Shop") | 124 | project = Project.find_by_name("Shop") |
125 | - create(:issue, | 125 | + create(:closed_issue, |
126 | :title => "Release 0.3", | 126 | :title => "Release 0.3", |
127 | :project => project, | 127 | :project => project, |
128 | - :author => project.users.first, | ||
129 | - :closed => true) | 128 | + :author => project.users.first) |
130 | end | 129 | end |
131 | end | 130 | end |
features/steps/project/project_merge_requests.rb
@@ -26,7 +26,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps | @@ -26,7 +26,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps | ||
26 | 26 | ||
27 | Then 'I should see closed merge request "Bug NS-04"' do | 27 | Then 'I should see closed merge request "Bug NS-04"' do |
28 | mr = MergeRequest.find_by_title("Bug NS-04") | 28 | mr = MergeRequest.find_by_title("Bug NS-04") |
29 | - mr.closed.should be_true | 29 | + mr.closed?.should be_true |
30 | page.should have_content "Closed by" | 30 | page.should have_content "Closed by" |
31 | end | 31 | end |
32 | 32 | ||
@@ -80,11 +80,10 @@ class ProjectMergeRequests < Spinach::FeatureSteps | @@ -80,11 +80,10 @@ class ProjectMergeRequests < Spinach::FeatureSteps | ||
80 | 80 | ||
81 | And 'project "Shop" have "Feature NS-03" closed merge request' do | 81 | And 'project "Shop" have "Feature NS-03" closed merge request' do |
82 | project = Project.find_by_name("Shop") | 82 | project = Project.find_by_name("Shop") |
83 | - create(:merge_request, | 83 | + create(:closed_merge_request, |
84 | title: "Feature NS-03", | 84 | title: "Feature NS-03", |
85 | project: project, | 85 | project: project, |
86 | - author: project.users.first, | ||
87 | - closed: true) | 86 | + author: project.users.first) |
88 | end | 87 | end |
89 | 88 | ||
90 | And 'I switch to the diff tab' do | 89 | And 'I switch to the diff tab' do |
lib/api/entities.rb
@@ -20,7 +20,7 @@ module Gitlab | @@ -20,7 +20,7 @@ module Gitlab | ||
20 | class Project < Grape::Entity | 20 | class Project < Grape::Entity |
21 | expose :id, :name, :description, :default_branch | 21 | expose :id, :name, :description, :default_branch |
22 | expose :owner, using: Entities::UserBasic | 22 | expose :owner, using: Entities::UserBasic |
23 | - expose :private_flag, as: :private | 23 | + expose :public |
24 | expose :path, :path_with_namespace | 24 | expose :path, :path_with_namespace |
25 | expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at | 25 | expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at |
26 | expose :namespace | 26 | expose :namespace |
@@ -35,12 +35,11 @@ module Gitlab | @@ -35,12 +35,11 @@ module Gitlab | ||
35 | class Group < Grape::Entity | 35 | class Group < Grape::Entity |
36 | expose :id, :name, :path, :owner_id | 36 | expose :id, :name, :path, :owner_id |
37 | end | 37 | end |
38 | - | 38 | + |
39 | class GroupDetail < Group | 39 | class GroupDetail < Group |
40 | expose :projects, using: Entities::Project | 40 | expose :projects, using: Entities::Project |
41 | end | 41 | end |
42 | 42 | ||
43 | - | ||
44 | class RepoObject < Grape::Entity | 43 | class RepoObject < Grape::Entity |
45 | expose :name, :commit | 44 | expose :name, :commit |
46 | expose :protected do |repo, options| | 45 | expose :protected do |repo, options| |
@@ -63,7 +62,7 @@ module Gitlab | @@ -63,7 +62,7 @@ module Gitlab | ||
63 | class Milestone < Grape::Entity | 62 | class Milestone < Grape::Entity |
64 | expose :id | 63 | expose :id |
65 | expose (:project_id) {|milestone| milestone.project.id} | 64 | expose (:project_id) {|milestone| milestone.project.id} |
66 | - expose :title, :description, :due_date, :closed, :updated_at, :created_at | 65 | + expose :title, :description, :due_date, :state, :updated_at, :created_at |
67 | end | 66 | end |
68 | 67 | ||
69 | class Issue < Grape::Entity | 68 | class Issue < Grape::Entity |
@@ -73,7 +72,7 @@ module Gitlab | @@ -73,7 +72,7 @@ module Gitlab | ||
73 | expose :label_list, as: :labels | 72 | expose :label_list, as: :labels |
74 | expose :milestone, using: Entities::Milestone | 73 | expose :milestone, using: Entities::Milestone |
75 | expose :assignee, :author, using: Entities::UserBasic | 74 | expose :assignee, :author, using: Entities::UserBasic |
76 | - expose :closed, :updated_at, :created_at | 75 | + expose :state, :updated_at, :created_at |
77 | end | 76 | end |
78 | 77 | ||
79 | class SSHKey < Grape::Entity | 78 | class SSHKey < Grape::Entity |
@@ -81,7 +80,7 @@ module Gitlab | @@ -81,7 +80,7 @@ module Gitlab | ||
81 | end | 80 | end |
82 | 81 | ||
83 | class MergeRequest < Grape::Entity | 82 | class MergeRequest < Grape::Entity |
84 | - expose :id, :target_branch, :source_branch, :project_id, :title, :closed, :merged | 83 | + expose :id, :target_branch, :source_branch, :project_id, :title, :state |
85 | expose :author, :assignee, using: Entities::UserBasic | 84 | expose :author, :assignee, using: Entities::UserBasic |
86 | end | 85 | end |
87 | 86 |
lib/api/internal.rb
lib/api/issues.rb
@@ -69,14 +69,14 @@ module Gitlab | @@ -69,14 +69,14 @@ module Gitlab | ||
69 | # assignee_id (optional) - The ID of a user to assign issue | 69 | # assignee_id (optional) - The ID of a user to assign issue |
70 | # milestone_id (optional) - The ID of a milestone to assign issue | 70 | # milestone_id (optional) - The ID of a milestone to assign issue |
71 | # labels (optional) - The labels of an issue | 71 | # labels (optional) - The labels of an issue |
72 | - # closed (optional) - The state of an issue (0 = false, 1 = true) | 72 | + # state (optional) - The state of an issue (close|reopen) |
73 | # Example Request: | 73 | # Example Request: |
74 | # PUT /projects/:id/issues/:issue_id | 74 | # PUT /projects/:id/issues/:issue_id |
75 | put ":id/issues/:issue_id" do | 75 | put ":id/issues/:issue_id" do |
76 | @issue = user_project.issues.find(params[:issue_id]) | 76 | @issue = user_project.issues.find(params[:issue_id]) |
77 | authorize! :modify_issue, @issue | 77 | authorize! :modify_issue, @issue |
78 | 78 | ||
79 | - attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :closed] | 79 | + attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event] |
80 | attrs[:label_list] = params[:labels] if params[:labels].present? | 80 | attrs[:label_list] = params[:labels] if params[:labels].present? |
81 | IssueObserver.current_user = current_user | 81 | IssueObserver.current_user = current_user |
82 | if @issue.update_attributes attrs | 82 | if @issue.update_attributes attrs |
lib/api/merge_requests.rb
@@ -91,12 +91,12 @@ module Gitlab | @@ -91,12 +91,12 @@ module Gitlab | ||
91 | # target_branch - The target branch | 91 | # target_branch - The target branch |
92 | # assignee_id - Assignee user ID | 92 | # assignee_id - Assignee user ID |
93 | # title - Title of MR | 93 | # title - Title of MR |
94 | - # closed - Status of MR. true - closed | 94 | + # state_event - Status of MR. (close|reopen|merge) |
95 | # Example: | 95 | # Example: |
96 | # PUT /projects/:id/merge_request/:merge_request_id | 96 | # PUT /projects/:id/merge_request/:merge_request_id |
97 | # | 97 | # |
98 | put ":id/merge_request/:merge_request_id" do | 98 | put ":id/merge_request/:merge_request_id" do |
99 | - attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :closed] | 99 | + attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :state_event] |
100 | merge_request = user_project.merge_requests.find(params[:merge_request_id]) | 100 | merge_request = user_project.merge_requests.find(params[:merge_request_id]) |
101 | 101 | ||
102 | authorize! :modify_merge_request, merge_request | 102 | authorize! :modify_merge_request, merge_request |
lib/api/milestones.rb
@@ -74,14 +74,14 @@ module Gitlab | @@ -74,14 +74,14 @@ module Gitlab | ||
74 | # title (optional) - The title of a milestone | 74 | # title (optional) - The title of a milestone |
75 | # description (optional) - The description of a milestone | 75 | # description (optional) - The description of a milestone |
76 | # due_date (optional) - The due date of a milestone | 76 | # due_date (optional) - The due date of a milestone |
77 | - # closed (optional) - The status of the milestone | 77 | + # state (optional) - The status of the milestone (close|activate) |
78 | # Example Request: | 78 | # Example Request: |
79 | # PUT /projects/:id/milestones/:milestone_id | 79 | # PUT /projects/:id/milestones/:milestone_id |
80 | put ":id/milestones/:milestone_id" do | 80 | put ":id/milestones/:milestone_id" do |
81 | authorize! :admin_milestone, user_project | 81 | authorize! :admin_milestone, user_project |
82 | 82 | ||
83 | @milestone = user_project.milestones.find(params[:milestone_id]) | 83 | @milestone = user_project.milestones.find(params[:milestone_id]) |
84 | - attrs = attributes_for_keys [:title, :description, :due_date, :closed] | 84 | + attrs = attributes_for_keys [:title, :description, :due_date, :state_event] |
85 | if @milestone.update_attributes attrs | 85 | if @milestone.update_attributes attrs |
86 | present @milestone, with: Entities::Milestone | 86 | present @milestone, with: Entities::Milestone |
87 | else | 87 | else |
lib/api/projects.rb
@@ -184,6 +184,7 @@ module Gitlab | @@ -184,6 +184,7 @@ module Gitlab | ||
184 | # Example Request: | 184 | # Example Request: |
185 | # GET /projects/:id/hooks/:hook_id | 185 | # GET /projects/:id/hooks/:hook_id |
186 | get ":id/hooks/:hook_id" do | 186 | get ":id/hooks/:hook_id" do |
187 | + authorize! :admin_project, user_project | ||
187 | @hook = user_project.hooks.find(params[:hook_id]) | 188 | @hook = user_project.hooks.find(params[:hook_id]) |
188 | present @hook, with: Entities::Hook | 189 | present @hook, with: Entities::Hook |
189 | end | 190 | end |
lib/gitlab/backend/grack_auth.rb
1 | +require_relative 'shell_env' | ||
2 | + | ||
1 | module Grack | 3 | module Grack |
2 | class Auth < Rack::Auth::Basic | 4 | class Auth < Rack::Auth::Basic |
3 | attr_accessor :user, :project | 5 | attr_accessor :user, :project |
@@ -7,9 +9,6 @@ module Grack | @@ -7,9 +9,6 @@ module Grack | ||
7 | @request = Rack::Request.new(env) | 9 | @request = Rack::Request.new(env) |
8 | @auth = Request.new(env) | 10 | @auth = Request.new(env) |
9 | 11 | ||
10 | - # Pass Gitolite update hook | ||
11 | - ENV['GL_BYPASS_UPDATE_HOOK'] = "true" | ||
12 | - | ||
13 | # Need this patch due to the rails mount | 12 | # Need this patch due to the rails mount |
14 | @env['PATH_INFO'] = @request.path | 13 | @env['PATH_INFO'] = @request.path |
15 | @env['SCRIPT_NAME'] = "" | 14 | @env['SCRIPT_NAME'] = "" |
@@ -35,8 +34,7 @@ module Grack | @@ -35,8 +34,7 @@ module Grack | ||
35 | self.user = User.find_by_email(login) || User.find_by_username(login) | 34 | self.user = User.find_by_email(login) || User.find_by_username(login) |
36 | return false unless user.try(:valid_password?, password) | 35 | return false unless user.try(:valid_password?, password) |
37 | 36 | ||
38 | - # Set GL_USER env variable | ||
39 | - ENV['GL_USER'] = user.email | 37 | + Gitlab::ShellEnv.set_env(user) |
40 | end | 38 | end |
41 | 39 | ||
42 | # Git upload and receive | 40 | # Git upload and receive |
lib/gitlab/backend/shell.rb
@@ -10,7 +10,7 @@ module Gitlab | @@ -10,7 +10,7 @@ module Gitlab | ||
10 | # add_repository("gitlab/gitlab-ci") | 10 | # add_repository("gitlab/gitlab-ci") |
11 | # | 11 | # |
12 | def add_repository(name) | 12 | def add_repository(name) |
13 | - system("/home/git/gitlab-shell/bin/gitlab-projects add-project #{name}.git") | 13 | + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects add-project #{name}.git") |
14 | end | 14 | end |
15 | 15 | ||
16 | # Import repository | 16 | # Import repository |
@@ -21,7 +21,7 @@ module Gitlab | @@ -21,7 +21,7 @@ module Gitlab | ||
21 | # import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git") | 21 | # import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git") |
22 | # | 22 | # |
23 | def import_repository(name, url) | 23 | def import_repository(name, url) |
24 | - system("/home/git/gitlab-shell/bin/gitlab-projects import-project #{name}.git #{url}") | 24 | + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects import-project #{name}.git #{url}") |
25 | end | 25 | end |
26 | 26 | ||
27 | # Remove repository from file system | 27 | # Remove repository from file system |
@@ -32,7 +32,7 @@ module Gitlab | @@ -32,7 +32,7 @@ module Gitlab | ||
32 | # remove_repository("gitlab/gitlab-ci") | 32 | # remove_repository("gitlab/gitlab-ci") |
33 | # | 33 | # |
34 | def remove_repository(name) | 34 | def remove_repository(name) |
35 | - system("/home/git/gitlab-shell/bin/gitlab-projects rm-project #{name}.git") | 35 | + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects rm-project #{name}.git") |
36 | end | 36 | end |
37 | 37 | ||
38 | # Add new key to gitlab-shell | 38 | # Add new key to gitlab-shell |
@@ -41,7 +41,7 @@ module Gitlab | @@ -41,7 +41,7 @@ module Gitlab | ||
41 | # add_key("key-42", "sha-rsa ...") | 41 | # add_key("key-42", "sha-rsa ...") |
42 | # | 42 | # |
43 | def add_key(key_id, key_content) | 43 | def add_key(key_id, key_content) |
44 | - system("/home/git/gitlab-shell/bin/gitlab-keys add-key #{key_id} \"#{key_content}\"") | 44 | + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys add-key #{key_id} \"#{key_content}\"") |
45 | end | 45 | end |
46 | 46 | ||
47 | # Remove ssh key from gitlab shell | 47 | # Remove ssh key from gitlab shell |
@@ -50,12 +50,16 @@ module Gitlab | @@ -50,12 +50,16 @@ module Gitlab | ||
50 | # remove_key("key-342", "sha-rsa ...") | 50 | # remove_key("key-342", "sha-rsa ...") |
51 | # | 51 | # |
52 | def remove_key(key_id, key_content) | 52 | def remove_key(key_id, key_content) |
53 | - system("/home/git/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"") | 53 | + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"") |
54 | end | 54 | end |
55 | 55 | ||
56 | - | ||
57 | def url_to_repo path | 56 | def url_to_repo path |
58 | Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git" | 57 | Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git" |
59 | end | 58 | end |
59 | + | ||
60 | + def gitlab_shell_user_home | ||
61 | + File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}") | ||
62 | + end | ||
63 | + | ||
60 | end | 64 | end |
61 | end | 65 | end |
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +module Gitlab | ||
2 | + # This module provide 2 methods | ||
3 | + # to set specific ENV variabled for GitLab Shell | ||
4 | + module ShellEnv | ||
5 | + extend self | ||
6 | + | ||
7 | + def set_env(user) | ||
8 | + # Set GL_ID env variable | ||
9 | + ENV['GL_ID'] = "user-#{user.id}" | ||
10 | + end | ||
11 | + | ||
12 | + def reset_env | ||
13 | + # Reset GL_ID env variable | ||
14 | + ENV['GL_ID'] = nil | ||
15 | + end | ||
16 | + end | ||
17 | +end |
lib/gitlab/regex.rb
@@ -10,6 +10,10 @@ module Gitlab | @@ -10,6 +10,10 @@ module Gitlab | ||
10 | /\A[a-zA-Z][a-zA-Z0-9_\-\. ]*\z/ | 10 | /\A[a-zA-Z][a-zA-Z0-9_\-\. ]*\z/ |
11 | end | 11 | end |
12 | 12 | ||
13 | + def name_regex | ||
14 | + /\A[a-zA-Z0-9_\-\. ]*\z/ | ||
15 | + end | ||
16 | + | ||
13 | def path_regex | 17 | def path_regex |
14 | default_regex | 18 | default_regex |
15 | end | 19 | end |
lib/gitlab/satellite/action.rb
@@ -17,6 +17,8 @@ module Gitlab | @@ -17,6 +17,8 @@ module Gitlab | ||
17 | # * Locks the satellite repo | 17 | # * Locks the satellite repo |
18 | # * Yields the prepared satellite repo | 18 | # * Yields the prepared satellite repo |
19 | def in_locked_and_timed_satellite | 19 | def in_locked_and_timed_satellite |
20 | + Gitlab::ShellEnv.set_env(user) | ||
21 | + | ||
20 | Grit::Git.with_timeout(options[:git_timeout]) do | 22 | Grit::Git.with_timeout(options[:git_timeout]) do |
21 | project.satellite.lock do | 23 | project.satellite.lock do |
22 | return yield project.satellite.repo | 24 | return yield project.satellite.repo |
@@ -28,6 +30,8 @@ module Gitlab | @@ -28,6 +30,8 @@ module Gitlab | ||
28 | rescue Grit::Git::GitTimeout => ex | 30 | rescue Grit::Git::GitTimeout => ex |
29 | Gitlab::GitLogger.error(ex.message) | 31 | Gitlab::GitLogger.error(ex.message) |
30 | return false | 32 | return false |
33 | + ensure | ||
34 | + Gitlab::ShellEnv.reset_env | ||
31 | end | 35 | end |
32 | 36 | ||
33 | # * Clears the satellite | 37 | # * Clears the satellite |
lib/tasks/gitlab/info.rake
@@ -40,8 +40,8 @@ namespace :gitlab do | @@ -40,8 +40,8 @@ namespace :gitlab do | ||
40 | 40 | ||
41 | puts "" | 41 | puts "" |
42 | puts "GitLab information".yellow | 42 | puts "GitLab information".yellow |
43 | - puts "Version:\t#{Gitlab::Version}" | ||
44 | - puts "Revision:\t#{Gitlab::Revision}" | 43 | + puts "Version:\t#{Gitlab::VERSION}" |
44 | + puts "Revision:\t#{Gitlab::REVISION}" | ||
45 | puts "Directory:\t#{Rails.root}" | 45 | puts "Directory:\t#{Rails.root}" |
46 | puts "DB Adapter:\t#{database_adapter}" | 46 | puts "DB Adapter:\t#{database_adapter}" |
47 | puts "URL:\t\t#{Gitlab.config.gitlab.url}" | 47 | puts "URL:\t\t#{Gitlab.config.gitlab.url}" |
lib/tasks/gitlab/setup.rake
1 | namespace :gitlab do | 1 | namespace :gitlab do |
2 | desc "GITLAB | Setup production application" | 2 | desc "GITLAB | Setup production application" |
3 | task :setup => :environment do | 3 | task :setup => :environment do |
4 | - setup | 4 | + setup_db |
5 | end | 5 | end |
6 | 6 | ||
7 | - def setup | 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." | 10 | puts "This will create the necessary database tables and seed the database." |
lib/tasks/gitlab/shell.rake
@@ -25,12 +25,13 @@ namespace :gitlab do | @@ -25,12 +25,13 @@ namespace :gitlab do | ||
25 | def setup | 25 | def setup |
26 | warn_user_is_not_gitlab | 26 | warn_user_is_not_gitlab |
27 | 27 | ||
28 | + gitlab_shell_authorized_keys = File.join(File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}"),'.ssh/authorized_keys') | ||
28 | puts "This will rebuild an authorized_keys file." | 29 | puts "This will rebuild an authorized_keys file." |
29 | - puts "You will lose any data stored in /home/git/.ssh/authorized_keys." | 30 | + puts "You will lose any data stored in #{gitlab_shell_authorized_keys}." |
30 | ask_to_continue | 31 | ask_to_continue |
31 | puts "" | 32 | puts "" |
32 | 33 | ||
33 | - system("echo '# Managed by gitlab-shell' > /home/git/.ssh/authorized_keys") | 34 | + system("echo '# Managed by gitlab-shell' > #{gitlab_shell_authorized_keys}") |
34 | 35 | ||
35 | Key.find_each(batch_size: 1000) do |key| | 36 | Key.find_each(batch_size: 1000) do |key| |
36 | if Gitlab::Shell.new.add_key(key.shell_id, key.key) | 37 | if Gitlab::Shell.new.add_key(key.shell_id, key.key) |
lib/tasks/gitlab/task_helpers.rake
@@ -77,8 +77,7 @@ namespace :gitlab do | @@ -77,8 +77,7 @@ namespace :gitlab do | ||
77 | end | 77 | end |
78 | 78 | ||
79 | def gid_for(group_name) | 79 | def gid_for(group_name) |
80 | - group_line = File.read("/etc/group").lines.select{|l| l.start_with?("#{group_name}:")}.first | ||
81 | - group_line.split(":")[2].to_i | 80 | + Etc.getgrnam(group_name).gid |
82 | end | 81 | end |
83 | 82 | ||
84 | def warn_user_is_not_gitlab | 83 | def warn_user_is_not_gitlab |
public/deploy.html
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | <link href="/static.css" media="screen" rel="stylesheet" type="text/css" /> | 5 | <link href="/static.css" media="screen" rel="stylesheet" type="text/css" /> |
6 | </head> | 6 | </head> |
7 | <body> | 7 | <body> |
8 | - <h1>Deploy in progress</h1> | 8 | + <h1><center><img src="/gitlab_logo.png"/></center>Deploy in progress</h1> |
9 | <h3>Please try again in few minutes or contact your administrator.</h3> | 9 | <h3>Please try again in few minutes or contact your administrator.</h3> |
10 | </body> | 10 | </body> |
11 | </html> | 11 | </html> |
17 KB
spec/factories.rb
@@ -54,10 +54,15 @@ FactoryGirl.define do | @@ -54,10 +54,15 @@ FactoryGirl.define do | ||
54 | project | 54 | project |
55 | 55 | ||
56 | trait :closed do | 56 | trait :closed do |
57 | - closed true | 57 | + state :closed |
58 | + end | ||
59 | + | ||
60 | + trait :reopened do | ||
61 | + state :reopened | ||
58 | end | 62 | end |
59 | 63 | ||
60 | factory :closed_issue, traits: [:closed] | 64 | factory :closed_issue, traits: [:closed] |
65 | + factory :reopened_issue, traits: [:reopened] | ||
61 | end | 66 | end |
62 | 67 | ||
63 | factory :merge_request do | 68 | factory :merge_request do |
@@ -67,10 +72,6 @@ FactoryGirl.define do | @@ -67,10 +72,6 @@ FactoryGirl.define do | ||
67 | source_branch "master" | 72 | source_branch "master" |
68 | target_branch "stable" | 73 | target_branch "stable" |
69 | 74 | ||
70 | - trait :closed do | ||
71 | - closed true | ||
72 | - end | ||
73 | - | ||
74 | # pick 3 commits "at random" (from bcf03b5d~3 to bcf03b5d) | 75 | # pick 3 commits "at random" (from bcf03b5d~3 to bcf03b5d) |
75 | trait :with_diffs do | 76 | trait :with_diffs do |
76 | target_branch "master" # pretend bcf03b5d~3 | 77 | target_branch "master" # pretend bcf03b5d~3 |
@@ -85,7 +86,16 @@ FactoryGirl.define do | @@ -85,7 +86,16 @@ FactoryGirl.define do | ||
85 | end | 86 | end |
86 | end | 87 | end |
87 | 88 | ||
89 | + trait :closed do | ||
90 | + state :closed | ||
91 | + end | ||
92 | + | ||
93 | + trait :reopened do | ||
94 | + state :reopened | ||
95 | + end | ||
96 | + | ||
88 | factory :closed_merge_request, traits: [:closed] | 97 | factory :closed_merge_request, traits: [:closed] |
98 | + factory :reopened_merge_request, traits: [:reopened] | ||
89 | factory :merge_request_with_diffs, traits: [:with_diffs] | 99 | factory :merge_request_with_diffs, traits: [:with_diffs] |
90 | end | 100 | end |
91 | 101 | ||
@@ -148,11 +158,23 @@ FactoryGirl.define do | @@ -148,11 +158,23 @@ FactoryGirl.define do | ||
148 | "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa ++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" | 158 | "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa ++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" |
149 | end | 159 | end |
150 | end | 160 | end |
161 | + | ||
162 | + factory :invalid_key do | ||
163 | + key do | ||
164 | + "ssh-rsa this_is_invalid_key==" | ||
165 | + end | ||
166 | + end | ||
151 | end | 167 | end |
152 | 168 | ||
153 | factory :milestone do | 169 | factory :milestone do |
154 | title | 170 | title |
155 | project | 171 | project |
172 | + | ||
173 | + trait :closed do | ||
174 | + state :closed | ||
175 | + end | ||
176 | + | ||
177 | + factory :closed_milestone, traits: [:closed] | ||
156 | end | 178 | end |
157 | 179 | ||
158 | factory :system_hook do | 180 | factory :system_hook do |
spec/factories_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | -INVALID_FACTORIES = [:key_with_a_space_in_the_middle] | 3 | +INVALID_FACTORIES = [ |
4 | + :key_with_a_space_in_the_middle, | ||
5 | + :invalid_key, | ||
6 | +] | ||
4 | 7 | ||
5 | FactoryGirl.factories.map(&:name).each do |factory_name| | 8 | FactoryGirl.factories.map(&:name).each do |factory_name| |
6 | next if INVALID_FACTORIES.include?(factory_name) | 9 | next if INVALID_FACTORIES.include?(factory_name) |
spec/models/concerns/issuable_spec.rb
@@ -15,7 +15,6 @@ describe Issue, "Issuable" do | @@ -15,7 +15,6 @@ describe Issue, "Issuable" do | ||
15 | it { should validate_presence_of(:author) } | 15 | it { should validate_presence_of(:author) } |
16 | it { should validate_presence_of(:title) } | 16 | it { should validate_presence_of(:title) } |
17 | it { should ensure_length_of(:title).is_at_least(0).is_at_most(255) } | 17 | it { should ensure_length_of(:title).is_at_least(0).is_at_most(255) } |
18 | - it { should ensure_inclusion_of(:closed).in_array([true, false]) } | ||
19 | end | 18 | end |
20 | 19 | ||
21 | describe "Scope" do | 20 | describe "Scope" do |
spec/models/issue_spec.rb
@@ -9,7 +9,7 @@ | @@ -9,7 +9,7 @@ | ||
9 | # project_id :integer | 9 | # project_id :integer |
10 | # created_at :datetime not null | 10 | # created_at :datetime not null |
11 | # updated_at :datetime not null | 11 | # updated_at :datetime not null |
12 | -# closed :boolean default(FALSE), not null | 12 | +# state :string default(FALSE), not null |
13 | # position :integer default(0) | 13 | # position :integer default(0) |
14 | # branch_name :string(255) | 14 | # branch_name :string(255) |
15 | # description :text | 15 | # description :text |
@@ -44,34 +44,15 @@ describe Issue do | @@ -44,34 +44,15 @@ describe Issue do | ||
44 | end | 44 | end |
45 | end | 45 | end |
46 | 46 | ||
47 | - describe '#is_being_closed?' do | ||
48 | - it 'returns true if the closed attribute has changed and is now true' do | ||
49 | - subject.closed = true | ||
50 | - subject.is_being_closed?.should be_true | ||
51 | - end | ||
52 | - it 'returns false if the closed attribute has changed and is now false' do | ||
53 | - issue = create(:closed_issue) | ||
54 | - issue.closed = false | ||
55 | - issue.is_being_closed?.should be_false | ||
56 | - end | ||
57 | - it 'returns false if the closed attribute has not changed' do | ||
58 | - subject.is_being_closed?.should be_false | ||
59 | - end | ||
60 | - end | 47 | + describe '#is_being_reassigned?' do |
48 | + it 'returnes issues assigned to user' do | ||
49 | + user = create :user | ||
61 | 50 | ||
51 | + 2.times do | ||
52 | + issue = create :issue, assignee: user | ||
53 | + end | ||
62 | 54 | ||
63 | - describe '#is_being_reopened?' do | ||
64 | - it 'returns true if the closed attribute has changed and is now false' do | ||
65 | - issue = create(:closed_issue) | ||
66 | - issue.closed = false | ||
67 | - issue.is_being_reopened?.should be_true | ||
68 | - end | ||
69 | - it 'returns false if the closed attribute has changed and is now true' do | ||
70 | - subject.closed = true | ||
71 | - subject.is_being_reopened?.should be_false | ||
72 | - end | ||
73 | - it 'returns false if the closed attribute has not changed' do | ||
74 | - subject.is_being_reopened?.should be_false | 55 | + Issue.open_for(user).count.should eq 2 |
75 | end | 56 | end |
76 | end | 57 | end |
77 | end | 58 | end |
spec/models/key_spec.rb
@@ -73,8 +73,12 @@ describe Key do | @@ -73,8 +73,12 @@ describe Key do | ||
73 | build(:key, user: user).should be_valid | 73 | build(:key, user: user).should be_valid |
74 | end | 74 | end |
75 | 75 | ||
76 | - it "rejects the unfingerprintable key" do | 76 | + it "rejects the unfingerprintable key (contains space in middle)" do |
77 | build(:key_with_a_space_in_the_middle).should_not be_valid | 77 | build(:key_with_a_space_in_the_middle).should_not be_valid |
78 | end | 78 | end |
79 | + | ||
80 | + it "rejects the unfingerprintable key (not a key)" do | ||
81 | + build(:invalid_key).should_not be_valid | ||
82 | + end | ||
79 | end | 83 | end |
80 | end | 84 | end |
spec/models/merge_request_spec.rb
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | # st_commits :text(2147483647) | 15 | # st_commits :text(2147483647) |
16 | # st_diffs :text(2147483647) | 16 | # st_diffs :text(2147483647) |
17 | # merged :boolean default(FALSE), not null | 17 | # merged :boolean default(FALSE), not null |
18 | -# state :integer default(1), not null | 18 | +# merge_status :integer default(1), not null |
19 | # milestone_id :integer | 19 | # milestone_id :integer |
20 | # | 20 | # |
21 | 21 | ||
@@ -37,6 +37,10 @@ describe MergeRequest do | @@ -37,6 +37,10 @@ describe MergeRequest do | ||
37 | end | 37 | end |
38 | 38 | ||
39 | describe "#mr_and_commit_notes" do | 39 | describe "#mr_and_commit_notes" do |
40 | + | ||
41 | + end | ||
42 | + | ||
43 | + describe "#mr_and_commit_notes" do | ||
40 | let!(:merge_request) { create(:merge_request) } | 44 | let!(:merge_request) { create(:merge_request) } |
41 | 45 | ||
42 | before do | 46 | before do |
@@ -62,35 +66,4 @@ describe MergeRequest do | @@ -62,35 +66,4 @@ describe MergeRequest do | ||
62 | subject.is_being_reassigned?.should be_false | 66 | subject.is_being_reassigned?.should be_false |
63 | end | 67 | end |
64 | end | 68 | end |
65 | - | ||
66 | - describe '#is_being_closed?' do | ||
67 | - it 'returns true if the closed attribute has changed and is now true' do | ||
68 | - subject.closed = true | ||
69 | - subject.is_being_closed?.should be_true | ||
70 | - end | ||
71 | - it 'returns false if the closed attribute has changed and is now false' do | ||
72 | - merge_request = create(:closed_merge_request) | ||
73 | - merge_request.closed = false | ||
74 | - merge_request.is_being_closed?.should be_false | ||
75 | - end | ||
76 | - it 'returns false if the closed attribute has not changed' do | ||
77 | - subject.is_being_closed?.should be_false | ||
78 | - end | ||
79 | - end | ||
80 | - | ||
81 | - | ||
82 | - describe '#is_being_reopened?' do | ||
83 | - it 'returns true if the closed attribute has changed and is now false' do | ||
84 | - merge_request = create(:closed_merge_request) | ||
85 | - merge_request.closed = false | ||
86 | - merge_request.is_being_reopened?.should be_true | ||
87 | - end | ||
88 | - it 'returns false if the closed attribute has changed and is now true' do | ||
89 | - subject.closed = true | ||
90 | - subject.is_being_reopened?.should be_false | ||
91 | - end | ||
92 | - it 'returns false if the closed attribute has not changed' do | ||
93 | - subject.is_being_reopened?.should be_false | ||
94 | - end | ||
95 | - end | ||
96 | end | 69 | end |
spec/models/milestone_spec.rb
@@ -7,7 +7,7 @@ | @@ -7,7 +7,7 @@ | ||
7 | # project_id :integer not null | 7 | # project_id :integer not null |
8 | # description :text | 8 | # description :text |
9 | # due_date :date | 9 | # due_date :date |
10 | -# closed :boolean default(FALSE), not null | 10 | +# state :string default(FALSE), not null |
11 | # created_at :datetime not null | 11 | # created_at :datetime not null |
12 | # updated_at :datetime not null | 12 | # updated_at :datetime not null |
13 | # | 13 | # |
@@ -27,7 +27,6 @@ describe Milestone do | @@ -27,7 +27,6 @@ describe Milestone do | ||
27 | describe "Validation" do | 27 | describe "Validation" do |
28 | it { should validate_presence_of(:title) } | 28 | it { should validate_presence_of(:title) } |
29 | it { should validate_presence_of(:project) } | 29 | it { should validate_presence_of(:project) } |
30 | - it { should ensure_inclusion_of(:closed).in_array([true, false]) } | ||
31 | end | 30 | end |
32 | 31 | ||
33 | let(:milestone) { create(:milestone) } | 32 | let(:milestone) { create(:milestone) } |
@@ -41,7 +40,7 @@ describe Milestone do | @@ -41,7 +40,7 @@ describe Milestone do | ||
41 | 40 | ||
42 | it "should count closed issues" do | 41 | it "should count closed issues" do |
43 | IssueObserver.current_user = issue.author | 42 | IssueObserver.current_user = issue.author |
44 | - issue.update_attributes(closed: true) | 43 | + issue.close |
45 | milestone.issues << issue | 44 | milestone.issues << issue |
46 | milestone.percent_complete.should == 100 | 45 | milestone.percent_complete.should == 100 |
47 | end | 46 | end |
@@ -96,7 +95,7 @@ describe Milestone do | @@ -96,7 +95,7 @@ describe Milestone do | ||
96 | describe :items_count do | 95 | describe :items_count do |
97 | before do | 96 | before do |
98 | milestone.issues << create(:issue) | 97 | milestone.issues << create(:issue) |
99 | - milestone.issues << create(:issue, closed: true) | 98 | + milestone.issues << create(:closed_issue) |
100 | milestone.merge_requests << create(:merge_request) | 99 | milestone.merge_requests << create(:merge_request) |
101 | end | 100 | end |
102 | 101 | ||
@@ -110,7 +109,35 @@ describe Milestone do | @@ -110,7 +109,35 @@ describe Milestone do | ||
110 | it { milestone.can_be_closed?.should be_true } | 109 | it { milestone.can_be_closed?.should be_true } |
111 | end | 110 | end |
112 | 111 | ||
113 | - describe :open? do | ||
114 | - it { milestone.open?.should be_true } | 112 | + describe :is_empty? do |
113 | + before do | ||
114 | + issue = create :closed_issue, milestone: milestone | ||
115 | + merge_request = create :merge_request, milestone: milestone | ||
116 | + end | ||
117 | + | ||
118 | + it 'Should return total count of issues and merge requests assigned to milestone' do | ||
119 | + milestone.total_items_count.should eq 2 | ||
120 | + end | ||
121 | + end | ||
122 | + | ||
123 | + describe :can_be_closed? do | ||
124 | + before do | ||
125 | + milestone = create :milestone | ||
126 | + create :closed_issue, milestone: milestone | ||
127 | + | ||
128 | + issue = create :issue | ||
129 | + end | ||
130 | + | ||
131 | + it 'should be true if milestone active and all nestied issues closed' do | ||
132 | + milestone.can_be_closed?.should be_true | ||
133 | + end | ||
134 | + | ||
135 | + it 'should be false if milestone active and not all nestied issues closed' do | ||
136 | + issue.milestone = milestone | ||
137 | + issue.save | ||
138 | + | ||
139 | + milestone.can_be_closed?.should be_false | ||
140 | + end | ||
115 | end | 141 | end |
142 | + | ||
116 | end | 143 | end |
spec/models/project_spec.rb
@@ -121,10 +121,7 @@ describe Project do | @@ -121,10 +121,7 @@ describe Project do | ||
121 | let(:project) { create(:project) } | 121 | let(:project) { create(:project) } |
122 | 122 | ||
123 | before do | 123 | before do |
124 | - @merge_request = create(:merge_request, | ||
125 | - project: project, | ||
126 | - merged: false, | ||
127 | - closed: false) | 124 | + @merge_request = create(:merge_request, project: project) |
128 | @key = create(:key, user_id: project.owner.id) | 125 | @key = create(:key, user_id: project.owner.id) |
129 | end | 126 | end |
130 | 127 | ||
@@ -133,8 +130,7 @@ describe Project do | @@ -133,8 +130,7 @@ describe Project do | ||
133 | @merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" | 130 | @merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" |
134 | project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a", "refs/heads/stable", @key.user) | 131 | project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a", "refs/heads/stable", @key.user) |
135 | @merge_request.reload | 132 | @merge_request.reload |
136 | - @merge_request.merged.should be_true | ||
137 | - @merge_request.closed.should be_true | 133 | + @merge_request.merged?.should be_true |
138 | end | 134 | end |
139 | 135 | ||
140 | it "should update merge request commits with new one if pushed to source branch" do | 136 | it "should update merge request commits with new one if pushed to source branch" do |
spec/observers/issue_observer_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | describe IssueObserver do | 3 | describe IssueObserver do |
4 | - let(:some_user) { double(:user, id: 1) } | ||
5 | - let(:assignee) { double(:user, id: 2) } | ||
6 | - let(:author) { double(:user, id: 3) } | ||
7 | - let(:issue) { double(:issue, id: 42, assignee: assignee, author: author) } | 4 | + let(:some_user) { create :user } |
5 | + let(:assignee) { create :user } | ||
6 | + let(:author) { create :user } | ||
7 | + let(:mock_issue) { double(:issue, id: 42, assignee: assignee, author: author) } | ||
8 | + let(:assigned_issue) { create(:issue, assignee: assignee, author: author) } | ||
9 | + let(:unassigned_issue) { create(:issue, author: author) } | ||
10 | + let(:closed_assigned_issue) { create(:closed_issue, assignee: assignee, author: author) } | ||
11 | + let(:closed_unassigned_issue) { create(:closed_issue, author: author) } | ||
12 | + | ||
8 | 13 | ||
9 | before(:each) { subject.stub(:current_user).and_return(some_user) } | 14 | before(:each) { subject.stub(:current_user).and_return(some_user) } |
10 | 15 | ||
@@ -21,137 +26,91 @@ describe IssueObserver do | @@ -21,137 +26,91 @@ describe IssueObserver do | ||
21 | end | 26 | end |
22 | 27 | ||
23 | it 'sends an email to the assignee' do | 28 | it 'sends an email to the assignee' do |
24 | - Notify.should_receive(:new_issue_email).with(issue.id) | 29 | + Notify.should_receive(:new_issue_email).with(mock_issue.id) |
25 | 30 | ||
26 | - subject.after_create(issue) | 31 | + subject.after_create(mock_issue) |
27 | end | 32 | end |
28 | 33 | ||
29 | it 'does not send an email to the assignee if assignee created the issue' do | 34 | it 'does not send an email to the assignee if assignee created the issue' do |
30 | subject.stub(:current_user).and_return(assignee) | 35 | subject.stub(:current_user).and_return(assignee) |
31 | Notify.should_not_receive(:new_issue_email) | 36 | Notify.should_not_receive(:new_issue_email) |
32 | 37 | ||
33 | - subject.after_create(issue) | 38 | + subject.after_create(mock_issue) |
34 | end | 39 | end |
35 | end | 40 | end |
36 | 41 | ||
37 | - context '#after_update' do | ||
38 | - before(:each) do | ||
39 | - issue.stub(:is_being_reassigned?).and_return(false) | ||
40 | - issue.stub(:is_being_closed?).and_return(false) | ||
41 | - issue.stub(:is_being_reopened?).and_return(false) | ||
42 | - end | ||
43 | - | ||
44 | - it 'is called when an issue is changed' do | ||
45 | - changed = create(:issue, project: create(:project)) | ||
46 | - subject.should_receive(:after_update) | ||
47 | - | ||
48 | - Issue.observers.enable :issue_observer do | ||
49 | - changed.description = 'I changed' | ||
50 | - changed.save | ||
51 | - end | ||
52 | - end | ||
53 | - | ||
54 | - context 'a reassigned email' do | ||
55 | - it 'is sent if the issue is being reassigned' do | ||
56 | - issue.should_receive(:is_being_reassigned?).and_return(true) | ||
57 | - subject.should_receive(:send_reassigned_email).with(issue) | ||
58 | - | ||
59 | - subject.after_update(issue) | ||
60 | - end | ||
61 | - | ||
62 | - it 'is not sent if the issue is not being reassigned' do | ||
63 | - issue.should_receive(:is_being_reassigned?).and_return(false) | ||
64 | - subject.should_not_receive(:send_reassigned_email) | ||
65 | - | ||
66 | - subject.after_update(issue) | ||
67 | - end | ||
68 | - end | ||
69 | - | 42 | + context '#after_close' do |
70 | context 'a status "closed"' do | 43 | context 'a status "closed"' do |
71 | it 'note is created if the issue is being closed' do | 44 | it 'note is created if the issue is being closed' do |
72 | - issue.should_receive(:is_being_closed?).and_return(true) | ||
73 | - Notify.should_receive(:issue_status_changed_email).twice | ||
74 | - Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed') | ||
75 | - | ||
76 | - subject.after_update(issue) | ||
77 | - end | ||
78 | - | ||
79 | - it 'note is not created if the issue is not being closed' do | ||
80 | - issue.should_receive(:is_being_closed?).and_return(false) | ||
81 | - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed') | 45 | + Note.should_receive(:create_status_change_note).with(assigned_issue, some_user, 'closed') |
82 | 46 | ||
83 | - subject.after_update(issue) | 47 | + assigned_issue.close |
84 | end | 48 | end |
85 | 49 | ||
86 | it 'notification is delivered if the issue being closed' do | 50 | it 'notification is delivered if the issue being closed' do |
87 | - issue.stub(:is_being_closed?).and_return(true) | ||
88 | Notify.should_receive(:issue_status_changed_email).twice | 51 | Notify.should_receive(:issue_status_changed_email).twice |
89 | - Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed') | ||
90 | 52 | ||
91 | - subject.after_update(issue) | ||
92 | - end | ||
93 | - | ||
94 | - it 'notification is not delivered if the issue not being closed' do | ||
95 | - issue.stub(:is_being_closed?).and_return(false) | ||
96 | - Notify.should_not_receive(:issue_status_changed_email) | ||
97 | - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed') | ||
98 | - | ||
99 | - subject.after_update(issue) | 53 | + assigned_issue.close |
100 | end | 54 | end |
101 | 55 | ||
102 | it 'notification is delivered only to author if the issue being closed' do | 56 | it 'notification is delivered only to author if the issue being closed' do |
103 | - issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil) | ||
104 | - issue_without_assignee.stub(:is_being_reassigned?).and_return(false) | ||
105 | - issue_without_assignee.stub(:is_being_closed?).and_return(true) | ||
106 | - issue_without_assignee.stub(:is_being_reopened?).and_return(false) | ||
107 | Notify.should_receive(:issue_status_changed_email).once | 57 | Notify.should_receive(:issue_status_changed_email).once |
108 | - Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'closed') | 58 | + Note.should_receive(:create_status_change_note).with(unassigned_issue, some_user, 'closed') |
109 | 59 | ||
110 | - subject.after_update(issue_without_assignee) | 60 | + unassigned_issue.close |
111 | end | 61 | end |
112 | end | 62 | end |
113 | 63 | ||
114 | context 'a status "reopened"' do | 64 | context 'a status "reopened"' do |
115 | it 'note is created if the issue is being reopened' do | 65 | it 'note is created if the issue is being reopened' do |
66 | + Note.should_receive(:create_status_change_note).with(closed_assigned_issue, some_user, 'reopened') | ||
67 | + | ||
68 | + closed_assigned_issue.reopen | ||
69 | + end | ||
70 | + | ||
71 | + it 'notification is delivered if the issue being reopened' do | ||
116 | Notify.should_receive(:issue_status_changed_email).twice | 72 | Notify.should_receive(:issue_status_changed_email).twice |
117 | - issue.should_receive(:is_being_reopened?).and_return(true) | ||
118 | - Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened') | ||
119 | 73 | ||
120 | - subject.after_update(issue) | 74 | + closed_assigned_issue.reopen |
121 | end | 75 | end |
122 | 76 | ||
123 | - it 'note is not created if the issue is not being reopened' do | ||
124 | - issue.should_receive(:is_being_reopened?).and_return(false) | ||
125 | - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened') | 77 | + it 'notification is delivered only to author if the issue being reopened' do |
78 | + Notify.should_receive(:issue_status_changed_email).once | ||
79 | + Note.should_receive(:create_status_change_note).with(closed_unassigned_issue, some_user, 'reopened') | ||
126 | 80 | ||
127 | - subject.after_update(issue) | 81 | + closed_unassigned_issue.reopen |
128 | end | 82 | end |
83 | + end | ||
84 | + end | ||
129 | 85 | ||
130 | - it 'notification is delivered if the issue being reopened' do | ||
131 | - issue.stub(:is_being_reopened?).and_return(true) | ||
132 | - Notify.should_receive(:issue_status_changed_email).twice | ||
133 | - Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened') | 86 | + context '#after_update' do |
87 | + before(:each) do | ||
88 | + mock_issue.stub(:is_being_reassigned?).and_return(false) | ||
89 | + end | ||
90 | + | ||
91 | + it 'is called when an issue is changed' do | ||
92 | + changed = create(:issue, project: create(:project)) | ||
93 | + subject.should_receive(:after_update) | ||
134 | 94 | ||
135 | - subject.after_update(issue) | 95 | + Issue.observers.enable :issue_observer do |
96 | + changed.description = 'I changed' | ||
97 | + changed.save | ||
136 | end | 98 | end |
99 | + end | ||
137 | 100 | ||
138 | - it 'notification is not delivered if the issue not being reopened' do | ||
139 | - issue.stub(:is_being_reopened?).and_return(false) | ||
140 | - Notify.should_not_receive(:issue_status_changed_email) | ||
141 | - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened') | 101 | + context 'a reassigned email' do |
102 | + it 'is sent if the issue is being reassigned' do | ||
103 | + mock_issue.should_receive(:is_being_reassigned?).and_return(true) | ||
104 | + subject.should_receive(:send_reassigned_email).with(mock_issue) | ||
142 | 105 | ||
143 | - subject.after_update(issue) | 106 | + subject.after_update(mock_issue) |
144 | end | 107 | end |
145 | 108 | ||
146 | - it 'notification is delivered only to author if the issue being reopened' do | ||
147 | - issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil) | ||
148 | - issue_without_assignee.stub(:is_being_reassigned?).and_return(false) | ||
149 | - issue_without_assignee.stub(:is_being_closed?).and_return(false) | ||
150 | - issue_without_assignee.stub(:is_being_reopened?).and_return(true) | ||
151 | - Notify.should_receive(:issue_status_changed_email).once | ||
152 | - Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'reopened') | 109 | + it 'is not sent if the issue is not being reassigned' do |
110 | + mock_issue.should_receive(:is_being_reassigned?).and_return(false) | ||
111 | + subject.should_not_receive(:send_reassigned_email) | ||
153 | 112 | ||
154 | - subject.after_update(issue_without_assignee) | 113 | + subject.after_update(mock_issue) |
155 | end | 114 | end |
156 | end | 115 | end |
157 | end | 116 | end |
@@ -160,23 +119,23 @@ describe IssueObserver do | @@ -160,23 +119,23 @@ describe IssueObserver do | ||
160 | let(:previous_assignee) { double(:user, id: 3) } | 119 | let(:previous_assignee) { double(:user, id: 3) } |
161 | 120 | ||
162 | before(:each) do | 121 | before(:each) do |
163 | - issue.stub(:assignee_id).and_return(assignee.id) | ||
164 | - issue.stub(:assignee_id_was).and_return(previous_assignee.id) | 122 | + mock_issue.stub(:assignee_id).and_return(assignee.id) |
123 | + mock_issue.stub(:assignee_id_was).and_return(previous_assignee.id) | ||
165 | end | 124 | end |
166 | 125 | ||
167 | def it_sends_a_reassigned_email_to(recipient) | 126 | def it_sends_a_reassigned_email_to(recipient) |
168 | - Notify.should_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id) | 127 | + Notify.should_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id) |
169 | end | 128 | end |
170 | 129 | ||
171 | def it_does_not_send_a_reassigned_email_to(recipient) | 130 | def it_does_not_send_a_reassigned_email_to(recipient) |
172 | - Notify.should_not_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id) | 131 | + Notify.should_not_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id) |
173 | end | 132 | end |
174 | 133 | ||
175 | it 'sends a reassigned email to the previous and current assignees' do | 134 | it 'sends a reassigned email to the previous and current assignees' do |
176 | it_sends_a_reassigned_email_to assignee.id | 135 | it_sends_a_reassigned_email_to assignee.id |
177 | it_sends_a_reassigned_email_to previous_assignee.id | 136 | it_sends_a_reassigned_email_to previous_assignee.id |
178 | 137 | ||
179 | - subject.send(:send_reassigned_email, issue) | 138 | + subject.send(:send_reassigned_email, mock_issue) |
180 | end | 139 | end |
181 | 140 | ||
182 | context 'does not send an email to the user who made the reassignment' do | 141 | context 'does not send an email to the user who made the reassignment' do |
@@ -185,14 +144,14 @@ describe IssueObserver do | @@ -185,14 +144,14 @@ describe IssueObserver do | ||
185 | it_sends_a_reassigned_email_to previous_assignee.id | 144 | it_sends_a_reassigned_email_to previous_assignee.id |
186 | it_does_not_send_a_reassigned_email_to assignee.id | 145 | it_does_not_send_a_reassigned_email_to assignee.id |
187 | 146 | ||
188 | - subject.send(:send_reassigned_email, issue) | 147 | + subject.send(:send_reassigned_email, mock_issue) |
189 | end | 148 | end |
190 | it 'if the user is the previous assignee' do | 149 | it 'if the user is the previous assignee' do |
191 | subject.stub(:current_user).and_return(previous_assignee) | 150 | subject.stub(:current_user).and_return(previous_assignee) |
192 | it_sends_a_reassigned_email_to assignee.id | 151 | it_sends_a_reassigned_email_to assignee.id |
193 | it_does_not_send_a_reassigned_email_to previous_assignee.id | 152 | it_does_not_send_a_reassigned_email_to previous_assignee.id |
194 | 153 | ||
195 | - subject.send(:send_reassigned_email, issue) | 154 | + subject.send(:send_reassigned_email, mock_issue) |
196 | end | 155 | end |
197 | end | 156 | end |
198 | end | 157 | end |
spec/observers/merge_request_observer_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | describe MergeRequestObserver do | 3 | describe MergeRequestObserver do |
4 | - let(:some_user) { double(:user, id: 1) } | ||
5 | - let(:assignee) { double(:user, id: 2) } | ||
6 | - let(:author) { double(:user, id: 3) } | ||
7 | - let(:mr) { double(:merge_request, id: 42, assignee: assignee, author: author) } | 4 | + let(:some_user) { create :user } |
5 | + let(:assignee) { create :user } | ||
6 | + let(:author) { create :user } | ||
7 | + let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author) } | ||
8 | + let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author) } | ||
9 | + let(:unassigned_mr) { create(:merge_request, author: author) } | ||
10 | + let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author) } | ||
11 | + let(:closed_unassigned_mr) { create(:closed_merge_request, author: author) } | ||
8 | 12 | ||
9 | before(:each) { subject.stub(:current_user).and_return(some_user) } | 13 | before(:each) { subject.stub(:current_user).and_return(some_user) } |
10 | 14 | ||
@@ -21,23 +25,21 @@ describe MergeRequestObserver do | @@ -21,23 +25,21 @@ describe MergeRequestObserver do | ||
21 | end | 25 | end |
22 | 26 | ||
23 | it 'sends an email to the assignee' do | 27 | it 'sends an email to the assignee' do |
24 | - Notify.should_receive(:new_merge_request_email).with(mr.id) | ||
25 | - subject.after_create(mr) | 28 | + Notify.should_receive(:new_merge_request_email).with(mr_mock.id) |
29 | + subject.after_create(mr_mock) | ||
26 | end | 30 | end |
27 | 31 | ||
28 | it 'does not send an email to the assignee if assignee created the merge request' do | 32 | it 'does not send an email to the assignee if assignee created the merge request' do |
29 | subject.stub(:current_user).and_return(assignee) | 33 | subject.stub(:current_user).and_return(assignee) |
30 | Notify.should_not_receive(:new_merge_request_email) | 34 | Notify.should_not_receive(:new_merge_request_email) |
31 | 35 | ||
32 | - subject.after_create(mr) | 36 | + subject.after_create(mr_mock) |
33 | end | 37 | end |
34 | end | 38 | end |
35 | 39 | ||
36 | context '#after_update' do | 40 | context '#after_update' do |
37 | before(:each) do | 41 | before(:each) do |
38 | - mr.stub(:is_being_reassigned?).and_return(false) | ||
39 | - mr.stub(:is_being_closed?).and_return(false) | ||
40 | - mr.stub(:is_being_reopened?).and_return(false) | 42 | + mr_mock.stub(:is_being_reassigned?).and_return(false) |
41 | end | 43 | end |
42 | 44 | ||
43 | it 'is called when a merge request is changed' do | 45 | it 'is called when a merge request is changed' do |
@@ -52,97 +54,50 @@ describe MergeRequestObserver do | @@ -52,97 +54,50 @@ describe MergeRequestObserver do | ||
52 | 54 | ||
53 | context 'a reassigned email' do | 55 | context 'a reassigned email' do |
54 | it 'is sent if the merge request is being reassigned' do | 56 | it 'is sent if the merge request is being reassigned' do |
55 | - mr.should_receive(:is_being_reassigned?).and_return(true) | ||
56 | - subject.should_receive(:send_reassigned_email).with(mr) | 57 | + mr_mock.should_receive(:is_being_reassigned?).and_return(true) |
58 | + subject.should_receive(:send_reassigned_email).with(mr_mock) | ||
57 | 59 | ||
58 | - subject.after_update(mr) | 60 | + subject.after_update(mr_mock) |
59 | end | 61 | end |
60 | 62 | ||
61 | it 'is not sent if the merge request is not being reassigned' do | 63 | it 'is not sent if the merge request is not being reassigned' do |
62 | - mr.should_receive(:is_being_reassigned?).and_return(false) | 64 | + mr_mock.should_receive(:is_being_reassigned?).and_return(false) |
63 | subject.should_not_receive(:send_reassigned_email) | 65 | subject.should_not_receive(:send_reassigned_email) |
64 | 66 | ||
65 | - subject.after_update(mr) | 67 | + subject.after_update(mr_mock) |
66 | end | 68 | end |
67 | end | 69 | end |
68 | 70 | ||
71 | + end | ||
72 | + | ||
73 | + context '#after_close' do | ||
69 | context 'a status "closed"' do | 74 | context 'a status "closed"' do |
70 | it 'note is created if the merge request is being closed' do | 75 | it 'note is created if the merge request is being closed' do |
71 | - mr.should_receive(:is_being_closed?).and_return(true) | ||
72 | - Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed') | ||
73 | - | ||
74 | - subject.after_update(mr) | ||
75 | - end | ||
76 | - | ||
77 | - it 'note is not created if the merge request is not being closed' do | ||
78 | - mr.should_receive(:is_being_closed?).and_return(false) | ||
79 | - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed') | ||
80 | - | ||
81 | - subject.after_update(mr) | ||
82 | - end | ||
83 | - | ||
84 | - it 'notification is delivered if the merge request being closed' do | ||
85 | - mr.stub(:is_being_closed?).and_return(true) | ||
86 | - Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed') | ||
87 | - | ||
88 | - subject.after_update(mr) | ||
89 | - end | ||
90 | - | ||
91 | - it 'notification is not delivered if the merge request not being closed' do | ||
92 | - mr.stub(:is_being_closed?).and_return(false) | ||
93 | - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed') | 76 | + Note.should_receive(:create_status_change_note).with(assigned_mr, some_user, 'closed') |
94 | 77 | ||
95 | - subject.after_update(mr) | 78 | + assigned_mr.close |
96 | end | 79 | end |
97 | 80 | ||
98 | it 'notification is delivered only to author if the merge request is being closed' do | 81 | it 'notification is delivered only to author if the merge request is being closed' do |
99 | - mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil) | ||
100 | - mr_without_assignee.stub(:is_being_reassigned?).and_return(false) | ||
101 | - mr_without_assignee.stub(:is_being_closed?).and_return(true) | ||
102 | - mr_without_assignee.stub(:is_being_reopened?).and_return(false) | ||
103 | - Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'closed') | 82 | + Note.should_receive(:create_status_change_note).with(unassigned_mr, some_user, 'closed') |
104 | 83 | ||
105 | - subject.after_update(mr_without_assignee) | 84 | + unassigned_mr.close |
106 | end | 85 | end |
107 | end | 86 | end |
87 | + end | ||
108 | 88 | ||
89 | + context '#after_reopen' do | ||
109 | context 'a status "reopened"' do | 90 | context 'a status "reopened"' do |
110 | it 'note is created if the merge request is being reopened' do | 91 | it 'note is created if the merge request is being reopened' do |
111 | - mr.should_receive(:is_being_reopened?).and_return(true) | ||
112 | - Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened') | ||
113 | - | ||
114 | - subject.after_update(mr) | ||
115 | - end | ||
116 | - | ||
117 | - it 'note is not created if the merge request is not being reopened' do | ||
118 | - mr.should_receive(:is_being_reopened?).and_return(false) | ||
119 | - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened') | ||
120 | - | ||
121 | - subject.after_update(mr) | ||
122 | - end | ||
123 | - | ||
124 | - it 'notification is delivered if the merge request being reopened' do | ||
125 | - mr.stub(:is_being_reopened?).and_return(true) | ||
126 | - Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened') | ||
127 | - | ||
128 | - subject.after_update(mr) | ||
129 | - end | ||
130 | - | ||
131 | - it 'notification is not delivered if the merge request is not being reopened' do | ||
132 | - mr.stub(:is_being_reopened?).and_return(false) | ||
133 | - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened') | 92 | + Note.should_receive(:create_status_change_note).with(closed_assigned_mr, some_user, 'reopened') |
134 | 93 | ||
135 | - subject.after_update(mr) | 94 | + closed_assigned_mr.reopen |
136 | end | 95 | end |
137 | 96 | ||
138 | it 'notification is delivered only to author if the merge request is being reopened' do | 97 | it 'notification is delivered only to author if the merge request is being reopened' do |
139 | - mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil) | ||
140 | - mr_without_assignee.stub(:is_being_reassigned?).and_return(false) | ||
141 | - mr_without_assignee.stub(:is_being_closed?).and_return(false) | ||
142 | - mr_without_assignee.stub(:is_being_reopened?).and_return(true) | ||
143 | - Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'reopened') | 98 | + Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, some_user, 'reopened') |
144 | 99 | ||
145 | - subject.after_update(mr_without_assignee) | 100 | + closed_unassigned_mr.reopen |
146 | end | 101 | end |
147 | end | 102 | end |
148 | end | 103 | end |
@@ -151,23 +106,23 @@ describe MergeRequestObserver do | @@ -151,23 +106,23 @@ describe MergeRequestObserver do | ||
151 | let(:previous_assignee) { double(:user, id: 3) } | 106 | let(:previous_assignee) { double(:user, id: 3) } |
152 | 107 | ||
153 | before(:each) do | 108 | before(:each) do |
154 | - mr.stub(:assignee_id).and_return(assignee.id) | ||
155 | - mr.stub(:assignee_id_was).and_return(previous_assignee.id) | 109 | + mr_mock.stub(:assignee_id).and_return(assignee.id) |
110 | + mr_mock.stub(:assignee_id_was).and_return(previous_assignee.id) | ||
156 | end | 111 | end |
157 | 112 | ||
158 | def it_sends_a_reassigned_email_to(recipient) | 113 | def it_sends_a_reassigned_email_to(recipient) |
159 | - Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id) | 114 | + Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id) |
160 | end | 115 | end |
161 | 116 | ||
162 | def it_does_not_send_a_reassigned_email_to(recipient) | 117 | def it_does_not_send_a_reassigned_email_to(recipient) |
163 | - Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id) | 118 | + Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id) |
164 | end | 119 | end |
165 | 120 | ||
166 | it 'sends a reassigned email to the previous and current assignees' do | 121 | it 'sends a reassigned email to the previous and current assignees' do |
167 | it_sends_a_reassigned_email_to assignee.id | 122 | it_sends_a_reassigned_email_to assignee.id |
168 | it_sends_a_reassigned_email_to previous_assignee.id | 123 | it_sends_a_reassigned_email_to previous_assignee.id |
169 | 124 | ||
170 | - subject.send(:send_reassigned_email, mr) | 125 | + subject.send(:send_reassigned_email, mr_mock) |
171 | end | 126 | end |
172 | 127 | ||
173 | context 'does not send an email to the user who made the reassignment' do | 128 | context 'does not send an email to the user who made the reassignment' do |
@@ -176,14 +131,14 @@ describe MergeRequestObserver do | @@ -176,14 +131,14 @@ describe MergeRequestObserver do | ||
176 | it_sends_a_reassigned_email_to previous_assignee.id | 131 | it_sends_a_reassigned_email_to previous_assignee.id |
177 | it_does_not_send_a_reassigned_email_to assignee.id | 132 | it_does_not_send_a_reassigned_email_to assignee.id |
178 | 133 | ||
179 | - subject.send(:send_reassigned_email, mr) | 134 | + subject.send(:send_reassigned_email, mr_mock) |
180 | end | 135 | end |
181 | it 'if the user is the previous assignee' do | 136 | it 'if the user is the previous assignee' do |
182 | subject.stub(:current_user).and_return(previous_assignee) | 137 | subject.stub(:current_user).and_return(previous_assignee) |
183 | it_sends_a_reassigned_email_to assignee.id | 138 | it_sends_a_reassigned_email_to assignee.id |
184 | it_does_not_send_a_reassigned_email_to previous_assignee.id | 139 | it_does_not_send_a_reassigned_email_to previous_assignee.id |
185 | 140 | ||
186 | - subject.send(:send_reassigned_email, mr) | 141 | + subject.send(:send_reassigned_email, mr_mock) |
187 | end | 142 | end |
188 | end | 143 | end |
189 | end | 144 | end |
spec/requests/api/issues_spec.rb
@@ -54,14 +54,24 @@ describe Gitlab::API do | @@ -54,14 +54,24 @@ describe Gitlab::API do | ||
54 | end | 54 | end |
55 | end | 55 | end |
56 | 56 | ||
57 | - describe "PUT /projects/:id/issues/:issue_id" do | 57 | + describe "PUT /projects/:id/issues/:issue_id to update only title" do |
58 | it "should update a project issue" do | 58 | it "should update a project issue" do |
59 | put api("/projects/#{project.id}/issues/#{issue.id}", user), | 59 | put api("/projects/#{project.id}/issues/#{issue.id}", user), |
60 | - title: 'updated title', labels: 'label2', closed: 1 | 60 | + title: 'updated title' |
61 | response.status.should == 200 | 61 | response.status.should == 200 |
62 | + | ||
62 | json_response['title'].should == 'updated title' | 63 | json_response['title'].should == 'updated title' |
64 | + end | ||
65 | + end | ||
66 | + | ||
67 | + describe "PUT /projects/:id/issues/:issue_id to update state and label" do | ||
68 | + it "should update a project issue" do | ||
69 | + put api("/projects/#{project.id}/issues/#{issue.id}", user), | ||
70 | + labels: 'label2', state_event: "close" | ||
71 | + response.status.should == 200 | ||
72 | + | ||
63 | json_response['labels'].should == ['label2'] | 73 | json_response['labels'].should == ['label2'] |
64 | - json_response['closed'].should be_true | 74 | + json_response['state'].should eq "closed" |
65 | end | 75 | end |
66 | end | 76 | end |
67 | 77 |
spec/requests/api/merge_requests_spec.rb
@@ -66,6 +66,23 @@ describe Gitlab::API do | @@ -66,6 +66,23 @@ describe Gitlab::API do | ||
66 | end | 66 | end |
67 | end | 67 | end |
68 | 68 | ||
69 | + describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do | ||
70 | + it "should return merge_request" do | ||
71 | + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "close" | ||
72 | + response.status.should == 200 | ||
73 | + json_response['state'].should == 'closed' | ||
74 | + end | ||
75 | + end | ||
76 | + | ||
77 | + describe "PUT /projects/:id/merge_request/:merge_request_id to merge MR" do | ||
78 | + it "should return merge_request" do | ||
79 | + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "merge" | ||
80 | + response.status.should == 200 | ||
81 | + json_response['state'].should == 'merged' | ||
82 | + end | ||
83 | + end | ||
84 | + | ||
85 | + | ||
69 | describe "PUT /projects/:id/merge_request/:merge_request_id" do | 86 | describe "PUT /projects/:id/merge_request/:merge_request_id" do |
70 | it "should return merge_request" do | 87 | it "should return merge_request" do |
71 | put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title" | 88 | put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title" |
spec/requests/api/milestones_spec.rb
@@ -68,4 +68,14 @@ describe Gitlab::API do | @@ -68,4 +68,14 @@ describe Gitlab::API do | ||
68 | response.status.should == 404 | 68 | response.status.should == 404 |
69 | end | 69 | end |
70 | end | 70 | end |
71 | + | ||
72 | + describe "PUT /projects/:id/milestones/:milestone_id to close milestone" do | ||
73 | + it "should update a project milestone" do | ||
74 | + put api("/projects/#{project.id}/milestones/#{milestone.id}", user), | ||
75 | + state_event: 'close' | ||
76 | + response.status.should == 200 | ||
77 | + | ||
78 | + json_response['state'].should == 'closed' | ||
79 | + end | ||
80 | + end | ||
71 | end | 81 | end |
spec/requests/api/projects_spec.rb
@@ -33,6 +33,20 @@ describe Gitlab::API do | @@ -33,6 +33,20 @@ describe Gitlab::API do | ||
33 | end | 33 | end |
34 | 34 | ||
35 | describe "POST /projects" do | 35 | describe "POST /projects" do |
36 | + context "maximum number of projects reached" do | ||
37 | + before do | ||
38 | + (1..user2.projects_limit).each do |project| | ||
39 | + post api("/projects", user2), name: "foo#{project}" | ||
40 | + end | ||
41 | + end | ||
42 | + | ||
43 | + it "should not create new project" do | ||
44 | + expect { | ||
45 | + post api("/projects", user2), name: 'foo' | ||
46 | + }.to change {Project.count}.by(0) | ||
47 | + end | ||
48 | + end | ||
49 | + | ||
36 | it "should create new project without path" do | 50 | it "should create new project without path" do |
37 | expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1) | 51 | expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1) |
38 | end | 52 | end |
@@ -46,6 +60,12 @@ describe Gitlab::API do | @@ -46,6 +60,12 @@ describe Gitlab::API do | ||
46 | response.status.should == 400 | 60 | response.status.should == 400 |
47 | end | 61 | end |
48 | 62 | ||
63 | + it "should create last project before reaching project limit" do | ||
64 | + (1..user2.projects_limit-1).each { |p| post api("/projects", user2), name: "foo#{p}" } | ||
65 | + post api("/projects", user2), name: "foo" | ||
66 | + response.status.should == 201 | ||
67 | + end | ||
68 | + | ||
49 | it "should respond with 201 on success" do | 69 | it "should respond with 201 on success" do |
50 | post api("/projects", user), name: 'foo' | 70 | post api("/projects", user), name: 'foo' |
51 | response.status.should == 201 | 71 | response.status.should == 201 |
@@ -314,22 +334,44 @@ describe Gitlab::API do | @@ -314,22 +334,44 @@ describe Gitlab::API do | ||
314 | end | 334 | end |
315 | 335 | ||
316 | describe "GET /projects/:id/hooks" do | 336 | describe "GET /projects/:id/hooks" do |
317 | - it "should return project hooks" do | ||
318 | - get api("/projects/#{project.id}/hooks", user) | 337 | + context "authorized user" do |
338 | + it "should return project hooks" do | ||
339 | + get api("/projects/#{project.id}/hooks", user) | ||
340 | + response.status.should == 200 | ||
319 | 341 | ||
320 | - response.status.should == 200 | 342 | + json_response.should be_an Array |
343 | + json_response.count.should == 1 | ||
344 | + json_response.first['url'].should == "http://example.com" | ||
345 | + end | ||
346 | + end | ||
321 | 347 | ||
322 | - json_response.should be_an Array | ||
323 | - json_response.count.should == 1 | ||
324 | - json_response.first['url'].should == "http://example.com" | 348 | + context "unauthorized user" do |
349 | + it "should not access project hooks" do | ||
350 | + get api("/projects/#{project.id}/hooks", user3) | ||
351 | + response.status.should == 403 | ||
352 | + end | ||
325 | end | 353 | end |
326 | end | 354 | end |
327 | 355 | ||
328 | describe "GET /projects/:id/hooks/:hook_id" do | 356 | describe "GET /projects/:id/hooks/:hook_id" do |
329 | - it "should return a project hook" do | ||
330 | - get api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
331 | - response.status.should == 200 | ||
332 | - json_response['url'].should == hook.url | 357 | + context "authorized user" do |
358 | + it "should return a project hook" do | ||
359 | + get api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
360 | + response.status.should == 200 | ||
361 | + json_response['url'].should == hook.url | ||
362 | + end | ||
363 | + | ||
364 | + it "should return a 404 error if hook id is not available" do | ||
365 | + get api("/projects/#{project.id}/hooks/1234", user) | ||
366 | + response.status.should == 404 | ||
367 | + end | ||
368 | + end | ||
369 | + | ||
370 | + context "unauthorized user" do | ||
371 | + it "should not access an existing hook" do | ||
372 | + get api("/projects/#{project.id}/hooks/#{hook.id}", user3) | ||
373 | + response.status.should == 403 | ||
374 | + end | ||
333 | end | 375 | end |
334 | 376 | ||
335 | it "should return a 404 error if hook id is not available" do | 377 | it "should return a 404 error if hook id is not available" do |
spec/requests/issues_spec.rb
@@ -58,8 +58,7 @@ describe "Issues" do | @@ -58,8 +58,7 @@ describe "Issues" do | ||
58 | 58 | ||
59 | it "should be able to search on different statuses" do | 59 | it "should be able to search on different statuses" do |
60 | issue = Issue.first # with title 'foobar' | 60 | issue = Issue.first # with title 'foobar' |
61 | - issue.closed = true | ||
62 | - issue.save | 61 | + issue.close |
63 | 62 | ||
64 | visit project_issues_path(project) | 63 | visit project_issues_path(project) |
65 | click_link 'Closed' | 64 | click_link 'Closed' |