summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ruby-version1
-rw-r--r--CHANGELOG6
-rw-r--r--CONTRIBUTING.md4
-rw-r--r--Gemfile.lock8
-rw-r--r--PROCESS.md6
-rw-r--r--app/assets/javascripts/application.js.coffee7
-rw-r--r--app/assets/javascripts/behaviors/taskable.js.coffee21
-rw-r--r--app/assets/javascripts/confirm_danger_modal.js.coffee20
-rw-r--r--app/assets/javascripts/issue.js.coffee26
-rw-r--r--app/assets/javascripts/merge_request.js.coffee28
-rw-r--r--app/assets/stylesheets/generic/issue_box.scss4
-rw-r--r--app/assets/stylesheets/gl_bootstrap.scss40
-rw-r--r--app/assets/stylesheets/main/mixins.scss11
-rw-r--r--app/assets/stylesheets/main/variables.scss1
-rw-r--r--app/assets/stylesheets/sections/merge_requests.scss2
-rw-r--r--app/controllers/admin/users_controller.rb1
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb35
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/snippets_controller.rb7
-rw-r--r--app/controllers/snippets_controller.rb42
-rw-r--r--app/finders/README.md8
-rw-r--r--app/finders/snippets_finder.rb61
-rw-r--r--app/helpers/application_helper.rb8
-rw-r--r--app/helpers/commits_helper.rb4
-rw-r--r--app/helpers/dashboard_helper.rb33
-rw-r--r--app/helpers/events_helper.rb5
-rw-r--r--app/helpers/gitlab_markdown_helper.rb62
-rw-r--r--app/helpers/projects_helper.rb4
-rw-r--r--app/helpers/visibility_level_helper.rb17
-rw-r--r--app/models/commit.rb20
-rw-r--r--app/models/event.rb2
-rw-r--r--app/models/member.rb15
-rw-r--r--app/models/members/group_member.rb15
-rw-r--r--app/models/members/project_member.rb15
-rw-r--r--app/models/merge_request_diff.rb2
-rw-r--r--app/models/personal_snippet.rb22
-rw-r--r--app/models/project.rb3
-rw-r--r--app/models/project_services/assembla_service.rb16
-rw-r--r--app/models/project_services/buildbox_service.rb121
-rw-r--r--app/models/project_services/campfire_service.rb16
-rw-r--r--app/models/project_services/ci_service.rb16
-rw-r--r--app/models/project_services/emails_on_push_service.rb16
-rw-r--r--app/models/project_services/flowdock_service.rb16
-rw-r--r--app/models/project_services/gemnasium_service.rb16
-rw-r--r--app/models/project_services/gitlab_ci_service.rb16
-rw-r--r--app/models/project_services/hipchat_service.rb16
-rw-r--r--app/models/project_services/pivotaltracker_service.rb16
-rw-r--r--app/models/project_services/slack_service.rb16
-rw-r--r--app/models/project_snippet.rb22
-rw-r--r--app/models/project_team.rb4
-rw-r--r--app/models/repository.rb2
-rw-r--r--app/models/service.rb17
-rw-r--r--app/models/snippet.rb38
-rw-r--r--app/models/user.rb10
-rw-r--r--app/services/issuable_base_service.rb13
-rw-r--r--app/services/issues/base_service.rb10
-rw-r--r--app/services/issues/update_service.rb7
-rw-r--r--app/services/merge_requests/base_service.rb12
-rw-r--r--app/views/admin/users/index.html.haml20
-rw-r--r--app/views/events/_commit.html.haml2
-rw-r--r--app/views/events/_event_push.atom.haml2
-rw-r--r--app/views/events/event/_push.html.haml2
-rw-r--r--app/views/help/index.html.haml4
-rw-r--r--app/views/projects/blame/show.html.haml2
-rw-r--r--app/views/projects/commit/_commit_box.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/commits/_inline_commit.html.haml2
-rw-r--r--app/views/projects/edit.html.haml152
-rw-r--r--app/views/projects/issues/show.html.haml3
-rw-r--r--app/views/projects/protected_branches/index.html.haml6
-rw-r--r--app/views/projects/show.html.haml13
-rw-r--r--app/views/projects/tree/_submodule_item.html.haml4
-rw-r--r--app/views/projects/wikis/history.html.haml2
-rw-r--r--app/views/search/results/_note.html.haml2
-rw-r--r--app/views/shared/_confirm_modal.html.haml22
-rw-r--r--app/views/shared/_promo.html.haml4
-rw-r--r--app/views/shared/snippets/_form.html.haml18
-rw-r--r--app/views/shared/snippets/_visibility_level.html.haml27
-rw-r--r--app/views/snippets/current_user_index.html.haml5
-rw-r--r--app/views/snippets/index.html.haml10
-rw-r--r--app/views/snippets/user_index.html.haml5
-rw-r--r--db/migrate/20141007100818_add_visibility_level_to_snippet.rb21
-rw-r--r--db/schema.rb7
-rw-r--r--doc/development/architecture.md2
-rw-r--r--doc/install/installation.md4
-rw-r--r--doc/release/security.md4
-rw-r--r--doc/update/6.x-or-7.x-to-7.3.md3
-rw-r--r--doc/update/7.2-to-7.3.md3
-rw-r--r--doc/update/7.3-to-7.4.md68
-rw-r--r--features/admin/active_tab.feature2
-rw-r--r--features/project/issues/issues.feature2
-rw-r--r--features/project/merge_requests.feature3
-rw-r--r--features/project/source/browse_files.feature2
-rw-r--r--features/snippets/discover.feature2
-rw-r--r--features/snippets/user.feature13
-rw-r--r--features/steps/project/commits/commits.rb2
-rw-r--r--features/steps/project/issues/issues.rb22
-rw-r--r--features/steps/project/merge_requests.rb14
-rw-r--r--features/steps/shared/markdown.rb29
-rw-r--r--features/steps/shared/snippet.rb16
-rw-r--r--features/steps/snippets/discover.rb4
-rw-r--r--features/steps/snippets/user.rb14
-rw-r--r--lib/api/internal.rb13
-rw-r--r--lib/gitlab/git_access.rb43
-rw-r--r--lib/gitlab/git_access_wiki.rb7
-rw-r--r--lib/gitlab/ldap/user.rb75
-rw-r--r--lib/gitlab/markdown.rb18
-rw-r--r--lib/gitlab/oauth/auth_hash.rb2
-rw-r--r--lib/gitlab/oauth/user.rb71
-rw-r--r--lib/redcarpet/render/gitlab_html.rb12
-rw-r--r--lib/support/nginx/gitlab-ssl9
-rw-r--r--lib/tasks/gitlab/import.rake5
-rw-r--r--spec/features/projects_spec.rb8
-rw-r--r--spec/finders/snippets_finder_spec.rb94
-rw-r--r--spec/helpers/events_helper_spec.rb52
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb34
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb22
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb20
-rw-r--r--spec/lib/gitlab/oauth/auth_hash_spec.rb55
-rw-r--r--spec/lib/gitlab/oauth/user_spec.rb88
-rw-r--r--spec/models/assembla_service_spec.rb16
-rw-r--r--spec/models/buildbox_service_spec.rb73
-rw-r--r--spec/models/commit_spec.rb2
-rw-r--r--spec/models/flowdock_service_spec.rb16
-rw-r--r--spec/models/gemnasium_service_spec.rb16
-rw-r--r--spec/models/gitlab_ci_service_spec.rb16
-rw-r--r--spec/models/group_member_spec.rb8
-rw-r--r--spec/models/note_spec.rb4
-rw-r--r--spec/models/project_member_spec.rb10
-rw-r--r--spec/models/project_snippet_spec.rb22
-rw-r--r--spec/models/project_team_spec.rb4
-rw-r--r--spec/models/service_spec.rb16
-rw-r--r--spec/models/slack_service_spec.rb16
-rw-r--r--spec/models/snippet_spec.rb22
-rw-r--r--spec/models/user_spec.rb28
-rw-r--r--spec/support/mentionable_shared_examples.rb11
136 files changed, 1676 insertions, 764 deletions
diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 00000000000..ac2cdeba013
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+2.1.3
diff --git a/CHANGELOG b/CHANGELOG
index 7e6e0f5f64b..c98d21f9865 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -20,6 +20,12 @@ v 7.4.0
- Add select field type for services options (Sullivan Senechal)
- Add cross-project references to the Markdown parser (Vinnie Okada)
- Add task lists to issue and merge request descriptions (Vinnie Okada)
+ - Snippets can be public, internal or private
+ - Improve danger zone: ask project path to confirm data-loss action
+ - Raise exception on forgery
+ - Show build coverage in Merge Requests (requires GitLab CI v5.1)
+ - New milestone and label links on issue edit form
+ - Improved repository graphs
v 7.3.2
- Fix creating new file via web editor
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3d1e8270f46..ed49080d57a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,7 +10,7 @@ By submitting code as an individual you agree to the [individual contributor lic
## Security vulnerability disclosure
-Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](http://www.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
+Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](http://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
## Closing policy for issues and merge requests
@@ -22,7 +22,7 @@ Issues and merge requests should be in English and contain appropriate language
## Issue tracker
-To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from [GitLab.com](http://www.gitlab.com/).
+To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://about.gitlab.com/subscription/) and [consulting services](http://about.gitlab.com/consultancy/) are available from [GitLab.com](http://about.gitlab.com/).
The [issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues) is only for obvious errors in the latest [stable or development release of GitLab](MAINTENANCE.md). If something is wrong but it is not a regression compared to older versions of GitLab please do not open an issue but a feature request. When submitting an issue please conform to the issue submission guidelines listed below. Not all issues will be addressed and your issue is more likely to be addressed if you submit a merge request which partially or fully addresses the issue.
diff --git a/Gemfile.lock b/Gemfile.lock
index babb23ed606..0e82f14ca9d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -168,7 +168,7 @@ GEM
multi_json
gitlab-grack (2.0.0.pre)
rack (~> 1.5.1)
- gitlab-grit (2.6.11)
+ gitlab-grit (2.6.12)
charlock_holmes (~> 0.6)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
@@ -241,9 +241,11 @@ GEM
html-pipeline (1.11.0)
activesupport (>= 2)
nokogiri (~> 1.4)
- html-pipeline-gitlab (0.1.0)
- gitlab_emoji (~> 0.0.1.1)
+ html-pipeline-gitlab (0.1.5)
+ actionpack (~> 4)
+ gitlab_emoji (~> 0.0.1)
html-pipeline (~> 1.11.0)
+ sanitize (~> 2.1)
http_parser.rb (0.5.3)
httparty (0.13.0)
json (~> 1.8)
diff --git a/PROCESS.md b/PROCESS.md
index c3a787662f7..1dd28d6b670 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -18,7 +18,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
- Responds to merge requests the issue team mentions them in and monitors for new merge requests
- Provides feedback to the merge request submitter to improve the merge request (style, tests, etc.)
- Mark merge requests 'ready-for-merge' when they meet the contribution guidelines
-- Mention developer(s) based on the [list of members and their specialities](https://www.gitlab.com/core-team/)
+- Mention developer(s) based on the [list of members and their specialities](https://about.gitlab.com/core-team/)
- Closes merge requests with no feedback from the reporter for two weeks
## Priorities of the issue team
@@ -30,7 +30,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
## Mentioning people
-The most important thing is making sure valid issues receive feedback from the development team. Therefore the priority is mentioning developers that can help on those issue. Please select someone with relevant experience from [GitLab core team](https://www.gitlab.com/core-team/). If there is nobody mentioned with that expertise look in the commit history for the affected files to find someone. Avoid mentioning the lead developer, this is the person that is least likely to give a timely response. If the involvement of the lead developer is needed the other core team members will mention this person.
+The most important thing is making sure valid issues receive feedback from the development team. Therefore the priority is mentioning developers that can help on those issue. Please select someone with relevant experience from [GitLab core team](https://about.gitlab.com/core-team/). If there is nobody mentioned with that expertise look in the commit history for the affected files to find someone. Avoid mentioning the lead developer, this is the person that is least likely to give a timely response. If the involvement of the lead developer is needed the other core team members will mention this person.
## Workflow labels
@@ -79,7 +79,7 @@ Thanks for the issue report but we only support issues for the latest stable ver
### Support requests and configuration questions
-Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the #gitlab IRC channel on Freenode or the http://www.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
+Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the #gitlab IRC channel on Freenode or the http://about.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
### Code format
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index a1a4dc8e24f..ff0d0bb32b9 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -177,6 +177,13 @@ $ ->
$(@).closest(".diff-file").find(".notes_holder").toggle()
e.preventDefault()
+ $(document).on "click", '.js-confirm-danger', (e) ->
+ e.preventDefault()
+ btn = $(e.target)
+ text = btn.data("confirm-danger-message")
+ form = btn.closest("form")
+ new ConfirmDangerModal(form, text)
+
(($) ->
# Disable an element and add the 'disabled' Bootstrap class
$.fn.extend disable: ->
diff --git a/app/assets/javascripts/behaviors/taskable.js.coffee b/app/assets/javascripts/behaviors/taskable.js.coffee
new file mode 100644
index 00000000000..ddce71c1886
--- /dev/null
+++ b/app/assets/javascripts/behaviors/taskable.js.coffee
@@ -0,0 +1,21 @@
+window.updateTaskState = (taskableType) ->
+ objType = taskableType.data
+ isChecked = $(this).prop("checked")
+ if $(this).is(":checked")
+ stateEvent = "task_check"
+ else
+ stateEvent = "task_uncheck"
+
+ taskableUrl = $("form.edit-" + objType).first().attr("action")
+ taskableNum = taskableUrl.match(/\d+$/)
+ taskNum = 0
+ $("li.task-list-item input:checkbox").each( (index, e) =>
+ if e == this
+ taskNum = index + 1
+ )
+
+ $.ajax
+ type: "PATCH"
+ url: taskableUrl
+ data: objType + "[state_event]=" + stateEvent +
+ "&" + objType + "[task_num]=" + taskNum
diff --git a/app/assets/javascripts/confirm_danger_modal.js.coffee b/app/assets/javascripts/confirm_danger_modal.js.coffee
new file mode 100644
index 00000000000..1687b7d961c
--- /dev/null
+++ b/app/assets/javascripts/confirm_danger_modal.js.coffee
@@ -0,0 +1,20 @@
+class ConfirmDangerModal
+ constructor: (form, text) ->
+ @form = form
+ $('.js-confirm-text').text(text || '')
+ $('.js-confirm-danger-input').val('')
+ $('#modal-confirm-danger').modal('show')
+ project_path = $('.js-confirm-danger-match').text()
+ submit = $('.js-confirm-danger-submit')
+ submit.disable()
+
+ $('.js-confirm-danger-input').on 'input', ->
+ if rstrip($(@).val()) is project_path
+ submit.enable()
+ else
+ submit.disable()
+
+ $('.js-confirm-danger-submit').on 'click', =>
+ @form.submit()
+
+@ConfirmDangerModal = ConfirmDangerModal
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
index f2b531fb2b1..0e2a2fa792a 100644
--- a/app/assets/javascripts/issue.js.coffee
+++ b/app/assets/javascripts/issue.js.coffee
@@ -9,25 +9,11 @@ class Issue
if $("a.btn-close").length
$("li.task-list-item input:checkbox").prop("disabled", false)
- $(".task-list-item input:checkbox").on "click", ->
- is_checked = $(this).prop("checked")
- if $(this).is(":checked")
- state_event = "task_check"
- else
- state_event = "task_uncheck"
-
- mr_url = $("form.edit-issue").first().attr("action")
- mr_num = mr_url.match(/\d+$/)
- task_num = 0
- $("li.task-list-item input:checkbox").each( (index, e) =>
- if e == this
- task_num = index + 1
- )
-
- $.ajax
- type: "PATCH"
- url: mr_url
- data: "issue[state_event]=" + state_event +
- "&issue[task_num]=" + task_num
+ $(".task-list-item input:checkbox").on(
+ "click"
+ null
+ "issue"
+ updateTaskState
+ )
@Issue = Issue
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index c0460a7ec4e..9f99ff403f8 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -17,7 +17,7 @@ class MergeRequest
disableButtonIfEmptyField '#commit_message', '.accept_merge_request'
- if $("a.close-mr-link").length
+ if $("a.btn-close").length
$("li.task-list-item input:checkbox").prop("disabled", false)
# Local jQuery finder
@@ -74,26 +74,12 @@ class MergeRequest
this.$('.remove_source_branch_in_progress').hide()
this.$('.remove_source_branch_widget.failed').show()
- this.$(".task-list-item input:checkbox").on "click", ->
- is_checked = $(this).prop("checked")
- if $(this).is(":checked")
- state_event = "task_check"
- else
- state_event = "task_uncheck"
-
- mr_url = $("form.edit-merge_request").first().attr("action")
- mr_num = mr_url.match(/\d+$/)
- task_num = 0
- $("li.task-list-item input:checkbox").each( (index, e) =>
- if e == this
- task_num = index + 1
- )
-
- $.ajax
- type: "PATCH"
- url: mr_url
- data: "merge_request[state_event]=" + state_event +
- "&merge_request[task_num]=" + task_num
+ $(".task-list-item input:checkbox").on(
+ "click"
+ null
+ "merge_request"
+ updateTaskState
+ )
activateTab: (action) ->
this.$('.merge-request-tabs li').removeClass 'active'
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss
index 0486955d6e1..94149594e24 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/generic/issue_box.scss
@@ -10,8 +10,7 @@
.issue-box {
color: #555;
margin:20px 0;
- background: #f9f9f9;
- border-top-left-radius: 5px;
+ background: $box_bg;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
&.issue-box-closed {
@@ -112,7 +111,6 @@
float: left;
font-weight: bold;
padding: 10px 15px;
- border-top-left-radius: 5px;
}
.creator {
diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss
index 45044c5acb6..9c5e76ab8e2 100644
--- a/app/assets/stylesheets/gl_bootstrap.scss
+++ b/app/assets/stylesheets/gl_bootstrap.scss
@@ -233,8 +233,8 @@ $list-group-active-bg: $bg_primary;
}
.form-actions {
- margin-bottom: 0;
- background: #FFF;
+ margin: -15px;
+ margin-top: 18px;
}
}
@@ -262,53 +262,33 @@ $list-group-active-bg: $bg_primary;
}
.panel-danger {
- border-color: $border_danger;
+ @include panel-colored;
.panel-heading {
- color: #ffffff;
- background-color: $bg_danger;
+ color: $border_danger;
border-color: $border_danger;
- a {
- color: #FFF;
- text-decoration: underline;
- }
}
}
.panel-success {
- border-color: $border_success;
+ @include panel-colored;
.panel-heading {
- color: #ffffff;
- background-color: $bg_success;
+ color: $border_success;
border-color: $border_success;
- a {
- color: #FFF;
- text-decoration: underline;
- }
}
}
.panel-primary {
- border-color: $border_primary;
+ @include panel-colored;
.panel-heading {
- color: #ffffff;
- background-color: $bg_primary;
+ color: $border_primary;
border-color: $border_primary;
- a {
- color: #FFF;
- text-decoration: underline;
- }
}
}
.panel-warning {
- border-color: $border_warning;
+ @include panel-colored;
.panel-heading {
- color: #ffffff;
- background-color: $bg_warning;
+ color: $border_warning;
border-color: $border_warning;
- a {
- color: #FFF;
- text-decoration: underline;
- }
}
}
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss
index 93faf5ced65..7f607fc4e8b 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/main/mixins.scss
@@ -132,3 +132,14 @@
white-space: nowrap;
max-width: $max_width;
}
+
+@mixin panel-colored {
+ border: none;
+ background: $box_bg;
+ @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
+
+ .panel-heading {
+ font-weight: bold;
+ background-color: $box_bg;
+ }
+}
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
index 72d84226fe7..c71984a5665 100644
--- a/app/assets/stylesheets/main/variables.scss
+++ b/app/assets/stylesheets/main/variables.scss
@@ -3,6 +3,7 @@
*/
$style_color: #474D57;
$hover: #FFECDB;
+$box_bg: #F9F9F9;
/*
* Link colors
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index 46e3884b302..c8d0cac2926 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -104,7 +104,7 @@
}
.mr-state-widget {
- background: #f9f9f9;
+ background: $box_bg;
margin-bottom: 20px;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index f63df27eebd..baad9095b70 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -4,6 +4,7 @@ class Admin::UsersController < Admin::ApplicationController
def index
@users = User.filter(params[:filter])
@users = @users.search(params[:name]) if params[:name].present?
+ @users = @users.sort(@sort = params[:sort])
@users = @users.alphabetically.page(params[:page])
end
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 3ed6a69c2d8..fa5685938f0 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -15,15 +15,17 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
error.to_s.humanize if error
end
+ # We only find ourselves here
+ # if the authentication to LDAP was successful.
def ldap
- # We only find ourselves here
- # if the authentication to LDAP was successful.
- @user = Gitlab::LDAP::User.find_or_create(oauth)
- @user.remember_me = true if @user.persisted?
+ @user = Gitlab::LDAP::User.new(oauth)
+ @user.save if @user.changed? # will also save new users
+ gl_user = @user.gl_user
+ gl_user.remember_me = true if @user.persisted?
# Do additional LDAP checks for the user filter and EE features
- if Gitlab::LDAP::Access.allowed?(@user)
- sign_in_and_redirect(@user)
+ if Gitlab::LDAP::Access.allowed?(gl_user)
+ sign_in_and_redirect(gl_user)
else
flash[:alert] = "Access denied for your LDAP account."
redirect_to new_user_session_path
@@ -46,24 +48,17 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
current_user.save
redirect_to profile_path
else
- @user = Gitlab::OAuth::User.find(oauth)
+ @user = Gitlab::OAuth::User.new(oauth)
- # Create user if does not exist
- # and allow_single_sign_on is true
- if Gitlab.config.omniauth['allow_single_sign_on'] && !@user
- @user, errors = Gitlab::OAuth::User.create(oauth)
+ if Gitlab.config.omniauth['allow_single_sign_on'] && @user.new?
+ @user.save
end
- if @user && !errors
- sign_in_and_redirect(@user)
+ if @user.valid?
+ sign_in_and_redirect(@user.gl_user)
else
- if errors
- error_message = errors.map{ |attribute, message| "#{attribute} #{message}" }.join(", ")
- redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
- else
- flash[:notice] = "There's no such user!"
- end
- redirect_to new_user_session_path
+ error_message = @user.gl_user.errors.map{ |attribute, message| "#{attribute} #{message}" }.join(", ")
+ redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
end
end
end
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 038645aa497..b7f09eb271d 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -17,7 +17,7 @@ class Projects::CommitsController < Projects::ApplicationController
group(:commit_id).count
respond_to do |format|
- format.html # index.html.erb
+ format.html
format.json { pager_json("projects/commits/_commits", @commits.size) }
format.atom { render layout: false }
end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index cba058fe214..9d5dd8a95cc 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -17,7 +17,10 @@ class Projects::SnippetsController < Projects::ApplicationController
respond_to :html
def index
- @snippets = @project.snippets.fresh.non_expired
+ @snippets = SnippetsFinder.new.execute(current_user, {
+ filter: :by_project,
+ project: @project
+ })
end
def new
@@ -88,6 +91,6 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def snippet_params
- params.require(:project_snippet).permit(:title, :content, :file_name, :private)
+ params.require(:project_snippet).permit(:title, :content, :file_name, :private, :visibility_level)
end
end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 5904dbbceda..30fb4c5552d 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -9,12 +9,14 @@ class SnippetsController < ApplicationController
before_filter :set_title
+ skip_before_filter :authenticate_user!, only: [:index, :user_index]
+
respond_to :html
- layout 'navless'
+ layout :determine_layout
def index
- @snippets = Snippet.are_internal.fresh.non_expired.page(params[:page]).per(20)
+ @snippets = SnippetsFinder.new.execute(current_user, filter: :all).page(params[:page]).per(20)
end
def user_index
@@ -22,22 +24,11 @@ class SnippetsController < ApplicationController
render_404 and return unless @user
- @snippets = @user.snippets.fresh.non_expired
-
- if @user == current_user
- @snippets = case params[:scope]
- when 'are_internal' then
- @snippets.are_internal
- when 'are_private' then
- @snippets.are_private
- else
- @snippets
- end
- else
- @snippets = @snippets.are_internal
- end
-
- @snippets = @snippets.page(params[:page]).per(20)
+ @snippets = SnippetsFinder.new.execute(current_user, {
+ filter: :by_user,
+ user: @user,
+ scope: params[:scope]}).
+ page(params[:page]).per(20)
if @user == current_user
render 'current_user_index'
@@ -95,7 +86,14 @@ class SnippetsController < ApplicationController
protected
def snippet
- @snippet ||= PersonalSnippet.where('author_id = :user_id or private is false', user_id: current_user.id).find(params[:id])
+ @snippet ||= if current_user
+ PersonalSnippet.where("author_id = ? OR visibility_level IN (?)",
+ current_user.id,
+ [Snippet::PUBLIC, Snippet::INTERNAL]).
+ find(params[:id])
+ else
+ PersonalSnippet.are_public.find(params[:id])
+ end
end
def authorize_modify_snippet!
@@ -111,6 +109,10 @@ class SnippetsController < ApplicationController
end
def snippet_params
- params.require(:personal_snippet).permit(:title, :content, :file_name, :private)
+ params.require(:personal_snippet).permit(:title, :content, :file_name, :private, :visibility_level)
+ end
+
+ def determine_layout
+ current_user ? 'navless' : 'public_users'
end
end
diff --git a/app/finders/README.md b/app/finders/README.md
index 47823c51efb..1f46518d230 100644
--- a/app/finders/README.md
+++ b/app/finders/README.md
@@ -1,7 +1,7 @@
# Finders
-This type of classes responsible for collectiong items based on different conditions.
-To prevent lookup methods in models like this:
+This type of classes responsible for collection items based on different conditions.
+To prevent lookup methods in models like this:
```ruby
class Project
@@ -13,10 +13,10 @@ end
issues = project.issues_for_user_filtered_by(user, params)
```
-Better use this:
+Better use this:
```ruby
issues = IssuesFinder.new.execute(project, user, filter)
```
-It will help keep models thiner
+It will help keep models thiner.
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
new file mode 100644
index 00000000000..b29ab6cf40b
--- /dev/null
+++ b/app/finders/snippets_finder.rb
@@ -0,0 +1,61 @@
+class SnippetsFinder
+ def execute(current_user, params = {})
+ filter = params[:filter]
+
+ case filter
+ when :all then
+ snippets(current_user).fresh.non_expired
+ when :by_user then
+ by_user(current_user, params[:user], params[:scope])
+ when :by_project
+ by_project(current_user, params[:project])
+ end
+ end
+
+ private
+
+ def snippets(current_user)
+ if current_user
+ Snippet.public_and_internal
+ else
+ # Not authenticated
+ #
+ # Return only:
+ # public snippets
+ Snippet.are_public
+ end
+ end
+
+ def by_user(current_user, user, scope)
+ snippets = user.snippets.fresh.non_expired
+
+ if user == current_user
+ case scope
+ when 'are_internal' then
+ snippets.are_internal
+ when 'are_private' then
+ snippets.are_private
+ when 'are_public' then
+ snippets.are_public
+ else
+ snippets
+ end
+ else
+ snippets.public_and_internal
+ end
+ end
+
+ def by_project(current_user, project)
+ snippets = project.snippets.fresh.non_expired
+
+ if current_user
+ if project.team.member?(current_user.id)
+ snippets
+ else
+ snippets.public_and_internal
+ end
+ else
+ snippets.are_public
+ end
+ end
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index e8a9c2efadf..021bd0a494c 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -263,4 +263,12 @@ module ApplicationHelper
def escaped_autolink(text)
auto_link ERB::Util.html_escape(text), link: :urls
end
+
+ def promo_host
+ 'about.gitlab.com'
+ end
+
+ def promo_url
+ 'https://' + promo_host
+ end
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index cab2984a4c4..0e0532b65b2 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -120,4 +120,8 @@ module CommitsHelper
class: 'commit-short-id')
end
end
+
+ def truncate_sha(sha)
+ Commit.truncate_sha(sha)
+ end
end
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index c4e33e3308f..acc0eeb76b3 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -37,40 +37,31 @@ module DashboardHelper
end
def assigned_entities_count(current_user, entity, scope = nil)
- items = current_user.send("assigned_" + entity.pluralize).opened
-
- if scope.kind_of?(Group)
- items = items.of_group(scope)
- elsif scope.kind_of?(Project)
- items = items.of_projects(scope)
- end
-
- items.count
+ items = current_user.send('assigned_' + entity.pluralize)
+ get_count(items, scope)
end
def authored_entities_count(current_user, entity, scope = nil)
- items = current_user.send(entity.pluralize).opened
-
- if scope.kind_of?(Group)
- items = items.of_group(scope)
- elsif scope.kind_of?(Project)
- items = items.of_projects(scope)
- end
-
- items.count
+ items = current_user.send(entity.pluralize)
+ get_count(items, scope)
end
def authorized_entities_count(current_user, entity, scope = nil)
- items = entity.classify.constantize.opened
+ items = entity.classify.constantize
+ get_count(items, scope, true, current_user)
+ end
+
+ protected
+ def get_count(items, scope, get_authorized = false, current_user = nil)
+ items = items.opened
if scope.kind_of?(Group)
items = items.of_group(scope)
elsif scope.kind_of?(Project)
items = items.of_projects(scope)
- else
+ elsif get_authorized
items = items.of_projects(current_user.authorized_projects)
end
-
items.count
end
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 6aeab7bb8ce..71f97fbb8c8 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -136,9 +136,8 @@ module EventsHelper
end
def event_note(text)
- text = first_line_in_markdown(text)
- text = truncate(text, length: 150)
- sanitize(markdown(text), tags: %w(a img b pre p))
+ text = first_line_in_markdown(text, 150)
+ sanitize(text, tags: %w(a img b pre code p))
end
def event_commit_title(message)
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 0365681a128..7d3cb749829 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -51,12 +51,14 @@ module GitlabMarkdownHelper
@markdown.render(text).html_safe
end
- def first_line_in_markdown(text)
- line = text.split("\n").detect do |i|
- i.present? && markdown(i).present?
- end
- line += '...' unless line.nil?
- line
+ # Return the first line of +text+, up to +max_chars+, after parsing the line
+ # as Markdown. HTML tags in the parsed output are not counted toward the
+ # +max_chars+ limit. If the length limit falls within a tag's contents, then
+ # the tag contents are truncated without removing the closing tag.
+ def first_line_in_markdown(text, max_chars = nil)
+ md = markdown(text).strip
+
+ truncate_visible(md, max_chars || md.length) if md.present?
end
def render_wiki_content(wiki_page)
@@ -204,4 +206,52 @@ module GitlabMarkdownHelper
def correct_ref
@ref ? @ref : "master"
end
+
+ private
+
+ # Return +text+, truncated to +max_chars+ characters, excluding any HTML
+ # tags.
+ def truncate_visible(text, max_chars)
+ doc = Nokogiri::HTML.fragment(text)
+ content_length = 0
+ truncated = false
+
+ doc.traverse do |node|
+ if node.text? || node.content.empty?
+ if truncated
+ node.remove
+ next
+ end
+
+ # Handle line breaks within a node
+ if node.content.strip.lines.length > 1
+ node.content = "#{node.content.lines.first.chomp}..."
+ truncated = true
+ end
+
+ num_remaining = max_chars - content_length
+ if node.content.length > num_remaining
+ node.content = node.content.truncate(num_remaining)
+ truncated = true
+ end
+ content_length += node.content.length
+ end
+
+ truncated = truncate_if_block(node, truncated)
+ end
+
+ doc.to_html
+ end
+
+ # Used by #truncate_visible. If +node+ is the first block element, and the
+ # text hasn't already been truncated, then append "..." to the node contents
+ # and return true. Otherwise return false.
+ def truncate_if_block(node, truncated)
+ if node.element? && node.description.block? && !truncated
+ node.content = "#{node.content}..." if node.next_sibling
+ true
+ else
+ truncated
+ end
+ end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 2188b30a9af..883c1f63af6 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -56,6 +56,10 @@ module ProjectsHelper
"You are going to remove #{project.name_with_namespace}.\n Removed project CANNOT be restored!\n Are you ABSOLUTELY sure?"
end
+ def transfer_project_message(project)
+ "You are going to transfer #{project.name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
+ end
+
def project_nav_tabs
@nav_tabs ||= get_project_nav_tabs(@project, current_user)
end
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index 8b83b8ff640..deb9c8b4d49 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -28,6 +28,23 @@ module VisibilityLevelHelper
end
end
+ def snippet_visibility_level_description(level)
+ capture_haml do
+ haml_tag :span do
+ case level
+ when Gitlab::VisibilityLevel::PRIVATE
+ haml_concat "The snippet is visible only for me"
+ when Gitlab::VisibilityLevel::INTERNAL
+ haml_concat "The snippet is visible for any logged in user."
+ when Gitlab::VisibilityLevel::PUBLIC
+ haml_concat "The snippet can be accessed"
+ haml_concat "without any"
+ haml_concat "authentication."
+ end
+ end
+ end
+ end
+
def visibility_level_icon(level)
case level
when Gitlab::VisibilityLevel::PRIVATE
diff --git a/app/models/commit.rb b/app/models/commit.rb
index a1343b65c72..212229649fc 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -19,13 +19,24 @@ class Commit
class << self
def decorate(commits)
- commits.map { |c| self.new(c) }
+ commits.map do |commit|
+ if commit.kind_of?(Commit)
+ commit
+ else
+ self.new(commit)
+ end
+ end
end
# Calculate number of lines to render for diffs
def diff_line_count(diffs)
diffs.reduce(0) { |sum, d| sum + d.diff.lines.count }
end
+
+ # Truncate sha to 8 characters
+ def truncate_sha(sha)
+ sha[0..7]
+ end
end
attr_accessor :raw
@@ -111,7 +122,7 @@ class Commit
# Mentionable override.
def gfm_reference
- "commit #{sha[0..5]}"
+ "commit #{id}"
end
def method_missing(m, *args, &block)
@@ -124,6 +135,11 @@ class Commit
super
end
+ # Truncate sha to 8 characters
+ def short_id
+ @raw.short_id(7)
+ end
+
def parents
@parents ||= Commit.decorate(super)
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 9e296c00281..c0b126713a6 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -266,7 +266,7 @@ class Event < ActiveRecord::Base
end
def note_short_commit_id
- note_commit_id[0..8]
+ Commit.truncate_sha(note_commit_id)
end
def note_commit?
diff --git a/app/models/member.rb b/app/models/member.rb
index 7dc13c18bf3..671ef466baa 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -1,3 +1,18 @@
+# == Schema Information
+#
+# Table name: members
+#
+# id :integer not null, primary key
+# access_level :integer not null
+# source_id :integer not null
+# source_type :string(255) not null
+# user_id :integer not null
+# notification_level :integer not null
+# type :string(255)
+# created_at :datetime
+# updated_at :datetime
+#
+
class Member < ActiveRecord::Base
include Notifiable
include Gitlab::Access
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
index e72393c4278..b7f296b13fb 100644
--- a/app/models/members/group_member.rb
+++ b/app/models/members/group_member.rb
@@ -1,3 +1,18 @@
+# == Schema Information
+#
+# Table name: members
+#
+# id :integer not null, primary key
+# access_level :integer not null
+# source_id :integer not null
+# source_type :string(255) not null
+# user_id :integer not null
+# notification_level :integer not null
+# type :string(255)
+# created_at :datetime
+# updated_at :datetime
+#
+
class GroupMember < Member
SOURCE_TYPE = 'Namespace'
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index 71525f91961..30c09f768d7 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -1,3 +1,18 @@
+# == Schema Information
+#
+# Table name: members
+#
+# id :integer not null, primary key
+# access_level :integer not null
+# source_id :integer not null
+# source_type :string(255) not null
+# user_id :integer not null
+# notification_level :integer not null
+# type :string(255)
+# created_at :datetime
+# updated_at :datetime
+#
+
class ProjectMember < Member
SOURCE_TYPE = 'Project'
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 409e82ed1ef..a71122d5e07 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -55,7 +55,7 @@ class MergeRequestDiff < ActiveRecord::Base
end
def last_commit_short_sha
- @last_commit_short_sha ||= last_commit.sha[0..10]
+ @last_commit_short_sha ||= last_commit.short_id
end
private
diff --git a/app/models/personal_snippet.rb b/app/models/personal_snippet.rb
index a3c0d201ee5..9cee3b70cb3 100644
--- a/app/models/personal_snippet.rb
+++ b/app/models/personal_snippet.rb
@@ -2,17 +2,17 @@
#
# Table name: snippets
#
-# id :integer not null, primary key
-# title :string(255)
-# content :text
-# author_id :integer not null
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# file_name :string(255)
-# expires_at :datetime
-# private :boolean default(TRUE), not null
-# type :string(255)
+# id :integer not null, primary key
+# title :string(255)
+# content :text
+# author_id :integer not null
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# file_name :string(255)
+# expires_at :datetime
+# type :string(255)
+# visibility_level :integer default(0), not null
#
class PersonalSnippet < Snippet
diff --git a/app/models/project.rb b/app/models/project.rb
index 44d63d37bee..90d2649ba23 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -64,6 +64,7 @@ class Project < ActiveRecord::Base
has_one :assembla_service, dependent: :destroy
has_one :gemnasium_service, dependent: :destroy
has_one :slack_service, dependent: :destroy
+ has_one :buildbox_service, dependent: :destroy
has_one :pushover_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link
@@ -312,7 +313,7 @@ class Project < ActiveRecord::Base
end
def available_services_names
- %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack pushover)
+ %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack pushover buildbox)
end
def gitlab_ci?
diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb
index 3421a0330aa..0b90a14f39c 100644
--- a/app/models/project_services/assembla_service.rb
+++ b/app/models/project_services/assembla_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
class AssemblaService < Service
diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildbox_service.rb
new file mode 100644
index 00000000000..b0f8e28c97f
--- /dev/null
+++ b/app/models/project_services/buildbox_service.rb
@@ -0,0 +1,121 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+#
+
+class BuildboxService < CiService
+ prop_accessor :project_url, :token
+
+ validates :project_url, presence: true, if: :activated?
+ validates :token, presence: true, if: :activated?
+
+ after_save :compose_service_hook, if: :activated?
+
+ def webhook_url
+ "#{buildbox_endpoint('webhook')}/deliver/#{webhook_token}"
+ end
+
+ def compose_service_hook
+ hook = service_hook || build_service_hook
+ hook.url = webhook_url
+ hook.save
+ end
+
+ def execute(data)
+ service_hook.execute(data)
+ end
+
+ def commit_status(sha)
+ response = HTTParty.get(commit_status_path(sha), verify: false)
+
+ if response.code == 200 && response['status']
+ response['status']
+ else
+ :error
+ end
+ end
+
+ def commit_status_path(sha)
+ "#{buildbox_endpoint('gitlab')}/status/#{status_token}.json?commit=#{sha}"
+ end
+
+ def build_page(sha)
+ "#{project_url}/builds?commit=#{sha}"
+ end
+
+ def builds_path
+ "#{project_url}/builds?branch=#{project.default_branch}"
+ end
+
+ def status_img_path
+ "#{buildbox_endpoint('badge')}/#{status_token}.svg"
+ end
+
+ def title
+ 'Buildbox'
+ end
+
+ def description
+ 'Continuous integration and deployments'
+ end
+
+ def to_param
+ 'buildbox'
+ end
+
+ def fields
+ [
+ { type: 'text',
+ name: 'token',
+ placeholder: 'Buildbox project GitLab token' },
+
+ { type: 'text',
+ name: 'project_url',
+ placeholder: 'https://buildbox.io/example/project' }
+ ]
+ end
+
+ private
+
+ def webhook_token
+ token_parts.first
+ end
+
+ def status_token
+ token_parts.second
+ end
+
+ def token_parts
+ if token.present?
+ token.split(':')
+ else
+ []
+ end
+ end
+
+ def buildbox_endpoint(subdomain = nil)
+ endpoint = 'https://buildbox.io'
+
+ if subdomain.present?
+ uri = Addressable::URI.parse(endpoint)
+ new_endpoint = "#{uri.scheme || 'http'}://#{subdomain}.#{uri.host}"
+
+ if uri.port.present?
+ "#{new_endpoint}:#{uri.port}"
+ else
+ new_endpoint
+ end
+ else
+ endpoint
+ end
+ end
+end
diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb
index 2d8950db491..0736ddab99b 100644
--- a/app/models/project_services/campfire_service.rb
+++ b/app/models/project_services/campfire_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
class CampfireService < Service
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
index 829f495abc6..b1d5e49ede3 100644
--- a/app/models/project_services/ci_service.rb
+++ b/app/models/project_services/ci_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
# Base class for CI services
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
index 5c4537cfca5..b9071b98295 100644
--- a/app/models/project_services/emails_on_push_service.rb
+++ b/app/models/project_services/emails_on_push_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
class EmailsOnPushService < Service
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 4d11b00c192..0020b4482e5 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
require "flowdock-git-hook"
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
index 7b6c87e4cec..6d2fc06a5d0 100644
--- a/app/models/project_services/gemnasium_service.rb
+++ b/app/models/project_services/gemnasium_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
require "gemnasium/gitlab_service"
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index 001b11c5966..a897c4ab76b 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# property :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
class GitlabCiService < CiService
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 3a1ba168e6a..4078938cdbb 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
class HipchatService < Service
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
index 3aa928b92a0..09e114f9cca 100644
--- a/app/models/project_services/pivotaltracker_service.rb
+++ b/app/models/project_services/pivotaltracker_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
class PivotaltrackerService < Service
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index dfa1e9c9820..95f3ddcef45 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
class SlackService < Service
diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb
index 14c88046423..9e2c1b0e18e 100644
--- a/app/models/project_snippet.rb
+++ b/app/models/project_snippet.rb
@@ -2,17 +2,17 @@
#
# Table name: snippets
#
-# id :integer not null, primary key
-# title :string(255)
-# content :text
-# author_id :integer not null
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# file_name :string(255)
-# expires_at :datetime
-# private :boolean default(TRUE), not null
-# type :string(255)
+# id :integer not null, primary key
+# title :string(255)
+# content :text
+# author_id :integer not null
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# file_name :string(255)
+# expires_at :datetime
+# type :string(255)
+# visibility_level :integer default(0), not null
#
class ProjectSnippet < Snippet
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index e065554d3b8..657ee23ae23 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -133,6 +133,10 @@ class ProjectTeam
max_tm_access(user.id) == Gitlab::Access::MASTER
end
+ def member?(user_id)
+ !!find_tm(user_id)
+ end
+
def max_tm_access(user_id)
access = []
access << project.project_members.find_by(user_id: user_id).try(:access_field)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 339e485e6d2..93994123a90 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -30,6 +30,8 @@ class Repository
commit = Gitlab::Git::Commit.find(raw_repository, id)
commit = Commit.new(commit) if commit
commit
+ rescue Rugged::OdbError => ex
+ nil
end
def commits(ref, path = nil, limit = nil, offset = nil, skip_merges = false)
diff --git a/app/models/service.rb b/app/models/service.rb
index 1f3a6520473..c489c1e96e1 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -2,14 +2,15 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+#
# To add new service you should build a class inherited from Service
# and implement a set of methods
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index addde2d106a..a47fbca3260 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -2,23 +2,24 @@
#
# Table name: snippets
#
-# id :integer not null, primary key
-# title :string(255)
-# content :text
-# author_id :integer not null
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# file_name :string(255)
-# expires_at :datetime
-# private :boolean default(TRUE), not null
-# type :string(255)
+# id :integer not null, primary key
+# title :string(255)
+# content :text
+# author_id :integer not null
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# file_name :string(255)
+# expires_at :datetime
+# type :string(255)
+# visibility_level :integer default(0), not null
#
class Snippet < ActiveRecord::Base
include Linguist::BlobHelper
+ include Gitlab::VisibilityLevel
- default_value_for :private, true
+ default_value_for :visibility_level, Snippet::PRIVATE
belongs_to :author, class_name: "User"
@@ -30,10 +31,13 @@ class Snippet < ActiveRecord::Base
validates :title, presence: true, length: { within: 0..255 }
validates :file_name, presence: true, length: { within: 0..255 }
validates :content, presence: true
+ validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values }
# Scopes
- scope :are_internal, -> { where(private: false) }
- scope :are_private, -> { where(private: true) }
+ scope :are_internal, -> { where(visibility_level: Snippet::INTERNAL) }
+ scope :are_private, -> { where(visibility_level: Snippet::PRIVATE) }
+ scope :are_public, -> { where(visibility_level: Snippet::PUBLIC) }
+ scope :public_and_internal, -> { where(visibility_level: [Snippet::PUBLIC, Snippet::INTERNAL]) }
scope :fresh, -> { order("created_at DESC") }
scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) }
scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) }
@@ -66,6 +70,10 @@ class Snippet < ActiveRecord::Base
expires_at && expires_at < Time.current
end
+ def visibility_level_field
+ visibility_level
+ end
+
class << self
def search(query)
where('(title LIKE :query OR file_name LIKE :query)', query: "%#{query}%")
@@ -76,7 +84,7 @@ class Snippet < ActiveRecord::Base
end
def accessible_to(user)
- where('private = ? OR author_id = ?', false, user)
+ where('visibility_level IN (?) OR author_id = ?', [Snippet::INTERNAL, Snippet::PUBLIC], user)
end
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index c90f2462426..c6baa7ee704 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -196,6 +196,16 @@ class User < ActiveRecord::Base
end
end
+ def sort(method)
+ case method.to_s
+ when 'recent_sign_in' then reorder('users.last_sign_in_at DESC')
+ when 'oldest_sign_in' then reorder('users.last_sign_in_at ASC')
+ when 'recently_created' then reorder('users.created_at DESC')
+ when 'late_created' then reorder('users.created_at ASC')
+ else reorder("users.name ASC")
+ end
+ end
+
def find_for_commit(email, name)
# Prefer email match over name match
User.where(email: email).first ||
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
new file mode 100644
index 00000000000..e3371ec3c1b
--- /dev/null
+++ b/app/services/issuable_base_service.rb
@@ -0,0 +1,13 @@
+class IssuableBaseService < BaseService
+ private
+
+ def create_assignee_note(issuable)
+ Note.create_assignee_change_note(
+ issuable, issuable.project, current_user, issuable.assignee)
+ end
+
+ def create_milestone_note(issuable)
+ Note.create_milestone_change_note(
+ issuable, issuable.project, current_user, issuable.milestone)
+ end
+end
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index 71b9ffc3489..41948f226a6 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -1,21 +1,13 @@
module Issues
- class BaseService < ::BaseService
+ class BaseService < ::IssuableBaseService
private
- def create_assignee_note(issue)
- Note.create_assignee_change_note(issue, issue.project, current_user, issue.assignee)
- end
-
def execute_hooks(issue, action = 'open')
issue_data = issue.to_hook_data
issue_url = Gitlab::UrlBuilder.new(:issue).build(issue.id)
issue_data[:object_attributes].merge!(url: issue_url, action: action)
issue.project.execute_hooks(issue_data, :issue_hooks)
end
-
- def create_milestone_note(issue)
- Note.create_milestone_change_note(issue, issue.project, current_user, issue.milestone)
- end
end
end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 5b2746ffecf..0ee9635ed99 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -33,12 +33,5 @@ module Issues
issue
end
-
- private
-
- def update_task(issue, params, checked)
- issue.update_nth_task(params[:task_num].to_i, checked)
- params.except!(:task_num)
- end
end
end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 2907f3587da..694994001b0 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -1,11 +1,5 @@
module MergeRequests
- class BaseService < ::BaseService
-
- private
-
- def create_assignee_note(merge_request)
- Note.create_assignee_change_note(merge_request, merge_request.project, current_user, merge_request.assignee)
- end
+ class BaseService < ::IssuableBaseService
def create_note(merge_request)
Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil)
@@ -16,9 +10,5 @@ module MergeRequests
merge_request.project.execute_hooks(merge_request.to_hook_data, :merge_request_hooks)
end
end
-
- def create_milestone_note(merge_request)
- Note.create_milestone_change_note(merge_request, merge_request.project, current_user, merge_request.milestone)
- end
end
end
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 5c2664e14fe..92c619738a2 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -32,6 +32,26 @@
.panel-heading
Users (#{@users.total_count})
.panel-head-actions
+ .dropdown.inline
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %span.light sort:
+ - if @sort.present?
+ = @sort.humanize
+ - else
+ Name
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to admin_users_path(sort: nil) do
+ Name
+ = link_to admin_users_path(sort: 'recent_sign_in') do
+ Recent sign in
+ = link_to admin_users_path(sort: 'oldest_sign_in') do
+ Oldest sign in
+ = link_to admin_users_path(sort: 'recently_created') do
+ Recently created
+ = link_to admin_users_path(sort: 'late_created') do
+ Late created
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
%ul.well-list
- @users.each do |user|
diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml
index 0e03e116e7d..f0c34def145 100644
--- a/app/views/events/_commit.html.haml
+++ b/app/views/events/_commit.html.haml
@@ -1,5 +1,5 @@
%li.commit
.commit-row-title
- = link_to commit[:id][0..8], project_commit_path(project, commit[:id]), class: "commit_short_id", alt: ''
+ = link_to truncate_sha(commit[:id]), project_commit_path(project, commit[:id]), class: "commit_short_id", alt: ''
&nbsp;
= gfm event_commit_title(commit[:message]), project
diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml
index 17228c430ca..2b63519edac 100644
--- a/app/views/events/_event_push.atom.haml
+++ b/app/views/events/_event_push.atom.haml
@@ -2,7 +2,7 @@
- event.commits.first(15).each do |commit|
%p
%strong= commit[:author][:name]
- = link_to "(##{commit[:id][0...8]})", project_commit_path(event.project, id: commit[:id])
+ = link_to "(##{truncate_sha(commit[:id])})", project_commit_path(event.project, id: commit[:id])
%i
at
= commit[:timestamp].to_time.to_s(:short)
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index 1bca64c7d50..b912b5e092f 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -22,4 +22,4 @@
- if event.commits_count > 2
%span ... and #{event.commits_count - 2} more commits.
= link_to project_compare_path(event.project, from: event.commit_from, to: event.commit_to) do
- %strong Compare &rarr; #{event.commit_from[0..7]}...#{event.commit_to[0..7]}
+ %strong Compare &rarr; #{truncate_sha(event.commit_from)}...#{truncate_sha(event.commit_to)}
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index 903e093e5fc..7b8193abfdf 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -14,7 +14,7 @@
%br
Used by more than 100,000 organizations, GitLab is the most popular solution to manage git repositories on-premises.
%br
- Read more about GitLab at #{link_to "www.gitlab.com", "https://www.gitlab.com/", target: "_blank"}.
+ Read more about GitLab at #{link_to promo_host, promo_url, target: '_blank'}.
%hr
@@ -34,7 +34,7 @@
%ul.well-list
%li
See our website for
- = link_to "getting help", "https://www.gitlab.com/getting-help/"
+ = link_to 'getting help', promo_url + '/getting-help/'
%li
Use the
= link_to 'search bar', '#', onclick: 'Shortcuts.focusSearch(event)'
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index e5cde488c3c..bdf02c6285d 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -15,7 +15,7 @@
%tr
%td.blame-commit
%span.commit
- = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
+ = link_to commit.short_id, project_commit_path(@project, commit), class: "commit_short_id"
&nbsp;
= commit_author_link(commit, avatar: true, size: 16)
&nbsp;
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 0b6b6af4f90..e149f017f84 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -35,7 +35,7 @@
.commit-info-row
%span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent|
- = link_to parent.id[0...10], project_commit_path(@project, parent)
+ = link_to parent.short_id, project_commit_path(@project, parent)
- if @branches.any?
.commit-info-row
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 68852ba973f..1eb17f760dc 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -1,6 +1,6 @@
%li.commit.js-toggle-container
.commit-row-title
- = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
+ = link_to commit.short_id, project_commit_path(project, commit), class: "commit_short_id"
&nbsp;
%span.str-truncated
= link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
diff --git a/app/views/projects/commits/_inline_commit.html.haml b/app/views/projects/commits/_inline_commit.html.haml
index b36369b4285..574599aa2d2 100644
--- a/app/views/projects/commits/_inline_commit.html.haml
+++ b/app/views/projects/commits/_inline_commit.html.haml
@@ -1,6 +1,6 @@
%li.commit.inline-commit
.commit-row-title
- = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
+ = link_to commit.short_id, project_commit_path(project, commit), class: "commit_short_id"
&nbsp;
%span.str-truncated
= link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 5ee5641b069..f48f4bb2953 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -86,101 +86,92 @@
- .danger-settings.js-toggle-container
- .centered-light-block
- %h3
- %i.fa.fa-exclamation-triangle
- Dangerous settings
-
- %p Project settings below may result in data loss!
- = link_to '#', class: 'btn js-toggle-button' do
- Show them to me
- %i.fa.fa-chevron-down
-
- .js-toggle-content.hide
- - if can? current_user, :archive_project, @project
- .panel.panel-default.panel.panel-warning
+ .danger-settings
+ - if can? current_user, :archive_project, @project
+ - if @project.archived?
+ .panel.panel-success
.panel-heading
- - if @project.archived?
- Unarchive project
- - else
- Archive project
+ Unarchive project
.panel-body
- - if @project.archived?
- %p
- Unarchiving the project will mark its repository as active.
- %br
- The project can be committed to.
- %br
- %strong Once active this project shows up in the search and on the dashboard.
- = link_to 'Unarchive', unarchive_project_path(@project),
- data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be committed to again." },
- method: :post, class: "btn btn-remove"
- - else
- %p
- Archiving the project will mark its repository as read-only.
- %br
- It is hidden from the dashboard and doesn't show up in searches.
- %br
- %strong Archived projects cannot be committed to!
- = link_to 'Archive', archive_project_path(@project),
- data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },
- method: :post, class: "btn btn-warning"
+ %p
+ Unarchiving the project will mark its repository as active.
+ %br
+ The project can be committed to.
+ %br
+ %strong Once active this project shows up in the search and on the dashboard.
+ = link_to 'Unarchive', unarchive_project_path(@project),
+ data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be committed to again." },
+ method: :post, class: "btn btn-success"
- else
- .nothing-here-block Only the project owner can archive a project
-
- .panel.panel-default.panel.panel-warning
- .panel-heading Rename repository
+ .panel.panel-warning
+ .panel-heading
+ Archive project
+ .panel-body
+ %p
+ Archiving the project will mark its repository as read-only.
+ %br
+ It is hidden from the dashboard and doesn't show up in searches.
+ %br
+ %strong Archived projects cannot be committed to!
+ = link_to 'Archive', archive_project_path(@project),
+ data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },
+ method: :post, class: "btn btn-warning"
+ - else
+ .nothing-here-block Only the project owner can archive a project
+
+ .panel.panel-default.panel.panel-warning
+ .panel-heading Rename repository
+ .errors-holder
+ .panel-body
+ = form_for(@project, html: { class: 'form-horizontal' }) do |f|
+ .form-group
+ = f.label :path, class: 'control-label' do
+ %span Path
+ .col-sm-9
+ .form-group
+ .input-group
+ = f.text_field :path, class: 'form-control'
+ %span.input-group-addon .git
+ %ul
+ %li Be careful. Renaming a project's repository can have unintended side effects.
+ %li You will need to update your local repositories to point to the new location.
+ .form-actions
+ = f.submit 'Rename', class: "btn btn-warning"
+
+ - if can?(current_user, :change_namespace, @project)
+ .panel.panel-default.panel.panel-danger
+ .panel-heading Transfer project
.errors-holder
.panel-body
- = form_for(@project, html: { class: 'form-horizontal' }) do |f|
+ = form_for(@project, url: transfer_project_path(@project), method: :put, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
.form-group
- = f.label :path, class: 'control-label' do
- %span Path
- .col-sm-9
+ = f.label :namespace_id, class: 'control-label' do
+ %span Namespace
+ .col-sm-10
.form-group
- .input-group
- = f.text_field :path, class: 'form-control'
- %span.input-group-addon .git
+ = f.select :namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace' }, { class: 'select2' }
%ul
- %li Be careful. Renaming a project's repository can have unintended side effects.
+ %li Be careful. Changing the project's namespace can have unintended side effects.
+ %li You can only transfer the project to namespaces you manage.
%li You will need to update your local repositories to point to the new location.
.form-actions
- = f.submit 'Rename', class: "btn btn-warning"
-
- - if can?(current_user, :change_namespace, @project)
- .panel.panel-default.panel.panel-danger
- .panel-heading Transfer project
- .errors-holder
- .panel-body
- = form_for(@project, url: transfer_project_path(@project), method: :put, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
- .form-group
- = f.label :namespace_id, class: 'control-label' do
- %span Namespace
- .col-sm-10
- .form-group
- = f.select :namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace' }, { class: 'select2' }
- %ul
- %li Be careful. Changing the project's namespace can have unintended side effects.
- %li You can only transfer the project to namespaces you manage.
- %li You will need to update your local repositories to point to the new location.
- .form-actions
- = f.submit 'Transfer', class: "btn btn-remove"
- - else
- .nothing-here-block Only the project owner can transfer a project
+ = f.submit 'Transfer', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => transfer_project_message(@project) }
+ - else
+ .nothing-here-block Only the project owner can transfer a project
- - if can?(current_user, :remove_project, @project)
- .panel.panel-default.panel.panel-danger
- .panel-heading Remove project
- .panel-body
+ - if can?(current_user, :remove_project, @project)
+ .panel.panel-default.panel.panel-danger
+ .panel-heading Remove project
+ .panel-body
+ = form_tag(project_path(@project), method: :delete, html: { class: 'form-horizontal'}) do
%p
Removing the project will delete its repository and all related resources including issues, merge requests etc.
%br
%strong Removed projects cannot be restored!
- = link_to 'Remove project', @project, data: { confirm: remove_project_message(@project) }, method: :delete, class: "btn btn-remove"
- - else
- .nothing-here-block Only project owner can remove a project
+ = link_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) }
+ - else
+ .nothing-here-block Only project owner can remove a project
.save-project-loader.hide
.center
@@ -188,3 +179,6 @@
%i.fa.fa-spinner.fa-spin
Saving project.
%p Please wait a moment, this page will automatically refresh when ready.
+
+
+= render 'shared/confirm_modal', phrase: @project.path
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index e1849b3f8b8..71eb0d5c866 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -62,7 +62,8 @@
= link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close js-note-target-close", title: "Close Issue"
.participants
- %cite.cgray #{@issue.participants.count} participants
+ %cite.cgray
+ = pluralize(@issue.participants.count, 'participant')
- @issue.participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index 49a3ef4c8a7..227a2f9a061 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -1,13 +1,13 @@
%h3.page-title Protected branches
-%p.light This ability keeps stable branches secure and forces developers to use code reviews
+%p.light Keep stable branches secure and force developers to use Merge Requests
%hr
.bs-callout.bs-callout-info
%p Protected branches are designed to
%ul
%li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions", "permissions"), class: "vlink"}
- %li prevents anyone from force pushing to the branch
- %li prevents anyone from deleting the branch
+ %li prevent anyone from force pushing to the branch
+ %li prevent anyone from deleting the branch
%p Read more about #{link_to "project permissions", help_page_path("permissions", "permissions"), class: "underlined-link"}
- if can? current_user, :admin_project, @project
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 09664ed51eb..9b06ebe95a4 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -62,11 +62,14 @@
- else
#{link_to @project.owner_name, @project.owner}
-
- - if @project.gitlab_ci?
- %hr
- = link_to @project.gitlab_ci_service.builds_path do
- = image_tag @project.gitlab_ci_service.status_img_path, alt: "build status"
+ - @project.ci_services.each do |ci_service|
+ - if ci_service.active? && ci_service.respond_to?(:builds_path)
+ - if ci_service.respond_to?(:status_img_path)
+ = link_to ci_service.builds_path do
+ = image_tag ci_service.status_img_path, alt: "build status"
+ - else
+ %span.light CI provided by
+ = link_to ci_service.title, ci_service.builds_path
- if readme
.tab-pane#tab-readme
diff --git a/app/views/projects/tree/_submodule_item.html.haml b/app/views/projects/tree/_submodule_item.html.haml
index a8ec9df2c8f..46e9be4af83 100644
--- a/app/views/projects/tree/_submodule_item.html.haml
+++ b/app/views/projects/tree/_submodule_item.html.haml
@@ -7,8 +7,8 @@
@
%span.monospace
- if commit.nil?
- #{submodule_item.id[0..10]}
+ #{truncate_sha(submodule_item.id)}
- else
- = link_to "#{submodule_item.id[0..10]}", commit
+ = link_to "#{truncate_sha(submodule_item.id)}", commit
%td
%td.hidden-xs
diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml
index d3a66c48c9b..ef4b8f74714 100644
--- a/app/views/projects/wikis/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -17,7 +17,7 @@
%tr
%td
= link_to project_wiki_path(@project, @page, version_id: commit.id) do
- = commit.id[0..10]
+ = truncate_sha(commit.id)
%td
= commit.author.name
%td
diff --git a/app/views/search/results/_note.html.haml b/app/views/search/results/_note.html.haml
index f2327cd69cc..a44a4542df5 100644
--- a/app/views/search/results/_note.html.haml
+++ b/app/views/search/results/_note.html.haml
@@ -10,7 +10,7 @@
= project.name_with_namespace
&middot;
= link_to project_commit_path(project, note.commit_id, anchor: dom_id(note)) do
- Commit #{note.commit_id[0..8]}
+ Commit #{truncate_sha(note.commit_id)}
- else
= link_to project do
= project.name_with_namespace
diff --git a/app/views/shared/_confirm_modal.html.haml b/app/views/shared/_confirm_modal.html.haml
new file mode 100644
index 00000000000..30ba361c860
--- /dev/null
+++ b/app/views/shared/_confirm_modal.html.haml
@@ -0,0 +1,22 @@
+#modal-confirm-danger.modal.hide{tabindex: -1}
+ .modal-dialog
+ .modal-content
+ .modal-header
+ %a.close{href: "#", "data-dismiss" => "modal"} ×
+ %h4 Confirmation required
+
+ .modal-body
+ %p.cred.lead.js-confirm-text
+
+ %p
+ This action can lead to data loss.
+ To prevent accidental actions we ask you to confirm your intention.
+ %br
+ Please type
+ %code.js-confirm-danger-match #{phrase}
+ to proceed or close this modal to cancel
+
+ .form-group
+ = text_field_tag 'confirm_name_input', '', class: 'form-control js-confirm-danger-input'
+ .form-group
+ = submit_tag 'Confirm', class: "btn btn-danger js-confirm-danger-submit"
diff --git a/app/views/shared/_promo.html.haml b/app/views/shared/_promo.html.haml
index 5675e43b05f..3400c345c4c 100644
--- a/app/views/shared/_promo.html.haml
+++ b/app/views/shared/_promo.html.haml
@@ -1,5 +1,5 @@
.gitlab-promo
- = link_to "Homepage", "https://www.gitlab.com/"
- = link_to "Blog", "https://www.gitlab.com/blog/"
+ = link_to 'Homepage', promo_url
+ = link_to "Blog", promo_url + '/blog/'
= link_to "@gitlabhq", "https://twitter.com/gitlabhq"
= link_to "Requests", "http://feedback.gitlab.com/"
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index f4d74045f77..f729f129e45 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -10,22 +10,8 @@
= f.label :title, class: 'control-label'
.col-sm-10= f.text_field :title, placeholder: "Example Snippet", class: 'form-control', required: true
- - unless @snippet.respond_to?(:project)
- .form-group
- = f.label "Access", class: 'control-label'
- .col-sm-10
- = f.label :private_true, class: 'radio-label' do
- = f.radio_button :private, true
- %span
- %strong Private
- (only you can see this snippet)
- %br
- = f.label :private_false, class: 'radio-label' do
- = f.radio_button :private, false
- %span
- %strong Internal
- (GitLab users can see this snippet)
-
+ = render "shared/snippets/visibility_level", f: f, visibility_level: gitlab_config.default_projects_features.visibility_level, can_change_visibility_level: true
+
.form-group
.file-editor
= f.label :file_name, "File", class: 'control-label'
diff --git a/app/views/shared/snippets/_visibility_level.html.haml b/app/views/shared/snippets/_visibility_level.html.haml
new file mode 100644
index 00000000000..9acff18e450
--- /dev/null
+++ b/app/views/shared/snippets/_visibility_level.html.haml
@@ -0,0 +1,27 @@
+.form-group.project-visibility-level-holder
+ = f.label :visibility_level, class: 'control-label' do
+ Visibility Level
+ = link_to "(?)", help_page_path("public_access", "public_access")
+ .col-sm-10
+ - if can_change_visibility_level
+ - Gitlab::VisibilityLevel.values.each do |level|
+ .radio
+ - restricted = restricted_visibility_levels.include?(level)
+ = f.radio_button :visibility_level, level, disabled: restricted
+ = label "#{dom_class(@snippet)}_visibility_level", level do
+ = visibility_level_icon(level)
+ .option-title
+ = visibility_level_label(level)
+ .option-descr
+ = snippet_visibility_level_description(level)
+ - unless restricted_visibility_levels.empty?
+ .col-sm-10
+ %span.info
+ Some visibility level settings have been restricted by the administrator.
+ - else
+ .col-sm-10
+ %span.info
+ = visibility_level_icon(visibility_level)
+ %strong
+ = visibility_level_label(visibility_level)
+ .light= visibility_level_description(visibility_level)
diff --git a/app/views/snippets/current_user_index.html.haml b/app/views/snippets/current_user_index.html.haml
index 14b5b072ec2..b2b7ea4df0e 100644
--- a/app/views/snippets/current_user_index.html.haml
+++ b/app/views/snippets/current_user_index.html.haml
@@ -28,6 +28,11 @@
Internal
%span.pull-right
= @user.snippets.are_internal.count
+ = nav_tab :scope, 'are_public' do
+ = link_to user_snippets_path(@user, scope: 'are_public') do
+ Public
+ %span.pull-right
+ = @user.snippets.are_public.count
.col-md-9.my-snippets
= render 'snippets'
diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml
index cea2517a8e1..0d71c41e2e7 100644
--- a/app/views/snippets/index.html.haml
+++ b/app/views/snippets/index.html.haml
@@ -2,10 +2,12 @@
Public snippets
.pull-right
- = link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
- Add new snippet
- = link_to user_snippets_path(current_user), class: "btn btn-grouped" do
- My snippets
+
+ - if current_user
+ = link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
+ Add new snippet
+ = link_to user_snippets_path(current_user), class: "btn btn-grouped" do
+ My snippets
%p.light
Public snippets created by you and other users are listed here
diff --git a/app/views/snippets/user_index.html.haml b/app/views/snippets/user_index.html.haml
index 1cb53ec6a25..67f3a68aa22 100644
--- a/app/views/snippets/user_index.html.haml
+++ b/app/views/snippets/user_index.html.haml
@@ -4,8 +4,9 @@
%span
\/
Snippets
- = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do
- Add new snippet
+ - if current_user
+ = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do
+ Add new snippet
%hr
diff --git a/db/migrate/20141007100818_add_visibility_level_to_snippet.rb b/db/migrate/20141007100818_add_visibility_level_to_snippet.rb
new file mode 100644
index 00000000000..7f125acb5d1
--- /dev/null
+++ b/db/migrate/20141007100818_add_visibility_level_to_snippet.rb
@@ -0,0 +1,21 @@
+class AddVisibilityLevelToSnippet < ActiveRecord::Migration
+ def up
+ add_column :snippets, :visibility_level, :integer, :default => 0, :null => false
+
+ Snippet.where(private: true).update_all(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ Snippet.where(private: false).update_all(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
+
+ add_index :snippets, :visibility_level
+
+ remove_column :snippets, :private
+ end
+
+ def down
+ add_column :snippets, :private, :boolean, :default => false, :null => false
+
+ Snippet.where(visibility_level: Gitlab::VisibilityLevel::INTERNAL).update_all(private: false)
+ Snippet.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE).update_all(private: true)
+
+ remove_column :snippets, :visibility_level
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 84fd1256677..8ddebc5132a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20141006143943) do
+ActiveRecord::Schema.define(version: 20141007100818) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -293,20 +293,21 @@ ActiveRecord::Schema.define(version: 20141006143943) do
create_table "snippets", force: true do |t|
t.string "title"
t.text "content"
- t.integer "author_id", null: false
+ t.integer "author_id", null: false
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "file_name"
t.datetime "expires_at"
- t.boolean "private", default: true, null: false
t.string "type"
+ t.integer "visibility_level", default: 0, null: false
end
add_index "snippets", ["author_id"], name: "index_snippets_on_author_id", using: :btree
add_index "snippets", ["created_at"], name: "index_snippets_on_created_at", using: :btree
add_index "snippets", ["expires_at"], name: "index_snippets_on_expires_at", using: :btree
add_index "snippets", ["project_id"], name: "index_snippets_on_project_id", using: :btree
+ add_index "snippets", ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree
create_table "taggings", force: true do |t|
t.integer "tag_id"
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index 4624d9f60b6..c4813d22eaa 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -2,7 +2,7 @@
## Software delivery
-There are two editions of GitLab: [Enterprise Edition](https://www.gitlab.com/gitlab-ee/) (EE) and [Community Edition](https://www.gitlab.com/gitlab-ce/) (CE). GitLab CE is delivered via git from the [gitlabhq repository](https://gitlab.com/gitlab-org/gitlab-ce/tree/master). New versions of GitLab are released in stable branches and the master branch is for bleeding edge development.
+There are two editions of GitLab: [Enterprise Edition](https://about.gitlab.com/gitlab-ee/) (EE) and [Community Edition](https://about.gitlab.com/gitlab-ce/) (CE). GitLab CE is delivered via git from the [gitlabhq repository](https://gitlab.com/gitlab-org/gitlab-ce/tree/master). New versions of GitLab are released in stable branches and the master branch is for bleeding edge development.
EE releases are available not long after CE releases. To obtain the GitLab EE there is a [repository at gitlab.com](https://gitlab.com/subscribers/gitlab-ee). For more information about the release process see the section 'New versions and upgrading' in the readme.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index af6e182cfa0..0d1a8da4d1b 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -6,13 +6,13 @@ Make sure you view [this installation guide](https://gitlab.com/gitlab-org/gitla
![Select latest branch](https://i.imgur.com/Lrdxk1k.png)
-If the highest number stable branch is unclear please check the [GitLab Blog](https://www.gitlab.com/blog/) for installation guide links by version.
+If the highest number stable branch is unclear please check the [GitLab Blog](https://about.gitlab.com/blog/) for installation guide links by version.
## Important Notes
This guide is long because it covers many cases and includes all commands you need, this is [one of the few installation scripts that actually works out of the box](https://twitter.com/robinvdvleuten/status/424163226532986880).
-This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [doc/install/requirements.md](./requirements.md) for hardware and operating system requirements. If you want to install on RHEL/CentOS we recommend using the [Omnibus packages](https://www.gitlab.com/downloads/).
+This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [doc/install/requirements.md](./requirements.md) for hardware and operating system requirements. If you want to install on RHEL/CentOS we recommend using the [Omnibus packages](https://about.gitlab.com/downloads/).
This is the official installation guide to set up a production server. To set up a **development installation** or for many other installation options please see [the installation section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#installation).
diff --git a/doc/release/security.md b/doc/release/security.md
index da442de6ee1..79d23c02ea4 100644
--- a/doc/release/security.md
+++ b/doc/release/security.md
@@ -8,7 +8,7 @@ Do a security release when there is a critical issue that needs to be addresses
## Security vulnerability disclosure
-Please report suspected security vulnerabilities in private to <support@gitlab.com>, also see the [disclosure section on the GitLab.com website](http://www.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
+Please report suspected security vulnerabilities in private to <support@gitlab.com>, also see the [disclosure section on the GitLab.com website](http://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
## Release Procedure
@@ -21,7 +21,7 @@ Please report suspected security vulnerabilities in private to <support@gitlab.c
1. Send out an email to the 'GitLab Newsletter' mailing list on MailChimp (or the 'Subscribers' list if the security fix is for EE only)
1. Send out an email to [the community google mailing list](https://groups.google.com/forum/#!forum/gitlabhq)
1. Post a signed copy of our complete announcement to [oss-security](http://www.openwall.com/lists/oss-security/) and request a CVE number
-1. Add the security researcher to the [Security Researcher Acknowledgments list](http://www.gitlab.com/vulnerability-acknowledgements/)
+1. Add the security researcher to the [Security Researcher Acknowledgments list](http://about.gitlab.com/vulnerability-acknowledgements/)
1. Thank the security researcher in an email for their cooperation
1. Update the blog post and the CHANGELOG when we receive the CVE number
diff --git a/doc/update/6.x-or-7.x-to-7.3.md b/doc/update/6.x-or-7.x-to-7.3.md
index 171fcb4033a..fe3530ef9c1 100644
--- a/doc/update/6.x-or-7.x-to-7.3.md
+++ b/doc/update/6.x-or-7.x-to-7.3.md
@@ -64,12 +64,12 @@ sudo gem install bundler --no-ri --no-rdoc
```bash
cd /home/git/gitlab
sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
```
For GitLab Community Edition:
```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
sudo -u git -H git checkout 7-3-stable
```
@@ -78,7 +78,6 @@ OR
For GitLab Enterprise Edition:
```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
sudo -u git -H git checkout 7-3-stable-ee
```
diff --git a/doc/update/7.2-to-7.3.md b/doc/update/7.2-to-7.3.md
index 329b763322a..44f3f8f1a38 100644
--- a/doc/update/7.2-to-7.3.md
+++ b/doc/update/7.2-to-7.3.md
@@ -18,12 +18,12 @@ sudo service gitlab stop
```bash
cd /home/git/gitlab
sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
```
For GitLab Community Edition:
```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
sudo -u git -H git checkout 7-3-stable
```
@@ -32,7 +32,6 @@ OR
For GitLab Enterprise Edition:
```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
sudo -u git -H git checkout 7-3-stable-ee
```
diff --git a/doc/update/7.3-to-7.4.md b/doc/update/7.3-to-7.4.md
new file mode 100644
index 00000000000..2e1b993aeb8
--- /dev/null
+++ b/doc/update/7.3-to-7.4.md
@@ -0,0 +1,68 @@
+# From 7.3 to 7.4
+
+## GitLab 7.4 has not been released yet!
+
+This document currently just serves as a place to keep track of updates that will be needed for the 7.4 update.
+
+## Update config files
+
+* Add `collation: utf8_general_ci` to config/database.yml as seen in [config/database.yml.mysql](config/database.yml.mysql)
+
+## Optional optimizations for GitLab setups with MySQL databases
+
+Only applies if running MySQL database created with GitLab 6.7 or earlier. If you are not experiencing any issues you may not need the following instructions however following them will bring your database in line with the latest recommended installation configuration and help avoid future issues. Be sure to follow these directions exactly. These directions should be safe for any MySQL instance but to be sure make a current MySQL database backup beforehand.
+
+```
+# Secure your MySQL installation (added in GitLab 6.2)
+sudo mysql_secure_installation
+
+# Login to MySQL
+mysql -u root -p
+
+# do not type the 'mysql>', this is part of the prompt
+
+# Convert all tables to use the InnoDB storage engine (added in GitLab 6.8)
+SELECT CONCAT('ALTER TABLE gitlabhq_production.', table_name, ' ENGINE=InnoDB;') AS 'Copy & run these SQL statements:' FROM information_schema.tables WHERE table_schema = 'gitlabhq_production' AND `ENGINE` <> 'InnoDB' AND `TABLE_TYPE` = 'BASE TABLE';
+
+# If previous query returned results, copy & run all outputed SQL statements
+
+# Find MySQL users
+mysql> SELECT user FROM mysql.user WHERE user LIKE '%git%';
+
+# If git user exists and gitlab user does not exist
+# you are done with the database cleanup tasks
+mysql> \q
+
+# If both users exist skip to Delete gitlab user
+
+# Create new user for GitLab (changed in GitLab 6.4)
+# change $password in the command below to a real password you pick
+mysql> CREATE USER 'git'@'localhost' IDENTIFIED BY '$password';
+
+# Grant the git user necessary permissions on the database
+mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, LOCK TABLES ON `gitlabhq_production`.* TO 'git'@'localhost';
+
+# Delete the old gitlab user
+mysql> DELETE FROM mysql.user WHERE user='gitlab';
+
+# Quit the database session
+mysql> \q
+
+# Try connecting to the new database with the new user
+sudo -u git -H mysql -u git -p -D gitlabhq_production
+
+# Type the password you replaced $password with earlier
+
+# You should now see a 'mysql>' prompt
+
+# Quit the database session
+mysql> \q
+
+# Update database configuration details
+# See config/database.yml.mysql for latest recommended configuration details
+# Remove the reaping_frequency setting line if it exists (removed in GitLab 6.8)
+# Set production -> pool: 10 (updated in GitLab 5.3)
+# Set production -> username: git
+# Set production -> password: the password your replaced $password with earlier
+sudo -u git -H editor /home/git/gitlab/config/database.yml
+```
diff --git a/features/admin/active_tab.feature b/features/admin/active_tab.feature
index b28e16f0d6a..5de07e90e28 100644
--- a/features/admin/active_tab.feature
+++ b/features/admin/active_tab.feature
@@ -1,5 +1,5 @@
@admin
-Feature: Admin active tab
+Feature: Admin Active Tab
Background:
Given I sign in as an admin
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index e989569ccd4..4db8551559b 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -144,7 +144,7 @@ Feature: Project Issues
Scenario: Issues list should display task status
Given project "Shop" has "Tasks-open" open issue with task markdown
When I visit project "Shop" issues page
- Then I should see the task status for issue "Tasks-open"
+ Then I should see the task status for the Taskable
# Toggling task items
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index e1e0edd0545..d20358a7dc6 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -168,11 +168,10 @@ Feature: Project Merge Requests
# Task status in issues list
- @now
Scenario: Merge requests list should display task status
Given project "Shop" has "MR-task-open" open MR with task markdown
When I visit project "Shop" merge requests page
- Then I should see the task status for merge request "MR-task-open"
+ Then I should see the task status for the Taskable
# Toggling task items
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index 8ff2f583b38..aca255b9444 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -1,4 +1,4 @@
-Feature: Project Source Browse files
+Feature: Project Source Browse Files
Background:
Given I sign in as a user
And I own project "Shop"
diff --git a/features/snippets/discover.feature b/features/snippets/discover.feature
index 5094062c8c3..1a7e132ea25 100644
--- a/features/snippets/discover.feature
+++ b/features/snippets/discover.feature
@@ -4,8 +4,10 @@ Feature: Snippets Discover
Given I sign in as a user
And I have public "Personal snippet one" snippet
And I have private "Personal snippet private" snippet
+ And I have internal "Personal snippet internal" snippet
Scenario: I should see snippets
Given I visit snippets page
Then I should see "Personal snippet one" in snippets
+ And I should see "Personal snippet internal" in snippets
And I should not see "Personal snippet private" in snippets
diff --git a/features/snippets/user.feature b/features/snippets/user.feature
index ae34e8e7ffa..5b5dadb7b39 100644
--- a/features/snippets/user.feature
+++ b/features/snippets/user.feature
@@ -4,20 +4,31 @@ Feature: Snippets User
Given I sign in as a user
And I have public "Personal snippet one" snippet
And I have private "Personal snippet private" snippet
+ And I have internal "Personal snippet internal" snippet
Scenario: I should see all my snippets
Given I visit my snippets page
Then I should see "Personal snippet one" in snippets
And I should see "Personal snippet private" in snippets
+ And I should see "Personal snippet internal" in snippets
Scenario: I can see only my private snippets
Given I visit my snippets page
And I click "Private" filter
Then I should not see "Personal snippet one" in snippets
+ And I should not see "Personal snippet internal" in snippets
And I should see "Personal snippet private" in snippets
Scenario: I can see only my public snippets
Given I visit my snippets page
- And I click "Internal" filter
+ And I click "Public" filter
Then I should see "Personal snippet one" in snippets
And I should not see "Personal snippet private" in snippets
+ And I should not see "Personal snippet internal" in snippets
+
+ Scenario: I can see only my internal snippets
+ Given I visit my snippets page
+ And I click "Internal" filter
+ Then I should see "Personal snippet internal" in snippets
+ And I should not see "Personal snippet private" in snippets
+ And I should not see "Personal snippet one" in snippets
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index c054e0e8282..935f313e298 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -8,7 +8,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
commit = @project.repository.commit
page.should have_content(@project.name)
page.should have_content(commit.message[0..20])
- page.should have_content(commit.id.to_s[0..5])
+ page.should have_content(commit.short_id)
end
step 'I click atom feed link' do
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index 26c3c7c14bc..640603562dd 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -154,29 +154,11 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
end
step 'project "Shop" has "Tasks-open" open issue with task markdown' do
- desc_text = <<EOT.gsub(/^ {6}/, '')
- * [ ] Task 1
- * [x] Task 2
-EOT
- create(:issue,
- title: 'Tasks-open',
- project: project,
- author: project.users.first,
- description: desc_text
- )
+ create_taskable(:issue, 'Tasks-open')
end
step 'project "Shop" has "Tasks-closed" closed issue with task markdown' do
- desc_text = <<EOT.gsub(/^ {6}/, '')
- * [ ] Task 1
- * [x] Task 2
-EOT
- create(:closed_issue,
- title: 'Tasks-closed',
- project: project,
- author: project.users.first,
- description: desc_text
- )
+ create_taskable(:closed_issue, 'Tasks-closed')
end
step 'empty project "Empty Project"' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 0fec2604915..fae0cec53a6 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -98,17 +98,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'project "Shop" has "MR-task-open" open MR with task markdown' do
- desc_text = <<EOT.gsub(/^ {6}/, '')
- * [ ] Task 1
- * [x] Task 2
-EOT
- create(:merge_request,
- title: 'MR-task-open',
- source_project: project,
- target_project: project,
- author: project.users.first,
- description: desc_text
- )
+ create_taskable(:merge_request, 'MR-task-open')
end
step 'I switch to the diff tab' do
@@ -121,7 +111,7 @@ EOT
step 'I click on the commit in the merge request' do
within '.mr-commits' do
- click_link sample_commit.id[0..8]
+ click_link Commit.truncate_sha(sample_commit.id)
end
end
diff --git a/features/steps/shared/markdown.rb b/features/steps/shared/markdown.rb
index 1d9058cf256..8bf138065b0 100644
--- a/features/steps/shared/markdown.rb
+++ b/features/steps/shared/markdown.rb
@@ -6,6 +6,27 @@ module SharedMarkdown
find(:css, "#{parent} h#{level}##{id} > :last-child")[:href].should =~ /##{id}$/
end
+ def create_taskable(type, title)
+ desc_text = <<EOT.gsub(/^ {6}/, '')
+ * [ ] Task 1
+ * [x] Task 2
+EOT
+
+ case type
+ when :issue, :closed_issue
+ options = { project: project }
+ when :merge_request
+ options = { source_project: project, target_project: project }
+ end
+
+ create(
+ type,
+ options.merge(title: title,
+ author: project.users.first,
+ description: desc_text)
+ )
+ end
+
step 'Header "Description header" should have correct id and link' do
header_should_have_correct_id_and_link(1, 'Description header', 'description-header')
end
@@ -16,13 +37,7 @@ module SharedMarkdown
)
end
- step 'I should see the task status for issue "Tasks-open"' do
- expect(find(:css, 'span.task-status').text).to eq(
- '2 tasks (1 done, 1 unfinished)'
- )
- end
-
- step 'I should see the task status for merge request "MR-task-open"' do
+ step 'I should see the task status for the Taskable' do
expect(find(:css, 'span.task-status').text).to eq(
'2 tasks (1 done, 1 unfinished)'
)
diff --git a/features/steps/shared/snippet.rb b/features/steps/shared/snippet.rb
index 5a27e8750cf..432f32defce 100644
--- a/features/steps/shared/snippet.rb
+++ b/features/steps/shared/snippet.rb
@@ -6,7 +6,7 @@ module SharedSnippet
title: "Personal snippet one",
content: "Test content",
file_name: "snippet.rb",
- private: false,
+ visibility_level: Snippet::PUBLIC,
author: current_user)
end
@@ -15,9 +15,19 @@ module SharedSnippet
title: "Personal snippet private",
content: "Provate content",
file_name: "private_snippet.rb",
- private: true,
+ visibility_level: Snippet::PRIVATE,
author: current_user)
end
+
+ step 'I have internal "Personal snippet internal" snippet' do
+ create(:personal_snippet,
+ title: "Personal snippet internal",
+ content: "Provate content",
+ file_name: "internal_snippet.rb",
+ visibility_level: Snippet::INTERNAL,
+ author: current_user)
+ end
+
step 'I have a public many lined snippet' do
create(:personal_snippet,
title: 'Many lined snippet',
@@ -38,7 +48,7 @@ module SharedSnippet
|line fourteen
END
file_name: 'many_lined_snippet.rb',
- private: true,
+ visibility_level: Snippet::PUBLIC,
author: current_user)
end
end
diff --git a/features/steps/snippets/discover.rb b/features/steps/snippets/discover.rb
index 42bccafcc84..2667c1e3d44 100644
--- a/features/steps/snippets/discover.rb
+++ b/features/steps/snippets/discover.rb
@@ -7,6 +7,10 @@ class Spinach::Features::SnippetsDiscover < Spinach::FeatureSteps
page.should have_content "Personal snippet one"
end
+ step 'I should see "Personal snippet internal" in snippets' do
+ page.should have_content "Personal snippet internal"
+ end
+
step 'I should not see "Personal snippet private" in snippets' do
page.should_not have_content "Personal snippet private"
end
diff --git a/features/steps/snippets/user.rb b/features/steps/snippets/user.rb
index c41bc436142..866f637ab6c 100644
--- a/features/steps/snippets/user.rb
+++ b/features/steps/snippets/user.rb
@@ -15,6 +15,10 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
page.should have_content "Personal snippet private"
end
+ step 'I should see "Personal snippet internal" in snippets' do
+ page.should have_content "Personal snippet internal"
+ end
+
step 'I should not see "Personal snippet one" in snippets' do
page.should_not have_content "Personal snippet one"
end
@@ -23,6 +27,10 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
page.should_not have_content "Personal snippet private"
end
+ step 'I should not see "Personal snippet internal" in snippets' do
+ page.should_not have_content "Personal snippet internal"
+ end
+
step 'I click "Internal" filter' do
within('.nav-stacked') do
click_link "Internal"
@@ -35,6 +43,12 @@ class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
end
end
+ step 'I click "Public" filter' do
+ within('.nav-stacked') do
+ click_link "Public"
+ end
+ end
+
def snippet
@snippet ||= PersonalSnippet.find_by!(title: "Personal snippet one")
end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 5f484f63418..9ac659f50fd 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -14,13 +14,20 @@ module API
#
post "/allowed" do
status 200
+ project_path = params[:project]
# Check for *.wiki repositories.
# Strip out the .wiki from the pathname before finding the
# project. This applies the correct project permissions to
# the wiki repository as well.
- project_path = params[:project]
- project_path.gsub!(/\.wiki/,'') if project_path =~ /\.wiki/
+ access =
+ if project_path =~ /\.wiki\Z/
+ project_path.sub!(/\.wiki\Z/, '')
+ Gitlab::GitAccessWiki.new
+ else
+ Gitlab::GitAccess.new
+ end
+
project = Project.find_with_namespace(project_path)
return false unless project
@@ -32,7 +39,7 @@ module API
return false unless actor
- Gitlab::GitAccess.new.allowed?(
+ access.allowed?(
actor,
params[:action],
project,
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 6247dd59867..b768a99a0e8 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -49,25 +49,7 @@ module Gitlab
# Iterate over all changes to find if user allowed all of them to be applied
changes.each do |change|
- oldrev, newrev, ref = change.split(' ')
-
- action = if project.protected_branch?(branch_name(ref))
- # we dont allow force push to protected branch
- if forced_push?(project, oldrev, newrev)
- :force_push_code_to_protected_branches
- # and we dont allow remove of protected branch
- elsif newrev =~ /0000000/
- :remove_protected_branches
- else
- :push_code_to_protected_branches
- end
- elsif project.repository && project.repository.tag_names.include?(tag_name(ref))
- # Prevent any changes to existing git tag unless user has permissions
- :admin_project
- else
- :push_code
- end
- unless user.can?(action, project)
+ unless change_allowed?(user, project, change)
# If user does not have access to make at least one change - cancel all push
return false
end
@@ -77,6 +59,29 @@ module Gitlab
true
end
+ def change_allowed?(user, project, change)
+ oldrev, newrev, ref = change.split(' ')
+
+ action = if project.protected_branch?(branch_name(ref))
+ # we dont allow force push to protected branch
+ if forced_push?(project, oldrev, newrev)
+ :force_push_code_to_protected_branches
+ # and we dont allow remove of protected branch
+ elsif newrev =~ /0000000/
+ :remove_protected_branches
+ else
+ :push_code_to_protected_branches
+ end
+ elsif project.repository && project.repository.tag_names.include?(tag_name(ref))
+ # Prevent any changes to existing git tag unless user has permissions
+ :admin_project
+ else
+ :push_code
+ end
+
+ user.can?(action, project)
+ end
+
def forced_push?(project, oldrev, newrev)
return false if project.empty_repo?
diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb
new file mode 100644
index 00000000000..9f0eb3be20f
--- /dev/null
+++ b/lib/gitlab/git_access_wiki.rb
@@ -0,0 +1,7 @@
+module Gitlab
+ class GitAccessWiki < GitAccess
+ def change_allowed?(user, project, change)
+ user.can?(:write_wiki, project)
+ end
+ end
+end
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index 25b5a702f9a..006ef170726 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -10,22 +10,6 @@ module Gitlab
module LDAP
class User < Gitlab::OAuth::User
class << self
- def find_or_create(auth_hash)
- self.auth_hash = auth_hash
- find(auth_hash) || find_and_connect_by_email(auth_hash) || create(auth_hash)
- end
-
- def find_and_connect_by_email(auth_hash)
- self.auth_hash = auth_hash
- user = model.find_by(email: self.auth_hash.email)
-
- if user
- user.update_attributes(extern_uid: auth_hash.uid, provider: auth_hash.provider)
- Gitlab::AppLogger.info("(LDAP) Updating legacy LDAP user #{self.auth_hash.email} with extern_uid => #{auth_hash.uid}")
- return user
- end
- end
-
def authenticate(login, password)
# Check user against LDAP backend if user is not authenticated
# Only check with valid login and password to prevent anonymous bind results
@@ -44,10 +28,18 @@ module Gitlab
@adapter ||= OmniAuth::LDAP::Adaptor.new(ldap_conf)
end
- protected
+ def user_filter(login)
+ filter = Net::LDAP::Filter.eq(adapter.uid, login)
+ # Apply LDAP user filter if present
+ if ldap_conf['user_filter'].present?
+ user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter'])
+ filter = Net::LDAP::Filter.join(filter, user_filter)
+ end
+ filter
+ end
- def find_by_uid_and_provider
- find_by_uid(auth_hash.uid)
+ def ldap_conf
+ Gitlab.config.ldap
end
def find_by_uid(uid)
@@ -58,24 +50,39 @@ module Gitlab
def provider
'ldap'
end
+ end
- def raise_error(message)
- raise OmniAuth::Error, "(LDAP) " + message
- end
+ def initialize(auth_hash)
+ super
+ update_user_attributes
+ end
- def ldap_conf
- Gitlab.config.ldap
- end
+ # instance methods
+ def gl_user
+ @gl_user ||= find_by_uid_and_provider || find_by_email || build_new_user
+ end
- def user_filter(login)
- filter = Net::LDAP::Filter.eq(adapter.uid, login)
- # Apply LDAP user filter if present
- if ldap_conf['user_filter'].present?
- user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter'])
- filter = Net::LDAP::Filter.join(filter, user_filter)
- end
- filter
- end
+ def find_by_uid_and_provider
+ # LDAP distinguished name is case-insensitive
+ model.
+ where(provider: auth_hash.provider).
+ where('lower(extern_uid) = ?', auth_hash.uid.downcase).last
+ end
+
+ def find_by_email
+ model.find_by(email: auth_hash.email)
+ end
+
+ def update_user_attributes
+ gl_user.attributes = {
+ extern_uid: auth_hash.uid,
+ provider: auth_hash.provider,
+ email: auth_hash.email
+ }
+ end
+
+ def changed?
+ gl_user.changed?
end
def needs_blocking?
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 17512a51658..ddcce7557a0 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -70,14 +70,22 @@ module Gitlab
insert_piece($1)
end
- # Context passed to the markdoqwn pipeline
+ # Used markdown pipelines in GitLab:
+ # GitlabEmojiFilter - performs emoji replacement.
+ #
+ # see https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters
+ filters = [
+ HTML::Pipeline::Gitlab::GitlabEmojiFilter
+ ]
+
markdown_context = {
- asset_root: File.join(root_url,
- Gitlab::Application.config.assets.prefix)
+ asset_root: Gitlab.config.gitlab.url,
+ asset_host: Gitlab::Application.config.asset_host
}
- result = HTML::Pipeline::Gitlab::MarkdownPipeline.call(text,
- markdown_context)
+ markdown_pipeline = HTML::Pipeline::Gitlab.new(filters).pipeline
+
+ result = markdown_pipeline.call(text, markdown_context)
text = result[:output].to_html(save_with: 0)
allowed_attributes = ActionView::Base.sanitized_allowed_attributes
diff --git a/lib/gitlab/oauth/auth_hash.rb b/lib/gitlab/oauth/auth_hash.rb
index 0198f61f427..ce52beec78e 100644
--- a/lib/gitlab/oauth/auth_hash.rb
+++ b/lib/gitlab/oauth/auth_hash.rb
@@ -21,7 +21,7 @@ module Gitlab
end
def name
- (info.name || full_name).to_s.force_encoding('utf-8')
+ (info.try(:name) || full_name).to_s.force_encoding('utf-8')
end
def full_name
diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb
index b768eda185f..699258baee4 100644
--- a/lib/gitlab/oauth/user.rb
+++ b/lib/gitlab/oauth/user.rb
@@ -6,55 +6,52 @@
module Gitlab
module OAuth
class User
- class << self
- attr_reader :auth_hash
+ attr_accessor :auth_hash, :gl_user
- def find(auth_hash)
- self.auth_hash = auth_hash
- find_by_uid_and_provider
- end
-
- def create(auth_hash)
- user = new(auth_hash)
- user.save_and_trigger_callbacks
- end
+ def initialize(auth_hash)
+ self.auth_hash = auth_hash
+ end
- def model
- ::User
- end
+ def persisted?
+ gl_user.persisted?
+ end
- def auth_hash=(auth_hash)
- @auth_hash = AuthHash.new(auth_hash)
- end
+ def new?
+ !gl_user.persisted?
+ end
- protected
- def find_by_uid_and_provider
- model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last
- end
+ def valid?
+ gl_user.valid?
end
- # Instance methods
- attr_accessor :auth_hash, :user
+ def save
+ gl_user.save!
+ log.info "(OAuth) saving user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}"
+ gl_user.block if needs_blocking?
- def initialize(auth_hash)
- self.auth_hash = auth_hash
- self.user = self.class.model.new(user_attributes)
- user.skip_confirmation!
+ gl_user
+ rescue ActiveRecord::RecordInvalid => e
+ log.info "(OAuth) Error saving user: #{gl_user.errors.full_messages}"
+ return self, e.record.errors
+ end
+
+ def gl_user
+ @user ||= find_by_uid_and_provider || build_new_user
end
+ protected
def auth_hash=(auth_hash)
@auth_hash = AuthHash.new(auth_hash)
end
- def save_and_trigger_callbacks
- user.save!
- log.info "(OAuth) Creating user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}"
- user.block if needs_blocking?
+ def find_by_uid_and_provider
+ model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last
+ end
- user
- rescue ActiveRecord::RecordInvalid => e
- log.info "(OAuth) Email #{e.record.errors[:email]}. Username #{e.record.errors[:username]}"
- return nil, e.record.errors
+ def build_new_user
+ model.new(user_attributes).tap do |user|
+ user.skip_confirmation!
+ end
end
def user_attributes
@@ -80,6 +77,10 @@ module Gitlab
def needs_blocking?
Gitlab.config.omniauth['block_auto_created_users']
end
+
+ def model
+ ::User
+ end
end
end
end
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index c3378d6a18f..54d740908d5 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -10,6 +10,17 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
super options
end
+ # If project has issue number 39, apostrophe will be linked in
+ # regular text to the issue as Redcarpet will convert apostrophe to
+ # #39;
+ # We replace apostrophe with right single quote before Redcarpet
+ # does the processing and put the apostrophe back in postprocessing.
+ # This only influences regular text, code blocks are untouched.
+ def normal_text(text)
+ return text unless text.present?
+ text.gsub("'", "&rsquo;")
+ end
+
def block_code(code, language)
# New lines are placed to fix an rendering issue
# with code wrapped inside <h1> tag for next case:
@@ -44,6 +55,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
end
def postprocess(full_document)
+ full_document.gsub!("&rsquo;", "'")
unless @template.instance_variable_get("@project_wiki") || @project.nil?
full_document = h.create_relative_links(full_document)
end
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 5f1afe6575c..d3fb467ef27 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -19,7 +19,7 @@
## - installing an old version of Nginx with the chunkin module [2] compiled in, or
## - using a newer version of Nginx.
##
-## At the time of writing we do not know if either of these theoretical solutions works.
+## At the time of writing we do not know if either of these theoretical solutions works.
## As a workaround users can use Git over SSH to push large files.
##
## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
@@ -42,7 +42,7 @@ server {
listen *:80 default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice
-
+
## Redirects all traffic to the HTTPS host
root /nowhere; ## root doesn't have to be a valid path since we are redirecting
rewrite ^ https://$server_name$request_uri? permanent;
@@ -65,14 +65,15 @@ server {
ssl_certificate /etc/nginx/ssl/gitlab.crt;
ssl_certificate_key /etc/nginx/ssl/gitlab.key;
- ssl_ciphers 'AES256+EECDH:AES256+EDH';
+ # GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
+ ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_prefer_server_ciphers on;
- ## [WARNING] The following header states that the browser should only communicate
+ ## [WARNING] The following header states that the browser should only communicate
## with your server over a secure connection for the next 24 months.
add_header Strict-Transport-Security max-age=63072000;
add_header X-Frame-Options SAMEORIGIN;
diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake
index cbfa736c84c..b6ed874e11a 100644
--- a/lib/tasks/gitlab/import.rake
+++ b/lib/tasks/gitlab/import.rake
@@ -27,7 +27,10 @@ namespace :gitlab do
group_name = nil if group_name == '.'
# Skip if group or user
- next if namespaces.include?(name)
+ if namespaces.include?(name)
+ puts "Skipping #{project.name} due to namespace conflict with group or user".yellow
+ next
+ end
puts "Processing #{repo_path}".yellow
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 524c4d5fa21..98ba5a47ee5 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -10,8 +10,12 @@ describe "Projects", feature: true do
visit edit_project_path(@project)
end
- it "should be correct path" do
- expect { click_link "Remove project" }.to change {Project.count}.by(-1)
+ it "should be correct path", js: true do
+ expect {
+ click_link "Remove project"
+ fill_in 'confirm_name_input', with: @project.path
+ click_button 'Confirm'
+ }.to change {Project.count}.by(-1)
end
end
end
diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb
new file mode 100644
index 00000000000..5af76968183
--- /dev/null
+++ b/spec/finders/snippets_finder_spec.rb
@@ -0,0 +1,94 @@
+require 'spec_helper'
+
+describe SnippetsFinder do
+ let(:user) { create :user }
+ let(:user1) { create :user }
+ let(:group) { create :group }
+
+ let(:project1) { create(:empty_project, :public, group: group) }
+ let(:project2) { create(:empty_project, :private, group: group) }
+
+
+ context ':all filter' do
+ before do
+ @snippet1 = create(:personal_snippet, visibility_level: Snippet::PRIVATE)
+ @snippet2 = create(:personal_snippet, visibility_level: Snippet::INTERNAL)
+ @snippet3 = create(:personal_snippet, visibility_level: Snippet::PUBLIC)
+ end
+
+ it "returns all private and internal snippets" do
+ snippets = SnippetsFinder.new.execute(user, filter: :all)
+ snippets.should include(@snippet2, @snippet3)
+ snippets.should_not include(@snippet1)
+ end
+
+ it "returns all public snippets" do
+ snippets = SnippetsFinder.new.execute(nil, filter: :all)
+ snippets.should include(@snippet3)
+ snippets.should_not include(@snippet1, @snippet2)
+ end
+ end
+
+ context ':by_user filter' do
+ before do
+ @snippet1 = create(:personal_snippet, visibility_level: Snippet::PRIVATE, author: user)
+ @snippet2 = create(:personal_snippet, visibility_level: Snippet::INTERNAL, author: user)
+ @snippet3 = create(:personal_snippet, visibility_level: Snippet::PUBLIC, author: user)
+ end
+
+ it "returns all public and internal snippets" do
+ snippets = SnippetsFinder.new.execute(user1, filter: :by_user, user: user)
+ snippets.should include(@snippet2, @snippet3)
+ snippets.should_not include(@snippet1)
+ end
+
+ it "returns internal snippets" do
+ snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_internal")
+ snippets.should include(@snippet2)
+ snippets.should_not include(@snippet1, @snippet3)
+ end
+
+ it "returns private snippets" do
+ snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_private")
+ snippets.should include(@snippet1)
+ snippets.should_not include(@snippet2, @snippet3)
+ end
+
+ it "returns public snippets" do
+ snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_public")
+ snippets.should include(@snippet3)
+ snippets.should_not include(@snippet1, @snippet2)
+ end
+
+ it "returns all snippets" do
+ snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user)
+ snippets.should include(@snippet1, @snippet2, @snippet3)
+ end
+ end
+
+ context 'by_project filter' do
+ before do
+ @snippet1 = create(:project_snippet, visibility_level: Snippet::PRIVATE, project: project1)
+ @snippet2 = create(:project_snippet, visibility_level: Snippet::INTERNAL, project: project1)
+ @snippet3 = create(:project_snippet, visibility_level: Snippet::PUBLIC, project: project1)
+ end
+
+ it "returns public snippets for unauthorized user" do
+ snippets = SnippetsFinder.new.execute(nil, filter: :by_project, project: project1)
+ snippets.should include(@snippet3)
+ snippets.should_not include(@snippet1, @snippet2)
+ end
+
+ it "returns public and internal snippets for none project members" do
+ snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
+ snippets.should include(@snippet2, @snippet3)
+ snippets.should_not include(@snippet1)
+ end
+
+ it "returns all snippets for project members" do
+ project1.team << [user, :developer]
+ snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
+ snippets.should include(@snippet1, @snippet2, @snippet3)
+ end
+ end
+end
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
new file mode 100644
index 00000000000..4de54d291f2
--- /dev/null
+++ b/spec/helpers/events_helper_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe EventsHelper do
+ include ApplicationHelper
+ include GitlabMarkdownHelper
+
+ it 'should display one line of plain text without alteration' do
+ input = 'A short, plain note'
+ expect(event_note(input)).to match(input)
+ expect(event_note(input)).not_to match(/\.\.\.\z/)
+ end
+
+ it 'should display inline code' do
+ input = 'A note with `inline code`'
+ expected = 'A note with <code>inline code</code>'
+
+ expect(event_note(input)).to match(expected)
+ end
+
+ it 'should truncate a note with multiple paragraphs' do
+ input = "Paragraph 1\n\nParagraph 2"
+ expected = 'Paragraph 1...'
+
+ expect(event_note(input)).to match(expected)
+ end
+
+ it 'should display the first line of a code block' do
+ input = "```\nCode block\nwith two lines\n```"
+ expected = '<pre><code class="">Code block...</code></pre>'
+
+ expect(event_note(input)).to match(expected)
+ end
+
+ it 'should truncate a single long line of text' do
+ text = 'The quick brown fox jumped over the lazy dog twice' # 50 chars
+ input = "#{text}#{text}#{text}#{text}" # 200 chars
+ expected = "#{text}#{text}".sub(/.{3}/, '...')
+
+ expect(event_note(input)).to match(expected)
+ end
+
+ it 'should preserve a link href when link text is truncated' do
+ text = 'The quick brown fox jumped over the lazy dog' # 44 chars
+ input = "#{text}#{text}#{text} " # 133 chars
+ link_url = 'http://example.com/foo/bar/baz' # 30 chars
+ input << link_url
+ expected_link_text = 'http://example...</a>'
+
+ expect(event_note(input)).to match(link_url)
+ expect(event_note(input)).to match(expected_link_text)
+ end
+end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 15033f07432..61751a82369 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -60,7 +60,7 @@ describe GitlabMarkdownHelper do
end
it "should link using a short id" do
- actual = "Backported from #{commit.short_id(6)}"
+ actual = "Backported from #{commit.short_id}"
gfm(actual).should match(expected)
end
@@ -530,6 +530,24 @@ describe GitlabMarkdownHelper do
markdown(actual).should match(%r{<li>light by <a.+>@#{member.user.username}</a></li>})
end
+ it "should not link the apostrophe to issue 39" do
+ project.team << [user, :master]
+ project.issues.stub(:where).with(iid: '39').and_return([issue])
+
+ actual = "Yes, it is @#{member.user.username}'s task."
+ expected = /Yes, it is <a.+>@#{member.user.username}<\/a>'s task/
+ markdown(actual).should match(expected)
+ end
+
+ it "should not link the apostrophe to issue 39 in code blocks" do
+ project.team << [user, :master]
+ project.issues.stub(:where).with(iid: '39').and_return([issue])
+
+ actual = "Yes, `it is @#{member.user.username}'s task.`"
+ expected = /Yes, <code>it is @gfm\'s task.<\/code>/
+ markdown(actual).should match(expected)
+ end
+
it "should handle references in <em>" do
actual = "Apply _!#{merge_request.iid}_ ASAP"
@@ -576,9 +594,21 @@ describe GitlabMarkdownHelper do
end
it "should generate absolute urls for emoji" do
- markdown(":smile:").should include("src=\"#{url_helper('emoji/smile')}")
+ markdown(":smile:").should include("src=\"http://localhost/assets/emoji/smile.png")
+ end
+
+ it "should generate absolute urls for emoji if relative url is present" do
+ Gitlab.config.gitlab.stub(:url).and_return('http://localhost/gitlab/root')
+ markdown(":smile:").should include("src=\"http://localhost/gitlab/root/assets/emoji/smile.png")
end
+ it "should generate absolute urls for emoji if asset_host is present" do
+ Gitlab::Application.config.stub(:asset_host).and_return("https://cdn.example.com")
+ ActionView::Base.any_instance.stub_chain(:config, :asset_host).and_return("https://cdn.example.com")
+ markdown(":smile:").should include("src=\"https://cdn.example.com/assets/emoji/smile.png")
+ end
+
+
it "should handle relative urls for a file in master" do
actual = "[GitLab API doc](doc/api/README.md)\n"
expected = "<p><a href=\"/#{project.path_with_namespace}/blob/#{@ref}/doc/api/README.md\">GitLab API doc</a></p>\n"
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
new file mode 100644
index 00000000000..ed5785b31e6
--- /dev/null
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe Gitlab::GitAccessWiki do
+ let(:access) { Gitlab::GitAccessWiki.new }
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ describe 'push_allowed?' do
+ before do
+ create(:protected_branch, name: 'master', project: project)
+ project.team << [user, :developer]
+ end
+
+ subject { access.push_allowed?(user, project, changes) }
+
+ it { should be_true }
+ end
+
+ def changes
+ ['6f6d7e7ed 570e7b2ab refs/heads/master']
+ end
+end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index d232cb20759..a1aec0bb96f 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -1,30 +1,28 @@
require 'spec_helper'
describe Gitlab::LDAP::User do
- let(:gl_user) { Gitlab::LDAP::User }
+ let(:gl_user) { Gitlab::LDAP::User.new(auth_hash) }
let(:info) do
- double(
+ {
name: 'John',
email: 'john@example.com',
nickname: 'john'
- )
+ }
+ end
+ let(:auth_hash) do
+ double(uid: 'my-uid', provider: 'ldap', info: double(info))
end
- before { Gitlab.config.stub(omniauth: {}) }
describe :find_or_create do
- let(:auth) do
- double(info: info, provider: 'ldap', uid: 'my-uid')
- end
-
it "finds the user if already existing" do
existing_user = create(:user, extern_uid: 'my-uid', provider: 'ldap')
- expect{ gl_user.find_or_create(auth) }.to_not change{ User.count }
+ expect{ gl_user.save }.to_not change{ User.count }
end
it "connects to existing non-ldap user if the email matches" do
existing_user = create(:user, email: 'john@example.com')
- expect{ gl_user.find_or_create(auth) }.to_not change{ User.count }
+ expect{ gl_user.save }.to_not change{ User.count }
existing_user.reload
expect(existing_user.extern_uid).to eql 'my-uid'
@@ -32,7 +30,7 @@ describe Gitlab::LDAP::User do
end
it "creates a new user if not found" do
- expect{ gl_user.find_or_create(auth) }.to change{ User.count }.by(1)
+ expect{ gl_user.save }.to change{ User.count }.by(1)
end
end
diff --git a/spec/lib/gitlab/oauth/auth_hash_spec.rb b/spec/lib/gitlab/oauth/auth_hash_spec.rb
new file mode 100644
index 00000000000..5eb77b492b2
--- /dev/null
+++ b/spec/lib/gitlab/oauth/auth_hash_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe Gitlab::OAuth::AuthHash do
+ let(:auth_hash) do
+ Gitlab::OAuth::AuthHash.new(double({
+ provider: 'twitter',
+ uid: uid,
+ info: double(info_hash)
+ }))
+ end
+ let(:uid) { 'my-uid' }
+ let(:email) { 'my-email@example.com' }
+ let(:nickname) { 'my-nickname' }
+ let(:info_hash) {
+ {
+ email: email,
+ nickname: nickname,
+ name: 'John',
+ first_name: "John",
+ last_name: "Who"
+ }
+ }
+
+ context "defaults" do
+ it { expect(auth_hash.provider).to eql 'twitter' }
+ it { expect(auth_hash.uid).to eql uid }
+ it { expect(auth_hash.email).to eql email }
+ it { expect(auth_hash.username).to eql nickname }
+ it { expect(auth_hash.name).to eql "John" }
+ it { expect(auth_hash.password).to_not be_empty }
+ end
+
+ context "email not provided" do
+ before { info_hash.delete(:email) }
+ it "generates a temp email" do
+ expect( auth_hash.email).to start_with('temp-email-for-oauth')
+ end
+ end
+
+ context "username not provided" do
+ before { info_hash.delete(:nickname) }
+
+ it "takes the first part of the email as username" do
+ expect( auth_hash.username ).to eql "my-email"
+ end
+ end
+
+ context "name not provided" do
+ before { info_hash.delete(:name) }
+
+ it "concats first and lastname as the name" do
+ expect( auth_hash.name ).to eql "John Who"
+ end
+ end
+end \ No newline at end of file
diff --git a/spec/lib/gitlab/oauth/user_spec.rb b/spec/lib/gitlab/oauth/user_spec.rb
index c241e198609..e4e96fd9f49 100644
--- a/spec/lib/gitlab/oauth/user_spec.rb
+++ b/spec/lib/gitlab/oauth/user_spec.rb
@@ -1,83 +1,55 @@
require 'spec_helper'
describe Gitlab::OAuth::User do
- let(:gl_auth) { Gitlab::OAuth::User }
- let(:info) do
- double(
+ let(:oauth_user) { Gitlab::OAuth::User.new(auth_hash) }
+ let(:gl_user) { oauth_user.gl_user }
+ let(:uid) { 'my-uid' }
+ let(:provider) { 'my-provider' }
+ let(:auth_hash) { double(uid: uid, provider: provider, info: double(info_hash)) }
+ let(:info_hash) do
+ {
nickname: 'john',
name: 'John',
email: 'john@mail.com'
- )
+ }
end
- before do
- Gitlab.config.stub(omniauth: {})
- end
-
- describe :find do
+ describe :persisted? do
let!(:existing_user) { create(:user, extern_uid: 'my-uid', provider: 'my-provider') }
it "finds an existing user based on uid and provider (facebook)" do
auth = double(info: double(name: 'John'), uid: 'my-uid', provider: 'my-provider')
- assert gl_auth.find(auth)
+ expect( oauth_user.persisted? ).to be_true
end
- it "finds an existing user based on nested uid and provider" do
- auth = double(info: info, uid: 'my-uid', provider: 'my-provider')
- assert gl_auth.find(auth)
+ it "returns false if use is not found in database" do
+ auth_hash.stub(uid: 'non-existing')
+ expect( oauth_user.persisted? ).to be_false
end
end
- describe :create do
- it "should create user from LDAP" do
- auth = double(info: info, uid: 'my-uid', provider: 'ldap')
- user = gl_auth.create(auth)
-
- user.should be_valid
- user.extern_uid.should == auth.uid
- user.provider.should == 'ldap'
- end
-
- it "should create user from Omniauth" do
- auth = double(info: info, uid: 'my-uid', provider: 'twitter')
- user = gl_auth.create(auth)
+ describe :save do
+ context "LDAP" do
+ let(:provider) { 'ldap' }
+ it "creates a user from LDAP" do
+ oauth_user.save
- user.should be_valid
- user.extern_uid.should == auth.uid
- user.provider.should == 'twitter'
+ expect(gl_user).to be_valid
+ expect(gl_user.extern_uid).to eql uid
+ expect(gl_user.provider).to eql 'ldap'
+ end
end
- it "should apply defaults to user" do
- auth = double(info: info, uid: 'my-uid', provider: 'ldap')
- user = gl_auth.create(auth)
-
- user.should be_valid
- user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit
- user.can_create_group.should == Gitlab.config.gitlab.default_can_create_group
- end
-
- it "Set a temp email address if not provided (like twitter does)" do
- info = double(
- uid: 'my-uid',
- nickname: 'john',
- name: 'John'
- )
- auth = double(info: info, uid: 'my-uid', provider: 'my-provider')
-
- user = gl_auth.create(auth)
- expect(user.email).to_not be_empty
- end
+ context "twitter" do
+ let(:provider) { 'twitter' }
- it 'generates a username if non provided (google)' do
- info = double(
- uid: 'my-uid',
- name: 'John',
- email: 'john@example.com'
- )
- auth = double(info: info, uid: 'my-uid', provider: 'my-provider')
+ it "creates a user from Omniauth" do
+ oauth_user.save
- user = gl_auth.create(auth)
- expect(user.username).to eql 'john'
+ expect(gl_user).to be_valid
+ expect(gl_user.extern_uid).to eql uid
+ expect(gl_user.provider).to eql 'twitter'
+ end
end
end
end
diff --git a/spec/models/assembla_service_spec.rb b/spec/models/assembla_service_spec.rb
index 0ef475b87c3..4300090eb13 100644
--- a/spec/models/assembla_service_spec.rb
+++ b/spec/models/assembla_service_spec.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
require 'spec_helper'
diff --git a/spec/models/buildbox_service_spec.rb b/spec/models/buildbox_service_spec.rb
new file mode 100644
index 00000000000..1d9ca51be16
--- /dev/null
+++ b/spec/models/buildbox_service_spec.rb
@@ -0,0 +1,73 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+#
+
+require 'spec_helper'
+
+describe BuildboxService do
+ describe 'Associations' do
+ it { should belong_to :project }
+ it { should have_one :service_hook }
+ end
+
+ describe 'commits methods' do
+ before do
+ @project = Project.new
+ @project.stub(
+ default_branch: 'default-brancho'
+ )
+
+ @service = BuildboxService.new
+ @service.stub(
+ project: @project,
+ service_hook: true,
+ project_url: 'https://buildbox.io/account-name/example-project',
+ token: 'secret-sauce-webhook-token:secret-sauce-status-token'
+ )
+ end
+
+ describe :webhook_url do
+ it 'returns the webhook url' do
+ @service.webhook_url.should ==
+ 'https://webhook.buildbox.io/deliver/secret-sauce-webhook-token'
+ end
+ end
+
+ describe :commit_status_path do
+ it 'returns the correct status page' do
+ @service.commit_status_path('2ab7834c').should ==
+ 'https://gitlab.buildbox.io/status/secret-sauce-status-token.json?commit=2ab7834c'
+ end
+ end
+
+ describe :build_page do
+ it 'returns the correct build page' do
+ @service.build_page('2ab7834c').should ==
+ 'https://buildbox.io/account-name/example-project/builds?commit=2ab7834c'
+ end
+ end
+
+ describe :builds_page do
+ it 'returns the correct path to the builds page' do
+ @service.builds_path.should ==
+ 'https://buildbox.io/account-name/example-project/builds?branch=default-brancho'
+ end
+ end
+
+ describe :status_img_path do
+ it 'returns the correct path to the status image' do
+ @service.status_img_path.should == 'https://badge.buildbox.io/secret-sauce-status-token.svg'
+ end
+ end
+ end
+end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 6f201adc4e8..a6ec44da4be 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -75,7 +75,7 @@ eos
it_behaves_like 'a mentionable' do
let(:subject) { commit }
let(:mauthor) { create :user, email: commit.author_email }
- let(:backref_text) { "commit #{subject.sha[0..5]}" }
+ let(:backref_text) { "commit #{subject.id}" }
let(:set_mentionable_text) { ->(txt){ subject.stub(safe_message: txt) } }
# Include the subject in the repository stub.
diff --git a/spec/models/flowdock_service_spec.rb b/spec/models/flowdock_service_spec.rb
index 710b8cba502..5540f0fa988 100644
--- a/spec/models/flowdock_service_spec.rb
+++ b/spec/models/flowdock_service_spec.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
require 'spec_helper'
diff --git a/spec/models/gemnasium_service_spec.rb b/spec/models/gemnasium_service_spec.rb
index 5de645cdf33..60ffa6f8b05 100644
--- a/spec/models/gemnasium_service_spec.rb
+++ b/spec/models/gemnasium_service_spec.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
require 'spec_helper'
diff --git a/spec/models/gitlab_ci_service_spec.rb b/spec/models/gitlab_ci_service_spec.rb
index e4cd8bb90c3..ebc377047be 100644
--- a/spec/models/gitlab_ci_service_spec.rb
+++ b/spec/models/gitlab_ci_service_spec.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
require 'spec_helper'
diff --git a/spec/models/group_member_spec.rb b/spec/models/group_member_spec.rb
index 6acbc9bb4ae..38657de6793 100644
--- a/spec/models/group_member_spec.rb
+++ b/spec/models/group_member_spec.rb
@@ -1,14 +1,16 @@
# == Schema Information
#
-# Table name: group_members
+# Table name: members
#
# id :integer not null, primary key
# access_level :integer not null
-# group_id :integer not null
+# source_id :integer not null
+# source_type :string(255) not null
# user_id :integer not null
+# notification_level :integer not null
+# type :string(255)
# created_at :datetime
# updated_at :datetime
-# notification_level :integer default(3), not null
#
require 'spec_helper'
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index eeecd714a28..2d839e9611b 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -228,7 +228,7 @@ describe Note do
it { should be_valid }
its(:noteable) { should == issue }
- its(:note) { should == "_mentioned in commit #{commit.sha[0..5]}_" }
+ its(:note) { should == "_mentioned in commit #{commit.sha}_" }
end
context 'merge request from an issue' do
@@ -267,7 +267,7 @@ describe Note do
its(:noteable_type) { should == "Commit" }
its(:noteable_id) { should be_nil }
its(:commit_id) { should == commit.id }
- its(:note) { should == "_mentioned in commit #{parent_commit.id[0...6]}_" }
+ its(:note) { should == "_mentioned in commit #{parent_commit.id}_" }
end
end
diff --git a/spec/models/project_member_spec.rb b/spec/models/project_member_spec.rb
index 0178d065e57..9b5f89b6d7d 100644
--- a/spec/models/project_member_spec.rb
+++ b/spec/models/project_member_spec.rb
@@ -1,14 +1,16 @@
# == Schema Information
#
-# Table name: project_members
+# Table name: members
#
# id :integer not null, primary key
+# access_level :integer not null
+# source_id :integer not null
+# source_type :string(255) not null
# user_id :integer not null
-# project_id :integer not null
+# notification_level :integer not null
+# type :string(255)
# created_at :datetime
# updated_at :datetime
-# project_access :integer default(0), not null
-# notification_level :integer default(3), not null
#
require 'spec_helper'
diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb
index e4df934460b..a6e1d9eef50 100644
--- a/spec/models/project_snippet_spec.rb
+++ b/spec/models/project_snippet_spec.rb
@@ -2,17 +2,17 @@
#
# Table name: snippets
#
-# id :integer not null, primary key
-# title :string(255)
-# content :text
-# author_id :integer not null
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# file_name :string(255)
-# expires_at :datetime
-# private :boolean default(TRUE), not null
-# type :string(255)
+# id :integer not null, primary key
+# title :string(255)
+# content :text
+# author_id :integer not null
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# file_name :string(255)
+# expires_at :datetime
+# type :string(255)
+# visibility_level :integer default(0), not null
#
require 'spec_helper'
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 34c1a686c96..bbf50b654f4 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -27,6 +27,8 @@ describe ProjectTeam do
it { project.team.master?(guest).should be_false }
it { project.team.master?(reporter).should be_false }
it { project.team.master?(nonmember).should be_false }
+ it { project.team.member?(nonmember).should be_false }
+ it { project.team.member?(guest).should be_true }
end
end
@@ -60,6 +62,8 @@ describe ProjectTeam do
it { project.team.master?(guest).should be_true }
it { project.team.master?(reporter).should be_false }
it { project.team.master?(nonmember).should be_false }
+ it { project.team.member?(nonmember).should be_false }
+ it { project.team.member?(guest).should be_true }
end
end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 480aeabf67f..c96f2b20529 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
require 'spec_helper'
diff --git a/spec/models/slack_service_spec.rb b/spec/models/slack_service_spec.rb
index 3e555193b32..95df38d9400 100644
--- a/spec/models/slack_service_spec.rb
+++ b/spec/models/slack_service_spec.rb
@@ -2,14 +2,14 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
#
require 'spec_helper'
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index d179e9516e2..1ef2c512c1f 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -2,17 +2,17 @@
#
# Table name: snippets
#
-# id :integer not null, primary key
-# title :string(255)
-# content :text
-# author_id :integer not null
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# file_name :string(255)
-# expires_at :datetime
-# private :boolean default(TRUE), not null
-# type :string(255)
+# id :integer not null, primary key
+# title :string(255)
+# content :text
+# author_id :integer not null
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# file_name :string(255)
+# expires_at :datetime
+# type :string(255)
+# visibility_level :integer default(0), not null
#
require 'spec_helper'
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 0250014bc21..8c79bf5f3c2 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -429,4 +429,32 @@ describe User do
expect(user.starred?(project)).to be_false
end
end
+
+ describe "#sort" do
+ before do
+ User.delete_all
+ @user = create :user, created_at: Date.today, last_sign_in_at: Date.today, name: 'Alpha'
+ @user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega'
+ end
+
+ it "sorts users as recently_signed_in" do
+ User.sort('recent_sign_in').first.should == @user
+ end
+
+ it "sorts users as late_signed_in" do
+ User.sort('oldest_sign_in').first.should == @user1
+ end
+
+ it "sorts users as recently_created" do
+ User.sort('recently_created').first.should == @user
+ end
+
+ it "sorts users as late_created" do
+ User.sort('late_created').first.should == @user1
+ end
+
+ it "sorts users by name when nil is passed" do
+ User.sort(nil).first.should == @user
+ end
+ end
end
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index 692834c9f29..ebd74206699 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -30,15 +30,15 @@ def common_mentionable_setup
"!#{mentioned_mr.iid}, " +
"#{ext_proj.path_with_namespace}##{ext_issue.iid}, " +
"#{ext_proj.path_with_namespace}!#{ext_mr.iid}, " +
- "#{ext_proj.path_with_namespace}@#{ext_commit.id[0..5]}, " +
- "#{mentioned_commit.sha[0..5]} and itself as #{backref_text}"
+ "#{ext_proj.path_with_namespace}@#{ext_commit.short_id}, " +
+ "#{mentioned_commit.sha[0..10]} and itself as #{backref_text}"
end
before do
# Wire the project's repository to return the mentioned commit, and +nil+ for any
# unrecognized commits.
- commitmap = { '123456' => mentioned_commit }
- extra_commits.each { |c| commitmap[c.sha[0..5]] = c }
+ commitmap = { '1234567890a' => mentioned_commit }
+ extra_commits.each { |c| commitmap[c.short_id] = c }
mproject.repository.stub(:commit) { |sha| commitmap[sha] }
set_mentionable_text.call(ref_string)
end
@@ -54,7 +54,6 @@ shared_examples 'a mentionable' do
it "extracts references from its reference property" do
# De-duplicate and omit itself
refs = subject.references(mproject)
-
refs.should have(6).items
refs.should include(mentioned_issue)
refs.should include(mentioned_mr)
@@ -90,7 +89,7 @@ shared_examples 'an editable mentionable' do
it 'creates new cross-reference notes when the mentionable text is edited' do
new_text = "still mentions ##{mentioned_issue.iid}, " +
- "#{mentioned_commit.sha[0..5]}, " +
+ "#{mentioned_commit.sha[0..10]}, " +
"#{ext_issue.iid}, " +
"new refs: ##{other_issue.iid}, " +
"#{ext_proj.path_with_namespace}##{other_ext_issue.iid}"