summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.lock2
-rw-r--r--app/assets/javascripts/main.js.coffee4
-rw-r--r--app/assets/javascripts/merge_requests.js.coffee2
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/mixins.scss4
-rw-r--r--app/assets/stylesheets/sections/commits.scss27
-rw-r--r--app/assets/stylesheets/sections/header.scss29
-rw-r--r--app/assets/stylesheets/sections/projects.scss4
-rw-r--r--app/assets/stylesheets/themes/ui_mars.scss59
-rw-r--r--app/contexts/merge_requests_load_context.rb2
-rw-r--r--app/contexts/projects/create_context.rb2
-rw-r--r--app/controllers/dashboard_controller.rb2
-rw-r--r--app/controllers/files_controller.rb13
-rw-r--r--app/controllers/merge_requests_controller.rb6
-rw-r--r--app/controllers/milestones_controller.rb2
-rw-r--r--app/controllers/profiles_controller.rb4
-rw-r--r--app/controllers/team_members_controller.rb6
-rw-r--r--app/controllers/teams/members_controller.rb9
-rw-r--r--app/controllers/teams_controller.rb5
-rw-r--r--app/helpers/application_helper.rb9
-rw-r--r--app/helpers/dashboard_helper.rb2
-rw-r--r--app/helpers/issues_helper.rb2
-rw-r--r--app/helpers/merge_requests_helper.rb2
-rw-r--r--app/helpers/namespaces_helper.rb4
-rw-r--r--app/helpers/projects_helper.rb10
-rw-r--r--app/models/ability.rb2
-rw-r--r--app/models/concerns/issuable.rb13
-rw-r--r--app/models/event.rb4
-rw-r--r--app/models/issue.rb33
-rw-r--r--app/models/key.rb4
-rw-r--r--app/models/merge_request.rb94
-rw-r--r--app/models/milestone.rb27
-rw-r--r--app/models/namespace.rb8
-rw-r--r--app/models/project.rb4
-rw-r--r--app/models/repository.rb6
-rw-r--r--app/models/user.rb8
-rw-r--r--app/models/user_team.rb5
-rw-r--r--app/models/user_team_project_relationship.rb4
-rw-r--r--app/observers/activity_observer.rb16
-rw-r--r--app/observers/issue_observer.rb29
-rw-r--r--app/observers/merge_request_observer.rb19
-rw-r--r--app/uploaders/attachment_uploader.rb8
-rw-r--r--app/views/admin/groups/index.html.haml2
-rw-r--r--app/views/admin/teams/index.html.haml2
-rw-r--r--app/views/commits/_commit.html.haml4
-rw-r--r--app/views/events/event/_note.html.haml2
-rw-r--r--app/views/groups/_filter.html.haml2
-rw-r--r--app/views/groups/_people_filter.html.haml2
-rw-r--r--app/views/groups/edit.html.haml2
-rw-r--r--app/views/help/index.html.haml4
-rw-r--r--app/views/issues/_show.html.haml6
-rw-r--r--app/views/issues/show.html.haml8
-rw-r--r--app/views/merge_requests/_show.html.haml4
-rw-r--r--app/views/merge_requests/show/_mr_accept.html.haml2
-rw-r--r--app/views/merge_requests/show/_mr_box.html.haml22
-rw-r--r--app/views/merge_requests/show/_mr_ci.html.haml2
-rw-r--r--app/views/merge_requests/show/_mr_title.html.haml4
-rw-r--r--app/views/milestones/_milestone.html.haml6
-rw-r--r--app/views/milestones/show.html.haml10
-rw-r--r--app/views/notes/_note.html.haml2
-rw-r--r--app/views/profiles/account.html.haml49
-rw-r--r--app/views/profiles/show.html.haml2
-rw-r--r--app/views/projects/_new_form.html.haml2
-rw-r--r--app/views/projects/files.html.haml2
-rw-r--r--app/views/team_members/_assigned_team.html.haml10
-rw-r--r--app/views/team_members/_assigned_teams.html.haml4
-rw-r--r--app/views/team_members/_show_team.html.haml15
-rw-r--r--app/views/team_members/_team.html.haml14
-rw-r--r--app/views/team_members/_team_member.html.haml (renamed from app/views/team_members/_show.html.haml)12
-rw-r--r--app/views/team_members/_teams.html.haml16
-rw-r--r--app/views/team_members/index.html.haml41
-rw-r--r--app/views/teams/edit.html.haml43
-rw-r--r--app/views/teams/members/_show.html.haml35
-rw-r--r--app/views/teams/new.html.haml14
-rw-r--r--app/workers/post_receive.rb16
-rw-r--r--config/gitlab.yml.example245
-rw-r--r--config/initializers/1_settings.rb2
-rw-r--r--config/initializers/2_app.rb4
-rw-r--r--config/routes.rb5
-rw-r--r--db/fixtures/development/02_source_code.rb2
-rw-r--r--db/fixtures/development/09_issues.rb2
-rw-r--r--db/fixtures/development/10_merge_requests.rb2
-rw-r--r--db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb5
-rw-r--r--db/migrate/20130218140952_add_state_to_issue.rb5
-rw-r--r--db/migrate/20130218141038_add_state_to_merge_request.rb5
-rw-r--r--db/migrate/20130218141117_add_state_to_milestone.rb5
-rw-r--r--db/migrate/20130218141258_convert_closed_to_state_in_issue.rb14
-rw-r--r--db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb16
-rw-r--r--db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb14
-rw-r--r--db/migrate/20130218141444_remove_merged_from_merge_request.rb9
-rw-r--r--db/migrate/20130218141507_remove_closed_from_issue.rb9
-rw-r--r--db/migrate/20130218141536_remove_closed_from_merge_request.rb9
-rw-r--r--db/migrate/20130218141554_remove_closed_from_milestone.rb9
-rw-r--r--db/schema.rb35
-rw-r--r--doc/api/milestones.md1
-rw-r--r--doc/api/projects.md6
-rw-r--r--doc/install/databases.md4
-rw-r--r--doc/install/installation.md53
-rw-r--r--features/steps/profile/profile_ssh_keys.rb2
-rw-r--r--features/steps/project/project_issues.rb5
-rw-r--r--features/steps/project/project_merge_requests.rb7
-rw-r--r--lib/api/entities.rb11
-rw-r--r--lib/api/internal.rb4
-rw-r--r--lib/api/issues.rb4
-rw-r--r--lib/api/merge_requests.rb4
-rw-r--r--lib/api/milestones.rb4
-rw-r--r--lib/api/projects.rb1
-rw-r--r--lib/gitlab/backend/grack_auth.rb8
-rw-r--r--lib/gitlab/backend/shell.rb16
-rw-r--r--lib/gitlab/backend/shell_env.rb17
-rw-r--r--lib/gitlab/regex.rb4
-rw-r--r--lib/gitlab/satellite/action.rb4
-rw-r--r--lib/tasks/gitlab/info.rake4
-rw-r--r--lib/tasks/gitlab/setup.rake4
-rw-r--r--lib/tasks/gitlab/shell.rake5
-rw-r--r--lib/tasks/gitlab/task_helpers.rake3
-rw-r--r--public/deploy.html2
-rw-r--r--public/gitlab_logo.pngbin0 -> 17388 bytes
-rw-r--r--spec/factories.rb32
-rw-r--r--spec/factories_spec.rb5
-rw-r--r--spec/models/concerns/issuable_spec.rb1
-rw-r--r--spec/models/issue_spec.rb35
-rw-r--r--spec/models/key_spec.rb6
-rw-r--r--spec/models/merge_request_spec.rb37
-rw-r--r--spec/models/milestone_spec.rb39
-rw-r--r--spec/models/project_spec.rb8
-rw-r--r--spec/observers/issue_observer_spec.rb159
-rw-r--r--spec/observers/merge_request_observer_spec.rb119
-rw-r--r--spec/requests/api/issues_spec.rb16
-rw-r--r--spec/requests/api/merge_requests_spec.rb17
-rw-r--r--spec/requests/api/milestones_spec.rb10
-rw-r--r--spec/requests/api/projects_spec.rb62
-rw-r--r--spec/requests/issues_spec.rb3
134 files changed, 1119 insertions, 862 deletions
diff --git a/.gitignore b/.gitignore
index 912d61a8f0a..7e621d260fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,7 @@
.rbx/
db/*.sqlite3
db/*.sqlite3-journal
-log/*.log
+log/*.log*
tmp/
.sass-cache/
coverage/*
@@ -20,6 +20,7 @@ config/database.yml
config/initializers/omniauth.rb
config/unicorn.rb
config/resque.yml
+config/aws.yml
db/data.yml
.idea
.DS_Store
diff --git a/Gemfile b/Gemfile
index 01696152b62..4a7db0eb711 100644
--- a/Gemfile
+++ b/Gemfile
@@ -70,6 +70,9 @@ gem "github-markup", "~> 0.7.4", require: 'github/markup'
# Servers
gem "unicorn", "~> 4.4.0"
+# State machine
+gem "state_machine"
+
# Issue tags
gem "acts-as-taggable-on", "2.3.3"
diff --git a/Gemfile.lock b/Gemfile.lock
index 1bc7124fff4..1b8c5837302 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -425,6 +425,7 @@ GEM
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
stamp (0.3.0)
+ state_machine (1.1.2)
temple (0.5.5)
test_after_commit (0.0.1)
therubyracer (0.10.2)
@@ -536,6 +537,7 @@ DEPENDENCIES
slim
spinach-rails
stamp
+ state_machine
test_after_commit
therubyracer
thin
diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee
index 5aaea50cf21..d789f54a4e6 100644
--- a/app/assets/javascripts/main.js.coffee
+++ b/app/assets/javascripts/main.js.coffee
@@ -49,6 +49,10 @@ $ ->
# Bottom tooltip
$('.has_bottom_tooltip').tooltip(placement: 'bottom')
+ # Form submitter
+ $('.trigger-submit').on 'change', ->
+ $(@).parents('form').submit()
+
# Flash
if (flash = $("#flash-container")).length > 0
flash.click -> $(@).slideUp("slow")
diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee
index 65ed817c7c6..496da7316fd 100644
--- a/app/assets/javascripts/merge_requests.js.coffee
+++ b/app/assets/javascripts/merge_requests.js.coffee
@@ -27,7 +27,7 @@ class MergeRequest
this.$el.find(selector)
initMergeWidget: ->
- this.showState( @opts.current_state )
+ this.showState( @opts.current_status )
if this.$('.automerge_widget').length and @opts.check_enable
$.get @opts.url_to_automerge_check, (data) =>
diff --git a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss
index 9b1e2f2c728..c8cc9a70678 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss
@@ -63,7 +63,7 @@
color: $style_color;
text-shadow: 0 1px 1px #FFF;
font-family: 'Yanone', sans-serif;
- font-size: 26px;
- line-height: 42px;
+ font-size: 24px;
+ line-height: 36px;
font-weight: normal;
}
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss
index 8b93287ed1e..a389a9baa84 100644
--- a/app/assets/stylesheets/sections/commits.scss
+++ b/app/assets/stylesheets/sections/commits.scss
@@ -29,7 +29,7 @@
a{
color: $style_color;
}
-
+
> span {
font-family: $monospace_font;
font-size: 14px;
@@ -124,7 +124,7 @@
.wrap{
display: inline-block;
}
-
+
.frame {
display: inline-block;
background-color: #fff;
@@ -149,7 +149,7 @@
.view.swipe{
position: relative;
-
+
.swipe-frame{
display: block;
margin: auto;
@@ -228,7 +228,7 @@
bottom: 0px;
left: 50%;
margin-left: -150px;
-
+
.drag-track{
display: block;
position: absolute;
@@ -237,7 +237,7 @@
width: 276px;
background: url('onion_skin_sprites.gif') -4px -20px repeat-x;
}
-
+
.dragger {
display: block;
position: absolute;
@@ -248,7 +248,7 @@
background: url('onion_skin_sprites.gif') 0px -34px repeat-x;
cursor: pointer;
}
-
+
.transparent {
display: block;
position: absolute;
@@ -258,7 +258,7 @@
width: 10px;
background: url('onion_skin_sprites.gif') -2px 0px no-repeat;
}
-
+
.opaque {
display: block;
position: absolute;
@@ -275,19 +275,19 @@
padding: 10px;
text-align: center;
-
+
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
-
+
ul, li{
list-style: none;
margin: 0;
padding: 0;
display: inline-block;
}
-
+
li{
color: grey;
border-left: 1px solid #c1c1c1;
@@ -322,12 +322,12 @@
}
.commit-author, .commit-committer{
display: block;
- color: #999;
- font-weight: normal;
+ color: #999;
+ font-weight: normal;
font-style: italic;
}
.commit-author strong, .commit-committer strong{
- font-weight: bold;
+ font-weight: bold;
font-style: normal;
}
@@ -337,7 +337,6 @@
*/
.commit {
.browse_code_link_holder {
- @extend .span2;
float: right;
}
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index 5fe18131828..05c077a867a 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -5,15 +5,16 @@
header {
&.navbar-gitlab {
.navbar-inner {
- height: 45px;
- padding: 5px;
+ height: 40px;
+ padding: 3px;
background: #F1F1F1;
+ filter: none;
.nav > li > a {
color: $style_color;
text-shadow: 0 1px 0 #fff;
- font-size: 18px;
- padding: 12px;
+ font-size: 16px;
+ padding: 10px;
}
/** NAV block with links and profile **/
@@ -25,7 +26,6 @@ header {
}
z-index: 10;
- /*height: 60px;*/
/**
*
@@ -34,7 +34,7 @@ header {
*/
.app_logo {
float: left;
- margin-right: 15px;
+ margin-right: 9px;
position: relative;
top: -5px;
padding-top: 5px;
@@ -42,10 +42,10 @@ header {
a {
float: left;
padding: 0px;
- margin: 0 10px;
+ margin: 0 6px;
h1 {
- background: url('logo_dark.png') no-repeat 0px 2px;
+ background: url('logo_dark.png') no-repeat center 1px;
float: left;
height: 40px;
width: 40px;
@@ -79,7 +79,6 @@ header {
.search {
margin-right: 45px;
margin-left: 10px;
- margin-top: 2px;
.search-input {
@extend .span2;
@@ -105,7 +104,7 @@ header {
.account-box {
position: absolute;
right: 0;
- top: 6px;
+ top: 4px;
z-index: 10000;
width: 128px;
font-size: 11px;
@@ -228,6 +227,7 @@ header {
.search-input {
background-color: #D2D5DA;
background-color: rgba(255, 255, 255, 0.5);
+ border: 1px solid #AAA;
&:focus {
background-color: white;
@@ -240,13 +240,16 @@ header {
.app_logo {
a {
h1 {
- background: url('logo_white.png') no-repeat center center;
+ background: url('logo_white.png') no-repeat center 1px;
color: #fff;
text-shadow: 0 1px 1px #111;
}
}
}
.project_name {
+ a {
+ color: #FFF;
+ }
color: #fff;
text-shadow: 0 1px 1px #111;
}
@@ -261,11 +264,11 @@ header {
.separator {
float: left;
- height: 60px;
+ height: 46px;
width: 1px;
background: white;
border-left: 1px solid #DDD;
- margin-top: -10px;
+ margin-top: -3px;
margin-left: 10px;
margin-right: 10px;
}
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index 28df1b5ac28..b37830b138e 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -115,3 +115,7 @@ ul.nav.nav-projects-tabs {
}
}
}
+
+.team_member_row form {
+ margin: 0px;
+}
diff --git a/app/assets/stylesheets/themes/ui_mars.scss b/app/assets/stylesheets/themes/ui_mars.scss
index 0a78c5c09f5..a2b8c21ea11 100644
--- a/app/assets/stylesheets/themes/ui_mars.scss
+++ b/app/assets/stylesheets/themes/ui_mars.scss
@@ -8,66 +8,27 @@
*
*/
.ui_mars {
-
/*
* Application Header
*
*/
header {
-
+ @extend .header-dark;
&.navbar-gitlab {
.navbar-inner {
- background: #474D57 url('bg-header.png') repeat-x bottom;
- border-bottom: 1px solid #444;
-
- .nav > li > a {
- color: #eee;
- text-shadow: 0 1px 0 #444;
+ background: #474D57;
+ border-bottom: 1px solid #373D47;
+ .app_logo {
+ &:hover {
+ background-color: #373D47;
+ }
}
}
}
- .search {
- float: right;
- margin-right: 45px;
- .search-input {
- border: 1px solid rgba(0, 0, 0, 0.7);
- background-color: #D2D5DA;
- background-color: rgba(255, 255, 255, 0.5);
-
- &:focus {
- background-color: white;
- }
- }
- }
- .search-input::-webkit-input-placeholder {
- color: #666;
- }
- .app_logo {
- a {
- h1 {
- background: url('logo_white.png') no-repeat center center;
- color: #eee;
- text-shadow: 0 1px 1px #111;
- }
- }
- &:hover {
- background-color: #41464e;
- }
- }
- .project_name {
- color: #eee;
- text-shadow: 0 1px 1px #111;
+ .separator {
+ background: #31363E;
+ border-left: 1px solid #666;
}
}
-
- .separator {
- background: #31363E;
- border-left: 1px solid #666;
- }
-
- /*
- * End of Application Header
- *
- */
}
diff --git a/app/contexts/merge_requests_load_context.rb b/app/contexts/merge_requests_load_context.rb
index 4ec66cd9b78..683f4c83e77 100644
--- a/app/contexts/merge_requests_load_context.rb
+++ b/app/contexts/merge_requests_load_context.rb
@@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext
end
merge_requests = merge_requests.page(params[:page]).per(20)
- merge_requests = merge_requests.includes(:author, :project).order("closed, created_at desc")
+ merge_requests = merge_requests.includes(:author, :project).order("state, created_at desc")
# Filter by specific assignee_id (or lack thereof)?
if params[:assignee_id].present?
diff --git a/app/contexts/projects/create_context.rb b/app/contexts/projects/create_context.rb
index 629c5294754..fe8dde8c954 100644
--- a/app/contexts/projects/create_context.rb
+++ b/app/contexts/projects/create_context.rb
@@ -38,6 +38,8 @@ module Projects
if @project.valid? && @project.import_url.present?
shell = Gitlab::Shell.new
if shell.import_repository(@project.path_with_namespace, @project.import_url)
+ # We should create satellite for imported repo
+ @project.satellite.create unless @project.satellite.exists?
true
else
@project.errors.add(:import_url, 'cannot clone repo')
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index f320e819e26..9fd477dcdb6 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -5,7 +5,7 @@ class DashboardController < ApplicationController
before_filter :event_filter, only: :show
def show
- @groups = current_user.authorized_groups
+ @groups = current_user.authorized_groups.sort_by(&:human_name)
@has_authorized_projects = @projects.count > 0
@teams = current_user.authorized_teams
@projects_count = @projects.count
diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb
new file mode 100644
index 00000000000..3cd2e77322c
--- /dev/null
+++ b/app/controllers/files_controller.rb
@@ -0,0 +1,13 @@
+class FilesController < ApplicationController
+ def download
+ note = Note.find(params[:id])
+
+ if can?(current_user, :read_project, note.project)
+ uploader = note.attachment
+ send_file uploader.file.path, disposition: 'attachment'
+ else
+ not_found!
+ end
+ end
+end
+
diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb
index ab6bf595982..bf6652726d2 100644
--- a/app/controllers/merge_requests_controller.rb
+++ b/app/controllers/merge_requests_controller.rb
@@ -73,14 +73,14 @@ class MergeRequestsController < ProjectResourceController
if @merge_request.unchecked?
@merge_request.check_if_can_be_merged
end
- render json: {state: @merge_request.human_state}
+ render json: {merge_status: @merge_request.human_merge_status}
rescue Gitlab::SatelliteNotExistError
- render json: {state: :no_satellite}
+ render json: {merge_status: :no_satellite}
end
def automerge
return access_denied! unless can?(current_user, :accept_mr, @project)
- if @merge_request.open? && @merge_request.can_be_merged?
+ if @merge_request.opened? && @merge_request.can_be_merged?
@merge_request.should_remove_source_branch = params[:should_remove_source_branch]
@merge_request.automerge!(current_user)
@status = true
diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb
index a0c824e8abb..57f1e9e6bb3 100644
--- a/app/controllers/milestones_controller.rb
+++ b/app/controllers/milestones_controller.rb
@@ -12,7 +12,7 @@ class MilestonesController < ProjectResourceController
def index
@milestones = case params[:f]
- when 'all'; @project.milestones.order("closed, due_date DESC")
+ when 'all'; @project.milestones.order("state, due_date DESC")
when 'closed'; @project.milestones.closed.order("due_date DESC")
else @project.milestones.active.order("due_date ASC")
end
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 1d1efb16f04..051a6664519 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -51,7 +51,9 @@ class ProfilesController < ApplicationController
end
def update_username
- @user.update_attributes(username: params[:user][:username])
+ if @user.can_change_username?
+ @user.update_attributes(username: params[:user][:username])
+ end
respond_to do |format|
format.js
diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb
index 18d4ae3ac96..04348dc7977 100644
--- a/app/controllers/team_members_controller.rb
+++ b/app/controllers/team_members_controller.rb
@@ -4,7 +4,11 @@ class TeamMembersController < ProjectResourceController
before_filter :authorize_admin_project!, except: [:index, :show]
def index
- @teams = UserTeam.scoped
+ @team = @project.users_projects.scoped
+ @team = @team.send(params[:type]) if %w(masters developers reporters guests).include?(params[:type])
+ @team = @team.sort_by(&:project_access).reverse.group_by(&:project_access)
+
+ @assigned_teams = @project.user_team_project_relationships
end
def show
diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb
index db218b8ca5e..ead62e13afa 100644
--- a/app/controllers/teams/members_controller.rb
+++ b/app/controllers/teams/members_controller.rb
@@ -27,7 +27,13 @@ class Teams::MembersController < Teams::ApplicationController
end
def update
- options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]}
+ member_params = params[:team_member]
+
+ options = {
+ default_projects_access: member_params[:permission],
+ group_admin: member_params[:group_admin]
+ }
+
if user_team.update_membership(team_member, options)
redirect_to team_members_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users."
else
@@ -45,5 +51,4 @@ class Teams::MembersController < Teams::ApplicationController
def team_member
@member ||= user_team.members.find_by_username(params[:id])
end
-
end
diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb
index ef66b77e232..4861892d36e 100644
--- a/app/controllers/teams_controller.rb
+++ b/app/controllers/teams_controller.rb
@@ -9,13 +9,11 @@ class TeamsController < ApplicationController
layout 'user_team', except: [:new, :create]
def show
- user_team
projects
@events = Event.in_projects(user_team.project_ids).limit(20).offset(params[:offset] || 0)
end
def edit
- user_team
end
def update
@@ -41,6 +39,9 @@ class TeamsController < ApplicationController
@team.path = @team.name.dup.parameterize if @team.name
if @team.save
+ # Add current user as Master to the team
+ @team.add_members([current_user.id], UsersProject::MASTER, true)
+
redirect_to team_path(@team)
else
render action: :new
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 196105f0119..d02130c5eb1 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -73,8 +73,8 @@ module ApplicationHelper
def search_autocomplete_source
projects = current_user.authorized_projects.map { |p| { label: "project: #{p.name_with_namespace}", url: project_path(p) } }
- groups = current_user.authorized_groups.map { |group| { label: "group: #{group.name}", url: group_path(group) } }
- teams = current_user.authorized_teams.map { |team| { label: "team: #{team.name}", url: team_path(team) } }
+ groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } }
+ teams = current_user.authorized_teams.map { |team| { label: "team: #{simple_sanitize(team.name)}", url: team_path(team) } }
default_nav = [
{ label: "My Profile", url: profile_path },
@@ -159,8 +159,13 @@ module ApplicationHelper
alt: "Sign in with #{provider.to_s.titleize}")
end
+ def simple_sanitize str
+ sanitize(str, tags: %w(a span))
+ end
+
def image_url(source)
root_url + path_to_image(source)
end
+
alias_method :url_to_image, :image_url
end
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index c759dffa16e..e3be07c9fe0 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -27,6 +27,6 @@ module DashboardHelper
items.opened
end
- items.where(assignee_id: current_user.id).count
+ items.cared(current_user).count
end
end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 2825787fd2f..ed7e3e869c0 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -6,7 +6,7 @@ module IssuesHelper
def issue_css_classes issue
classes = "issue"
- classes << " closed" if issue.closed
+ classes << " closed" if issue.closed?
classes << " today" if issue.today?
classes
end
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index ca0a89c3749..155d03d1147 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -12,7 +12,7 @@ module MergeRequestsHelper
def mr_css_classes mr
classes = "merge_request"
- classes << " closed" if mr.closed
+ classes << " closed" if mr.closed?
classes << " merged" if mr.merged?
classes
end
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
index 6d0c6c98191..a9a6c78654f 100644
--- a/app/helpers/namespaces_helper.rb
+++ b/app/helpers/namespaces_helper.rb
@@ -10,8 +10,8 @@ module NamespacesHelper
global_opts = ["Global", [['/', Namespace.global_id]] ]
- group_opts = ["Groups", groups.map {|g| [g.human_name, g.id]} ]
- users_opts = [ "Users", users.map {|u| [u.human_name, u.id]} ]
+ group_opts = ["Groups", groups.sort_by(&:human_name).map {|g| [g.human_name, g.id]} ]
+ users_opts = [ "Users", users.sort_by(&:human_name).map {|u| [u.human_name, u.id]} ]
options = []
options << global_opts if current_user.admin
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 05303e86ae8..2c7984c071e 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -1,12 +1,4 @@
module ProjectsHelper
- def grouper_project_members(project)
- @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access)
- end
-
- def grouper_project_teams(project)
- @project.user_team_project_relationships.sort_by(&:greatest_access).reverse.group_by(&:greatest_access)
- end
-
def remove_from_project_team_message(project, user)
"You are going to remove #{user.name} from #{project.name} project team. Are you sure?"
end
@@ -56,7 +48,7 @@ module ProjectsHelper
def project_title project
if project.group
content_tag :span do
- link_to(project.group.name, group_path(project.group)) + " / " + project.name
+ link_to(simple_sanitize(project.group.name), group_path(project.group)) + " / " + project.name
end
else
project.name
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 6d087a959a9..6fda2e52c7c 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -123,7 +123,7 @@ class Ability
def user_team_abilities user, team
rules = []
- # Only group owner and administrators can manage group
+ # Only group owner and administrators can manage team
if team.owner == user || team.admin?(user) || user.admin?
rules << [ :manage_user_team ]
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 645b35ec660..85337583640 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -17,10 +17,9 @@ module Issuable
validates :project, presence: true
validates :author, presence: true
validates :title, presence: true, length: { within: 0..255 }
- validates :closed, inclusion: { in: [true, false] }
- scope :opened, -> { where(closed: false) }
- scope :closed, -> { where(closed: true) }
+ scope :opened, -> { with_state(:opened) }
+ scope :closed, -> { with_state(:closed) }
scope :of_group, ->(group) { where(project_id: group.project_ids) }
scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) }
scope :assigned, ->(u) { where(assignee_id: u.id)}
@@ -62,14 +61,6 @@ module Issuable
assignee_id_changed?
end
- def is_being_closed?
- closed_changed? && closed
- end
-
- def is_being_reopened?
- closed_changed? && !closed
- end
-
#
# Votes
#
diff --git a/app/models/event.rb b/app/models/event.rb
index 18422e192a4..ae14454c59a 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -130,10 +130,6 @@ class Event < ActiveRecord::Base
target if target_type == "MergeRequest"
end
- def author
- @author ||= User.find(author_id)
- end
-
def action_name
if closed?
"closed"
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 07c0401143c..112f43c4692 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -9,7 +9,7 @@
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
-# closed :boolean default(FALSE), not null
+# state :string default(FALSE), not null
# position :integer default(0)
# branch_name :string(255)
# description :text
@@ -19,12 +19,35 @@
class Issue < ActiveRecord::Base
include Issuable
- attr_accessible :title, :assignee_id, :closed, :position, :description,
- :milestone_id, :label_list, :author_id_of_changes
+ attr_accessible :title, :assignee_id, :position, :description,
+ :milestone_id, :label_list, :author_id_of_changes,
+ :state_event
acts_as_taggable_on :labels
- def self.open_for(user)
- opened.assigned(user)
+ class << self
+ def cared(user)
+ where('assignee_id = :user', user: user.id)
+ end
+
+ def open_for(user)
+ opened.assigned(user)
+ end
+ end
+
+ state_machine :state, initial: :opened do
+ event :close do
+ transition [:reopened, :opened] => :closed
+ end
+
+ event :reopen do
+ transition closed: :reopened
+ end
+
+ state :opened
+
+ state :reopened
+
+ state :closed
end
end
diff --git a/app/models/key.rb b/app/models/key.rb
index 895e8d6cb9c..edb0bcd61fd 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -35,7 +35,7 @@ class Key < ActiveRecord::Base
def fingerprintable_key
return true unless key # Don't test if there is no key.
- # `ssh-keygen -lf /dev/stdin <<< "#{key}"` errors with: redirection unexpected
+
file = Tempfile.new('key_file')
begin
file.puts key
@@ -45,7 +45,7 @@ class Key < ActiveRecord::Base
file.close
file.unlink # deletes the temp file
end
- errors.add(:key, "can't be fingerprinted") if fingerprint_output.match("failed")
+ errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0
end
def set_identifier
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 345b8d6e07d..06aa9f3c9e0 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -9,15 +9,14 @@
# author_id :integer
# assignee_id :integer
# title :string(255)
-# closed :boolean default(FALSE), not null
+# state :string(255) not null
# created_at :datetime not null
# updated_at :datetime not null
# st_commits :text(2147483647)
# st_diffs :text(2147483647)
-# merged :boolean default(FALSE), not null
-# state :integer default(1), not null
-# milestone_id :integer
+# merge_status :integer default(1), not null
#
+# milestone_id :integer
require Rails.root.join("app/models/commit")
require Rails.root.join("lib/static_model")
@@ -25,11 +24,33 @@ require Rails.root.join("lib/static_model")
class MergeRequest < ActiveRecord::Base
include Issuable
- attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id,
- :author_id_of_changes
+ attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id,
+ :author_id_of_changes, :state_event
attr_accessor :should_remove_source_branch
+ state_machine :state, initial: :opened do
+ event :close do
+ transition [:reopened, :opened] => :closed
+ end
+
+ event :merge do
+ transition [:reopened, :opened] => :merged
+ end
+
+ event :reopen do
+ transition closed: :reopened
+ end
+
+ state :opened
+
+ state :reopened
+
+ state :closed
+
+ state :merged
+ end
+
BROKEN_DIFF = "--broken-diff"
UNCHECKED = 1
@@ -43,21 +64,33 @@ class MergeRequest < ActiveRecord::Base
validates :target_branch, presence: true
validate :validate_branches
- def self.find_all_by_branch(branch_name)
- where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name)
- end
+ scope :merged, -> { with_state(:merged) }
- def self.find_all_by_milestone(milestone)
- where("milestone_id = :milestone_id", milestone_id: milestone)
+ class << self
+ def find_all_by_branch(branch_name)
+ where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name)
+ end
+
+ def cared(user)
+ where('assignee_id = :user OR author_id = :user', user: user.id)
+ end
+
+ def find_all_by_branch(branch_name)
+ where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name)
+ end
+
+ def find_all_by_milestone(milestone)
+ where("milestone_id = :milestone_id", milestone_id: milestone)
+ end
end
- def human_state
- states = {
+ def human_merge_status
+ merge_statuses = {
CAN_BE_MERGED => "can_be_merged",
CANNOT_BE_MERGED => "cannot_be_merged",
UNCHECKED => "unchecked"
}
- states[self.state]
+ merge_statuses[self.merge_status]
end
def validate_branches
@@ -72,20 +105,20 @@ class MergeRequest < ActiveRecord::Base
end
def unchecked?
- state == UNCHECKED
+ merge_status == UNCHECKED
end
def mark_as_unchecked
- self.state = UNCHECKED
+ self.merge_status = UNCHECKED
self.save
end
def can_be_merged?
- state == CAN_BE_MERGED
+ merge_status == CAN_BE_MERGED
end
def check_if_can_be_merged
- self.state = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
+ self.merge_status = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
CAN_BE_MERGED
else
CANNOT_BE_MERGED
@@ -98,7 +131,7 @@ class MergeRequest < ActiveRecord::Base
end
def reloaded_diffs
- if open? && unmerged_diffs.any?
+ if opened? && unmerged_diffs.any?
self.st_diffs = unmerged_diffs
self.save
end
@@ -128,10 +161,6 @@ class MergeRequest < ActiveRecord::Base
commits.first
end
- def merged?
- merged && merge_event
- end
-
def merge_event
self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last
end
@@ -146,26 +175,16 @@ class MergeRequest < ActiveRecord::Base
def probably_merged?
unmerged_commits.empty? &&
- commits.any? && open?
- end
-
- def open?
- !closed
- end
-
- def mark_as_merged!
- self.merged = true
- self.closed = true
- save
+ commits.any? && opened?
end
def mark_as_unmergable
- self.state = CANNOT_BE_MERGED
+ self.merge_status = CANNOT_BE_MERGED
self.save
end
def reloaded_commits
- if open? && unmerged_commits.any?
+ if opened? && unmerged_commits.any?
self.st_commits = unmerged_commits
save
end
@@ -181,7 +200,8 @@ class MergeRequest < ActiveRecord::Base
end
def merge!(user_id)
- self.mark_as_merged!
+ self.merge
+
Event.create(
project: self.project,
action: Event::MERGED,
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 457fe18f35b..d822a68dc7a 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -13,19 +13,32 @@
#
class Milestone < ActiveRecord::Base
- attr_accessible :title, :description, :due_date, :closed, :author_id_of_changes
+ attr_accessible :title, :description, :due_date, :state_event, :author_id_of_changes
attr_accessor :author_id_of_changes
belongs_to :project
has_many :issues
has_many :merge_requests
- scope :active, -> { where(closed: false) }
- scope :closed, -> { where(closed: true) }
+ scope :active, -> { with_state(:active) }
+ scope :closed, -> { with_state(:closed) }
validates :title, presence: true
validates :project, presence: true
- validates :closed, inclusion: { in: [true, false] }
+
+ state_machine :state, initial: :active do
+ event :close do
+ transition active: :closed
+ end
+
+ event :activate do
+ transition closed: :active
+ end
+
+ state :closed
+
+ state :active
+ end
def expired?
if due_date
@@ -68,17 +81,13 @@ class Milestone < ActiveRecord::Base
end
def can_be_closed?
- open? && issues.opened.count.zero?
+ active? && issues.opened.count.zero?
end
def is_empty?
total_items_count.zero?
end
- def open?
- !closed
- end
-
def author_id
author_id_of_changes
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 4e157839369..385fa291b48 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -17,11 +17,15 @@ class Namespace < ActiveRecord::Base
has_many :projects, dependent: :destroy
belongs_to :owner, class_name: "User"
- validates :name, presence: true, uniqueness: true
+ validates :owner, presence: true
+ validates :name, presence: true, uniqueness: true,
+ length: { within: 0..255 },
+ format: { with: Gitlab::Regex.name_regex,
+ message: "only letters, digits, spaces & '_' '-' '.' allowed." }
+
validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
- validates :owner, presence: true
delegate :name, to: :owner, allow_nil: true, prefix: true
diff --git a/app/models/project.rb b/app/models/project.rb
index 9c62e08fb82..54bfb88e915 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -43,7 +43,7 @@ class Project < ActiveRecord::Base
has_many :events, dependent: :destroy
has_many :merge_requests, dependent: :destroy
- has_many :issues, dependent: :destroy, order: "closed, created_at DESC"
+ has_many :issues, dependent: :destroy, order: "state, created_at DESC"
has_many :milestones, dependent: :destroy
has_many :users_projects, dependent: :destroy
has_many :notes, dependent: :destroy
@@ -146,7 +146,7 @@ class Project < ActiveRecord::Base
end
def saved?
- id && valid?
+ id && persisted?
end
def import?
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 37431fe3b0e..a5ca5533e08 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -132,16 +132,16 @@ class Repository
return nil unless commit
# Build file path
- file_name = self.path_with_namespace + "-" + commit.id.to_s + ".tar.gz"
+ file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz"
storage_path = Rails.root.join("tmp", "repositories")
- file_path = File.join(storage_path, file_name)
+ file_path = File.join(storage_path, self.path_with_namespace, file_name)
# Put files into a directory before archiving
prefix = self.path_with_namespace + "/"
# Create file if not exists
unless File.exists?(file_path)
- FileUtils.mkdir_p storage_path
+ FileUtils.mkdir_p File.dirname(file_path)
file = self.repo.archive_to_file(ref, prefix, file_path)
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 10af9b8c165..4ed31c7edce 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -234,8 +234,12 @@ class User < ActiveRecord::Base
keys.count == 0
end
+ def can_change_username?
+ Gitlab.config.gitlab.username_changing_enabled
+ end
+
def can_create_project?
- projects_limit > personal_projects.count
+ projects_limit > owned_projects.count
end
def can_create_group?
@@ -263,7 +267,7 @@ class User < ActiveRecord::Base
end
def cared_merge_requests
- MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id)
+ MergeRequest.cared(self)
end
# Remove user from all projects and
diff --git a/app/models/user_team.rb b/app/models/user_team.rb
index dc8cf9eeb22..2f3091c2353 100644
--- a/app/models/user_team.rb
+++ b/app/models/user_team.rb
@@ -21,8 +21,11 @@ class UserTeam < ActiveRecord::Base
has_many :projects, through: :user_team_project_relationships
has_many :members, through: :user_team_user_relationships, source: :user
- validates :name, presence: true, uniqueness: true
validates :owner, presence: true
+ validates :name, presence: true, uniqueness: true,
+ length: { within: 0..255 },
+ format: { with: Gitlab::Regex.name_regex,
+ message: "only letters, digits, spaces & '_' '-' '.' allowed." }
validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
diff --git a/app/models/user_team_project_relationship.rb b/app/models/user_team_project_relationship.rb
index a7aa88970c7..991510be936 100644
--- a/app/models/user_team_project_relationship.rb
+++ b/app/models/user_team_project_relationship.rb
@@ -26,6 +26,10 @@ class UserTeamProjectRelationship < ActiveRecord::Base
user_team.name
end
+ def human_max_access
+ UserTeam.access_roles.key(greatest_access)
+ end
+
private
def check_greatest_access
diff --git a/app/observers/activity_observer.rb b/app/observers/activity_observer.rb
index b568bb6b763..9c72a6d33f9 100644
--- a/app/observers/activity_observer.rb
+++ b/app/observers/activity_observer.rb
@@ -20,15 +20,23 @@ class ActivityObserver < ActiveRecord::Observer
end
end
- def after_save(record)
- if record.changed.include?("closed") && record.author_id_of_changes
+ def after_close(record, transition)
Event.create(
project: record.project,
target_id: record.id,
target_type: record.class.name,
- action: (record.closed ? Event::CLOSED : Event::REOPENED),
+ action: Event::CLOSED,
+ author_id: record.author_id_of_changes
+ )
+ end
+
+ def after_reopen(record, transition)
+ Event.create(
+ project: record.project,
+ target_id: record.id,
+ target_type: record.class.name,
+ action: Event::REOPENED,
author_id: record.author_id_of_changes
)
- end
end
end
diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb
index 262d0f892c4..592e2950f37 100644
--- a/app/observers/issue_observer.rb
+++ b/app/observers/issue_observer.rb
@@ -7,22 +7,31 @@ class IssueObserver < ActiveRecord::Observer
end
end
- def after_update(issue)
+ def after_close(issue, transition)
send_reassigned_email(issue) if issue.is_being_reassigned?
- status = nil
- status = 'closed' if issue.is_being_closed?
- status = 'reopened' if issue.is_being_reopened?
- if status
- Note.create_status_change_note(issue, current_user, status)
- [issue.author, issue.assignee].compact.each do |recipient|
- Notify.delay.issue_status_changed_email(recipient.id, issue.id, status, current_user.id)
- end
- end
+ create_note(issue)
+ end
+
+ def after_reopen(issue, transition)
+ send_reassigned_email(issue) if issue.is_being_reassigned?
+
+ create_note(issue)
+ end
+
+ def after_update(issue)
+ send_reassigned_email(issue) if issue.is_being_reassigned?
end
protected
+ def create_note(issue)
+ Note.create_status_change_note(issue, current_user, issue.state)
+ [issue.author, issue.assignee].compact.each do |recipient|
+ Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id)
+ end
+ end
+
def send_reassigned_email(issue)
recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id }
diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb
index 6d3c2bdd186..d89e7734c1a 100644
--- a/app/observers/merge_request_observer.rb
+++ b/app/observers/merge_request_observer.rb
@@ -7,15 +7,20 @@ class MergeRequestObserver < ActiveRecord::Observer
end
end
- def after_update(merge_request)
+ def after_close(merge_request, transition)
send_reassigned_email(merge_request) if merge_request.is_being_reassigned?
- status = nil
- status = 'closed' if merge_request.is_being_closed?
- status = 'reopened' if merge_request.is_being_reopened?
- if status
- Note.create_status_change_note(merge_request, current_user, status)
- end
+ Note.create_status_change_note(merge_request, current_user, merge_request.state)
+ end
+
+ def after_reopen(merge_request, transition)
+ send_reassigned_email(merge_request) if merge_request.is_being_reassigned?
+
+ Note.create_status_change_note(merge_request, current_user, merge_request.state)
+ end
+
+ def after_update(merge_request)
+ send_reassigned_email(merge_request) if merge_request.is_being_reassigned?
end
protected
diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb
index 3dbf2860bd4..200700b8810 100644
--- a/app/uploaders/attachment_uploader.rb
+++ b/app/uploaders/attachment_uploader.rb
@@ -19,4 +19,12 @@ class AttachmentUploader < CarrierWave::Uploader::Base
rescue
false
end
+
+ def secure_url
+ if self.class.storage == CarrierWave::Storage::File
+ "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}"
+ else
+ url
+ end
+ end
end
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 25ce66575bf..6d5a293ef7f 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -28,7 +28,7 @@
%td= group.path
%td= group.projects.count
%td
- = link_to group.owner_name, admin_user_path(group.owner_id)
+ = link_to group.owner_name, admin_user_path(group.owner)
%td.bgred
= link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small"
= link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml
index 1f2f4763f76..bb0487d43e9 100644
--- a/app/views/admin/teams/index.html.haml
+++ b/app/views/admin/teams/index.html.haml
@@ -30,7 +30,7 @@
%td= team.projects.count
%td= team.members.count
%td
- = link_to team.owner.name, admin_user_path(team.owner_id)
+ = link_to team.owner.name, admin_user_path(team.owner)
%td.bgred
= link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small"
= link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml
index eb0312d01e1..2f5ff130f03 100644
--- a/app/views/commits/_commit.html.haml
+++ b/app/views/commits/_commit.html.haml
@@ -6,9 +6,9 @@
= link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
= commit.author_link avatar: true, size: 24
&nbsp;
- = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title"
+ = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title"
- %span.committed_ago
+ %time.committed_ago{ datetime: commit.committed_date, title: commit.committed_date.stamp("Aug 21, 2011 9:23pm") }
= time_ago_in_words(commit.committed_date)
ago
&nbsp;
diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml
index 20c3b927067..19665ce0aea 100644
--- a/app/views/events/event/_note.html.haml
+++ b/app/views/events/event/_note.html.haml
@@ -26,7 +26,7 @@
= markdown truncate(event.target.note, length: 70)
- note = event.target
- if note.attachment.url
- = link_to note.attachment.url, target: "_blank", class: 'note-file-attach' do
+ = link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do
- if note.attachment.image?
= image_tag note.attachment.url, class: 'note-image-attach'
- else
diff --git a/app/views/groups/_filter.html.haml b/app/views/groups/_filter.html.haml
index c14fc8e5e4b..5c66f977531 100644
--- a/app/views/groups/_filter.html.haml
+++ b/app/views/groups/_filter.html.haml
@@ -26,6 +26,8 @@
= link_to group_filter_path(entity, project_id: project.id) do
= project.name_with_namespace
%small.pull-right= entities_per_project(project, entity)
+ - if @projects.blank?
+ %p.nothing_here_message This group has no projects yet
%fieldset
%hr
diff --git a/app/views/groups/_people_filter.html.haml b/app/views/groups/_people_filter.html.haml
index 901a037adf3..ee63743eb4f 100644
--- a/app/views/groups/_people_filter.html.haml
+++ b/app/views/groups/_people_filter.html.haml
@@ -7,6 +7,8 @@
= link_to people_group_path(@group, project_id: project.id) do
= project.name_with_namespace
%small.pull-right= project.users.count
+ - if @projects.blank?
+ %p.nothing_here_message This group has no projects yet
%fieldset
%hr
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 7202ef26c70..41ebf60698b 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -30,6 +30,8 @@
= link_to 'Team', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
= link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
= link_to 'Remove', project, confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
+ - if @group.projects.blank?
+ %p.nothing_here_message This group has no projects yet
.span5
.ui-box
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index 1a4411c8f30..879a19fdfb4 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -1,8 +1,8 @@
%h3.page_title
GITLAB
.pull-right
- %span= Gitlab::Version
- %small= Gitlab::Revision
+ %span= Gitlab::VERSION
+ %small= Gitlab::REVISION
%hr
%p.lead
Self Hosted Git Management
diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml
index fa888618066..3d1ecd43881 100644
--- a/app/views/issues/_show.html.haml
+++ b/app/views/issues/_show.html.haml
@@ -8,10 +8,10 @@
%i.icon-comment
= issue.notes.count
- if can? current_user, :modify_issue, issue
- - if issue.closed
- = 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
+ - if issue.closed?
+ = 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
- else
- = 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
+ = 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
= link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do
%i.icon-edit
Edit
diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml
index 474955cc665..f1a97e10913 100644
--- a/app/views/issues/show.html.haml
+++ b/app/views/issues/show.html.haml
@@ -7,10 +7,10 @@
%span.pull-right
- if can?(current_user, :admin_project, @project) || @issue.author == current_user
- - if @issue.closed
- = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn grouped reopen_issue"
+ - if @issue.closed?
+ = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue"
- else
- = link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue"
+ = 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"
- if can?(current_user, :admin_project, @project) || @issue.author == current_user
= link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do
%i.icon-edit
@@ -27,7 +27,7 @@
.ui-box.ui-box-show
.ui-box-head
%h4.box-title
- - if @issue.closed
+ - if @issue.closed?
.error.status_info Closed
= gfm escape_once(@issue.title)
diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml
index cefd33c0cdf..ae2cfe924ec 100644
--- a/app/views/merge_requests/_show.html.haml
+++ b/app/views/merge_requests/_show.html.haml
@@ -29,10 +29,10 @@
$(function(){
merge_request = new MergeRequest({
url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}",
- check_enable: #{@merge_request.state == MergeRequest::UNCHECKED ? "true" : "false"},
+ check_enable: #{@merge_request.merge_status == MergeRequest::UNCHECKED ? "true" : "false"},
url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}",
ci_enable: #{@project.gitlab_ci? ? "true" : "false"},
- current_state: "#{@merge_request.human_state}",
+ current_status: "#{@merge_request.human_merge_status}",
action: "#{controller.action_name}"
});
});
diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml
index c2c04b863e7..64f25a5118c 100644
--- a/app/views/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/merge_requests/show/_mr_accept.html.haml
@@ -3,7 +3,7 @@
%strong Only masters can accept MR
-- if @merge_request.open? && @commits.any? && can?(current_user, :accept_mr, @project)
+- if @merge_request.opened? && @commits.any? && can?(current_user, :accept_mr, @project)
.automerge_widget.can_be_merged{style: "display:none"}
.alert.alert-success
%span
diff --git a/app/views/merge_requests/show/_mr_box.html.haml b/app/views/merge_requests/show/_mr_box.html.haml
index 644d7fcc58e..3b54f613f58 100644
--- a/app/views/merge_requests/show/_mr_box.html.haml
+++ b/app/views/merge_requests/show/_mr_box.html.haml
@@ -1,11 +1,11 @@
.ui-box.ui-box-show
.ui-box-head
%h4.box-title
- - if @merge_request.merged
+ - if @merge_request.merged?
.error.status_info
%i.icon-ok
Merged
- - elsif @merge_request.closed
+ - elsif @merge_request.closed?
.error.status_info Closed
= gfm escape_once(@merge_request.title)
@@ -21,14 +21,14 @@
%strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone)
- - if @merge_request.closed
+ - if @merge_request.closed?
.ui-box-bottom
- - if @merge_request.merged?
- %span
- Merged by #{link_to_member(@project, @merge_request.merge_event.author)}
- %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago.
- - elsif @merge_request.closed_event
- %span
- Closed by #{link_to_member(@project, @merge_request.closed_event.author)}
- %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago.
+ %span
+ Closed by #{link_to_member(@project, @merge_request.closed_event.author)}
+ %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago.
+ - if @merge_request.merged?
+ .ui-box-bottom
+ %span
+ Merged by #{link_to_member(@project, @merge_request.merge_event.author)}
+ %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago.
diff --git a/app/views/merge_requests/show/_mr_ci.html.haml b/app/views/merge_requests/show/_mr_ci.html.haml
index dd1e78a0205..a8faa6ba617 100644
--- a/app/views/merge_requests/show/_mr_ci.html.haml
+++ b/app/views/merge_requests/show/_mr_ci.html.haml
@@ -1,4 +1,4 @@
-- if @merge_request.open? && @commits.any?
+- if @merge_request.opened? && @commits.any?
.ci_widget.ci-success{style: "display:none"}
.alert.alert-success
%i.icon-ok
diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml
index 8119728dcb9..3df7e4b21c6 100644
--- a/app/views/merge_requests/show/_mr_title.html.haml
+++ b/app/views/merge_requests/show/_mr_title.html.haml
@@ -7,7 +7,7 @@
%span.pull-right
- if can?(current_user, :modify_merge_request, @merge_request)
- - if @merge_request.open?
+ - if @merge_request.opened?
.left.btn-group
%a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} }
%i.icon-download-alt
@@ -17,7 +17,7 @@
%li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch)
%li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff)
- = 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"
+ = 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"
= link_to edit_project_merge_request_path(@project, @merge_request), class: "btn grouped" do
%i.icon-edit
diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml
index 00e20117f36..8a3727c6f6a 100644
--- a/app/views/milestones/_milestone.html.haml
+++ b/app/views/milestones/_milestone.html.haml
@@ -1,12 +1,12 @@
-%li{class: "milestone milestone-#{milestone.closed ? 'closed' : 'open'}", id: dom_id(milestone) }
+%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone) }
.pull-right
- - if can?(current_user, :admin_milestone, milestone.project) and milestone.open?
+ - if can?(current_user, :admin_milestone, milestone.project) and milestone.active?
= link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do
%i.icon-edit
Edit
%h4
= link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone)
- - if milestone.expired? and not milestone.closed
+ - if milestone.expired? and not milestone.closed?
%span.cred (Expired)
%small
= milestone.expires_at
diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml
index 43d82a54dd6..c2b09542246 100644
--- a/app/views/milestones/show.html.haml
+++ b/app/views/milestones/show.html.haml
@@ -9,7 +9,7 @@
&larr; To milestones list
.span6
.pull-right
- - unless @milestone.closed
+ - unless @milestone.closed?
= link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do
%i.icon-plus
New Issue
@@ -25,12 +25,12 @@
%hr
%p
%span All issues for this milestone are closed. You may close milestone now.
- = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn btn-small btn-remove"
+ = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-remove"
.ui-box.ui-box-show
.ui-box-head
%h4.box-title
- - if @milestone.closed
+ - if @milestone.closed?
.error.status_info Closed
- elsif @milestone.expired?
.error.status_info Expired
@@ -63,7 +63,7 @@
%li=link_to('All Issues', '#')
%ul.well-list
- @issues.each do |issue|
- %li{data: {closed: issue.closed}}
+ %li{data: {closed: issue.closed?}}
= link_to [@project, issue] do
%span.badge.badge-info ##{issue.id}
&ndash;
@@ -77,7 +77,7 @@
%li=link_to('All Merge Requests', '#')
%ul.well-list
- @merge_requests.each do |merge_request|
- %li{data: {closed: merge_request.closed}}
+ %li{data: {closed: merge_request.closed?}}
= link_to [@project, merge_request] do
%span.badge.badge-info ##{merge_request.id}
&ndash;
diff --git a/app/views/notes/_note.html.haml b/app/views/notes/_note.html.haml
index 4d3007a0ed1..b355e2a0bd4 100644
--- a/app/views/notes/_note.html.haml
+++ b/app/views/notes/_note.html.haml
@@ -31,7 +31,7 @@
- if note.attachment.image?
= image_tag note.attachment.url, class: 'note-image-attach'
.attachment.pull-right
- = link_to note.attachment.url, target: "_blank" do
+ = link_to note.attachment.secure_url, target: "_blank" do
%i.icon-paper-clip
= note.attachment_identifier
.clear
diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml
index 5465d1f96e9..5b6c298df4a 100644
--- a/app/views/profiles/account.html.haml
+++ b/app/views/profiles/account.html.haml
@@ -53,29 +53,30 @@
-%fieldset.update-username
- %legend
- Username
- %small.cred.pull-right
- Changing your username can have unintended side effects!
- = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f|
- .padded
- = f.label :username
- .input
- = f.text_field :username, required: true
- &nbsp;
- %span.loading-gif.hide= image_tag "ajax_loader.gif"
- %span.update-success.cgreen.hide
- %i.icon-ok
- Saved
- %span.update-failed.cred.hide
- %i.icon-remove
- Failed
- %ul.cred
- %li It will change web url for personal projects.
- %li It will change the git path to repositories for personal projects.
- .input
- = f.submit 'Save username', class: "btn btn-save"
+- if current_user.can_change_username?
+ %fieldset.update-username
+ %legend
+ Username
+ %small.cred.pull-right
+ Changing your username can have unintended side effects!
+ = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f|
+ .padded
+ = f.label :username
+ .input
+ = f.text_field :username, required: true
+ &nbsp;
+ %span.loading-gif.hide= image_tag "ajax_loader.gif"
+ %span.update-success.cgreen.hide
+ %i.icon-ok
+ Saved
+ %span.update-failed.cred.hide
+ %i.icon-remove
+ Failed
+ %ul.cred
+ %li It will change web url for personal projects.
+ %li It will change the git path to repositories for personal projects.
+ .input
+ = f.submit 'Save username', class: "btn btn-save"
- if Gitlab.config.gitlab.signup_enabled
%fieldset.remove-account
@@ -83,4 +84,4 @@
Remove account
%small.cred.pull-right
Before removing the account you must remove all projects!
- = 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" \ No newline at end of file
+ = 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"
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 3cf6330cc3c..9cab3ba5252 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -77,7 +77,7 @@
%legend
Personal projects:
%small.pull-right
- %span= current_user.personal_projects.count
+ %span= current_user.owned_projects.count
of
%span= current_user.projects_limit
.padded
diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml
index ba3ccc421cd..b6503636890 100644
--- a/app/views/projects/_new_form.html.haml
+++ b/app/views/projects/_new_form.html.haml
@@ -28,7 +28,7 @@
.input
= f.text_field :import_url, class: 'xlarge', placeholder: 'https://github.com/randx/six.git'
.light
- URL should be clonable
+ URL must be clonable
%p.padded
New projects are private by default. You choose who can see the project and commit to repository.
diff --git a/app/views/projects/files.html.haml b/app/views/projects/files.html.haml
index d108308318e..36948eff658 100644
--- a/app/views/projects/files.html.haml
+++ b/app/views/projects/files.html.haml
@@ -9,7 +9,7 @@
- @notes.each do |note|
%tr
%td
- %a{href: note.attachment.url}
+ = link_to note.attachment.secure_url, target: "_blank" do
= image_tag gravatar_icon(note.author_email), class: "avatar s24"
= note.attachment_identifier
%td
diff --git a/app/views/team_members/_assigned_team.html.haml b/app/views/team_members/_assigned_team.html.haml
new file mode 100644
index 00000000000..1d512c44b26
--- /dev/null
+++ b/app/views/team_members/_assigned_team.html.haml
@@ -0,0 +1,10 @@
+%li{id: dom_id(team), class: "user_team_row team_#{team.id}"}
+ .pull-right
+ - if can?(current_user, :admin_team_member, @project)
+ = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove btn-tiny" do
+ %i.icon-minus.icon-white
+
+ %strong= link_to team.name, team_path(team), title: team.name, class: "dark"
+ %br
+ %small.cgray Members: #{team.members.count}
+ %small.cgray Max access: #{team_relation.human_max_access}
diff --git a/app/views/team_members/_assigned_teams.html.haml b/app/views/team_members/_assigned_teams.html.haml
new file mode 100644
index 00000000000..91c6d8f7157
--- /dev/null
+++ b/app/views/team_members/_assigned_teams.html.haml
@@ -0,0 +1,4 @@
+.ui-box
+ %ul.well-list
+ - assigned_teams.sort_by(&:team_name).each do |team_relation|
+ = render "team_members/assigned_team", team_relation: team_relation, team: team_relation.user_team
diff --git a/app/views/team_members/_show_team.html.haml b/app/views/team_members/_show_team.html.haml
deleted file mode 100644
index f1555f0b87b..00000000000
--- a/app/views/team_members/_show_team.html.haml
+++ /dev/null
@@ -1,15 +0,0 @@
-- team = team_rel.user_team
-- allow_admin = can? current_user, :admin_team_member, @project
-%li{id: dom_id(team), class: "user_team_row team_#{team.id}"}
- .row
- .span6
- %strong= link_to team.name, team_path(team), title: team.name, class: "dark"
- %br
- %small.cgray Members: #{team.members.count}
-
- .span5.pull-right
- .pull-right
- - if allow_admin
- .left
- = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove small" do
- %i.icon-minus.icon-white
diff --git a/app/views/team_members/_team.html.haml b/app/views/team_members/_team.html.haml
index 365d9b65942..2ec8c1a8451 100644
--- a/app/views/team_members/_team.html.haml
+++ b/app/views/team_members/_team.html.haml
@@ -1,16 +1,8 @@
-- grouper_project_members(@project).each do |access, members|
+- team.each do |access, members|
.ui-box
%h5.title
= Project.access_options.key(access).pluralize
%small= members.size
%ul.well-list
- - members.sort_by(&:user_name).each do |up|
- = render(partial: 'team_members/show', locals: {member: up})
-
-
-:javascript
- $(function(){
- $('.repo-access-select, .project-access-select').live("change", function() {
- $(this.form).submit();
- });
- })
+ - members.sort_by(&:user_name).each do |team_member|
+ = render 'team_members/team_member', member: team_member
diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_team_member.html.haml
index 3df2caed64a..e7cba0b349c 100644
--- a/app/views/team_members/_show.html.haml
+++ b/app/views/team_members/_team_member.html.haml
@@ -2,7 +2,7 @@
- allow_admin = can? current_user, :admin_project, @project
%li{id: dom_id(user), class: "team_member_row user_#{user.id}"}
.row
- .span6
+ .span4
= link_to project_team_member_path(@project, user), title: user.name, class: "dark" do
= image_tag gravatar_icon(user.email, 40), class: "avatar s32"
= link_to project_team_member_path(@project, user), title: user.name, class: "dark" do
@@ -10,18 +10,18 @@
%br
%small.cgray= user.email
- .span5.pull-right
+ .span4.pull-right
- if allow_admin
.left
= form_for(member, as: :team_member, url: project_team_member_path(@project, member.user)) do |f|
- = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2"
+ = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2 trigger-submit"
.pull-right
- if current_user == user
- %span.btn.disabled This is you!
+ %span.label This is you!
- if @project.namespace_owner == user
- %span.btn.disabled Owner
+ %span.label Owner
- elsif user.blocked
- %span.btn.disabled.blocked Blocked
+ %span.label Blocked
- elsif allow_admin
= 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
%i.icon-minus.icon-white
diff --git a/app/views/team_members/_teams.html.haml b/app/views/team_members/_teams.html.haml
deleted file mode 100644
index 156fdd1befa..00000000000
--- a/app/views/team_members/_teams.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-- grouper_project_teams(@project).each do |access, teams|
- .ui-box
- %h5.title
- = UserTeam.access_roles.key(access).pluralize
- %small= teams.size
- %ul.well-list
- - teams.sort_by(&:team_name).each do |tofr|
- = render(partial: 'team_members/show_team', locals: {team_rel: tofr})
-
-
-:javascript
- $(function(){
- $('.repo-access-select, .project-access-select').live("change", function() {
- $(this.form).submit();
- });
- })
diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml
index 3264f58cb32..6958ec4cfcc 100644
--- a/app/views/team_members/index.html.haml
+++ b/app/views/team_members/index.html.haml
@@ -18,16 +18,39 @@
%hr
.clearfix
-%div.team-table
- = render partial: "team_members/team", locals: {project: @project}
+.row
+ .span3
+ %ul.nav.nav-pills.nav-stacked
+ %li{class: ("active" if !params[:type])}
+ = link_to project_team_members_path(type: nil) do
+ All
+ %li{class: ("active" if params[:type] == 'masters')}
+ = link_to project_team_members_path(type: 'masters') do
+ Masters
+ %span.pull-right= @project.users_projects.masters.count
+ %li{class: ("active" if params[:type] == 'developers')}
+ = link_to project_team_members_path(type: 'developers') do
+ Developers
+ %span.pull-right= @project.users_projects.developers.count
+ %li{class: ("active" if params[:type] == 'reporters')}
+ = link_to project_team_members_path(type: 'reporters') do
+ Reporters
+ %span.pull-right= @project.users_projects.reporters.count
+ %li{class: ("active" if params[:type] == 'guests')}
+ = link_to project_team_members_path(type: 'guests') do
+ Guests
+ %span.pull-right= @project.users_projects.guests.count
+ - if @assigned_teams.present?
+ %h5
+ Assigned teams
+ (#{@project.user_teams.count})
+ %div
+ = render "team_members/assigned_teams", assigned_teams: @assigned_teams
+
+ .span9
+ %div.team-table
+ = render "team_members/team", team: @team
-%h3.page_title
- Assigned teams
- (#{@project.user_teams.count})
-%hr
-.clearfix
-%div.team-table
- = render partial: "team_members/teams", locals: {project: @project}
diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml
index 3435583600d..751fe94c654 100644
--- a/app/views/teams/edit.html.haml
+++ b/app/views/teams/edit.html.haml
@@ -1,20 +1,29 @@
%h3.page_title= "Edit Team #{@team.name}"
%hr
-= form_for @team, url: team_path(@team) do |f|
- - if @team.errors.any?
- .alert.alert-error
- %span= @team.errors.full_messages.first
- .clearfix
- = f.label :name do
- Team name is
- .input
- = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
+.row
+ .span7
+ = form_for @team, url: team_path(@team) do |f|
+ - if @team.errors.any?
+ .alert.alert-error
+ %span= @team.errors.full_messages.first
+ .clearfix
+ = f.label :name do
+ Team name is
+ .input
+ = f.text_field :name, placeholder: "Ex. OpenSource", class: "xlarge left"
+
+ .clearfix
+ = f.label :path do
+ Team path is
+ .input
+ = f.text_field :path, placeholder: "opensource", class: "xlarge left"
+ .form-actions
+ = f.submit 'Save team changes', class: "btn btn-save"
+ .span5
+ .ui-box
+ %h5.title Remove team
+ .padded.bgred
+ %p
+ Removed team can not be restored!
+ = link_to 'Remove team', team_path(@team), method: :delete, confirm: "You are sure?", class: "btn btn-remove btn-small"
- .clearfix
- = f.label :path do
- Team path is
- .input
- = f.text_field :path, placeholder: "opensource", class: "xxlarge left"
- .form-actions
- = f.submit 'Save team changes', class: "btn btn-primary"
- = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn btn-remove pull-right"
diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml
index 6cddb8e4826..94d2fd50fe8 100644
--- a/app/views/teams/members/_show.html.haml
+++ b/app/views/teams/members/_show.html.haml
@@ -10,22 +10,21 @@
%br
%small.cgray= user.email
- .span6.pull-right
+ .span4
- if allow_admin
- .left.span2
- = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f|
- = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium project-access-select span2"
- .left.span2
- %span
- = check_box_tag :group_admin, true, @team.admin?(user)
- Admin access
- .pull-right
- - if current_user == user
- %span.btn.disabled This is you!
- - if @team.owner == user
- %span.btn.disabled.btn-success Owner
- - elsif user.blocked
- %span.btn.disabled.blocked Blocked
- - elsif allow_admin
- = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do
- %i.icon-minus.icon-white
+ = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f|
+ = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium trigger-submit"
+ %br
+ = label_tag do
+ = f.check_box :group_admin, class: 'trigger-submit'
+ %span Admin access
+ .pull-right
+ - if current_user == user
+ %span.btn.disabled This is you!
+ - if @team.owner == user
+ %span.btn.disabled Owner
+ - elsif user.blocked
+ %span.btn.disabled.blocked Blocked
+ - elsif allow_admin
+ = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do
+ %i.icon-minus.icon-white
diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml
index 38f61c11c0c..7089f791558 100644
--- a/app/views/teams/new.html.haml
+++ b/app/views/teams/new.html.haml
@@ -17,3 +17,17 @@
%li All created teams are public (users can view who enter into team and which project are assigned for this team)
%li People within a team see only projects they have access to
%li You will be able to assign existing projects for team
+ %hr
+
+ - if current_user.can_create_group?
+ .clearfix
+ .input.light
+ Need a group for several dependent projects?
+ = link_to new_group_path, class: "btn btn-tiny" do
+ Create a group
+ - if current_user.can_create_project?
+ .clearfix
+ .input.light
+ Want to create a project?
+ = link_to new_project_path, class: "btn btn-tiny" do
+ Create a project
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index e3f62d736ef..3ef6d5977cf 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -21,14 +21,18 @@ class PostReceive
return false
end
- # Ignore push from non-gitlab users
- user = if identifier.nil?
- raise identifier.inspect
+ user = if identifier.blank?
+ # Local push from gitlab
email = project.repository.commit(newrev).author.email rescue nil
User.find_by_email(email) if email
- elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier)
- User.find_by_email(identifier)
- elsif identifier =~ /key/
+
+ elsif identifier =~ /\Auser-\d+\Z/
+ # git push over http
+ user_id = identifier.gsub("user-", "")
+ User.find_by_id(user_id)
+
+ elsif identifier =~ /\Akey-\d+\Z/
+ # git push over ssh
key_id = identifier.gsub("key-", "")
Key.find_by_id(key_id).try(:user)
end
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 72d85e89b37..62761c80cbb 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -7,121 +7,132 @@
# 2. Replace gitlab -> host with your domain
# 3. Replace gitlab -> email_from
-#
-# 1. GitLab app settings
-# ==========================
-
-## GitLab settings
-gitlab:
- ## Web server settings
- host: localhost
- port: 80
- https: false
- # Uncomment and customize to run in non-root path
- # Note that ENV['RAILS_RELATIVE_URL_ROOT'] in config/unicorn.rb may need to be changed
- # relative_url_root: /gitlab
-
- # Uncomment and customize if you can't use the default user to run GitLab (default: 'git')
- # user: git
-
- ## Email settings
- # Email address used in the "From" field in mails sent by GitLab
- email_from: gitlab@localhost
-
- # Email address of your support contact (default: same as email_from)
- support_email: support@localhost
-
- ## Project settings
- default_projects_limit: 10
- # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled.
-
-## Gravatar
-gravatar:
- enabled: true # Use user avatar images from Gravatar.com (default: true)
- # plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm
- # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm
-
-
-
-#
-# 2. Auth settings
-# ==========================
-
-## LDAP settings
-ldap:
- enabled: false
- host: '_your_ldap_server'
- base: '_the_base_where_you_search_for_users'
- port: 636
- uid: 'sAMAccountName'
- method: 'ssl' # "ssl" or "plain"
- bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
- password: '_the_password_of_the_bind_user'
-
-## Omniauth settings
-omniauth:
- # Enable ability for users
- # Allow logging in via Twitter, Google, etc. using Omniauth providers
- enabled: false
-
+production: &base
+ #
+ # 1. GitLab app settings
+ # ==========================
+
+ ## GitLab settings
+ gitlab:
+ ## Web server settings
+ host: localhost
+ port: 80
+ https: false
+ # Uncomment and customize to run in non-root path
+ # Note that ENV['RAILS_RELATIVE_URL_ROOT'] in config/unicorn.rb may need to be changed
+ # relative_url_root: /gitlab
+
+ # Uncomment and customize if you can't use the default user to run GitLab (default: 'git')
+ # user: git
+
+ ## Email settings
+ # Email address used in the "From" field in mails sent by GitLab
+ email_from: gitlab@localhost
+
+ # Email address of your support contact (default: same as email_from)
+ support_email: support@localhost
+
+ ## Project settings
+ default_projects_limit: 10
+ # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled.
+ # username_changing_enabled: false # default: true - User can change her username/namespace
+
+ ## Gravatar
+ gravatar:
+ enabled: true # Use user avatar images from Gravatar.com (default: true)
+ # plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm
+ # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm
+
+
+
+ #
+ # 2. Auth settings
+ # ==========================
+
+ ## LDAP settings
+ ldap:
+ enabled: false
+ host: '_your_ldap_server'
+ base: '_the_base_where_you_search_for_users'
+ port: 636
+ uid: 'sAMAccountName'
+ method: 'ssl' # "ssl" or "plain"
+ bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
+ password: '_the_password_of_the_bind_user'
+
+ ## Omniauth settings
+ omniauth:
+ # Enable ability for users
+ # Allow logging in via Twitter, Google, etc. using Omniauth providers
+ enabled: false
+
+ # CAUTION!
+ # This allows users to login without having a user account first (default: false)
+ # User accounts will be created automatically when authentication was successful.
+ allow_single_sign_on: false
+ # Locks down those users until they have been cleared by the admin (default: true)
+ block_auto_created_users: true
+
+ ## Auth providers
+ # Uncomment the lines and fill in the data of the auth provider you want to use
+ # If your favorite auth provider is not listed you can user others:
+ # see https://github.com/gitlabhq/gitlabhq/wiki/Using-Custom-Omniauth-Providers
+ # The 'app_id' and 'app_secret' parameters are always passed as the first two
+ # arguments, followed by optional 'args' which can be either a hash or an array.
+ providers:
+ # - { name: 'google_oauth2', app_id: 'YOUR APP ID',
+ # app_secret: 'YOUR APP SECRET',
+ # args: { access_type: 'offline', approval_prompt: '' } }
+ # - { name: 'twitter', app_id: 'YOUR APP ID',
+ # app_secret: 'YOUR APP SECRET'}
+ # - { name: 'github', app_id: 'YOUR APP ID',
+ # app_secret: 'YOUR APP SECRET' }
+
+
+
+ #
+ # 3. Advanced settings
+ # ==========================
+
+ # GitLab Satellites
+ satellites:
+ # Relative paths are relative to Rails.root (default: tmp/repo_satellites/)
+ path: /home/git/gitlab-satellites/
+
+ ## Backup settings
+ backup:
+ path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/)
+ # keep_time: 604800 # default: 0 (forever) (in seconds)
+
+ ## GitLab Shell settings
+ gitlab_shell:
+ # REPOS_PATH MUST NOT BE A SYMLINK!!!
+ repos_path: /home/git/repositories/
+ hooks_path: /home/git/gitlab-shell/hooks/
+
+ # Git over HTTP
+ upload_pack: true
+ receive_pack: true
+
+ # If you use non-standart ssh port you need to specify it
+ # ssh_port: 22
+
+ ## Git settings
# CAUTION!
- # This allows users to login without having a user account first (default: false)
- # User accounts will be created automatically when authentication was successful.
- allow_single_sign_on: false
- # Locks down those users until they have been cleared by the admin (default: true)
- block_auto_created_users: true
-
- ## Auth providers
- # Uncomment the lines and fill in the data of the auth provider you want to use
- # If your favorite auth provider is not listed you can user others:
- # see https://github.com/gitlabhq/gitlabhq/wiki/Using-Custom-Omniauth-Providers
- # The 'app_id' and 'app_secret' parameters are always passed as the first two
- # arguments, followed by optional 'args' which can be either a hash or an array.
- providers:
- # - { name: 'google_oauth2', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET',
- # args: { access_type: 'offline', approval_prompt: '' } }
- # - { name: 'twitter', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET'}
- # - { name: 'github', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET' }
-
-
-
-#
-# 3. Advanced settings
-# ==========================
-
-# GitLab Satellites
-satellites:
- # Relative paths are relative to Rails.root (default: tmp/repo_satellites/)
- path: /home/git/gitlab-satellites/
-
-## Backup settings
-backup:
- path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/)
- # keep_time: 604800 # default: 0 (forever) (in seconds)
-
-## GitLab Shell settings
-gitlab_shell:
- # REPOS_PATH MUST NOT BE A SYMLINK!!!
- repos_path: /home/git/repositories/
- hooks_path: /home/git/gitlab-shell/hooks/
-
- # Git over HTTP
- upload_pack: true
- receive_pack: true
-
- # If you use non-standart ssh port you need to specify it
- # ssh_port: 22
-
-## Git settings
-# CAUTION!
-# Use the default values unless you really know what you are doing
-git:
- bin_path: /usr/bin/git
- # Max size of git object like commit, in bytes
- # This value can be increased if you have a very large commits
- max_size: 5242880 # 5.megabytes
- # Git timeout to read commit, in seconds
- timeout: 10
+ # Use the default values unless you really know what you are doing
+ git:
+ bin_path: /usr/bin/git
+ # Max size of git object like commit, in bytes
+ # This value can be increased if you have a very large commits
+ max_size: 5242880 # 5.megabytes
+ # Git timeout to read commit, in seconds
+ timeout: 10
+
+development:
+ <<: *base
+
+test:
+ <<: *base
+
+staging:
+ <<: *base
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index c1469530024..f7d18e67148 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -1,5 +1,6 @@
class Settings < Settingslogic
source "#{Rails.root}/config/gitlab.yml"
+ namespace Rails.env
class << self
def gitlab_on_non_standard_port?
@@ -56,6 +57,7 @@ Settings.gitlab['support_email'] ||= Settings.gitlab.email_from
Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url)
Settings.gitlab['user'] ||= 'git'
Settings.gitlab['signup_enabled'] ||= false
+Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
#
# Gravatar
diff --git a/config/initializers/2_app.rb b/config/initializers/2_app.rb
index 748f15a11d9..27a0c0ffeb2 100644
--- a/config/initializers/2_app.rb
+++ b/config/initializers/2_app.rb
@@ -1,6 +1,6 @@
module Gitlab
- Version = File.read(Rails.root.join("VERSION"))
- Revision = `git log --pretty=format:'%h' -n 1`
+ VERSION = File.read(Rails.root.join("VERSION")).strip
+ REVISION = `git log --pretty=format:'%h' -n 1`
def self.config
Settings
diff --git a/config/routes.rb b/config/routes.rb
index 125ec6bc588..10536a6e529 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -47,6 +47,11 @@ Gitlab::Application.routes.draw do
end
#
+ # Attachments serving
+ #
+ get 'files/:type/:id/:filename' => 'files#download', constraints: { id: /\d+/, type: /[a-z]+/, filename: /[a-zA-Z.0-9_\-\+]+/ }
+
+ #
# Admin Area
#
namespace :admin do
diff --git a/db/fixtures/development/02_source_code.rb b/db/fixtures/development/02_source_code.rb
index 4a9e5d0c258..a0a46c9e927 100644
--- a/db/fixtures/development/02_source_code.rb
+++ b/db/fixtures/development/02_source_code.rb
@@ -1,4 +1,4 @@
-root = Gitlab.config.gitolite.repos_path
+root = Gitlab.config.gitlab_shell.repos_path
projects = [
{ path: 'underscore.git', git: 'https://github.com/documentcloud/underscore.git' },
diff --git a/db/fixtures/development/09_issues.rb b/db/fixtures/development/09_issues.rb
index 8978db4742b..cd9b2b3e456 100644
--- a/db/fixtures/development/09_issues.rb
+++ b/db/fixtures/development/09_issues.rb
@@ -16,7 +16,7 @@ Gitlab::Seeder.quiet do
project_id: project.id,
author_id: user_id,
assignee_id: user_id,
- closed: [true, false].sample,
+ state: ['opened', 'closed'].sample,
milestone: project.milestones.sample,
title: Faker::Lorem.sentence(6)
}])
diff --git a/db/fixtures/development/10_merge_requests.rb b/db/fixtures/development/10_merge_requests.rb
index 9904b4a1505..6d111b26c53 100644
--- a/db/fixtures/development/10_merge_requests.rb
+++ b/db/fixtures/development/10_merge_requests.rb
@@ -17,7 +17,7 @@ Gitlab::Seeder.quiet do
project_id: project.id,
author_id: user_id,
assignee_id: user_id,
- closed: [true, false].sample,
+ state: ['opened', 'closed'].sample,
milestone: project.milestones.sample,
title: Faker::Lorem.sentence(6)
}])
diff --git a/db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb b/db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb
new file mode 100644
index 00000000000..23797fe1894
--- /dev/null
+++ b/db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb
@@ -0,0 +1,5 @@
+class RenameStateToMergeStatusInMilestone < ActiveRecord::Migration
+ def change
+ rename_column :merge_requests, :state, :merge_status
+ end
+end
diff --git a/db/migrate/20130218140952_add_state_to_issue.rb b/db/migrate/20130218140952_add_state_to_issue.rb
new file mode 100644
index 00000000000..062103d0e33
--- /dev/null
+++ b/db/migrate/20130218140952_add_state_to_issue.rb
@@ -0,0 +1,5 @@
+class AddStateToIssue < ActiveRecord::Migration
+ def change
+ add_column :issues, :state, :string
+ end
+end
diff --git a/db/migrate/20130218141038_add_state_to_merge_request.rb b/db/migrate/20130218141038_add_state_to_merge_request.rb
new file mode 100644
index 00000000000..ac4108ee311
--- /dev/null
+++ b/db/migrate/20130218141038_add_state_to_merge_request.rb
@@ -0,0 +1,5 @@
+class AddStateToMergeRequest < ActiveRecord::Migration
+ def change
+ add_column :merge_requests, :state, :string
+ end
+end
diff --git a/db/migrate/20130218141117_add_state_to_milestone.rb b/db/migrate/20130218141117_add_state_to_milestone.rb
new file mode 100644
index 00000000000..c84039106bd
--- /dev/null
+++ b/db/migrate/20130218141117_add_state_to_milestone.rb
@@ -0,0 +1,5 @@
+class AddStateToMilestone < ActiveRecord::Migration
+ def change
+ add_column :milestones, :state, :string
+ end
+end
diff --git a/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb
new file mode 100644
index 00000000000..0614a5c0064
--- /dev/null
+++ b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb
@@ -0,0 +1,14 @@
+class ConvertClosedToStateInIssue < ActiveRecord::Migration
+ def up
+ Issue.transaction do
+ Issue.where(closed: true).update_all("state = 'closed'")
+ Issue.where(closed: false).update_all("state = 'opened'")
+ end
+ end
+
+ def down
+ Issue.transaction do
+ Issue.where(state: :closed).update_all("closed = 1")
+ end
+ end
+end
diff --git a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb
new file mode 100644
index 00000000000..4d5c6ee569d
--- /dev/null
+++ b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb
@@ -0,0 +1,16 @@
+class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration
+ def up
+ MergeRequest.transaction do
+ MergeRequest.where("closed = 1 AND merged = 1").update_all("state = 'merged'")
+ MergeRequest.where("closed = 1 AND merged = 0").update_all("state = 'closed'")
+ MergeRequest.where("closed = 0").update_all("state = 'opened'")
+ end
+ end
+
+ def down
+ MergeRequest.transaction do
+ MergeRequest.where(state: :closed).update_all("closed = 1")
+ MergeRequest.where(state: :merged).update_all("closed = 1, merged = 1")
+ end
+ end
+end
diff --git a/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb
new file mode 100644
index 00000000000..78096666393
--- /dev/null
+++ b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb
@@ -0,0 +1,14 @@
+class ConvertClosedToStateInMilestone < ActiveRecord::Migration
+ def up
+ Milestone.transaction do
+ Milestone.where(closed: false).update_all("state = 'opened'")
+ Milestone.where(closed: false).update_all("state = 'active'")
+ end
+ end
+
+ def down
+ Milestone.transaction do
+ Milestone.where(state: :closed).update_all("closed = 1")
+ end
+ end
+end
diff --git a/db/migrate/20130218141444_remove_merged_from_merge_request.rb b/db/migrate/20130218141444_remove_merged_from_merge_request.rb
new file mode 100644
index 00000000000..a7bd82f5000
--- /dev/null
+++ b/db/migrate/20130218141444_remove_merged_from_merge_request.rb
@@ -0,0 +1,9 @@
+class RemoveMergedFromMergeRequest < ActiveRecord::Migration
+ def up
+ remove_column :merge_requests, :merged
+ end
+
+ def down
+ add_column :merge_requests, :merged, :boolean, default: true, null: false
+ end
+end
diff --git a/db/migrate/20130218141507_remove_closed_from_issue.rb b/db/migrate/20130218141507_remove_closed_from_issue.rb
new file mode 100644
index 00000000000..95cc064252b
--- /dev/null
+++ b/db/migrate/20130218141507_remove_closed_from_issue.rb
@@ -0,0 +1,9 @@
+class RemoveClosedFromIssue < ActiveRecord::Migration
+ def up
+ remove_column :issues, :closed
+ end
+
+ def down
+ add_column :issues, :closed, :boolean
+ end
+end
diff --git a/db/migrate/20130218141536_remove_closed_from_merge_request.rb b/db/migrate/20130218141536_remove_closed_from_merge_request.rb
new file mode 100644
index 00000000000..371835938b2
--- /dev/null
+++ b/db/migrate/20130218141536_remove_closed_from_merge_request.rb
@@ -0,0 +1,9 @@
+class RemoveClosedFromMergeRequest < ActiveRecord::Migration
+ def up
+ remove_column :merge_requests, :closed
+ end
+
+ def down
+ add_column :merge_requests, :closed, :boolean
+ end
+end
diff --git a/db/migrate/20130218141554_remove_closed_from_milestone.rb b/db/migrate/20130218141554_remove_closed_from_milestone.rb
new file mode 100644
index 00000000000..e8dae4a19b1
--- /dev/null
+++ b/db/migrate/20130218141554_remove_closed_from_milestone.rb
@@ -0,0 +1,9 @@
+class RemoveClosedFromMilestone < ActiveRecord::Migration
+ def up
+ remove_column :milestones, :closed
+ end
+
+ def down
+ add_column :milestones, :closed, :boolean
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 0f07d2bc8c5..f837e6edf98 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20130131070232) do
+ActiveRecord::Schema.define(:version => 20130218141554) do
create_table "events", :force => true do |t|
t.string "target_type"
@@ -37,18 +37,17 @@ ActiveRecord::Schema.define(:version => 20130131070232) do
t.integer "assignee_id"
t.integer "author_id"
t.integer "project_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.boolean "closed", :default => false, :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
t.integer "position", :default => 0
t.string "branch_name"
t.text "description"
t.integer "milestone_id"
+ t.string "state"
end
add_index "issues", ["assignee_id"], :name => "index_issues_on_assignee_id"
add_index "issues", ["author_id"], :name => "index_issues_on_author_id"
- add_index "issues", ["closed"], :name => "index_issues_on_closed"
add_index "issues", ["created_at"], :name => "index_issues_on_created_at"
add_index "issues", ["milestone_id"], :name => "index_issues_on_milestone_id"
add_index "issues", ["project_id"], :name => "index_issues_on_project_id"
@@ -69,25 +68,23 @@ ActiveRecord::Schema.define(:version => 20130131070232) do
add_index "keys", ["user_id"], :name => "index_keys_on_user_id"
create_table "merge_requests", :force => true do |t|
- t.string "target_branch", :null => false
- t.string "source_branch", :null => false
- t.integer "project_id", :null => false
+ t.string "target_branch", :null => false
+ t.string "source_branch", :null => false
+ t.integer "project_id", :null => false
t.integer "author_id"
t.integer "assignee_id"
t.string "title"
- t.boolean "closed", :default => false, :null => false
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
t.text "st_commits", :limit => 2147483647
t.text "st_diffs", :limit => 2147483647
- t.boolean "merged", :default => false, :null => false
- t.integer "state", :default => 1, :null => false
+ t.integer "merge_status", :default => 1, :null => false
t.integer "milestone_id"
+ t.string "state"
end
add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id"
add_index "merge_requests", ["author_id"], :name => "index_merge_requests_on_author_id"
- add_index "merge_requests", ["closed"], :name => "index_merge_requests_on_closed"
add_index "merge_requests", ["created_at"], :name => "index_merge_requests_on_created_at"
add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id"
add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id"
@@ -96,13 +93,13 @@ ActiveRecord::Schema.define(:version => 20130131070232) do
add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title"
create_table "milestones", :force => true do |t|
- t.string "title", :null => false
- t.integer "project_id", :null => false
+ t.string "title", :null => false
+ t.integer "project_id", :null => false
t.text "description"
t.date "due_date"
- t.boolean "closed", :default => false, :null => false
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "state"
end
add_index "milestones", ["due_date"], :name => "index_milestones_on_due_date"
diff --git a/doc/api/milestones.md b/doc/api/milestones.md
index b997e83901b..73d29afc37a 100644
--- a/doc/api/milestones.md
+++ b/doc/api/milestones.md
@@ -34,7 +34,6 @@ POST /projects/:id/milestones
Parameters:
+ `id` (required) - The ID of a project
-+ `milestone_id` (required) - The ID of a project milestone
+ `title` (required) - The title of an milestone
+ `description` (optional) - The description of the milestone
+ `due_date` (optional) - The due date of the milestone
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 16521917a7a..cff4327a58c 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -23,7 +23,7 @@ GET /projects
"blocked": false,
"created_at": "2012-05-23T08:00:58Z"
},
- "private": true,
+ "public": true,
"path": "rails",
"path_with_namespace": "rails/rails",
"issues_enabled": false,
@@ -45,7 +45,7 @@ GET /projects
"blocked": false,
"created_at": "2012-05-23T08:00:58Z"
},
- "private": true,
+ "public": true,
"path": "gitlab",
"path_with_namespace": "randx/gitlab",
"issues_enabled": true,
@@ -89,7 +89,7 @@ Parameters:
"blocked": false,
"created_at": "2012-05-23T08:00:58Z"
},
- "private": true,
+ "public": true,
"path": "gitlab",
"path_with_namespace": "randx/gitlab",
"issues_enabled": true,
diff --git a/doc/install/databases.md b/doc/install/databases.md
index 4c6c084d0b9..61882602bba 100644
--- a/doc/install/databases.md
+++ b/doc/install/databases.md
@@ -27,7 +27,7 @@ GitLab supports the following databases:
mysql> \q
# Try connecting to the new database with the new user
- sudo -u gitlab -H mysql -u gitlab -p -D gitlabhq_production
+ sudo -u git -H mysql -u gitlab -p -D gitlabhq_production
## PostgreSQL
@@ -47,5 +47,5 @@ GitLab supports the following databases:
template1=# \q
# Try connecting to the new database with the new user
- sudo -u gitlab -H psql -d gitlabhq_production
+ sudo -u git -H psql -d gitlabhq_production
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 501ae6db87a..4d2ab63b2e9 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -1,6 +1,6 @@
This installation guide was created for Debian/Ubuntu and tested on it.
-Please read `doc/install/requirements.md` for hardware and platform requirements.
+Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements.
**Important Note:**
@@ -8,12 +8,13 @@ The following steps have been known to work.
If you deviate from this guide, do it with caution and make sure you don't
violate any assumptions GitLab makes about its environment.
For things like AWS installation scripts, init scripts or config files for
-alternative web server have a look at the "Advanced Setup Tips" section.
+alternative web server have a look at the [`Advanced Setup
+Tips`](./installation.md#advanced-setup-tips) section.
**Important Note:**
If you find a bug/error in this guide please submit an issue or pull request
-following the contribution guide (see `CONTRIBUTING.md`).
+following the [`contribution guide`](../../CONTRIBUTING.md).
- - -
@@ -24,7 +25,7 @@ The GitLab installation consists of setting up the following components:
1. Packages / Dependencies
2. Ruby
3. System Users
-4. Gitolite
+4. GitLab shell
5. Database
6. GitLab
7. Nginx
@@ -32,16 +33,13 @@ The GitLab installation consists of setting up the following components:
# 1. Packages / Dependencies
-`sudo` is not installed on Debian by default. If you don't have it you'll need
-to install it first.
+`sudo` is not installed on Debian by default. Make sure your system is
+up-to-date and install it.
# run as root
- apt-get update && apt-get upgrade && apt-get install sudo
-
-Make sure your system is up-to-date:
-
- sudo apt-get update
- sudo apt-get upgrade
+ apt-get update
+ apt-get upgrade
+ apt-get install sudo
**Note:**
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:
# 4. GitLab shell
- # login as git
+ # Login as git
sudo su git
- # go to home directory
+ # Go to home directory
cd /home/git
- # clone gitlab shell
+ # Clone gitlab shell
git clone https://github.com/gitlabhq/gitlab-shell.git
- # setup
+ # Setup
cd gitlab-shell
cp config.yml.example config.yml
./bin/install
-
# 5. Database
-To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md) .
+To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md).
# 6. GitLab
@@ -154,9 +151,13 @@ do so with caution!
sudo chmod -R u+rwX log/
sudo chmod -R u+rwX tmp/
- # Make directory for satellites
+ # Create directory for satellites
sudo -u git -H mkdir /home/git/gitlab-satellites
+ # Create directory for pids and make sure GitLab can write to it
+ sudo -u git -H mkdir tmp/pids/
+ sudo chmod -R u+rwX tmp/pids/
+
# Copy the example Unicorn config
sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb
@@ -187,7 +188,9 @@ Make sure to update username/password in config/database.yml.
## Initialise Database and Activate Advanced Features
-
+
+ sudo -u git -H bundle exec rake db:setup RAILS_ENV=production
+ sudo -u git -H bundle exec rake db:seed_fu RAILS_ENV=production
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
@@ -205,7 +208,7 @@ Make GitLab start on boot:
## Check Application Status
-Check if GitLab and its environment is configured correctly:
+Check if GitLab and its environment are configured correctly:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
@@ -227,7 +230,7 @@ However there are still a few steps left.
**Note:**
If you can't or don't want to use Nginx as your web server, have a look at the
-"Advanced Setup Tips" section.
+[`Advanced Setup Tips`](./installation.md#advanced-setup-tips) section.
## Installation
sudo apt-get install nginx
@@ -244,11 +247,11 @@ Make sure to edit the config file to match your setup:
# Change **YOUR_SERVER_IP** and **YOUR_SERVER_FQDN**
# to the IP address and fully-qualified domain name
# of your host serving GitLab
- sudo vim /etc/nginx/sites-enabled/gitlab
+ sudo vim /etc/nginx/sites-available/gitlab
## Restart
- sudo /etc/init.d/nginx restart
+ sudo service nginx restart
# Done!
@@ -282,7 +285,7 @@ a different host, you can configure its connection string via the
## Custom SSH Connection
-If you are running SSH on a non-standard port, you must change the gitlab user'S SSH config.
+If you are running SSH on a non-standard port, you must change the gitlab user's SSH config.
# Add to /home/git/.ssh/config
host localhost # Give your setup a name (here: override localhost)
diff --git a/features/steps/profile/profile_ssh_keys.rb b/features/steps/profile/profile_ssh_keys.rb
index 8ae1fa91025..fbb92077f0a 100644
--- a/features/steps/profile/profile_ssh_keys.rb
+++ b/features/steps/profile/profile_ssh_keys.rb
@@ -43,6 +43,6 @@ class ProfileSshKeys < Spinach::FeatureSteps
end
And 'I have ssh key "ssh-rsa Work"' do
- create(:key, :user => @user, :title => "ssh-rsa Work", :key => "jfKLJDFKSFJSHFJssh-rsa Work")
+ create(:key, :user => @user, :title => "ssh-rsa Work", :key => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+L3TbFegm3k8QjejSwemk4HhlRh+DuN679Pc5ckqE/MPhVtE/+kZQDYCTB284GiT2aIoGzmZ8ee9TkaoejAsBwlA+Wz2Q3vhz65X6sMgalRwpdJx8kSEUYV8ZPV3MZvPo8KdNg993o4jL6G36GDW4BPIyO6FPZhfsawdf6liVD0Xo5kibIK7B9VoE178cdLQtLpS2YolRwf5yy6XR6hbbBGQR+6xrGOdP16eGZDb1CE2bMvvJijjloFqPscGktWOqW+nfh5txwFfBzlfARDTBsS8WZtg3Yoj1kn33kPsWRlgHfNutFRAIynDuDdQzQq8tTtVwm+Yi75RfcPHW8y3P Work")
end
end
diff --git a/features/steps/project/project_issues.rb b/features/steps/project/project_issues.rb
index 2103aeb1715..7d54009988f 100644
--- a/features/steps/project/project_issues.rb
+++ b/features/steps/project/project_issues.rb
@@ -122,10 +122,9 @@ class ProjectIssues < Spinach::FeatureSteps
And 'project "Shop" have "Release 0.3" closed issue' do
project = Project.find_by_name("Shop")
- create(:issue,
+ create(:closed_issue,
:title => "Release 0.3",
:project => project,
- :author => project.users.first,
- :closed => true)
+ :author => project.users.first)
end
end
diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb
index 329261add2a..ff95a47d4cf 100644
--- a/features/steps/project/project_merge_requests.rb
+++ b/features/steps/project/project_merge_requests.rb
@@ -26,7 +26,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps
Then 'I should see closed merge request "Bug NS-04"' do
mr = MergeRequest.find_by_title("Bug NS-04")
- mr.closed.should be_true
+ mr.closed?.should be_true
page.should have_content "Closed by"
end
@@ -80,11 +80,10 @@ class ProjectMergeRequests < Spinach::FeatureSteps
And 'project "Shop" have "Feature NS-03" closed merge request' do
project = Project.find_by_name("Shop")
- create(:merge_request,
+ create(:closed_merge_request,
title: "Feature NS-03",
project: project,
- author: project.users.first,
- closed: true)
+ author: project.users.first)
end
And 'I switch to the diff tab' do
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index c1873d87b55..1cae1d337fe 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -20,7 +20,7 @@ module Gitlab
class Project < Grape::Entity
expose :id, :name, :description, :default_branch
expose :owner, using: Entities::UserBasic
- expose :private_flag, as: :private
+ expose :public
expose :path, :path_with_namespace
expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at
expose :namespace
@@ -35,12 +35,11 @@ module Gitlab
class Group < Grape::Entity
expose :id, :name, :path, :owner_id
end
-
+
class GroupDetail < Group
expose :projects, using: Entities::Project
end
-
class RepoObject < Grape::Entity
expose :name, :commit
expose :protected do |repo, options|
@@ -63,7 +62,7 @@ module Gitlab
class Milestone < Grape::Entity
expose :id
expose (:project_id) {|milestone| milestone.project.id}
- expose :title, :description, :due_date, :closed, :updated_at, :created_at
+ expose :title, :description, :due_date, :state, :updated_at, :created_at
end
class Issue < Grape::Entity
@@ -73,7 +72,7 @@ module Gitlab
expose :label_list, as: :labels
expose :milestone, using: Entities::Milestone
expose :assignee, :author, using: Entities::UserBasic
- expose :closed, :updated_at, :created_at
+ expose :state, :updated_at, :created_at
end
class SSHKey < Grape::Entity
@@ -81,7 +80,7 @@ module Gitlab
end
class MergeRequest < Grape::Entity
- expose :id, :target_branch, :source_branch, :project_id, :title, :closed, :merged
+ expose :id, :target_branch, :source_branch, :project_id, :title, :state
expose :author, :assignee, using: Entities::UserBasic
end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 3e5e3a478ba..5d74a761c05 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -40,7 +40,9 @@ module Gitlab
get "/check" do
{
- api_version: '3'
+ api_version: Gitlab::API.version,
+ gitlab_version: Gitlab::VERSION,
+ gitlab_rev: Gitlab::REVISION,
}
end
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 4d832fbe593..70bbf47e72c 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -69,14 +69,14 @@ module Gitlab
# assignee_id (optional) - The ID of a user to assign issue
# milestone_id (optional) - The ID of a milestone to assign issue
# labels (optional) - The labels of an issue
- # closed (optional) - The state of an issue (0 = false, 1 = true)
+ # state (optional) - The state of an issue (close|reopen)
# Example Request:
# PUT /projects/:id/issues/:issue_id
put ":id/issues/:issue_id" do
@issue = user_project.issues.find(params[:issue_id])
authorize! :modify_issue, @issue
- attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :closed]
+ attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event]
attrs[:label_list] = params[:labels] if params[:labels].present?
IssueObserver.current_user = current_user
if @issue.update_attributes attrs
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 0c18ece3824..4b28094f1a4 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -91,12 +91,12 @@ module Gitlab
# target_branch - The target branch
# assignee_id - Assignee user ID
# title - Title of MR
- # closed - Status of MR. true - closed
+ # state_event - Status of MR. (close|reopen|merge)
# Example:
# PUT /projects/:id/merge_request/:merge_request_id
#
put ":id/merge_request/:merge_request_id" do
- attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :closed]
+ attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :state_event]
merge_request = user_project.merge_requests.find(params[:merge_request_id])
authorize! :modify_merge_request, merge_request
diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb
index cdb0e14690d..7f8fe053ba1 100644
--- a/lib/api/milestones.rb
+++ b/lib/api/milestones.rb
@@ -74,14 +74,14 @@ module Gitlab
# title (optional) - The title of a milestone
# description (optional) - The description of a milestone
# due_date (optional) - The due date of a milestone
- # closed (optional) - The status of the milestone
+ # state (optional) - The status of the milestone (close|activate)
# Example Request:
# PUT /projects/:id/milestones/:milestone_id
put ":id/milestones/:milestone_id" do
authorize! :admin_milestone, user_project
@milestone = user_project.milestones.find(params[:milestone_id])
- attrs = attributes_for_keys [:title, :description, :due_date, :closed]
+ attrs = attributes_for_keys [:title, :description, :due_date, :state_event]
if @milestone.update_attributes attrs
present @milestone, with: Entities::Milestone
else
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index cf3e8257a77..d171acc1ce1 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -184,6 +184,7 @@ module Gitlab
# Example Request:
# GET /projects/:id/hooks/:hook_id
get ":id/hooks/:hook_id" do
+ authorize! :admin_project, user_project
@hook = user_project.hooks.find(params[:hook_id])
present @hook, with: Entities::Hook
end
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index a2d15d57034..abbee6132d3 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -1,3 +1,5 @@
+require_relative 'shell_env'
+
module Grack
class Auth < Rack::Auth::Basic
attr_accessor :user, :project
@@ -7,9 +9,6 @@ module Grack
@request = Rack::Request.new(env)
@auth = Request.new(env)
- # Pass Gitolite update hook
- ENV['GL_BYPASS_UPDATE_HOOK'] = "true"
-
# Need this patch due to the rails mount
@env['PATH_INFO'] = @request.path
@env['SCRIPT_NAME'] = ""
@@ -35,8 +34,7 @@ module Grack
self.user = User.find_by_email(login) || User.find_by_username(login)
return false unless user.try(:valid_password?, password)
- # Set GL_USER env variable
- ENV['GL_USER'] = user.email
+ Gitlab::ShellEnv.set_env(user)
end
# Git upload and receive
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index 85fa5bda055..9ea08ccbdbf 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -10,7 +10,7 @@ module Gitlab
# add_repository("gitlab/gitlab-ci")
#
def add_repository(name)
- system("/home/git/gitlab-shell/bin/gitlab-projects add-project #{name}.git")
+ system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects add-project #{name}.git")
end
# Import repository
@@ -21,7 +21,7 @@ module Gitlab
# import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git")
#
def import_repository(name, url)
- system("/home/git/gitlab-shell/bin/gitlab-projects import-project #{name}.git #{url}")
+ system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects import-project #{name}.git #{url}")
end
# Remove repository from file system
@@ -32,7 +32,7 @@ module Gitlab
# remove_repository("gitlab/gitlab-ci")
#
def remove_repository(name)
- system("/home/git/gitlab-shell/bin/gitlab-projects rm-project #{name}.git")
+ system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects rm-project #{name}.git")
end
# Add new key to gitlab-shell
@@ -41,7 +41,7 @@ module Gitlab
# add_key("key-42", "sha-rsa ...")
#
def add_key(key_id, key_content)
- system("/home/git/gitlab-shell/bin/gitlab-keys add-key #{key_id} \"#{key_content}\"")
+ system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys add-key #{key_id} \"#{key_content}\"")
end
# Remove ssh key from gitlab shell
@@ -50,12 +50,16 @@ module Gitlab
# remove_key("key-342", "sha-rsa ...")
#
def remove_key(key_id, key_content)
- system("/home/git/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"")
+ system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"")
end
-
def url_to_repo path
Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git"
end
+
+ def gitlab_shell_user_home
+ File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}")
+ end
+
end
end
diff --git a/lib/gitlab/backend/shell_env.rb b/lib/gitlab/backend/shell_env.rb
new file mode 100644
index 00000000000..15721875093
--- /dev/null
+++ b/lib/gitlab/backend/shell_env.rb
@@ -0,0 +1,17 @@
+module Gitlab
+ # This module provide 2 methods
+ # to set specific ENV variabled for GitLab Shell
+ module ShellEnv
+ extend self
+
+ def set_env(user)
+ # Set GL_ID env variable
+ ENV['GL_ID'] = "user-#{user.id}"
+ end
+
+ def reset_env
+ # Reset GL_ID env variable
+ ENV['GL_ID'] = nil
+ end
+ end
+end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 483042205ea..5eeb7c80184 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -10,6 +10,10 @@ module Gitlab
/\A[a-zA-Z][a-zA-Z0-9_\-\. ]*\z/
end
+ def name_regex
+ /\A[a-zA-Z0-9_\-\. ]*\z/
+ end
+
def path_regex
default_regex
end
diff --git a/lib/gitlab/satellite/action.rb b/lib/gitlab/satellite/action.rb
index ed2541f3998..63303ca3de1 100644
--- a/lib/gitlab/satellite/action.rb
+++ b/lib/gitlab/satellite/action.rb
@@ -17,6 +17,8 @@ module Gitlab
# * Locks the satellite repo
# * Yields the prepared satellite repo
def in_locked_and_timed_satellite
+ Gitlab::ShellEnv.set_env(user)
+
Grit::Git.with_timeout(options[:git_timeout]) do
project.satellite.lock do
return yield project.satellite.repo
@@ -28,6 +30,8 @@ module Gitlab
rescue Grit::Git::GitTimeout => ex
Gitlab::GitLogger.error(ex.message)
return false
+ ensure
+ Gitlab::ShellEnv.reset_env
end
# * Clears the satellite
diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake
index c44016ef6e8..091de6ee6d5 100644
--- a/lib/tasks/gitlab/info.rake
+++ b/lib/tasks/gitlab/info.rake
@@ -40,8 +40,8 @@ namespace :gitlab do
puts ""
puts "GitLab information".yellow
- puts "Version:\t#{Gitlab::Version}"
- puts "Revision:\t#{Gitlab::Revision}"
+ puts "Version:\t#{Gitlab::VERSION}"
+ puts "Revision:\t#{Gitlab::REVISION}"
puts "Directory:\t#{Rails.root}"
puts "DB Adapter:\t#{database_adapter}"
puts "URL:\t\t#{Gitlab.config.gitlab.url}"
diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake
index bc0742564d0..8d4950cf396 100644
--- a/lib/tasks/gitlab/setup.rake
+++ b/lib/tasks/gitlab/setup.rake
@@ -1,10 +1,10 @@
namespace :gitlab do
desc "GITLAB | Setup production application"
task :setup => :environment do
- setup
+ setup_db
end
- def setup
+ def setup_db
warn_user_is_not_gitlab
puts "This will create the necessary database tables and seed the database."
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index 0ab8df1d094..ec5451dd47c 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -25,12 +25,13 @@ namespace :gitlab do
def setup
warn_user_is_not_gitlab
+ gitlab_shell_authorized_keys = File.join(File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}"),'.ssh/authorized_keys')
puts "This will rebuild an authorized_keys file."
- puts "You will lose any data stored in /home/git/.ssh/authorized_keys."
+ puts "You will lose any data stored in #{gitlab_shell_authorized_keys}."
ask_to_continue
puts ""
- system("echo '# Managed by gitlab-shell' > /home/git/.ssh/authorized_keys")
+ system("echo '# Managed by gitlab-shell' > #{gitlab_shell_authorized_keys}")
Key.find_each(batch_size: 1000) do |key|
if Gitlab::Shell.new.add_key(key.shell_id, key.key)
diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake
index d494125f76c..cb4e34cc0d7 100644
--- a/lib/tasks/gitlab/task_helpers.rake
+++ b/lib/tasks/gitlab/task_helpers.rake
@@ -77,8 +77,7 @@ namespace :gitlab do
end
def gid_for(group_name)
- group_line = File.read("/etc/group").lines.select{|l| l.start_with?("#{group_name}:")}.first
- group_line.split(":")[2].to_i
+ Etc.getgrnam(group_name).gid
end
def warn_user_is_not_gitlab
diff --git a/public/deploy.html b/public/deploy.html
index d8c287809ea..d9c4bb5c583 100644
--- a/public/deploy.html
+++ b/public/deploy.html
@@ -5,7 +5,7 @@
<link href="/static.css" media="screen" rel="stylesheet" type="text/css" />
</head>
<body>
- <h1>Deploy in progress</h1>
+ <h1><center><img src="/gitlab_logo.png"/></center>Deploy in progress</h1>
<h3>Please try again in few minutes or contact your administrator.</h3>
</body>
</html>
diff --git a/public/gitlab_logo.png b/public/gitlab_logo.png
new file mode 100644
index 00000000000..e3cda5978ab
--- /dev/null
+++ b/public/gitlab_logo.png
Binary files differ
diff --git a/spec/factories.rb b/spec/factories.rb
index d2e9f48c47b..b81984b5d53 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -54,10 +54,15 @@ FactoryGirl.define do
project
trait :closed do
- closed true
+ state :closed
+ end
+
+ trait :reopened do
+ state :reopened
end
factory :closed_issue, traits: [:closed]
+ factory :reopened_issue, traits: [:reopened]
end
factory :merge_request do
@@ -67,10 +72,6 @@ FactoryGirl.define do
source_branch "master"
target_branch "stable"
- trait :closed do
- closed true
- end
-
# pick 3 commits "at random" (from bcf03b5d~3 to bcf03b5d)
trait :with_diffs do
target_branch "master" # pretend bcf03b5d~3
@@ -85,7 +86,16 @@ FactoryGirl.define do
end
end
+ trait :closed do
+ state :closed
+ end
+
+ trait :reopened do
+ state :reopened
+ end
+
factory :closed_merge_request, traits: [:closed]
+ factory :reopened_merge_request, traits: [:reopened]
factory :merge_request_with_diffs, traits: [:with_diffs]
end
@@ -148,11 +158,23 @@ FactoryGirl.define do
"ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa ++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
end
end
+
+ factory :invalid_key do
+ key do
+ "ssh-rsa this_is_invalid_key=="
+ end
+ end
end
factory :milestone do
title
project
+
+ trait :closed do
+ state :closed
+ end
+
+ factory :closed_milestone, traits: [:closed]
end
factory :system_hook do
diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb
index 5ee7354688a..8360477d8fe 100644
--- a/spec/factories_spec.rb
+++ b/spec/factories_spec.rb
@@ -1,6 +1,9 @@
require 'spec_helper'
-INVALID_FACTORIES = [:key_with_a_space_in_the_middle]
+INVALID_FACTORIES = [
+ :key_with_a_space_in_the_middle,
+ :invalid_key,
+]
FactoryGirl.factories.map(&:name).each do |factory_name|
next if INVALID_FACTORIES.include?(factory_name)
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index b5d4bd7b406..551e1753be0 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -15,7 +15,6 @@ describe Issue, "Issuable" do
it { should validate_presence_of(:author) }
it { should validate_presence_of(:title) }
it { should ensure_length_of(:title).is_at_least(0).is_at_most(255) }
- it { should ensure_inclusion_of(:closed).in_array([true, false]) }
end
describe "Scope" do
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 10db53e0745..99d9f65b0d7 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -9,7 +9,7 @@
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
-# closed :boolean default(FALSE), not null
+# state :string default(FALSE), not null
# position :integer default(0)
# branch_name :string(255)
# description :text
@@ -44,34 +44,15 @@ describe Issue do
end
end
- describe '#is_being_closed?' do
- it 'returns true if the closed attribute has changed and is now true' do
- subject.closed = true
- subject.is_being_closed?.should be_true
- end
- it 'returns false if the closed attribute has changed and is now false' do
- issue = create(:closed_issue)
- issue.closed = false
- issue.is_being_closed?.should be_false
- end
- it 'returns false if the closed attribute has not changed' do
- subject.is_being_closed?.should be_false
- end
- end
+ describe '#is_being_reassigned?' do
+ it 'returnes issues assigned to user' do
+ user = create :user
+ 2.times do
+ issue = create :issue, assignee: user
+ end
- describe '#is_being_reopened?' do
- it 'returns true if the closed attribute has changed and is now false' do
- issue = create(:closed_issue)
- issue.closed = false
- issue.is_being_reopened?.should be_true
- end
- it 'returns false if the closed attribute has changed and is now true' do
- subject.closed = true
- subject.is_being_reopened?.should be_false
- end
- it 'returns false if the closed attribute has not changed' do
- subject.is_being_reopened?.should be_false
+ Issue.open_for(user).count.should eq 2
end
end
end
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index 94b952cf932..a9ab2f05a34 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -73,8 +73,12 @@ describe Key do
build(:key, user: user).should be_valid
end
- it "rejects the unfingerprintable key" do
+ it "rejects the unfingerprintable key (contains space in middle)" do
build(:key_with_a_space_in_the_middle).should_not be_valid
end
+
+ it "rejects the unfingerprintable key (not a key)" do
+ build(:invalid_key).should_not be_valid
+ end
end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 41f4ede5d89..e61bf44ce53 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -15,7 +15,7 @@
# st_commits :text(2147483647)
# st_diffs :text(2147483647)
# merged :boolean default(FALSE), not null
-# state :integer default(1), not null
+# merge_status :integer default(1), not null
# milestone_id :integer
#
@@ -37,6 +37,10 @@ describe MergeRequest do
end
describe "#mr_and_commit_notes" do
+
+ end
+
+ describe "#mr_and_commit_notes" do
let!(:merge_request) { create(:merge_request) }
before do
@@ -62,35 +66,4 @@ describe MergeRequest do
subject.is_being_reassigned?.should be_false
end
end
-
- describe '#is_being_closed?' do
- it 'returns true if the closed attribute has changed and is now true' do
- subject.closed = true
- subject.is_being_closed?.should be_true
- end
- it 'returns false if the closed attribute has changed and is now false' do
- merge_request = create(:closed_merge_request)
- merge_request.closed = false
- merge_request.is_being_closed?.should be_false
- end
- it 'returns false if the closed attribute has not changed' do
- subject.is_being_closed?.should be_false
- end
- end
-
-
- describe '#is_being_reopened?' do
- it 'returns true if the closed attribute has changed and is now false' do
- merge_request = create(:closed_merge_request)
- merge_request.closed = false
- merge_request.is_being_reopened?.should be_true
- end
- it 'returns false if the closed attribute has changed and is now true' do
- subject.closed = true
- subject.is_being_reopened?.should be_false
- end
- it 'returns false if the closed attribute has not changed' do
- subject.is_being_reopened?.should be_false
- end
- end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 2ea2c56a6f7..b473f843146 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -7,7 +7,7 @@
# project_id :integer not null
# description :text
# due_date :date
-# closed :boolean default(FALSE), not null
+# state :string default(FALSE), not null
# created_at :datetime not null
# updated_at :datetime not null
#
@@ -27,7 +27,6 @@ describe Milestone do
describe "Validation" do
it { should validate_presence_of(:title) }
it { should validate_presence_of(:project) }
- it { should ensure_inclusion_of(:closed).in_array([true, false]) }
end
let(:milestone) { create(:milestone) }
@@ -41,7 +40,7 @@ describe Milestone do
it "should count closed issues" do
IssueObserver.current_user = issue.author
- issue.update_attributes(closed: true)
+ issue.close
milestone.issues << issue
milestone.percent_complete.should == 100
end
@@ -96,7 +95,7 @@ describe Milestone do
describe :items_count do
before do
milestone.issues << create(:issue)
- milestone.issues << create(:issue, closed: true)
+ milestone.issues << create(:closed_issue)
milestone.merge_requests << create(:merge_request)
end
@@ -110,7 +109,35 @@ describe Milestone do
it { milestone.can_be_closed?.should be_true }
end
- describe :open? do
- it { milestone.open?.should be_true }
+ describe :is_empty? do
+ before do
+ issue = create :closed_issue, milestone: milestone
+ merge_request = create :merge_request, milestone: milestone
+ end
+
+ it 'Should return total count of issues and merge requests assigned to milestone' do
+ milestone.total_items_count.should eq 2
+ end
+ end
+
+ describe :can_be_closed? do
+ before do
+ milestone = create :milestone
+ create :closed_issue, milestone: milestone
+
+ issue = create :issue
+ end
+
+ it 'should be true if milestone active and all nestied issues closed' do
+ milestone.can_be_closed?.should be_true
+ end
+
+ it 'should be false if milestone active and not all nestied issues closed' do
+ issue.milestone = milestone
+ issue.save
+
+ milestone.can_be_closed?.should be_false
+ end
end
+
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 4b620a2fa3e..5c27f363401 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -121,10 +121,7 @@ describe Project do
let(:project) { create(:project) }
before do
- @merge_request = create(:merge_request,
- project: project,
- merged: false,
- closed: false)
+ @merge_request = create(:merge_request, project: project)
@key = create(:key, user_id: project.owner.id)
end
@@ -133,8 +130,7 @@ describe Project do
@merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a", "refs/heads/stable", @key.user)
@merge_request.reload
- @merge_request.merged.should be_true
- @merge_request.closed.should be_true
+ @merge_request.merged?.should be_true
end
it "should update merge request commits with new one if pushed to source branch" do
diff --git a/spec/observers/issue_observer_spec.rb b/spec/observers/issue_observer_spec.rb
index 700c9a3a69b..e4e66917e8a 100644
--- a/spec/observers/issue_observer_spec.rb
+++ b/spec/observers/issue_observer_spec.rb
@@ -1,10 +1,15 @@
require 'spec_helper'
describe IssueObserver do
- let(:some_user) { double(:user, id: 1) }
- let(:assignee) { double(:user, id: 2) }
- let(:author) { double(:user, id: 3) }
- let(:issue) { double(:issue, id: 42, assignee: assignee, author: author) }
+ let(:some_user) { create :user }
+ let(:assignee) { create :user }
+ let(:author) { create :user }
+ let(:mock_issue) { double(:issue, id: 42, assignee: assignee, author: author) }
+ let(:assigned_issue) { create(:issue, assignee: assignee, author: author) }
+ let(:unassigned_issue) { create(:issue, author: author) }
+ let(:closed_assigned_issue) { create(:closed_issue, assignee: assignee, author: author) }
+ let(:closed_unassigned_issue) { create(:closed_issue, author: author) }
+
before(:each) { subject.stub(:current_user).and_return(some_user) }
@@ -21,137 +26,91 @@ describe IssueObserver do
end
it 'sends an email to the assignee' do
- Notify.should_receive(:new_issue_email).with(issue.id)
+ Notify.should_receive(:new_issue_email).with(mock_issue.id)
- subject.after_create(issue)
+ subject.after_create(mock_issue)
end
it 'does not send an email to the assignee if assignee created the issue' do
subject.stub(:current_user).and_return(assignee)
Notify.should_not_receive(:new_issue_email)
- subject.after_create(issue)
+ subject.after_create(mock_issue)
end
end
- context '#after_update' do
- before(:each) do
- issue.stub(:is_being_reassigned?).and_return(false)
- issue.stub(:is_being_closed?).and_return(false)
- issue.stub(:is_being_reopened?).and_return(false)
- end
-
- it 'is called when an issue is changed' do
- changed = create(:issue, project: create(:project))
- subject.should_receive(:after_update)
-
- Issue.observers.enable :issue_observer do
- changed.description = 'I changed'
- changed.save
- end
- end
-
- context 'a reassigned email' do
- it 'is sent if the issue is being reassigned' do
- issue.should_receive(:is_being_reassigned?).and_return(true)
- subject.should_receive(:send_reassigned_email).with(issue)
-
- subject.after_update(issue)
- end
-
- it 'is not sent if the issue is not being reassigned' do
- issue.should_receive(:is_being_reassigned?).and_return(false)
- subject.should_not_receive(:send_reassigned_email)
-
- subject.after_update(issue)
- end
- end
-
+ context '#after_close' do
context 'a status "closed"' do
it 'note is created if the issue is being closed' do
- issue.should_receive(:is_being_closed?).and_return(true)
- Notify.should_receive(:issue_status_changed_email).twice
- Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed')
-
- subject.after_update(issue)
- end
-
- it 'note is not created if the issue is not being closed' do
- issue.should_receive(:is_being_closed?).and_return(false)
- Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed')
+ Note.should_receive(:create_status_change_note).with(assigned_issue, some_user, 'closed')
- subject.after_update(issue)
+ assigned_issue.close
end
it 'notification is delivered if the issue being closed' do
- issue.stub(:is_being_closed?).and_return(true)
Notify.should_receive(:issue_status_changed_email).twice
- Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed')
- subject.after_update(issue)
- end
-
- it 'notification is not delivered if the issue not being closed' do
- issue.stub(:is_being_closed?).and_return(false)
- Notify.should_not_receive(:issue_status_changed_email)
- Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed')
-
- subject.after_update(issue)
+ assigned_issue.close
end
it 'notification is delivered only to author if the issue being closed' do
- issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil)
- issue_without_assignee.stub(:is_being_reassigned?).and_return(false)
- issue_without_assignee.stub(:is_being_closed?).and_return(true)
- issue_without_assignee.stub(:is_being_reopened?).and_return(false)
Notify.should_receive(:issue_status_changed_email).once
- Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'closed')
+ Note.should_receive(:create_status_change_note).with(unassigned_issue, some_user, 'closed')
- subject.after_update(issue_without_assignee)
+ unassigned_issue.close
end
end
context 'a status "reopened"' do
it 'note is created if the issue is being reopened' do
+ Note.should_receive(:create_status_change_note).with(closed_assigned_issue, some_user, 'reopened')
+
+ closed_assigned_issue.reopen
+ end
+
+ it 'notification is delivered if the issue being reopened' do
Notify.should_receive(:issue_status_changed_email).twice
- issue.should_receive(:is_being_reopened?).and_return(true)
- Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened')
- subject.after_update(issue)
+ closed_assigned_issue.reopen
end
- it 'note is not created if the issue is not being reopened' do
- issue.should_receive(:is_being_reopened?).and_return(false)
- Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened')
+ it 'notification is delivered only to author if the issue being reopened' do
+ Notify.should_receive(:issue_status_changed_email).once
+ Note.should_receive(:create_status_change_note).with(closed_unassigned_issue, some_user, 'reopened')
- subject.after_update(issue)
+ closed_unassigned_issue.reopen
end
+ end
+ end
- it 'notification is delivered if the issue being reopened' do
- issue.stub(:is_being_reopened?).and_return(true)
- Notify.should_receive(:issue_status_changed_email).twice
- Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened')
+ context '#after_update' do
+ before(:each) do
+ mock_issue.stub(:is_being_reassigned?).and_return(false)
+ end
+
+ it 'is called when an issue is changed' do
+ changed = create(:issue, project: create(:project))
+ subject.should_receive(:after_update)
- subject.after_update(issue)
+ Issue.observers.enable :issue_observer do
+ changed.description = 'I changed'
+ changed.save
end
+ end
- it 'notification is not delivered if the issue not being reopened' do
- issue.stub(:is_being_reopened?).and_return(false)
- Notify.should_not_receive(:issue_status_changed_email)
- Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened')
+ context 'a reassigned email' do
+ it 'is sent if the issue is being reassigned' do
+ mock_issue.should_receive(:is_being_reassigned?).and_return(true)
+ subject.should_receive(:send_reassigned_email).with(mock_issue)
- subject.after_update(issue)
+ subject.after_update(mock_issue)
end
- it 'notification is delivered only to author if the issue being reopened' do
- issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil)
- issue_without_assignee.stub(:is_being_reassigned?).and_return(false)
- issue_without_assignee.stub(:is_being_closed?).and_return(false)
- issue_without_assignee.stub(:is_being_reopened?).and_return(true)
- Notify.should_receive(:issue_status_changed_email).once
- Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'reopened')
+ it 'is not sent if the issue is not being reassigned' do
+ mock_issue.should_receive(:is_being_reassigned?).and_return(false)
+ subject.should_not_receive(:send_reassigned_email)
- subject.after_update(issue_without_assignee)
+ subject.after_update(mock_issue)
end
end
end
@@ -160,23 +119,23 @@ describe IssueObserver do
let(:previous_assignee) { double(:user, id: 3) }
before(:each) do
- issue.stub(:assignee_id).and_return(assignee.id)
- issue.stub(:assignee_id_was).and_return(previous_assignee.id)
+ mock_issue.stub(:assignee_id).and_return(assignee.id)
+ mock_issue.stub(:assignee_id_was).and_return(previous_assignee.id)
end
def it_sends_a_reassigned_email_to(recipient)
- Notify.should_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id)
+ Notify.should_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id)
end
def it_does_not_send_a_reassigned_email_to(recipient)
- Notify.should_not_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id)
+ Notify.should_not_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id)
end
it 'sends a reassigned email to the previous and current assignees' do
it_sends_a_reassigned_email_to assignee.id
it_sends_a_reassigned_email_to previous_assignee.id
- subject.send(:send_reassigned_email, issue)
+ subject.send(:send_reassigned_email, mock_issue)
end
context 'does not send an email to the user who made the reassignment' do
@@ -185,14 +144,14 @@ describe IssueObserver do
it_sends_a_reassigned_email_to previous_assignee.id
it_does_not_send_a_reassigned_email_to assignee.id
- subject.send(:send_reassigned_email, issue)
+ subject.send(:send_reassigned_email, mock_issue)
end
it 'if the user is the previous assignee' do
subject.stub(:current_user).and_return(previous_assignee)
it_sends_a_reassigned_email_to assignee.id
it_does_not_send_a_reassigned_email_to previous_assignee.id
- subject.send(:send_reassigned_email, issue)
+ subject.send(:send_reassigned_email, mock_issue)
end
end
end
diff --git a/spec/observers/merge_request_observer_spec.rb b/spec/observers/merge_request_observer_spec.rb
index 4841bf88fc5..9d702107a89 100644
--- a/spec/observers/merge_request_observer_spec.rb
+++ b/spec/observers/merge_request_observer_spec.rb
@@ -1,10 +1,14 @@
require 'spec_helper'
describe MergeRequestObserver do
- let(:some_user) { double(:user, id: 1) }
- let(:assignee) { double(:user, id: 2) }
- let(:author) { double(:user, id: 3) }
- let(:mr) { double(:merge_request, id: 42, assignee: assignee, author: author) }
+ let(:some_user) { create :user }
+ let(:assignee) { create :user }
+ let(:author) { create :user }
+ let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author) }
+ let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author) }
+ let(:unassigned_mr) { create(:merge_request, author: author) }
+ let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author) }
+ let(:closed_unassigned_mr) { create(:closed_merge_request, author: author) }
before(:each) { subject.stub(:current_user).and_return(some_user) }
@@ -21,23 +25,21 @@ describe MergeRequestObserver do
end
it 'sends an email to the assignee' do
- Notify.should_receive(:new_merge_request_email).with(mr.id)
- subject.after_create(mr)
+ Notify.should_receive(:new_merge_request_email).with(mr_mock.id)
+ subject.after_create(mr_mock)
end
it 'does not send an email to the assignee if assignee created the merge request' do
subject.stub(:current_user).and_return(assignee)
Notify.should_not_receive(:new_merge_request_email)
- subject.after_create(mr)
+ subject.after_create(mr_mock)
end
end
context '#after_update' do
before(:each) do
- mr.stub(:is_being_reassigned?).and_return(false)
- mr.stub(:is_being_closed?).and_return(false)
- mr.stub(:is_being_reopened?).and_return(false)
+ mr_mock.stub(:is_being_reassigned?).and_return(false)
end
it 'is called when a merge request is changed' do
@@ -52,97 +54,50 @@ describe MergeRequestObserver do
context 'a reassigned email' do
it 'is sent if the merge request is being reassigned' do
- mr.should_receive(:is_being_reassigned?).and_return(true)
- subject.should_receive(:send_reassigned_email).with(mr)
+ mr_mock.should_receive(:is_being_reassigned?).and_return(true)
+ subject.should_receive(:send_reassigned_email).with(mr_mock)
- subject.after_update(mr)
+ subject.after_update(mr_mock)
end
it 'is not sent if the merge request is not being reassigned' do
- mr.should_receive(:is_being_reassigned?).and_return(false)
+ mr_mock.should_receive(:is_being_reassigned?).and_return(false)
subject.should_not_receive(:send_reassigned_email)
- subject.after_update(mr)
+ subject.after_update(mr_mock)
end
end
+ end
+
+ context '#after_close' do
context 'a status "closed"' do
it 'note is created if the merge request is being closed' do
- mr.should_receive(:is_being_closed?).and_return(true)
- Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed')
-
- subject.after_update(mr)
- end
-
- it 'note is not created if the merge request is not being closed' do
- mr.should_receive(:is_being_closed?).and_return(false)
- Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed')
-
- subject.after_update(mr)
- end
-
- it 'notification is delivered if the merge request being closed' do
- mr.stub(:is_being_closed?).and_return(true)
- Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed')
-
- subject.after_update(mr)
- end
-
- it 'notification is not delivered if the merge request not being closed' do
- mr.stub(:is_being_closed?).and_return(false)
- Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed')
+ Note.should_receive(:create_status_change_note).with(assigned_mr, some_user, 'closed')
- subject.after_update(mr)
+ assigned_mr.close
end
it 'notification is delivered only to author if the merge request is being closed' do
- mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil)
- mr_without_assignee.stub(:is_being_reassigned?).and_return(false)
- mr_without_assignee.stub(:is_being_closed?).and_return(true)
- mr_without_assignee.stub(:is_being_reopened?).and_return(false)
- Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'closed')
+ Note.should_receive(:create_status_change_note).with(unassigned_mr, some_user, 'closed')
- subject.after_update(mr_without_assignee)
+ unassigned_mr.close
end
end
+ end
+ context '#after_reopen' do
context 'a status "reopened"' do
it 'note is created if the merge request is being reopened' do
- mr.should_receive(:is_being_reopened?).and_return(true)
- Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened')
-
- subject.after_update(mr)
- end
-
- it 'note is not created if the merge request is not being reopened' do
- mr.should_receive(:is_being_reopened?).and_return(false)
- Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened')
-
- subject.after_update(mr)
- end
-
- it 'notification is delivered if the merge request being reopened' do
- mr.stub(:is_being_reopened?).and_return(true)
- Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened')
-
- subject.after_update(mr)
- end
-
- it 'notification is not delivered if the merge request is not being reopened' do
- mr.stub(:is_being_reopened?).and_return(false)
- Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened')
+ Note.should_receive(:create_status_change_note).with(closed_assigned_mr, some_user, 'reopened')
- subject.after_update(mr)
+ closed_assigned_mr.reopen
end
it 'notification is delivered only to author if the merge request is being reopened' do
- mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil)
- mr_without_assignee.stub(:is_being_reassigned?).and_return(false)
- mr_without_assignee.stub(:is_being_closed?).and_return(false)
- mr_without_assignee.stub(:is_being_reopened?).and_return(true)
- Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'reopened')
+ Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, some_user, 'reopened')
- subject.after_update(mr_without_assignee)
+ closed_unassigned_mr.reopen
end
end
end
@@ -151,23 +106,23 @@ describe MergeRequestObserver do
let(:previous_assignee) { double(:user, id: 3) }
before(:each) do
- mr.stub(:assignee_id).and_return(assignee.id)
- mr.stub(:assignee_id_was).and_return(previous_assignee.id)
+ mr_mock.stub(:assignee_id).and_return(assignee.id)
+ mr_mock.stub(:assignee_id_was).and_return(previous_assignee.id)
end
def it_sends_a_reassigned_email_to(recipient)
- Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id)
+ Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id)
end
def it_does_not_send_a_reassigned_email_to(recipient)
- Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id)
+ Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id)
end
it 'sends a reassigned email to the previous and current assignees' do
it_sends_a_reassigned_email_to assignee.id
it_sends_a_reassigned_email_to previous_assignee.id
- subject.send(:send_reassigned_email, mr)
+ subject.send(:send_reassigned_email, mr_mock)
end
context 'does not send an email to the user who made the reassignment' do
@@ -176,14 +131,14 @@ describe MergeRequestObserver do
it_sends_a_reassigned_email_to previous_assignee.id
it_does_not_send_a_reassigned_email_to assignee.id
- subject.send(:send_reassigned_email, mr)
+ subject.send(:send_reassigned_email, mr_mock)
end
it 'if the user is the previous assignee' do
subject.stub(:current_user).and_return(previous_assignee)
it_sends_a_reassigned_email_to assignee.id
it_does_not_send_a_reassigned_email_to previous_assignee.id
- subject.send(:send_reassigned_email, mr)
+ subject.send(:send_reassigned_email, mr_mock)
end
end
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 781ebab026b..630ac0f820a 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -54,14 +54,24 @@ describe Gitlab::API do
end
end
- describe "PUT /projects/:id/issues/:issue_id" do
+ describe "PUT /projects/:id/issues/:issue_id to update only title" do
it "should update a project issue" do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
- title: 'updated title', labels: 'label2', closed: 1
+ title: 'updated title'
response.status.should == 200
+
json_response['title'].should == 'updated title'
+ end
+ end
+
+ describe "PUT /projects/:id/issues/:issue_id to update state and label" do
+ it "should update a project issue" do
+ put api("/projects/#{project.id}/issues/#{issue.id}", user),
+ labels: 'label2', state_event: "close"
+ response.status.should == 200
+
json_response['labels'].should == ['label2']
- json_response['closed'].should be_true
+ json_response['state'].should eq "closed"
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 431aae7cc11..8de06c33394 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -66,6 +66,23 @@ describe Gitlab::API do
end
end
+ describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do
+ it "should return merge_request" do
+ put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "close"
+ response.status.should == 200
+ json_response['state'].should == 'closed'
+ end
+ end
+
+ describe "PUT /projects/:id/merge_request/:merge_request_id to merge MR" do
+ it "should return merge_request" do
+ put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "merge"
+ response.status.should == 200
+ json_response['state'].should == 'merged'
+ end
+ end
+
+
describe "PUT /projects/:id/merge_request/:merge_request_id" do
it "should return merge_request" do
put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title"
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index 3cab63557a9..00e800e8b91 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -68,4 +68,14 @@ describe Gitlab::API do
response.status.should == 404
end
end
+
+ describe "PUT /projects/:id/milestones/:milestone_id to close milestone" do
+ it "should update a project milestone" do
+ put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
+ state_event: 'close'
+ response.status.should == 200
+
+ json_response['state'].should == 'closed'
+ end
+ end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 486b63e74e5..06ab0f5e684 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -33,6 +33,20 @@ describe Gitlab::API do
end
describe "POST /projects" do
+ context "maximum number of projects reached" do
+ before do
+ (1..user2.projects_limit).each do |project|
+ post api("/projects", user2), name: "foo#{project}"
+ end
+ end
+
+ it "should not create new project" do
+ expect {
+ post api("/projects", user2), name: 'foo'
+ }.to change {Project.count}.by(0)
+ end
+ end
+
it "should create new project without path" do
expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1)
end
@@ -46,6 +60,12 @@ describe Gitlab::API do
response.status.should == 400
end
+ it "should create last project before reaching project limit" do
+ (1..user2.projects_limit-1).each { |p| post api("/projects", user2), name: "foo#{p}" }
+ post api("/projects", user2), name: "foo"
+ response.status.should == 201
+ end
+
it "should respond with 201 on success" do
post api("/projects", user), name: 'foo'
response.status.should == 201
@@ -314,22 +334,44 @@ describe Gitlab::API do
end
describe "GET /projects/:id/hooks" do
- it "should return project hooks" do
- get api("/projects/#{project.id}/hooks", user)
+ context "authorized user" do
+ it "should return project hooks" do
+ get api("/projects/#{project.id}/hooks", user)
+ response.status.should == 200
- response.status.should == 200
+ json_response.should be_an Array
+ json_response.count.should == 1
+ json_response.first['url'].should == "http://example.com"
+ end
+ end
- json_response.should be_an Array
- json_response.count.should == 1
- json_response.first['url'].should == "http://example.com"
+ context "unauthorized user" do
+ it "should not access project hooks" do
+ get api("/projects/#{project.id}/hooks", user3)
+ response.status.should == 403
+ end
end
end
describe "GET /projects/:id/hooks/:hook_id" do
- it "should return a project hook" do
- get api("/projects/#{project.id}/hooks/#{hook.id}", user)
- response.status.should == 200
- json_response['url'].should == hook.url
+ context "authorized user" do
+ it "should return a project hook" do
+ get api("/projects/#{project.id}/hooks/#{hook.id}", user)
+ response.status.should == 200
+ json_response['url'].should == hook.url
+ end
+
+ it "should return a 404 error if hook id is not available" do
+ get api("/projects/#{project.id}/hooks/1234", user)
+ response.status.should == 404
+ end
+ end
+
+ context "unauthorized user" do
+ it "should not access an existing hook" do
+ get api("/projects/#{project.id}/hooks/#{hook.id}", user3)
+ response.status.should == 403
+ end
end
it "should return a 404 error if hook id is not available" do
diff --git a/spec/requests/issues_spec.rb b/spec/requests/issues_spec.rb
index 2e94ffd0020..6fff59f036f 100644
--- a/spec/requests/issues_spec.rb
+++ b/spec/requests/issues_spec.rb
@@ -58,8 +58,7 @@ describe "Issues" do
it "should be able to search on different statuses" do
issue = Issue.first # with title 'foobar'
- issue.closed = true
- issue.save
+ issue.close
visit project_issues_path(project)
click_link 'Closed'