diff options
206 files changed, 2019 insertions, 2078 deletions
diff --git a/.gitignore b/.gitignore index 94a210b9461..24297583fd2 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ db/data.yml .DS_Store .chef vendor/bundle/* +rails_best_practices_output.html diff --git a/.simplecov b/.simplecov new file mode 100644 index 00000000000..d979288df44 --- /dev/null +++ b/.simplecov @@ -0,0 +1,4 @@ +# .simplecov +SimpleCov.start 'rails' do + merge_timeout 3600 +end diff --git a/.travis.yml b/.travis.yml index 59d22f32ee3..e8bd744267f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ branches: only: - 'master' rvm: - - 1.9.3 + - 1.9.2 services: - mysql - postgresql @@ -8,7 +8,7 @@ def linux_only(require_as) RUBY_PLATFORM.include?('linux') && require_as end -gem "rails", "3.2.9" +gem "rails", "3.2.10" # Supported DBs gem "mysql2", group: :mysql @@ -108,7 +108,7 @@ group :assets do gem "jquery-rails", "2.1.3" gem "jquery-ui-rails", "2.0.2" gem "modernizr", "2.6.2" - gem "raphael-rails", "1.5.2" + gem "raphael-rails", git: "https://github.com/gitlabhq/raphael-rails.git" gem 'bootstrap-sass', "2.2.1.1" gem "font-awesome-sass-rails", "~> 2.0.0" gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' @@ -123,6 +123,8 @@ group :development do gem 'better_errors' gem 'binding_of_caller' + gem 'rails_best_practices' + # Docs generator gem "sdoc" end diff --git a/Gemfile.lock b/Gemfile.lock index 4b08c3141b4..0965974051e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -49,6 +49,12 @@ GIT yajl-ruby (~> 1.1.0) GIT + remote: https://github.com/gitlabhq/raphael-rails.git + revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58 + specs: + raphael-rails (2.1.0) + +GIT remote: https://github.com/gitlabhq/resque.git revision: 9ef4700306dd946a3ac000612428967ce0c32213 ref: 9ef4700306dd946a3ac000612428967ce0c32213 @@ -74,12 +80,12 @@ GIT GEM remote: http://rubygems.org/ specs: - actionmailer (3.2.9) - actionpack (= 3.2.9) + actionmailer (3.2.10) + actionpack (= 3.2.10) mail (~> 2.4.4) - actionpack (3.2.9) - activemodel (= 3.2.9) - activesupport (= 3.2.9) + actionpack (3.2.10) + activemodel (= 3.2.10) + activesupport (= 3.2.10) builder (~> 3.0.0) erubis (~> 2.7.0) journey (~> 1.0.4) @@ -87,18 +93,18 @@ GEM rack-cache (~> 1.2) rack-test (~> 0.6.1) sprockets (~> 2.2.1) - activemodel (3.2.9) - activesupport (= 3.2.9) + activemodel (3.2.10) + activesupport (= 3.2.10) builder (~> 3.0.0) - activerecord (3.2.9) - activemodel (= 3.2.9) - activesupport (= 3.2.9) + activerecord (3.2.10) + activemodel (= 3.2.10) + activesupport (= 3.2.10) arel (~> 3.0.2) tzinfo (~> 0.3.29) - activeresource (3.2.9) - activemodel (= 3.2.9) - activesupport (= 3.2.9) - activesupport (3.2.9) + activeresource (3.2.10) + activemodel (= 3.2.10) + activesupport (= 3.2.10) + activesupport (3.2.10) i18n (~> 0.6) multi_json (~> 1.0) acts-as-taggable-on (2.3.3) @@ -132,6 +138,8 @@ GEM chosen-rails (0.9.8) railties (~> 3.0) thor (~> 0.14) + code_analyzer (0.3.1) + sexp_processor coderay (1.0.8) coffee-rails (3.2.2) coffee-script (>= 2.2.0) @@ -243,7 +251,7 @@ GEM jquery-ui-rails (2.0.2) jquery-rails railties (>= 3.1.0) - json (1.7.5) + json (1.7.6) jwt (0.1.5) multi_json (>= 1.0) kaminari (0.14.1) @@ -267,7 +275,7 @@ GEM mime-types (1.19) modernizr (2.6.2) sprockets (~> 2.0) - multi_json (1.3.7) + multi_json (1.5.0) multi_xml (0.5.1) multipart-post (1.1.5) mysql2 (0.3.11) @@ -302,6 +310,7 @@ GEM pg (0.14.1) polyglot (0.3.3) posix-spawn (0.3.6) + progressbar (0.12.0) pry (0.9.10) coderay (~> 1.0.5) method_source (~> 0.8) @@ -324,27 +333,34 @@ GEM rack rack-test (0.6.2) rack (>= 1.0) - rails (3.2.9) - actionmailer (= 3.2.9) - actionpack (= 3.2.9) - activerecord (= 3.2.9) - activeresource (= 3.2.9) - activesupport (= 3.2.9) + rails (3.2.10) + actionmailer (= 3.2.10) + actionpack (= 3.2.10) + activerecord (= 3.2.10) + activeresource (= 3.2.10) + activesupport (= 3.2.10) bundler (~> 1.0) - railties (= 3.2.9) + railties (= 3.2.10) rails-dev-tweaks (0.6.1) actionpack (~> 3.1) railties (~> 3.1) - railties (3.2.9) - actionpack (= 3.2.9) - activesupport (= 3.2.9) + rails_best_practices (1.13.2) + activesupport + awesome_print + code_analyzer + colored + erubis + i18n + progressbar + railties (3.2.10) + actionpack (= 3.2.10) + activesupport (= 3.2.10) rack-ssl (~> 1.3.2) rake (>= 0.8.7) rdoc (~> 3.4) thor (>= 0.14.6, < 2.0) raindrops (0.10.0) - rake (10.0.1) - raphael-rails (1.5.2) + rake (10.0.3) rb-fsevent (0.9.2) rb-inotify (0.8.8) ffi (>= 0.5.0) @@ -393,6 +409,7 @@ GEM multi_json (~> 1.0) rubyzip settingslogic (2.0.8) + sexp_processor (4.1.3) shoulda-matchers (1.3.0) activesupport (>= 3.0.0) simplecov (0.7.1) @@ -412,7 +429,7 @@ GEM capybara (~> 1) railties (>= 3) spinach (>= 0.4) - sprockets (2.2.1) + sprockets (2.2.2) hike (~> 1.2) multi_json (~> 1.0) rack (~> 1.0) @@ -510,9 +527,10 @@ DEPENDENCIES pygments.rb! quiet_assets (~> 1.0.1) rack-mini-profiler - rails (= 3.2.9) + rails (= 3.2.10) rails-dev-tweaks - raphael-rails (= 1.5.2) + rails_best_practices + raphael-rails! rb-fsevent rb-inotify redcarpet (~> 2.2.2) diff --git a/README.md b/README.md index c80b9f26bbe..1a43be134da 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ GitLab is a free project and repository management application +![CI](http://ci.gitlab.org/projects/1/status?ref=master) ## Application details diff --git a/app/assets/images/download.png b/app/assets/images/download.png Binary files differdeleted file mode 100644 index 5791e723de9..00000000000 --- a/app/assets/images/download.png +++ /dev/null diff --git a/app/assets/javascripts/issues.js b/app/assets/javascripts/issues.js index 719d2c176c1..9ba1a3f1bba 100644 --- a/app/assets/javascripts/issues.js +++ b/app/assets/javascripts/issues.js @@ -11,7 +11,7 @@ function initIssuesSearch() { last_terms = terms; if (terms.length >= 2 || terms.length == 0) { - $.get(href, { 'f': status, 'terms': terms, 'milestone_id': milestone_id }, function(response) { + $.get(href, { 'status': status, 'terms': terms, 'milestone_id': milestone_id }, function(response) { $('#issues-table').html(response); }); } diff --git a/app/assets/javascripts/merge_requests.js b/app/assets/javascripts/merge_requests.js deleted file mode 100644 index ee714f9cabb..00000000000 --- a/app/assets/javascripts/merge_requests.js +++ /dev/null @@ -1,132 +0,0 @@ -var MergeRequest = { - diffs_loaded: false, - commits_loaded: false, - opts: false, - - init: - function(opts) { - var self = this; - self.opts = opts; - - self.initTabs(); - self.initMergeWidget(); - - $(".mr_show_all_commits").bind("click", function() { - self.showAllCommits(); - }); - }, - - initMergeWidget: - function() { - var self = this; - self.showState(self.opts.current_state); - - if($(".automerge_widget").length && self.opts.check_enable){ - $.get(self.opts.url_to_automerge_check, function(data){ - self.showState(data.state); - }, "json"); - } - - if(self.opts.ci_enable){ - $.get(self.opts.url_to_ci_check, function(data){ - self.showCiState(data.status); - }, "json"); - } - }, - - initTabs: - function() { - $(".mr_nav_tabs a").live("click", function() { - $(".mr_nav_tabs a").parent().removeClass("active"); - $(this).parent().addClass("active"); - }); - - var current_tab; - if(this.opts.action == "diffs") { - current_tab = $(".mr_nav_tabs .merge-diffs-tab"); - } else { - current_tab = $(".mr_nav_tabs .merge-notes-tab"); - } - current_tab.parent().addClass("active"); - - this.initNotesTab(); - this.initDiffTab(); - }, - - initNotesTab: - function() { - $(".mr_nav_tabs a.merge-notes-tab").live("click", function(e) { - $(".merge-request-diffs").hide(); - $(".merge_request_notes").show(); - var mr_path = $(".merge-notes-tab").attr("data-url"); - history.pushState({ path: mr_path }, '', mr_path); - e.preventDefault(); - }); - }, - - initDiffTab: - function() { - $(".mr_nav_tabs a.merge-diffs-tab").live("click", function(e) { - if(!MergeRequest.diffs_loaded) { - MergeRequest.loadDiff(); - } - $(".merge_request_notes").hide(); - $(".merge-request-diffs").show(); - var mr_diff_path = $(".merge-diffs-tab").attr("data-url"); - history.pushState({ path: mr_diff_path }, '', mr_diff_path); - e.preventDefault(); - }); - - }, - - showState: - function(state){ - $(".automerge_widget").hide(); - $(".automerge_widget." + state).show(); - }, - - showCiState: - function(state){ - $(".ci_widget").hide(); - $(".ci_widget.ci-" + state).show(); - }, - - loadDiff: - function() { - $(".dashboard-loader").show(); - $.ajax({ - type: "GET", - url: $(".merge-diffs-tab").attr("data-url"), - beforeSend: function(){ $('.status').addClass("loading")}, - complete: function(){ - MergeRequest.diffs_loaded = true; - $(".merge_request_notes").hide(); - $('.status').removeClass("loading"); - }, - dataType: "script"}); - }, - - showAllCommits: - function() { - $(".first_mr_commits").remove(); - $(".all_mr_commits").removeClass("hide"); - }, - - already_cannot_be_merged: - function(){ - $(".automerge_widget").hide(); - $(".merge_in_progress").hide(); - $(".automerge_widget.already_cannot_be_merged").show(); - } -}; - -/* - * Filter merge requests - */ -function merge_requestsPage() { - $("#assignee_id").chosen(); - $("#milestone_id").chosen(); - $("#milestone_id, #assignee_id").on("change", function(){ - $(this).closest("form").submit(); - }); -} diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee new file mode 100644 index 00000000000..cdc685f2c09 --- /dev/null +++ b/app/assets/javascripts/merge_requests.js.coffee @@ -0,0 +1,97 @@ +# +# * Filter merge requests +# +@merge_requestsPage = -> + $('#assignee_id').chosen() + $('#milestone_id').chosen() + $('#milestone_id, #assignee_id').on 'change', -> + $(this).closest('form').submit() + +class MergeRequest + + constructor: (@opts) -> + this.$el = $('.merge-request') + @diffs_loaded = false + @commits_loaded = false + + this.activateTab(@opts.action) + + this.bindEvents() + + this.initMergeWidget() + this.$('.show-all-commits').on 'click', => + this.showAllCommits() + + # Local jQuery finder + $: (selector) -> + this.$el.find(selector) + + initMergeWidget: -> + this.showState( @opts.current_state ) + + if this.$('.automerge_widget').length and @opts.check_enable + $.get @opts.url_to_automerge_check, (data) => + this.showState( data.state ) + , 'json' + + if @opts.ci_enable + $.get @opts.url_to_ci_check, (data) => + this.showCiState data.status + , 'json' + + bindEvents: -> + this.$('.nav-tabs').on 'click', 'a', (event) => + a = $(event.currentTarget) + + href = a.attr('href') + History.replaceState {path: href}, document.title, href + + event.preventDefault() + + this.$('.nav-tabs').on 'click', 'li', (event) => + this.activateTab($(event.currentTarget).data('action')) + + activateTab: (action) -> + this.$('.nav-tabs li').removeClass 'active' + this.$('.tab-content').hide() + switch action + when 'diffs' + this.$('.nav-tabs .diffs-tab').addClass 'active' + this.loadDiff() unless @diffs_loaded + this.$('.diffs').show() + else + this.$('.nav-tabs .notes-tab').addClass 'active' + this.$('.notes').show() + + showState: (state) -> + $('.automerge_widget').hide() + $('.automerge_widget.' + state).show() + + showCiState: (state) -> + $('.ci_widget').hide() + $('.ci_widget.ci-' + state).show() + + loadDiff: (event) -> + $('.dashboard-loader').show() + $.ajax + type: 'GET' + url: this.$('.nav-tabs .diffs-tab a').attr('href') + beforeSend: => + this.$('.status').addClass 'loading' + + complete: => + @diffs_loaded = true + this.$('.status').removeClass 'loading' + + dataType: 'script' + + showAllCommits: -> + this.$('.first-commits').remove() + this.$('.all-commits').removeClass 'hide' + + alreadyOrCannotBeMerged: -> + this.$('.automerge_widget').hide() + this.$('.merge-in-progress').hide() + this.$('.automerge_widget.already_cannot_be_merged').show() + +this.MergeRequest = MergeRequest diff --git a/app/assets/javascripts/milestones.js.coffee b/app/assets/javascripts/milestones.js.coffee index e40a69ebaa5..99a52bf4d3f 100644 --- a/app/assets/javascripts/milestones.js.coffee +++ b/app/assets/javascripts/milestones.js.coffee @@ -1,14 +1,14 @@ $ -> - $('.milestone-issue-filter tr[data-closed]').addClass('hide') + $('.milestone-issue-filter li[data-closed]').addClass('hide') $('.milestone-issue-filter ul.nav li a').click -> $('.milestone-issue-filter li').toggleClass('active') - $('.milestone-issue-filter tr[data-closed]').toggleClass('hide') + $('.milestone-issue-filter li[data-closed]').toggleClass('hide') false - $('.milestone-merge-requests-filter tr[data-closed]').addClass('hide') + $('.milestone-merge-requests-filter li[data-closed]').addClass('hide') $('.milestone-merge-requests-filter ul.nav li a').click -> $('.milestone-merge-requests-filter li').toggleClass('active') - $('.milestone-merge-requests-filter tr[data-closed]').toggleClass('hide') + $('.milestone-merge-requests-filter li[data-closed]').toggleClass('hide') false diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js index 769e8a62343..7edd6bd6186 100644 --- a/app/assets/javascripts/pager.js +++ b/app/assets/javascripts/pager.js @@ -4,9 +4,16 @@ var Pager = { disable:false, init: - function(limit) { + function(limit, preload) { this.limit=limit; - this.offset=limit; + + if(preload) { + this.offset = 0; + this.getOld(); + } else { + this.offset = limit; + } + this.initLoadMore(); }, diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index dcdfcdb289c..bcaa6a2f76e 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -117,34 +117,10 @@ span.update-author { } .label { - background-color: #474D57; - - &.label-tag { - background: none; - border: none; - padding: 4px 6px; - color: #444; - text-shadow: 0 0 1px #fff; - - &.grouped { - float: left; - margin-right: 6px; - padding: 6px; - } - } - &.label-issue { - background-color: #eee; - border: 1px solid #ccc; - padding: 4px 6px; - color: #444; - text-shadow: 0 0 1px #fff; - - &.grouped { - float: left; - margin-right: 6px; - padding: 6px; - } - } + padding: 0px 4px; + font-size: 10px; + font-style: normal; + background-color: $link_color; &.label-success { background-color: #8D8; @@ -425,7 +401,7 @@ li.note { .supp_diff_link, -.mr_show_all_commits { +.show-all-commits { cursor: pointer; } diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index f9c8b7b05ea..8cb1c045778 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -1,23 +1,24 @@ /** * =================================== - * Contain 3 main UI block elements: - * .main_box - for show pages - * .ui-box - for simple block & widgets + * Contain UI block elements: + * .ui-box - for any block & widgets * =================================== */ /** - * UI box element - * contains top, middle, bottom blocks + * UI Block * */ -.main_box { - @extend .borders; - @extend .prepend-top-20; - @extend .append-bottom-20; - border-width: 1px; +.ui-box { + background: #F9F9F9; + margin-bottom: 25px; + border: 1px solid #CCC; @include solid-shade; + &.ui-box-show { + margin:20px 0; + background: #FFF; + } img { max-width: 100%; } @@ -27,9 +28,9 @@ } } - .top_box_content, - .middle_box_content, - .bottom_box_content { + .ui-box-head, + .ui-box-body, + .ui-box-bottom { padding: 15px; word-wrap: break-word; @@ -39,19 +40,25 @@ border: none; padding: 0; } + + .clearfix { + margin: 0; + } } - .top_box_content { + .ui-box-head { .box-title { color: $style_color; font-size: 18px; font-weight: normal; line-height: 28px; } + h3 { + margin: 0; + } } - .middle_box_content { - @include border-radius(0); + .ui-box-body { border: none; font-size: 12px; background-color: #f5f5f5; @@ -59,24 +66,9 @@ border-top: 1px solid #eee; } - .bottom_box_content { + .ui-box-bottom { border-top: 1px solid #eee; } -} - -/** - * Big UI Block for show page content - * - */ -.ui-box { - background: #F9F9F9; - margin-bottom: 25px; - - border: 1px solid #eaeaea; - @include border-radius(4px); - - border-color: #CCC; - @include solid-shade; &.white { background: #fff; @@ -86,47 +78,47 @@ margin: 0; } - h5, .title { - padding: 0 10px; - @include border-radius(4px 4px 0 0); + .title { @include bg-gray-gradient; - border-top: 1px solid #eaeaea; - border-bottom: 1px solid #bbb; + border-bottom: 1px solid #CCC; + color: #456; + font-size: 16px; + text-shadow: 0 1px 1px #fff; + padding: 0px 10px; + line-height: 36px; + font-size: 14px; + font-weight: normal; > a { text-shadow: 0 1px 1px #fff; } - &.small { - line-height: 28px; - font-size: 14px; - line-height: 28px; - text-shadow: 0 1px 1px white; - } - form { - padding: 9px 0; - margin: 0px; + margin-bottom: 0; + margin-top: 3px; } .nav-pills { - li { - padding: 3px 0; - &.active a { background-color: $style_color; } - a { - @include border-radius(7px); + > li { + > a { + padding: 13px; + margin: 0; + font-size: 13px; + } + &.active { + > a { + background: #D5D5D5; + color: $style_color; + @include border-radius(0); + border-radius: 0; + border-left: 1px solid #CCC; + border-right: 1px solid #CCC; + } } } } } - .bottom { - @include bg-gray-gradient; - @include border-radius(0 0 4px 4px); - border-bottom: none; - border-top: 1px solid #bbb; - } - &.padded { h5, .title { margin: -20px; @@ -143,6 +135,7 @@ color: #777; } } + .row_title { font-weight: bold; color: #444; @@ -151,8 +144,4 @@ text-decoration: underline; } } - - .ui-box-body { - padding: 10px; - } } diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss index 883a8773962..2b5ecce4246 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss @@ -7,6 +7,10 @@ color: #333; } + &.btn-white { + background: #FFF; + } + &.primary { background: #2a79A3; @include linear-gradient(#47A7b7, #2585b5); diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index 3bb7cdbf706..f088766afbd 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -17,20 +17,43 @@ .padded { padding:20px } .ipadded { padding:20px!important } .lborder { border-left:1px solid #eee } -.no-padding { padding:0 !important; } -.underlined { border-bottom: 1px solid #CCC; } -.no-borders { border: none; } -.vlink { color: $link_color !important; } .underlined_link { text-decoration: underline; } -.borders { border: 1px solid #ccc; @include shade; } .hint { font-style: italic; color: #999; } .light { color: #888 } .tiny { font-weight: normal } /** PILLS & TABS**/ -.nav-pills a:hover { background-color: #888; } -.nav-pills .active a { background-color: $style_color; } +.nav-pills { + .active a { + background: $primary_color; + } + + > li > a { + @include border-radius(0); + } + &.nav-stacked { + > li > a { + border-left: 4px solid #EEE; + padding: 12px; + } + > .active > a { + border-color: #29B; + border-radius: 0; + background: #F1F1F1; + color: $style_color; + font-weight: bold; + } + } +} + .nav-pills > .active > a > i[class^="icon-"] { background: inherit; } + + + +/** + * nav-tabs + * + */ .nav-tabs > li > a, .nav-pills > li > a { color: $style_color; } .nav.nav-tabs { li { diff --git a/app/assets/stylesheets/gitlab_bootstrap/lists.scss b/app/assets/stylesheets/gitlab_bootstrap/lists.scss index edaf3cef2cf..0f893a553ee 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/lists.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/lists.scss @@ -23,14 +23,12 @@ border-bottom: 1px solid #ADF; } - &:first-child { - @include border-radius(4px 4px 0 0); - border-top: none; - } - &:last-child { - @include border-radius(0 0 4px 4px); - border: none; + border-bottom: none; + + &.bottom { + background: #f5f5f5; + } } .author { color: #999; } diff --git a/app/assets/stylesheets/gitlab_bootstrap/tables.scss b/app/assets/stylesheets/gitlab_bootstrap/tables.scss index 5905efd3aae..7a9eac82566 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/tables.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/tables.scss @@ -25,7 +25,7 @@ table { } th, td { - padding: 8px; + padding: 10px; line-height: 18px; text-align: left; } diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index 7ed53333f8c..ebec51c9715 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -1,74 +1,17 @@ -.commit-box { - @extend .main_box; - - .commit-head { - @extend .top_box_content; - - .commit-title { - line-height: 26px; - margin: 0; - } - - .commit-description { - font-size: 14px; - border: none; - background-color: white; - padding-top: 10px; - } - - .browse-button { - @extend .btn; - @extend .btn-small; - float: right; - } - } - - .commit-info { - @extend .middle_box_content; - @extend .clearfix; - - .sha-block { - text-align: right; - &:first-child { - padding-bottom: 6px; - } - - a { - border-bottom: 1px solid #aaa; - margin-left: 9px; - } - } - - &.merge-commit .sha-block { - clear: right; - } - - .committer { - padding-left: 32px; - } - - .author a, - .committer a { - font-size: 14px; - line-height: 22px; - text-shadow: 0 1px 1px #fff; - color: #777; - &:hover { - color: #999; - } - } - - .avatar { - margin-right: 10px; - } - } -} - /** * * COMMIT SHOw * */ +.commit-committer-link, +.commit-author-link { + font-size: 13px; + color: #555; + &:hover { + color: #999; + } +} + .diff_file { border: 1px solid #CCC; margin-bottom: 1em; @@ -255,13 +198,6 @@ min-width: 65px; font-family: $monospace; } - - .commit-author-name { - color: #777; - &:hover { - color: #999; - } - } } .diff_file_header a, diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index 071a9c35468..2d41de25103 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -47,6 +47,12 @@ .event-info { color: #666; } + .event-note { + padding-top: 5px; + padding-left: 5px; + display: inline-block; + color: #777; + } } .avatar { position: relative; diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss index fd995728978..351f2404492 100644 --- a/app/assets/stylesheets/sections/issues.scss +++ b/app/assets/stylesheets/sections/issues.scss @@ -1,34 +1,6 @@ -.issue_form_box { - @extend .main_box; - .issue_title { - @extend .top_box_content; - .clearfix { - margin-bottom: 0px; - input { - @extend .span8; - } - } - } - .issue_middle_block { - @extend .middle_box_content; - height: 30px; - .issue_assignee { - @extend .span6; - float: left; - } - .issue_milestone { - @extend .span4; - float: left; - } - } - .issue_description { - @extend .bottom_box_content; - } -} - .issues_table { .issue { - padding: 7px 10px; + padding: 10px; .issue_check { float: left; @@ -82,38 +54,34 @@ input.check_all_issues { } } -@media (min-width: 800px) { .issues_filters select { width: 160px; } } -@media (min-width: 1000px) { .issues_filters select { width: 200px; } } +@media (min-width: 800px) { .issues_filters select { width: 160px; } } @media (min-width: 1200px) { .issues_filters select { width: 220px; } } +@media (min-width: 800px) { .issues_bulk_update select { width: 120px; } } +@media (min-width: 1200px) { .issues_bulk_update select { width: 160px; } } #issues-table-holder { .issues_filters { - form { - padding: 0; - margin: 0; - margin-top:7px - } } .issues_bulk_update { margin: 0; form { - padding: 0; - margin: 0; - margin-top:7px + float:left; } + .update_selected_issues { position: relative; - top:-2px; + top:5px; margin-left: 4px; float: left; } .update_issues_text { padding: 3px; - line-height: 18px; + line-height: 28px; float: left; + color: #479; } } } diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index 9fb1d14967f..5225a242726 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -1,17 +1,3 @@ -/** - * MR form - * - */ - -.mr_branch_box { - @extend .ui-box; - margin-bottom: 20px; - - .body { - background: #f1f1f1; - } - -} /** * MR -> show: Automerge widget @@ -57,7 +43,7 @@ } } -.mr_nav_tabs { +.merge-request .nav-tabs{ li { a { font-weight: bold; @@ -68,7 +54,7 @@ } li.merge_request { - padding: 7px 10px; + padding: 10px; img.avatar { width: 32px; margin-top: 1px; @@ -79,7 +65,7 @@ li.merge_request { } } -.merge_in_progress { +.merge-in-progress { @extend .padded; @extend .append-bottom-10; } @@ -121,19 +107,3 @@ li.merge_request { .mr_direction_tip { margin-top:40px } - -.merge_requests_form_box { - @extend .main_box; - .merge_requests_middle_box { - @extend .middle_box_content; - height: 30px; - .merge_requests_assignee { - @extend .span6; - float: left; - } - .merge_requests_milestone { - @extend .span4; - float: left; - } - } -} diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 0c2a56d62f5..34c7391da18 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -21,7 +21,7 @@ /* Note textare */ #note_note { height: 80px; - width: 99%; + width: 98%; font-size: 14px; } @@ -228,6 +228,6 @@ td .line_note_link { } .note-text { - border: 1px solid #aaa; + border: 1px solid #DDD; box-shadow: none; } diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index 717f85024cc..072ade80ad3 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -8,16 +8,12 @@ .groups_box, .projects_box { - > h5 { - color: $style_color; - font-size: 16px; - text-shadow: 0 1px 1px #fff; - padding: 2px 10px; - line-height: 32px; - font-size: 14px; + > .title { + padding: 2px 15px; } .nav-projects-tabs li { padding: 0; } .well-list { + li { padding: 15px; } .arrow { float: right; padding: 10px; @@ -109,7 +105,7 @@ ul.nav.nav-projects-tabs { li { a { - padding: 4px 20px; + padding: 6px 25px; margin-top: 2px; border-color: #DDD; background-color: #EEE; diff --git a/app/contexts/commit_load_context.rb b/app/contexts/commit_load_context.rb index e43e5a07805..1f23f633af3 100644 --- a/app/contexts/commit_load_context.rb +++ b/app/contexts/commit_load_context.rb @@ -9,16 +9,16 @@ class CommitLoadContext < BaseContext status: :ok } - commit = project.commit(params[:id]) + commit = project.repository.commit(params[:id]) if commit commit = CommitDecorator.decorate(commit) - line_notes = project.commit_line_notes(commit) + line_notes = project.notes.for_commit_id(commit.id).inline result[:commit] = commit result[:note] = project.build_commit_note(commit) result[:line_notes] = line_notes - result[:notes_count] = line_notes.count + project.commit_notes(commit).count + result[:notes_count] = project.notes.for_commit_id(commit.id).count begin result[:suppress_diff] = true if commit.diffs.size > Commit::DIFF_SAFE_SIZE && !params[:force_show_diff] diff --git a/app/contexts/filter_context.rb b/app/contexts/filter_context.rb new file mode 100644 index 00000000000..401d19b31c8 --- /dev/null +++ b/app/contexts/filter_context.rb @@ -0,0 +1,31 @@ +class FilterContext + attr_accessor :items, :params + + def initialize(items, params) + @items = items + @params = params + end + + def execute + apply_filter(items) + end + + def apply_filter items + if params[:project_id] + items = items.where(project_id: params[:project_id]) + end + + if params[:search].present? + items = items.search(params[:search]) + end + + case params[:status] + when 'closed' + items.closed + when 'all' + items + else + items.opened + end + end +end diff --git a/app/contexts/issues_list_context.rb b/app/contexts/issues_list_context.rb index 9bbdfe1db39..0cc73f99535 100644 --- a/app/contexts/issues_list_context.rb +++ b/app/contexts/issues_list_context.rb @@ -4,7 +4,7 @@ class IssuesListContext < BaseContext attr_accessor :issues def execute - @issues = case params[:f] + @issues = case params[:status] when issues_filter[:all] then @project.issues when issues_filter[:closed] then @project.issues.closed when issues_filter[:to_me] then @project.issues.opened.assigned(current_user) diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb index 9f8299f52f7..a8f617a782b 100644 --- a/app/contexts/notes/load_context.rb +++ b/app/contexts/notes/load_context.rb @@ -9,7 +9,7 @@ module Notes @notes = case target_type when "commit" - project.commit_notes(project.commit(target_id)).fresh.limit(20) + project.notes.for_commit_id(target_id).not_inline.fresh.limit(20) when "issue" project.issues.find(target_id).notes.inc_author.fresh.limit(20) when "merge_request" @@ -18,7 +18,7 @@ module Notes project.snippets.find(target_id).notes.fresh when "wall" # this is the only case, where the order is DESC - project.common_notes.order("created_at DESC, id DESC").limit(50) + project.notes.common.inc_author_project.order("created_at DESC, id DESC").limit(50) end @notes = if after_id diff --git a/app/contexts/test_hook_context.rb b/app/contexts/test_hook_context.rb index cba5d1f87c2..d2d82a52cf5 100644 --- a/app/contexts/test_hook_context.rb +++ b/app/contexts/test_hook_context.rb @@ -1,7 +1,7 @@ class TestHookContext < BaseContext def execute hook = project.hooks.find(params[:id]) - commits = project.commits(project.default_branch, nil, 3) + commits = project.repository.commits(project.default_branch, nil, 3) data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) hook.execute(data) end diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index e1982eee577..d5e6f3cdc0e 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -10,6 +10,7 @@ class Admin::ProjectsController < AdminController end def show + @repository = @project.repository @users = User.active @users = @users.not_in_project(@project) if @project.users.present? @users = @users.all @@ -19,7 +20,7 @@ class Admin::ProjectsController < AdminController end def team_update - @project.add_users_ids_to_team(params[:user_ids], params[:project_access]) + @project.team.add_users_ids(params[:user_ids], params[:project_access]) redirect_to [:admin, @project], notice: 'Project was successfully updated.' end @@ -36,7 +37,7 @@ class Admin::ProjectsController < AdminController def destroy # Delete team first in order to prevent multiple gitolite calls - @project.truncate_team + @project.team.truncate @project.destroy diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index b255c73a21f..8669f5d1d38 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -19,9 +19,9 @@ class Admin::UsersController < AdminController def team_update @admin_user = User.find(params[:id]) - UsersProject.user_bulk_import( - @admin_user, + UsersProject.add_users_into_projects( params[:project_ids], + [@admin_user.id], params[:project_access] ) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 75cd8f15605..3457a1ab1b4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -76,6 +76,12 @@ class ApplicationController < ActionController::Base end end + def repository + @repository ||= project.repository + rescue Grit::NoSuchPathError + nil + end + def add_abilities abilities << Ability end diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index 3b8ebdb5ddc..534ae1edd31 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -9,10 +9,10 @@ class CommitsController < ProjectResourceController before_filter :require_non_empty_project def show - @repo = @project.repo + @repo = @project.repository @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) - @commits = @project.commits(@ref, @path, @limit, @offset) + @commits = @repo.commits(@ref, @path, @limit, @offset) @commits = CommitDecorator.decorate(@commits) respond_to do |format| diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 695e8cb88c1..4bd840a07fb 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -36,14 +36,14 @@ class DashboardController < ApplicationController # Get authored or assigned open merge requests def merge_requests @merge_requests = current_user.cared_merge_requests - @merge_requests = dashboard_filter(@merge_requests) + @merge_requests = FilterContext.new(@merge_requests, params).execute @merge_requests = @merge_requests.recent.page(params[:page]).per(20) end # Get only assigned issues def issues @issues = current_user.assigned_issues - @issues = dashboard_filter(@issues) + @issues = FilterContext.new(@issues, params).execute @issues = @issues.recent.page(params[:page]).per(20) @issues = @issues.includes(:author, :project) @@ -62,23 +62,4 @@ class DashboardController < ApplicationController def event_filter @event_filter ||= EventFilter.new(params[:event_filter]) end - - def dashboard_filter items - if params[:project_id] - items = items.where(project_id: params[:project_id]) - end - - if params[:search].present? - items = items.search(params[:search]) - end - - case params[:status] - when 'closed' - items.closed - when 'all' - items - else - items.opened - end - end end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 981adf061f0..c25fc32a62c 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -21,15 +21,16 @@ class GroupsController < ApplicationController # Get authored or assigned open merge requests def merge_requests - @merge_requests = current_user.cared_merge_requests.opened - @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20) + @merge_requests = current_user.cared_merge_requests.of_group(@group) + @merge_requests = FilterContext.new(@merge_requests, params).execute + @merge_requests = @merge_requests.recent.page(params[:page]).per(20) end # Get only assigned issues def issues - @user = current_user - @issues = current_user.assigned_issues.opened - @issues = @issues.of_group(@group).recent.page(params[:page]).per(20) + @issues = current_user.assigned_issues.of_group(@group) + @issues = FilterContext.new(@issues, params).execute + @issues = @issues.recent.page(params[:page]).per(20) @issues = @issues.includes(:author, :project) respond_to do |format| @@ -44,6 +45,7 @@ class GroupsController < ApplicationController @projects = result[:projects] @merge_requests = result[:merge_requests] @issues = result[:issues] + @wiki_pages = result[:wiki_pages] end def people diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index fa4eaff8469..6ead406aac5 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -69,6 +69,8 @@ class MergeRequestsController < ProjectResourceController @merge_request.check_if_can_be_merged end render json: {state: @merge_request.human_state} + rescue Gitlab::SatelliteNotExistError + render json: {state: :no_satellite} end def automerge @@ -83,12 +85,12 @@ class MergeRequestsController < ProjectResourceController end def branch_from - @commit = project.commit(params[:ref]) + @commit = @repository.commit(params[:ref]) @commit = CommitDecorator.decorate(@commit) end def branch_to - @commit = project.commit(params[:ref]) + @commit = @repository.commit(params[:ref]) @commit = CommitDecorator.decorate(@commit) end diff --git a/app/controllers/project_resource_controller.rb b/app/controllers/project_resource_controller.rb index 81bc3a91bd1..ea78b3ff7c4 100644 --- a/app/controllers/project_resource_controller.rb +++ b/app/controllers/project_resource_controller.rb @@ -1,3 +1,4 @@ class ProjectResourceController < ApplicationController before_filter :project + before_filter :repository end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 47143624ec4..1a9c890ca80 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -2,6 +2,7 @@ require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder') class ProjectsController < ProjectResourceController skip_before_filter :project, only: [:new, :create] + skip_before_filter :repository, only: [:new, :create] # Authorize before_filter :authorize_read_project!, except: [:index, :new, :create] @@ -58,7 +59,7 @@ class ProjectsController < ProjectResourceController respond_to do |format| format.html do - unless @project.empty_repo? + if @project.repository && !@project.repository.empty? @last_push = current_user.recent_push(@project.id) render :show else @@ -100,7 +101,7 @@ class ProjectsController < ProjectResourceController return access_denied! unless can?(current_user, :remove_project, project) # Delete team first in order to prevent multiple gitolite calls - project.truncate_team + project.team.truncate project.destroy diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb index b48d5ec7027..09d9eb51b82 100644 --- a/app/controllers/refs_controller.rb +++ b/app/controllers/refs_controller.rb @@ -12,7 +12,7 @@ class RefsController < ProjectResourceController respond_to do |format| format.html do new_path = if params[:destination] == "tree" - project_tree_path(@project, @ref) + project_tree_path(@project, (@ref + "/" + params[:path])) else project_commits_path(@project, @ref) end @@ -31,7 +31,7 @@ class RefsController < ProjectResourceController contents = @tree.contents @logs = contents.map do |content| file = params[:path] ? File.join(params[:path], content.name) : content.name - last_commit = @project.commits(@commit.id, file, 1).last + last_commit = @repo.commits(@commit.id, file, 1).last last_commit = CommitDecorator.decorate(last_commit) { file_name: content.name, @@ -45,10 +45,10 @@ class RefsController < ProjectResourceController def define_tree_vars params[:path] = nil if params[:path].blank? - @repo = project.repo - @commit = project.commit(@ref) + @repo = project.repository + @commit = @repo.commit(@ref) @commit = CommitDecorator.decorate(@commit) - @tree = Tree.new(@commit.tree, project, @ref, params[:path]) + @tree = Tree.new(@commit.tree, @ref, params[:path]) @tree = TreeDecorator.new(@tree) @hex_path = Digest::SHA1.hexdigest(params[:path] || "") diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 7678fbff3f1..229cb36949b 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -5,19 +5,19 @@ class RepositoriesController < ProjectResourceController before_filter :require_non_empty_project def show - @activities = @project.commits_with_refs(20) + @activities = @repository.commits_with_refs(20) end def branches - @branches = @project.branches + @branches = @repository.branches end def tags - @tags = @project.tags + @tags = @repository.tags end def stats - @stats = Gitlab::GitStats.new(@project.repo, @project.root_ref) + @stats = Gitlab::GitStats.new(@repository.raw, @repository.root_ref) @graph = @stats.graph end @@ -27,7 +27,7 @@ class RepositoriesController < ProjectResourceController end - file_path = @project.archive_repo(params[:ref]) + file_path = @repository.archive_repo(params[:ref]) if file_path # Send file to user diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb index 50f7e97af9f..d0df469b967 100644 --- a/app/controllers/services_controller.rb +++ b/app/controllers/services_controller.rb @@ -26,7 +26,7 @@ class ServicesController < ProjectResourceController end def test - commits = project.commits(project.default_branch, nil, 3) + commits = project.repository.commits(project.default_branch, nil, 3) data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) @service = project.gitlab_ci_service diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index d037ad11ef1..119ef9b2be3 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -16,7 +16,7 @@ class SnippetsController < ProjectResourceController respond_to :html def index - @snippets = @project.snippets.fresh + @snippets = @project.snippets.fresh.non_expired end def new diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 311af62b8db..8378a8458ff 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -16,10 +16,9 @@ class TeamMembersController < ProjectResourceController end def create - @project.add_users_ids_to_team( - params[:user_ids], - params[:project_access] - ) + users = User.where(id: params[:user_ids]) + + @project.team << [users, params[:project_access]] if params[:redirect_to] redirect_to params[:redirect_to] @@ -50,7 +49,7 @@ class TeamMembersController < ProjectResourceController def apply_import giver = Project.find(params[:source_project_id]) - status = UsersProject.import_team(giver, project) + status = @project.team.import(giver) notice = status ? "Succesfully imported" : "Import failed" redirect_to project_team_members_path(project), notice: notice diff --git a/app/controllers/tree_controller.rb b/app/controllers/tree_controller.rb index 725f48fa014..2151bd7cbbd 100644 --- a/app/controllers/tree_controller.rb +++ b/app/controllers/tree_controller.rb @@ -22,7 +22,7 @@ class TreeController < ProjectResourceController end def edit - @last_commit = @project.last_commit_for(@ref, @path).sha + @last_commit = @project.repository.last_commit_for(@ref, @path).sha end def update diff --git a/app/decorators/tree_decorator.rb b/app/decorators/tree_decorator.rb index c12227afb5d..0e760f97dee 100644 --- a/app/decorators/tree_decorator.rb +++ b/app/decorators/tree_decorator.rb @@ -6,16 +6,14 @@ class TreeDecorator < ApplicationDecorator part_path = "" parts = path.split("\/") - #parts = parts[0...-1] if is_blob? - - yield(h.link_to("..", "#")) if parts.count > max_links + yield('..', nil) if parts.count > max_links parts.each do |part| part_path = File.join(part_path, part) unless part_path.empty? part_path = part if part_path.empty? next unless parts.last(2).include?(part) if parts.count > max_links - yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path)))) + yield(part, h.tree_join(ref, part_path)) end end end @@ -26,7 +24,7 @@ class TreeDecorator < ApplicationDecorator def up_dir_path file = File.join(path, "..") - h.project_tree_path(project, h.tree_join(ref, file)) + h.tree_join(ref, file) end def readme diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2a33bae24f3..a1eea96be43 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -53,7 +53,7 @@ module ApplicationHelper def last_commit(project) if project.repo_exists? - time_ago_in_words(project.commit.committed_date) + " ago" + time_ago_in_words(project.repository.commit.committed_date) + " ago" else "Never" end @@ -62,9 +62,11 @@ module ApplicationHelper end def grouped_options_refs(destination = :tree) + repository = @project.repository + options = [ - ["Branch", @project.branch_names ], - [ "Tag", @project.tag_names ] + ["Branch", repository.branch_names ], + [ "Tag", repository.tag_names ] ] # If reference is commit id - @@ -100,15 +102,15 @@ module ApplicationHelper ] project_nav = [] - if @project && !@project.new_record? + if @project && @project.repository && @project.repository.root_ref project_nav = [ { label: "#{@project.name} Issues", url: project_issues_path(@project) }, - { label: "#{@project.name} Commits", url: project_commits_path(@project, @ref || @project.root_ref) }, + { label: "#{@project.name} Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, { label: "#{@project.name} Merge Requests", url: project_merge_requests_path(@project) }, { label: "#{@project.name} Milestones", url: project_milestones_path(@project) }, { label: "#{@project.name} Snippets", url: project_snippets_path(@project) }, { label: "#{@project.name} Team", url: project_team_index_path(@project) }, - { label: "#{@project.name} Tree", url: project_tree_path(@project, @ref || @project.root_ref) }, + { label: "#{@project.name} Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) }, { label: "#{@project.name} Wall", url: wall_project_path(@project) }, { label: "#{@project.name} Wiki", url: project_wikis_path(@project) }, ] @@ -140,6 +142,7 @@ module ApplicationHelper event.last_push_to_non_root? && !event.rm_ref? && event.project && + event.project.repository && event.project.merge_requests_enabled end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index a2548a23e5e..2b9e7186bcd 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -20,20 +20,6 @@ module EventsHelper [event.action_name, target].join(" ") end - def event_image event - event_image_path = if event.push? - "event_push.png" - elsif event.merged? - "event_mr_merged.png" - end - - return nil unless event_image_path - - content_tag :div, class: 'event_icon' do - image_tag event_image_path - end - end - def event_filter_link key, tooltip key = key.to_s diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb new file mode 100644 index 00000000000..283119bc24c --- /dev/null +++ b/app/helpers/groups_helper.rb @@ -0,0 +1,17 @@ +module GroupsHelper + def group_filter_path(entity, options={}) + exist_opts = { + status: params[:status], + project_id: params[:project_id], + } + + options = exist_opts.merge(options) + + case entity + when 'issue' then + issues_group_path(@group, options) + when 'merge_request' + merge_requests_group_path(@group, options) + end + end +end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index f48425bd6de..ca0a89c3749 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -4,7 +4,7 @@ module MergeRequestsHelper event.project, merge_request: { source_branch: event.branch_name, - target_branch: event.project.root_ref, + target_branch: event.project.repository.root_ref, title: event.branch_name.titleize } ) diff --git a/app/models/ability.rb b/app/models/ability.rb index 75a7163c219..256af1e800b 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -15,17 +15,19 @@ class Ability def project_abilities(user, project) rules = [] + team = project.team + # Rules based on role in project - if project.master_access_for?(user) + if team.masters.include?(user) rules << project_master_rules - elsif project.dev_access_for?(user) + elsif team.developers.include?(user) rules << project_dev_rules - elsif project.report_access_for?(user) + elsif team.reporters.include?(user) rules << project_report_rules - elsif project.guest_access_for?(user) + elsif team.guests.include?(user) rules << project_guest_rules end diff --git a/app/models/commit.rb b/app/models/commit.rb index 07c5fbd7183..17d41f27f34 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -11,7 +11,7 @@ class Commit attr_accessor :commit, :head, :refs delegate :message, :authored_date, :committed_date, :parents, :sha, - :date, :committer, :author, :diffs, :tree, :id, + :date, :committer, :author, :diffs, :tree, :id, :stats, :to_patch, to: :commit class << self @@ -83,8 +83,8 @@ class Commit return result unless from && to - first = project.commit(to.try(:strip)) - last = project.commit(from.try(:strip)) + first = project.repository.commit(to.try(:strip)) + last = project.repository.commit(from.try(:strip)) if first && last result[:same] = (first.id == last.id) @@ -98,6 +98,8 @@ class Commit end def initialize(raw_commit, head = nil) + raise "Nil as raw commit passed" unless raw_commit + @commit = raw_commit @head = head end @@ -136,17 +138,17 @@ class Commit end def prev_commit - parents.try :first + @prev_commit ||= if parents.present? + Commit.new(parents.first) + else + nil + end end def prev_commit_id prev_commit.try :id end - def parents_count - parents && parents.count || 0 - end - # Shows the diff between the commit's parent and the commit. # # Cuts out the header and stats from #to_patch and returns only the diff. diff --git a/app/models/event.rb b/app/models/event.rb index 95075ffae71..d0ba61544d1 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -110,26 +110,6 @@ class Event < ActiveRecord::Base target_type == "MergeRequest" end - def new_issue? - target_type == "Issue" && - action == Created - end - - def new_merge_request? - target_type == "MergeRequest" && - action == Created - end - - def changed_merge_request? - target_type == "MergeRequest" && - [Closed, Reopened].include?(action) - end - - def changed_issue? - target_type == "Issue" && - [Closed, Reopened].include?(action) - end - def joined? action == Joined end @@ -224,7 +204,7 @@ class Event < ActiveRecord::Base # Max 20 commits from push DESC def commits - @commits ||= data[:commits].map { |commit| project.commit(commit[:id]) }.reverse + @commits ||= data[:commits].map { |commit| repository.commit(commit[:id]) }.reverse end def commits_count @@ -245,14 +225,18 @@ class Event < ActiveRecord::Base end end + def repository + project.repository + end + def parent_commit - project.commit(commit_from) + repository.commit(commit_from) rescue => ex nil end def last_commit - project.commit(commit_to) + repository.commit(commit_to) rescue => ex nil end diff --git a/app/models/gitlab_ci_service.rb b/app/models/gitlab_ci_service.rb index 0b0b65e2863..4eb39c7ef4d 100644 --- a/app/models/gitlab_ci_service.rb +++ b/app/models/gitlab_ci_service.rb @@ -29,10 +29,6 @@ class GitlabCiService < Service hook.save end - def commit_badge_path sha - project_url + "/status?sha=#{sha}" - end - def commit_status_path sha project_url + "/builds/#{sha}/status.json?token=#{token}" end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index d34e5a99c79..89c1f9adb5a 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -52,7 +52,7 @@ class Namespace < ActiveRecord::Base def ensure_dir_exist unless dir_exists? - system("mkdir -m 770 #{namespace_full_path}") + FileUtils.mkdir( namespace_full_path, mode: 0770 ) end end @@ -71,11 +71,12 @@ class Namespace < ActiveRecord::Base if File.exists?(new_path) raise "Already exists" end - - if system("mv #{old_path} #{new_path}") + + begin + FileUtils.mv( old_path, new_path ) send_update_instructions @require_update_gitolite = true - else + rescue Exception => e raise "Namespace move error #{old_path} #{new_path}" end end @@ -88,7 +89,7 @@ class Namespace < ActiveRecord::Base def rm_dir dir_path = File.join(Gitlab.config.gitolite.repos_path, path) - system("rm -rf #{dir_path}") + FileUtils.rm_r( dir_path, force: true ) end def send_update_instructions diff --git a/app/models/note.rb b/app/models/note.rb index 28b3879239f..b055ae623b2 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -4,7 +4,6 @@ # # id :integer not null, primary key # note :text -# noteable_id :string(255) # noteable_type :string(255) # author_id :integer # created_at :datetime not null @@ -12,6 +11,8 @@ # project_id :integer # attachment :string(255) # line_code :string(255) +# commit_id :string(255) +# noteable_id :integer # require 'carrierwave/orm/activerecord' @@ -41,11 +42,11 @@ class Note < ActiveRecord::Base mount_uploader :attachment, AttachmentUploader # Scopes - scope :for_commits, ->{ where(noteable_type: "Commit") } - scope :common, ->{ where(noteable_id: nil, commit_id: nil) } - scope :today, ->{ where("created_at >= :date", date: Date.today) } - scope :last_week, ->{ where("created_at >= :date", date: (Date.today - 7.days)) } - scope :since, ->(day) { where("created_at >= :date", date: (day)) } + scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) } + scope :inline, where("line_code IS NOT NULL") + scope :not_inline, where("line_code IS NULL") + + scope :common, ->{ where(noteable_type: ["", nil]) } scope :fresh, ->{ order("created_at ASC, id ASC") } scope :inc_author_project, ->{ includes(:project, :author) } scope :inc_author, ->{ includes(:author) } @@ -70,7 +71,7 @@ class Note < ActiveRecord::Base # override to return commits, which are not active record def noteable if for_commit? - project.commit(commit_id) + project.repository.commit(commit_id) else super end diff --git a/app/models/project.rb b/app/models/project.rb index f60c24426aa..702f4b2bf81 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -9,7 +9,7 @@ # created_at :datetime not null # updated_at :datetime not null # private_flag :boolean default(TRUE), not null -# owner_id :integer +# creator_id :integer # default_branch :string(255) # issues_enabled :boolean default(TRUE), not null # wall_enabled :boolean default(TRUE), not null @@ -75,7 +75,6 @@ class Project < ActiveRecord::Base validate :check_limit, :repo_name # Scopes - scope :public_only, where(private_flag: false) scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) } scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) } scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) } @@ -84,10 +83,6 @@ class Project < ActiveRecord::Base scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } class << self - def authorized_for user - raise "DERECATED" - end - def active joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") end @@ -162,6 +157,20 @@ class Project < ActiveRecord::Base end end + def team + @team ||= Team.new(self) + end + + def repository + if path + @repository ||= Repository.new(path_with_namespace, default_branch) + else + nil + end + rescue Grit::NoSuchPathError + nil + end + def git_error? error_code == :gitolite end @@ -198,30 +207,10 @@ class Project < ActiveRecord::Base [Gitlab.config.gitlab.url, path_with_namespace].join("/") end - def common_notes - notes.where(noteable_type: ["", nil]).inc_author_project - end - def build_commit_note(commit) notes.new(commit_id: commit.id, noteable_type: "Commit") end - def commit_notes(commit) - notes.where(commit_id: commit.id, noteable_type: "Commit", line_code: nil) - end - - def commit_line_notes(commit) - notes.where(commit_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL") - end - - def public? - !private_flag - end - - def private? - private_flag - end - def last_activity last_event end @@ -284,110 +273,6 @@ class Project < ActiveRecord::Base users_projects.find_by_user_id(user_id) end - # Add user to project - # with passed access role - def add_user_to_team(user, access_role) - add_user_id_to_team(user.id, access_role) - end - - # Add multiple users to project - # with same access role - def add_users_to_team(users, access_role) - add_users_ids_to_team(users.map(&:id), access_role) - end - - # Add user to project - # with passed access role by user id - def add_user_id_to_team(user_id, access_role) - users_projects.create( - user_id: user_id, - project_access: access_role - ) - end - - # Add multiple users to project - # with same access role by user ids - def add_users_ids_to_team(users_ids, access_role) - UsersProject.bulk_import(self, users_ids, access_role) - end - - # Update multiple project users - # to same access role by user ids - def update_users_ids_to_role(users_ids, access_role) - UsersProject.bulk_update(self, users_ids, access_role) - end - - # Delete multiple users from project by user ids - def delete_users_ids_from_team(users_ids) - UsersProject.bulk_delete(self, users_ids) - end - - # Remove all users from project team - def truncate_team - UsersProject.truncate_team(self) - end - - # Compatible with all access rights - # Should be rewrited for new access rights - def add_access(user, *access) - access = if access.include?(:admin) - { project_access: UsersProject::MASTER } - elsif access.include?(:write) - { project_access: UsersProject::DEVELOPER } - else - { project_access: UsersProject::REPORTER } - end - opts = { user: user } - opts.merge!(access) - users_projects.create(opts) - end - - def reset_access(user) - users_projects.where(project_id: self.id, user_id: user.id).destroy if self.id - end - - def repository_readers - repository_members[UsersProject::REPORTER] - end - - def repository_writers - repository_members[UsersProject::DEVELOPER] - end - - def repository_masters - repository_members[UsersProject::MASTER] - end - - def repository_members - keys = Hash.new {|h,k| h[k] = [] } - UsersProject.select("keys.identifier, project_access"). - joins(user: :keys).where(project_id: id). - each {|row| keys[row.project_access] << [row.identifier] } - - keys[UsersProject::REPORTER] += deploy_keys.pluck(:identifier) - keys - end - - def allow_read_for?(user) - !users_projects.where(user_id: user.id).empty? - end - - def guest_access_for?(user) - !users_projects.where(user_id: user.id).empty? - end - - def report_access_for?(user) - !users_projects.where(user_id: user.id, project_access: [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty? - end - - def dev_access_for?(user) - !users_projects.where(user_id: user.id, project_access: [UsersProject::DEVELOPER, UsersProject::MASTER]).empty? - end - - def master_access_for?(user) - !users_projects.where(user_id: user.id, project_access: [UsersProject::MASTER]).empty? - end - def transfer(new_namespace) Project.transaction do old_namespace = namespace @@ -464,8 +349,8 @@ class Project < ActiveRecord::Base # Discover the default branch, but only if it hasn't already been set to # something else - if default_branch.nil? - update_attributes(default_branch: discover_default_branch) + if repository && default_branch.nil? + update_attributes(default_branch: self.repository.discover_default_branch) end end @@ -517,7 +402,7 @@ class Project < ActiveRecord::Base # def post_receive_data(oldrev, newrev, ref, user) - push_commits = commits_between(oldrev, newrev) + push_commits = repository.commits_between(oldrev, newrev) # Total commits count push_commits_count = push_commits.size @@ -564,7 +449,7 @@ class Project < ActiveRecord::Base def update_merge_requests(oldrev, newrev, ref, user) return true unless ref =~ /heads/ branch_name = ref.gsub("refs/heads/", "") - c_ids = self.commits_between(oldrev, newrev).map(&:id) + c_ids = self.repository.commits_between(oldrev, newrev).map(&:id) # Update code for merge requests mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all @@ -586,97 +471,21 @@ class Project < ActiveRecord::Base end def empty_repo? - !repo_exists? || !has_commits? - end - - def commit(commit_id = nil) - Commit.find_or_first(repo, commit_id, root_ref) - end - - def fresh_commits(n = 10) - Commit.fresh_commits(repo, n) - end - - def commits_with_refs(n = 20) - Commit.commits_with_refs(repo, n) - end - - def commits_since(date) - Commit.commits_since(repo, date) - end - - def commits(ref, path = nil, limit = nil, offset = nil) - Commit.commits(repo, ref, path, limit, offset) - end - - def last_commit_for(ref, path = nil) - commits(ref, path, 1).first - end - - def commits_between(from, to) - Commit.commits_between(repo, from, to) + !repository || repository.empty? end def satellite @satellite ||= Gitlab::Satellite::Satellite.new(self) end - def has_post_receive_file? - !!hook_file - end - - def valid_post_receive_file? - valid_hook_file == hook_file - end - - def valid_hook_file - @valid_hook_file ||= File.read(Rails.root.join('lib', 'hooks', 'post-receive')) - end - - def hook_file - @hook_file ||= begin - hook_path = File.join(path_to_repo, 'hooks', 'post-receive') - File.read(hook_path) if File.exists?(hook_path) - end - end - - # Returns an Array of branch names - def branch_names - repo.branches.collect(&:name).sort - end - - # Returns an Array of Branches - def branches - repo.branches.sort_by(&:name) - end - - # Returns an Array of tag names - def tag_names - repo.tags.collect(&:name).sort.reverse - end - - # Returns an Array of Tags - def tags - repo.tags.sort_by(&:name).reverse - end - - # Returns an Array of branch and tag names - def ref_names - [branch_names + tag_names].flatten - end - def repo - @repo ||= Grit::Repo.new(path_to_repo) + repository.raw end def url_to_repo gitolite.url_to_repo(path_with_namespace) end - def path_to_repo - File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git") - end - def namespace_dir namespace.try(:path) || '' end @@ -690,21 +499,11 @@ class Project < ActiveRecord::Base end def repo_exists? - @repo_exists ||= (repo && !repo.branches.empty?) + @repo_exists ||= (repository && repository.branches.present?) rescue @repo_exists = false end - def heads - @heads ||= repo.heads - end - - def tree(fcommit, path = nil) - fcommit = commit if fcommit == :head - tree = fcommit.tree - path ? (tree / path) : tree - end - def open_branches if protected_branches.empty? self.repo.heads @@ -714,61 +513,8 @@ class Project < ActiveRecord::Base end.sort_by(&:name) end - # Discovers the default branch based on the repository's available branches - # - # - If no branches are present, returns nil - # - If one branch is present, returns its name - # - If two or more branches are present, returns the one that has a name - # matching root_ref (default_branch or 'master' if default_branch is nil) - def discover_default_branch - if branch_names.length == 0 - nil - elsif branch_names.length == 1 - branch_names.first - else - branch_names.select { |v| v == root_ref }.first - end - end - - def has_commits? - !!commit - rescue Grit::NoSuchPathError - false - end - - def root_ref - default_branch || "master" - end - def root_ref?(branch) - root_ref == branch - end - - # Archive Project to .tar.gz - # - # Already packed repo archives stored at - # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz - # - def archive_repo(ref) - ref = ref || self.root_ref - commit = self.commit(ref) - return nil unless commit - - # Build file path - file_name = self.path + "-" + commit.id.to_s + ".tar.gz" - storage_path = Rails.root.join("tmp", "repositories", self.path_with_namespace) - file_path = File.join(storage_path, file_name) - - # Put files into a directory before archiving - prefix = self.path + "/" - - # Create file if not exists - unless File.exists?(file_path) - FileUtils.mkdir_p storage_path - file = self.repo.archive_to_file(ref, prefix, file_path) - end - - file_path + repository.root_ref == branch end def ssh_url_to_repo diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index f405a7bf7bc..3308caf360a 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -26,6 +26,6 @@ class ProtectedBranch < ActiveRecord::Base end def commit - project.commit(self.name) + project.repository.commit(self.name) end end diff --git a/app/models/repository.rb b/app/models/repository.rb new file mode 100644 index 00000000000..cf8ba4530a1 --- /dev/null +++ b/app/models/repository.rb @@ -0,0 +1,169 @@ +class Repository + # Repository directory name with namespace direcotry + # Examples: + # gitlab/gitolite + # diaspora + # + attr_accessor :path_with_namespace + + # Grit repo object + attr_accessor :repo + + # Default branch in the repository + attr_accessor :root_ref + + def initialize(path_with_namespace, root_ref = 'master') + @root_ref = root_ref || "master" + @path_with_namespace = path_with_namespace + + # Init grit repo object + repo + end + + def raw + repo + end + + def path_to_repo + @path_to_repo ||= File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git") + end + + def repo + @repo ||= Grit::Repo.new(path_to_repo) + end + + def commit(commit_id = nil) + Commit.find_or_first(repo, commit_id, root_ref) + end + + def fresh_commits(n = 10) + Commit.fresh_commits(repo, n) + end + + def commits_with_refs(n = 20) + Commit.commits_with_refs(repo, n) + end + + def commits_since(date) + Commit.commits_since(repo, date) + end + + def commits(ref, path = nil, limit = nil, offset = nil) + Commit.commits(repo, ref, path, limit, offset) + end + + def last_commit_for(ref, path = nil) + commits(ref, path, 1).first + end + + def commits_between(from, to) + Commit.commits_between(repo, from, to) + end + + def has_post_receive_file? + !!hook_file + end + + def valid_post_receive_file? + valid_hook_file == hook_file + end + + def valid_hook_file + @valid_hook_file ||= File.read(Rails.root.join('lib', 'hooks', 'post-receive')) + end + + def hook_file + @hook_file ||= begin + hook_path = File.join(path_to_repo, 'hooks', 'post-receive') + File.read(hook_path) if File.exists?(hook_path) + end + end + + # Returns an Array of branch names + def branch_names + repo.branches.collect(&:name).sort + end + + # Returns an Array of Branches + def branches + repo.branches.sort_by(&:name) + end + + # Returns an Array of tag names + def tag_names + repo.tags.collect(&:name).sort.reverse + end + + # Returns an Array of Tags + def tags + repo.tags.sort_by(&:name).reverse + end + + # Returns an Array of branch and tag names + def ref_names + [branch_names + tag_names].flatten + end + + def heads + @heads ||= repo.heads + end + + def tree(fcommit, path = nil) + fcommit = commit if fcommit == :head + tree = fcommit.tree + path ? (tree / path) : tree + end + + def has_commits? + !!commit + rescue Grit::NoSuchPathError + false + end + + def empty? + !has_commits? + end + + # Discovers the default branch based on the repository's available branches + # + # - If no branches are present, returns nil + # - If one branch is present, returns its name + # - If two or more branches are present, returns the one that has a name + # matching root_ref (default_branch or 'master' if default_branch is nil) + def discover_default_branch + if branch_names.length == 0 + nil + elsif branch_names.length == 1 + branch_names.first + else + branch_names.select { |v| v == root_ref }.first + end + end + + # Archive Project to .tar.gz + # + # Already packed repo archives stored at + # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz + # + def archive_repo(ref) + ref = ref || self.root_ref + commit = self.commit(ref) + return nil unless commit + + # Build file path + file_name = self.path + "-" + commit.id.to_s + ".tar.gz" + storage_path = Rails.root.join("tmp", "repositories", self.path_with_namespace) + file_path = File.join(storage_path, file_name) + + # Put files into a directory before archiving + prefix = self.path + "/" + + # Create file if not exists + unless File.exists?(file_path) + FileUtils.mkdir_p storage_path + file = self.repo.archive_to_file(ref, prefix, file_path) + end + + file_path + end +end diff --git a/app/models/team.rb b/app/models/team.rb new file mode 100644 index 00000000000..f235d20ebdb --- /dev/null +++ b/app/models/team.rb @@ -0,0 +1,118 @@ +class Team + attr_accessor :project + + def initialize(project) + @project = project + end + + # Shortcut to add users + # + # Use: + # @team << [@user, :master] + # @team << [@users, :master] + # + def << args + users = args.first + + if users.respond_to?(:each) + add_users(users, args.second) + else + add_user(users, args.second) + end + end + + def add_user(user, access) + add_users_ids([user.id], access) + end + + def add_users(users, access) + add_users_ids(users.map(&:id), access) + end + + def add_users_ids(user_ids, access) + UsersProject.add_users_into_projects( + [project.id], + user_ids, + access + ) + end + + # Remove all users from project team + def truncate + UsersProject.truncate_team(project) + end + + def members + project.users_projects + end + + def guests + members.guests.map(&:user) + end + + def reporters + members.reporters.map(&:user) + end + + def developers + members.developers.map(&:user) + end + + def masters + members.masters.map(&:user) + end + + def repository_readers + repository_members[UsersProject::REPORTER] + end + + def repository_writers + repository_members[UsersProject::DEVELOPER] + end + + def repository_masters + repository_members[UsersProject::MASTER] + end + + def repository_members + keys = Hash.new {|h,k| h[k] = [] } + UsersProject.select("keys.identifier, project_access"). + joins(user: :keys).where(project_id: project.id). + each {|row| keys[row.project_access] << [row.identifier] } + + keys[UsersProject::REPORTER] += project.deploy_keys.pluck(:identifier) + keys + end + + def import(source_project) + target_project = project + + source_team = source_project.users_projects.all + target_team = target_project.users_projects.all + target_user_ids = target_team.map(&:user_id) + + source_team.reject! do |tm| + # Skip if user already present in team + target_user_ids.include?(tm.user_id) + end + + source_team.map! do |tm| + new_tm = tm.dup + new_tm.id = nil + new_tm.project_id = target_project.id + new_tm.skip_git = true + new_tm + end + + UsersProject.transaction do + source_team.each do |tm| + tm.save + end + target_project.update_repository + end + + true + rescue + false + end +end diff --git a/app/models/tree.rb b/app/models/tree.rb index c3dfd4c718c..96395a42394 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -1,12 +1,13 @@ class Tree include Linguist::BlobHelper - attr_accessor :path, :tree, :project, :ref + + attr_accessor :path, :tree, :ref delegate :contents, :basename, :name, :data, :mime_type, :mode, :size, :text?, :colorize, to: :tree - def initialize(raw_tree, project, ref = nil, path = nil) - @project, @ref, @path = project, ref, path + def initialize(raw_tree, ref = nil, path = nil) + @ref, @path = ref, path @tree = if path.present? raw_tree / path else diff --git a/app/models/user.rb b/app/models/user.rb index d166ae4dc79..55d75892fc4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -67,6 +67,8 @@ class User < ActiveRecord::Base message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } + validate :namespace_uniq, if: ->(user) { user.username_changed? } + before_validation :generate_password, on: :create before_save :ensure_authentication_token alias_attribute :private_token, :authentication_token @@ -135,6 +137,12 @@ class User < ActiveRecord::Base end end + def namespace_uniq + namespace_name = self.username + if Namespace.find_by_path(namespace_name) + self.errors.add :username, "already exist" + end + end # Namespaces user has access to def namespaces @@ -188,7 +196,7 @@ class User < ActiveRecord::Base # Team membership in personal projects def tm_in_personal_projects - personal_projects.users_projects.where(user_id: self.id) + UsersProject.where(project_id: personal_projects.map(&:id), user_id: self.id) end # Returns a string for use as a Gitolite user identifier @@ -230,10 +238,6 @@ class User < ActiveRecord::Base abilities.allowed?(self, action, subject) end - def last_activity_project - projects.first - end - def first_name name.split.first unless name.blank? end diff --git a/app/models/users_project.rb b/app/models/users_project.rb index f8e0078400f..79146289836 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -42,7 +42,34 @@ class UsersProject < ActiveRecord::Base scope :in_project, ->(project) { where(project_id: project.id) } class << self - def add_users_into_projects(project_ids, user_ids, project_access) + + # Add users to project teams with passed access option + # + # access can be an integer representing a access code + # or symbol like :master representing role + # + # Ex. + # add_users_into_projects( + # project_ids, + # user_ids, + # UsersProject::MASTER + # ) + # + # add_users_into_projects( + # project_ids, + # user_ids, + # :master + # ) + # + def add_users_into_projects(project_ids, user_ids, access) + project_access = if roles_hash.has_key?(access) + roles_hash[access] + elsif roles_hash.values.include?(access.to_i) + access + else + raise "Non valid access" + end + UsersProject.transaction do project_ids.each do |project_id| user_ids.each do |user_id| @@ -79,66 +106,13 @@ class UsersProject < ActiveRecord::Base truncate_teams [project.id] end - def import_team(source_project, target_project) - source_team = source_project.users_projects.all - target_team = target_project.users_projects.all - target_user_ids = target_team.map(&:user_id) - - source_team.reject! do |tm| - # Skip if user already present in team - target_user_ids.include?(tm.user_id) - end - - source_team.map! do |tm| - new_tm = tm.dup - new_tm.id = nil - new_tm.project_id = target_project.id - new_tm.skip_git = true - new_tm - end - - UsersProject.transaction do - source_team.each do |tm| - tm.save - end - target_project.update_repository - end - - true - rescue - false - end - - def bulk_delete(project, user_ids) - UsersProject.transaction do - UsersProject.where(user_id: user_ids, project_id: project.id).each do |users_project| - users_project.skip_git = true - users_project.destroy - end - - project.update_repository - end - end - - def bulk_update(project, user_ids, project_access) - UsersProject.transaction do - UsersProject.where(user_id: user_ids, project_id: project.id).each do |users_project| - users_project.project_access = project_access - users_project.skip_git = true - users_project.save - end - project.update_repository - end - end - - # TODO: depreceate in future in favor of add_users_into_projects - def bulk_import(project, user_ids, project_access) - add_users_into_projects([project.id], user_ids, project_access) - end - - # TODO: depreceate in future in favor of add_users_into_projects - def user_bulk_import(user, project_ids, project_access) - add_users_into_projects(project_ids, [user.id], project_access) + def roles_hash + { + guest: GUEST, + reporter: REPORTER, + developer: DEVELOPER, + master: MASTER + } end def access_roles @@ -151,10 +125,6 @@ class UsersProject < ActiveRecord::Base end end - def role_access - project_access - end - def update_repository gitolite.update_repository(project) end diff --git a/app/models/wiki.rb b/app/models/wiki.rb index 252a97e8cca..4f113957f99 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -50,5 +50,4 @@ class Wiki < ActiveRecord::Base def set_slug self.slug = self.title.parameterize end - end diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb index bb7dc0dab10..391731d9470 100644 --- a/app/uploaders/attachment_uploader.rb +++ b/app/uploaders/attachment_uploader.rb @@ -1,49 +1,13 @@ # encoding: utf-8 class AttachmentUploader < CarrierWave::Uploader::Base - - # Include RMagick or ImageScience support: - # include CarrierWave::RMagick - # include CarrierWave::MiniMagick - # include CarrierWave::ImageScience - - # Choose what kind of storage to use for this uploader: storage :file - # storage :fog - # Override the directory where uploaded files will be stored. - # This is a sensible default for uploaders that are meant to be mounted: def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end - # Provide a default URL as a default if there hasn't been a file uploaded: - # def default_url - # "/images/fallback/" + [version_name, "default.png"].compact.join('_') - # end - - # Process files as they are uploaded: - # process scale: [200, 300] - # - # def scale(width, height) - # # do something - # end - - # Create different versions of your uploaded files: - # version :thumb do - # process scale: [50, 50] - # end - - # Add a white list of extensions which are allowed to be uploaded. - # For images you might use something like this: - # def extension_white_list - # %w(jpg jpeg gif png) - # end - - # Override the filename of the uploaded files: - # Avoid using model.id or version_name here, see uploader/store.rb for details. - # def filename - # "something.jpg" if original_filename - # end - + def image? + %w(png jpg jpeg).include?(file.extension) + end end diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 4320bda4999..672dad4377e 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -1,7 +1,7 @@ .admin_dash.row .span3 .ui-box - %h5 Projects + %h5.title Projects .data.padded = link_to admin_projects_path do %h1= Project.count @@ -9,7 +9,7 @@ = link_to 'New Project', new_project_path, class: "btn small" .span3 .ui-box - %h5 Groups + %h5.title Groups .data.padded = link_to admin_groups_path do %h1= Group.count @@ -17,7 +17,7 @@ = link_to 'New Group', new_admin_group_path, class: "btn small" .span3 .ui-box - %h5 Users + %h5.title Users .data.padded = link_to admin_users_path do %h1= User.count @@ -25,7 +25,7 @@ = link_to 'New User', new_admin_user_path, class: "btn small" .span3 .ui-box - %h5 + %h5.title Resque Workers .data.padded - if @resque_accessible diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index 27c22872d50..36c0c655cae 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -11,18 +11,18 @@ .input = f.text_field :name, placeholder: "Example Project", class: "xxlarge" - %fieldset.adv_settings - %legend Advanced settings: - .clearfix - = f.label :path do - Path - .input - = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true + - if project.repo_exists? + %fieldset.adv_settings + %legend Advanced settings: + .clearfix + = f.label :path do + Path + .input + = text_field_tag :ppath, @project.repository.path_to_repo, class: "xlarge", disabled: true - - if project.repo_exists? .clearfix = f.label :default_branch, "Default Branch" - .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;") + .input= f.select(:default_branch, @project.repository.heads.map(&:name), {}, style: "width:210px;") %fieldset.adv_settings %legend Features: diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index ca9b9d3d444..5a745f58fe3 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -4,15 +4,15 @@ %i.icon-edit Edit -- if @project.has_commits? - - if !@project.has_post_receive_file? +- if @repository && @repository.has_commits? + - if !@repository.has_post_receive_file? %br .alert.alert-error %span %strong Project has commits but missing post-receive file. %br If you exported project manually - make a link of post-receive hook file from gitolite to project repository - - elsif !@project.valid_post_receive_file? + - elsif !@repository.valid_post_receive_file? %br .alert.alert-error %span @@ -65,42 +65,43 @@ Created at: %td = @project.created_at.stamp("March 1, 1999") + %tr + %td + %b + Smart HTTP: + %td + = link_to @project.http_url_to_repo + %tr + %td + %b + SSH: + %td + = link_to @project.ssh_url_to_repo -%table.zebra-striped - %thead +- if @repository + %table.zebra-striped + %thead + %tr + %th Repository + %th %tr - %th Repository - %th - %tr - %td - %b - FS Path: - %td - %code= @project.path_to_repo - %tr - %td - %b - Smart HTTP: - %td - = link_to @project.http_url_to_repo - %tr - %td - %b - SSH: - %td - = link_to @project.ssh_url_to_repo - %tr - %td - %b - Last commit at: - %td - = last_commit(@project) - %tr - %td - %b - Post Receive File: - %td - = check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true + %td + %b + FS Path: + %td + %code= @repository.path_to_repo + %tr + %td + %b + Last commit at: + %td + = last_commit(@project) + %tr + %td + %b + Post Receive File: + %td + = check_box_tag :post_receive_file, 1, @repository.has_post_receive_file?, disabled: true %br %h5 diff --git a/app/views/commit/show.html.haml b/app/views/commit/show.html.haml index 432d55b19e3..0144e4754c5 100644 --- a/app/views/commit/show.html.haml +++ b/app/views/commit/show.html.haml @@ -1,9 +1,15 @@ = render "commits/commit_box" + +%p.right.cgray + This commit has + %span.cgreen #{@commit.stats.additions} additions + and + %span.cred #{@commit.stats.deletions} deletions + = render "commits/diffs", diffs: @commit.diffs = render "notes/notes_with_form", tid: @commit.id, tt: "commit" = render "notes/per_line_form" - :javascript $(function(){ PerLineNotes.init(); @@ -19,7 +25,7 @@ , h = event.currentTarget.naturalHeight; $('.image.diff_added .image-info', this).append(' | <b>W:</b> ' + w + 'px | <b>H:</b> ' + h + 'px'); }, this)); - + }); - + }); diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml index 156ff1e9d85..eb0312d01e1 100644 --- a/app/views/commits/_commit.html.haml +++ b/app/views/commits/_commit.html.haml @@ -14,8 +14,8 @@ %span.notes_count - - notes = @project.commit_notes(commit) + @project.commit_line_notes(commit) + - notes = @project.notes.for_commit_id(commit.id) - if notes.any? - %span.btn.small.disabled.grouped + %span.btn.disabled.grouped %i.icon-comment = notes.count diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commits/_commit_box.html.haml index 8f7826e0c8d..0544a1d10fe 100644 --- a/app/views/commits/_commit_box.html.haml +++ b/app/views/commits/_commit_box.html.haml @@ -1,47 +1,50 @@ -.commit-box{class: @commit.parents_count > 1 ? "merge-commit" : ""} - .commit-head +.ui-box.ui-box-show + .ui-box-head .right - if @notes_count > 0 %span.btn.disabled.grouped %i.icon-comment = @notes_count .left.btn-group - %a.btn.small.grouped.dropdown-toggle{ data: {toggle: :dropdown} } + %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} } %i.icon-download-alt Download as %span.caret %ul.dropdown-menu %li= link_to "Email Patches", project_commit_path(@project, @commit, format: :patch) %li= link_to "Plain Diff", project_commit_path(@project, @commit, format: :diff) - = link_to project_tree_path(@project, @commit), class: "browse-button primary grouped" do - %strong Browse Code » + = link_to project_tree_path(@project, @commit), class: "btn primary grouped" do + %span Browse Code » %h3.commit-title.page_title = gfm escape_once(@commit.title) - if @commit.description.present? %pre.commit-description = gfm escape_once(@commit.description) - .commit-info + .ui-box-body .row .span5 .author - %strong= @commit.author_link avatar: true, size: 40 + = @commit.author_link avatar: true, size: 32 authored %time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")} #{time_ago_in_words(@commit.authored_date)} ago - if @commit.different_committer? .committer → - %strong= @commit.committer_link + = @commit.committer_link committed %time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")} #{time_ago_in_words(@commit.committed_date)} ago - .span6.right - .sha-block - %span.cgray commit - %code.label_commit= @commit.id - .sha-block - %span.cgray= pluralize(@commit.parents.count, "parent") - - @commit.parents.each do |parent| - = link_to parent.id[0...10], project_commit_path(@project, parent) + .span6.pull-right + .pull-right + .sha-block + %span.cgray commit + %span.label_commit= @commit.id + .clearfix + .pull-right + .sha-block + %span.cgray= pluralize(@commit.parents.count, "parent") + - @commit.parents.each do |parent| + = link_to parent.id[0...10], project_commit_path(@project, parent) diff --git a/app/views/commits/_commits.html.haml b/app/views/commits/_commits.html.haml index c9217989884..0dc6664c1d6 100644 --- a/app/views/commits/_commits.html.haml +++ b/app/views/commits/_commits.html.haml @@ -1,6 +1,6 @@ - @commits.group_by { |c| c.committed_date.to_date }.each do |day, commits| %div.ui-box - %h5.small + %h5.title %i.icon-calendar = day.stamp("28 Aug, 2010") %ul.well-list= render commits diff --git a/app/views/commits/_head.html.haml b/app/views/commits/_head.html.haml index 2ec1d24bbef..a5f3fdf5c5e 100644 --- a/app/views/commits/_head.html.haml +++ b/app/views/commits/_head.html.haml @@ -2,19 +2,19 @@ %li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'} = nav_link(controller: [:commit, :commits]) do - = link_to 'Commits', project_commits_path(@project, @project.root_ref) + = link_to 'Commits', project_commits_path(@project, @repository.root_ref) = nav_link(controller: :compare) do = link_to 'Compare', project_compare_index_path(@project) = nav_link(html_options: {class: branches_tab_class}) do = link_to project_repository_path(@project) do Branches - %span.badge= @project.branches.length + %span.badge= @repository.branches.length = nav_link(controller: :repositories, action: :tags) do = link_to tags_project_repository_path(@project) do Tags - %span.badge= @project.tags.length + %span.badge= @repository.tags.length = nav_link(controller: :repositories, action: :stats) do = link_to stats_project_repository_path(@project) do diff --git a/app/views/compare/_form.html.haml b/app/views/compare/_form.html.haml index 7e3a2a0e1f5..0915782dddc 100644 --- a/app/views/compare/_form.html.haml +++ b/app/views/compare/_form.html.haml @@ -28,7 +28,7 @@ :javascript $(function() { - var availableTags = #{@project.ref_names.to_json}; + var availableTags = #{@project.repository.ref_names.to_json}; $("#from, #to").autocomplete({ source: availableTags, diff --git a/app/views/compare/show.html.haml b/app/views/compare/show.html.haml index 2abbd3fc0ee..d8ea3727d57 100644 --- a/app/views/compare/show.html.haml +++ b/app/views/compare/show.html.haml @@ -8,7 +8,8 @@ - if @commits.present? %div.ui-box - %h5.small Commits (#{@commits.count}) + %h5.title + Commits (#{@commits.count}) %ul.well-list= render @commits - unless @diffs.empty? diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml index c63ef24fca5..2b7d23c225d 100644 --- a/app/views/dashboard/_activities.html.haml +++ b/app/views/dashboard/_activities.html.haml @@ -7,7 +7,7 @@ = event_filter_link EventFilter.team, 'Team' - if @events.any? - .content_list= render @events + .content_list - else %p.nothing_here_message Projects activity will be displayed here .loading.hide diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index 5a95ab3fb98..7f544406761 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -1,5 +1,5 @@ .groups_box - %h5 + %h5.title Groups %small (#{groups.count}) diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml index cffafb5445c..6c1304ee4a8 100644 --- a/app/views/dashboard/_projects.html.haml +++ b/app/views/dashboard/_projects.html.haml @@ -1,5 +1,5 @@ .projects_box - %h5 + %h5.title Projects %small (#{projects.total_count}) diff --git a/app/views/dashboard/index.html.haml b/app/views/dashboard/index.html.haml index b64aa86cf73..d1422bda617 100644 --- a/app/views/dashboard/index.html.haml +++ b/app/views/dashboard/index.html.haml @@ -8,4 +8,4 @@ - else = render "zero_authorized_projects" :javascript - $(function(){ Pager.init(20); }); + $(function(){ Pager.init(20, true); }); diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index 52863229644..68e3b3dcaf5 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -13,7 +13,8 @@ - @issues.group_by(&:project).each do |group| %div.ui-box - @project = group[0] - %h5= link_to_project @project + %h5.title + = link_to_project @project %ul.well-list.issues_table - group[1].each do |issue| = render(partial: 'issues/show', locals: {issue: issue}) diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index ea7c8c9a3d5..c5245da731a 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -12,7 +12,8 @@ - @merge_requests.group_by(&:project).each do |group| .ui-box - @project = group[0] - %h5= link_to_project @project + %h5.title + = link_to_project @project %ul.well-list - group[1].each do |merge_request| = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index 8c12969345f..7b57f424d61 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -19,7 +19,6 @@ = event.project_name .event-body - %span.hint - - %i.icon-comment + %span.event-note + %i.icon-comment-alt = truncate event.target.note, length: 70 diff --git a/app/views/groups/_filter.html.haml b/app/views/groups/_filter.html.haml new file mode 100644 index 00000000000..c8b0ad0f433 --- /dev/null +++ b/app/views/groups/_filter.html.haml @@ -0,0 +1,33 @@ += form_tag group_filter_path(entity), method: 'get' do + %fieldset.dashboard-search-filter + = search_field_tag "search", params[:search], { placeholder: 'Search', class: 'search-text-input' } + = button_tag type: 'submit', class: 'btn' do + %i.icon-search + + %fieldset + %legend Status: + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if !params[:status])} + = link_to group_filter_path(entity, status: nil) do + Open + %li{class: ("active" if params[:status] == 'closed')} + = link_to group_filter_path(entity, status: 'closed') do + Closed + %li{class: ("active" if params[:status] == 'all')} + = link_to group_filter_path(entity, status: 'all') do + All + + %fieldset + %legend Projects: + %ul.nav.nav-pills.nav-stacked + - @projects.each do |project| + - unless entities_per_project(project, entity).zero? + %li{class: ("active" if params[:project_id] == project.id.to_s)} + = link_to group_filter_path(entity, project_id: project.id) do + = project.name_with_namespace + %small.right= entities_per_project(project, entity) + + %fieldset + %hr + = link_to "Reset", group_filter_path(entity), class: 'btn right' + diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index 0b491879fe0..040d1ae94aa 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -1,5 +1,5 @@ .projects_box - %h5 + %h5.title Projects %small (#{projects.count}) diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index 0daf4d752a8..ffca2dc75ea 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -3,17 +3,21 @@ %small (assigned to you) %small.right #{@issues.total_count} issues -%br -.clearfix -- if @issues.any? - - @issues.group_by(&:project).each do |group| - %div.ui-box - - @project = group[0] - %h5= @project.name - %ul.well-list.issues_table - - group[1].each do |issue| - = render(partial: 'issues/show', locals: {issue: issue}) - %hr - = paginate @issues, theme: "gitlab" -- else - %h3.nothing_here_message Nothing to show here +%hr +.row + .span3 + = render 'filter', entity: 'issue' + .span9 + - if @issues.any? + - @issues.group_by(&:project).each do |group| + %div.ui-box + - @project = group[0] + %h5.title + = link_to_project @project + %ul.well-list.issues_table + - group[1].each do |issue| + = render(partial: 'issues/show', locals: {issue: issue}) + %hr + = paginate @issues, theme: "gitlab" + - else + %p.nothing_here_message Nothing to show here diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index 72aa4ad11e1..c5245da731a 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -3,16 +3,22 @@ %small (authored by or assigned to you) %small.right #{@merge_requests.total_count} merge requests -%br -- if @merge_requests.any? - - @merge_requests.group_by(&:project).each do |group| - %ul.well-list.ui-box - - @project = group[0] - %h5= @project.name - - group[1].each do |merge_request| - = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) - %hr - = paginate @merge_requests, theme: "gitlab" +%hr +.row + .span3 + = render 'filter', entity: 'merge_request' + .span9 + - if @merge_requests.any? + - @merge_requests.group_by(&:project).each do |group| + .ui-box + - @project = group[0] + %h5.title + = link_to_project @project + %ul.well-list + - group[1].each do |merge_request| + = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) + %hr + = paginate @merge_requests, theme: "gitlab" -- else - %h3.nothing_here_message Nothing to show here + - else + %h3.nothing_here_message Nothing to show here diff --git a/app/views/groups/people.html.haml b/app/views/groups/people.html.haml index 091f68756c3..0bceeaa3ceb 100644 --- a/app/views/groups/people.html.haml +++ b/app/views/groups/people.html.haml @@ -5,7 +5,7 @@ - if can?(current_user, :manage_group, @group) = render (@project ? "new_member" : "new_group_member") .ui-box - %h5 + %h5.title Team %small (#{@users.size}) diff --git a/app/views/groups/search.html.haml b/app/views/groups/search.html.haml index 6ca5630f43d..1ba4707aa52 100644 --- a/app/views/groups/search.html.haml +++ b/app/views/groups/search.html.haml @@ -6,70 +6,4 @@ = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" = submit_tag 'Search', class: "btn primary wide" - if params[:search].present? - %br - %h3 - Search results - %small (#{@projects.count + @merge_requests.count + @issues.count}) - %hr - .search_results - .row - .span6 - %table - %thead - %tr - %th Projects - %tbody - - @projects.each do |project| - %tr - %td - = link_to project do - %strong.term= project.name - %small.cgray - last activity at - = project.last_activity_date.stamp("Aug 25, 2011") - - if @projects.blank? - %tr - %td - %h4.nothing_here_message No Projects - %br - %table - %thead - %tr - %th Merge Requests - %tbody - - @merge_requests.each do |merge_request| - %tr - %td - = link_to [merge_request.project, merge_request] do - %span.badge.badge-info ##{merge_request.id} - – - %strong.term= truncate merge_request.title, length: 50 - %strong.right - %span.label= merge_request.project.name - - if @merge_requests.blank? - %tr - %td - %h4.nothing_here_message No Merge Requests - .span6 - %table - %thead - %tr - %th Issues - %tbody - - @issues.each do |issue| - %tr - %td - = link_to [issue.project, issue] do - %span.badge.badge-info ##{issue.id} - – - %strong.term= truncate issue.title, length: 40 - %strong.right - %span.label= issue.project.name - - if @issues.blank? - %tr - %td - %h4.nothing_here_message No Issues - :javascript - $(function() { - $(".search_results .term").highlight("#{params[:search]}"); - }) + = render 'search/result' diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 76bc2639d61..d7d3f869895 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -7,7 +7,7 @@ %span.cgray Events and projects are filtered in scope of group %hr - if @events.any? - .content_list= render @events + .content_list - else %p.nothing_here_message Projects activity will be displayed here .loading.hide @@ -26,4 +26,4 @@ = link_to "@gitlabhq", "https://twitter.com/gitlabhq" :javascript - $(function(){ Pager.init(20); }); + $(function(){ Pager.init(20, true); }); diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index ebd499c05e0..dc22b672cb7 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -9,31 +9,41 @@ %br Fast, secure and stable solution based on Ruby on Rails & Gitolite. -%hr +%br + +.row + .span6 + .ui-box + .title + %h5 Help + %ul.well-list + %li + %span= link_to "Workflow", help_workflow_path -%h3 Help + %li + %span= link_to "Permissions", help_permissions_path -%ol - %li - %h5= link_to "Workflow", help_workflow_path + %li + %span= link_to "Web Hooks", help_web_hooks_path - %li - %h5= link_to "Permissions", help_permissions_path + %li + %span= link_to "API", help_api_path - %li - %h5= link_to "Web Hooks", help_web_hooks_path + %li + %span= link_to "GitLab Markdown", help_markdown_path - %li - %h5= link_to "System Hooks", help_system_hooks_path + %li + %span= link_to "SSH keys", help_ssh_path - %li - %h5= link_to "API", help_api_path + .span6 + .ui-box + .title + %h5 Admin Guide + %ul.well-list - %li - %h5= link_to "GitLab Markdown", help_markdown_path + %li + %span= link_to "GitLab Rake Tasks", help_raketasks_path - %li - %h5= link_to "SSH keys", help_ssh_path + %li + %span= link_to "System Hooks", help_system_hooks_path - %li - %h5= link_to "GitLab Rake Tasks", help_raketasks_path diff --git a/app/views/help/raketasks.html.haml b/app/views/help/raketasks.html.haml index 62cfa1521a7..f015451a673 100644 --- a/app/views/help/raketasks.html.haml +++ b/app/views/help/raketasks.html.haml @@ -16,6 +16,8 @@ = link_to "User Management", "#user_management", 'data-toggle' => 'tab' %li = link_to "Backup & Restore", "#backup_restore", 'data-toggle' => 'tab' + %li + = link_to "Cleanup", "#cleanup", 'data-toggle' => 'tab' .tab-content .tab-pane.active#features @@ -45,6 +47,15 @@ = preserve do = markdown File.read(Rails.root.join("doc", "raketasks", "user_management.md")) + .tab-pane#cleanup + .file_holder + .file_title + %i.icon-file + Cleanup + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "raketasks", "cleanup.md")) + .tab-pane#backup_restore .file_holder .file_title diff --git a/app/views/hooks/_data_ex.html.erb b/app/views/hooks/_data_ex.html.erb index 246a8235517..b4281fa18c7 100644 --- a/app/views/hooks/_data_ex.html.erb +++ b/app/views/hooks/_data_ex.html.erb @@ -1,44 +1,43 @@ <% data_ex_str = <<eos { - :before => "95790bf891e76fee5e1747ab589903a6a1f80f22", - :after => "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", - :ref => "refs/heads/master", - :user_id => 4, - :user_name => "John Smith", - :repository => { - :name => "Diaspora", - :url => "git@localhost:diaspora.git", - :description => "", - :homepage => "http://localhost/diaspora", + "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", + "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "ref": "refs/heads/master", + "user_id": 4, + "user_name": "John Smith", + "repository": { + "name": "Diaspora", + "url": "git@localhost:diaspora.git", + "description": "", + "homepage": "http://localhost/diaspora", + }, + "commits": [ + { + "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "message": "Update Catalan translation to e38cb41.", + "timestamp": "2011-12-12T14:27:31+02:00", + "url": "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "author": { + "name": "Jordi Mallach", + "email": "jordi@softcatala.org", + } }, - :commits => [ - [0] { - :id => "450d0de7532f8b663b9c5cce183b...", - :message => "Update Catalan translation to e38cb41.", - :timestamp => "2011-12-12T14:27:31+02:00", - :url => "http://localhost/diaspora/commits/450d0de7532f...", - :author => { - :name => "Jordi Mallach", - :email => "jordi@softcatala.org" - } - }, - - .... - - [3] { - :id => "da1560886d4f094c3e6c9ef40349...", - :message => "fixed readme", - :timestamp => "2012-01-03T23:36:29+02:00", - :url => "http://localhost/diaspora/commits/da1560886d...", - :author => { - :name => "GitLab dev user", - :email => "gitlabdev@dv6700.(none)" - } - } - ], - total_commits_count => 4 -} + // ... + { + "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "message": "fixed readme", + "timestamp": "2012-01-03T23:36:29+02:00", + "url": "http://localhost/diaspora/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "author": { + "name": "GitLab dev user", + "email": "gitlabdev@dv6700.(none)", + }, + }, + ], + "total_commits_count": 4, +}; eos %> -<% js_lexer = Pygments::Lexer[:js] %> -<%= raw js_lexer.highlight(data_ex_str) %> +<div class="<%= user_color_scheme_class%>"> + <%= raw Pygments::Lexer[:js].highlight(data_ex_str) %> +</div> diff --git a/app/views/issues/_filter.html.haml b/app/views/issues/_filter.html.haml new file mode 100644 index 00000000000..9b710a71772 --- /dev/null +++ b/app/views/issues/_filter.html.haml @@ -0,0 +1,20 @@ += form_tag project_issues_path(@project), method: 'get' do + %fieldset + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if !params[:status])} + = link_to project_issues_path(@project, status: nil) do + Open + %li{class: ("active" if params[:status] == 'to_me')} + = link_to project_issues_path(@project, status: 'to_me') do + Assigned To Me + %li{class: ("active" if params[:status] == 'closed')} + = link_to project_issues_path(@project, status: 'closed') do + Closed + %li{class: ("active" if params[:status] == 'all')} + = link_to project_issues_path(@project, status: 'all') do + All + + %fieldset + %hr + = link_to "Reset", project_issues_path(@project), class: 'btn right' + diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml index 030f797c088..bef235f2dea 100644 --- a/app/views/issues/_form.html.haml +++ b/app/views/issues/_form.html.haml @@ -6,26 +6,27 @@ - @issue.errors.full_messages.each do |msg| %span= msg %br - .issue_form_box - .issue_title + .ui-box.ui-box-show + .ui-box-head .clearfix = f.label :title do %strong= "Subject *" .input = f.text_field :title, maxlength: 255, class: "xxlarge js-gfm-input", autofocus: true, required: true - .issue_middle_block - .issue_assignee - = f.label :assignee_id do - %i.icon-user - Assign to - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'}) - .issue_milestone - = f.label :milestone_id do - %i.icon-time - Milestone - .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'}) + .ui-box-body + .clearfix + .issue_assignee.pull-left + = f.label :assignee_id do + %i.icon-user + Assign to + .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'}) + .issue_milestone.pull-left + = f.label :milestone_id do + %i.icon-time + Milestone + .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'}) - .issue_description + .ui-box-bottom .clearfix = f.label :label_list do %i.icon-tag @@ -43,7 +44,7 @@ .actions - if @issue.new_record? - = f.submit 'Submit new issue', class: "btn save-btn" + = f.submit 'Submit new issue', class: "btn success" -else = f.submit 'Save changes', class: "save-btn btn" diff --git a/app/views/issues/_issues.html.haml b/app/views/issues/_issues.html.haml index d7ba4300ce7..8821dbb8d98 100644 --- a/app/views/issues/_issues.html.haml +++ b/app/views/issues/_issues.html.haml @@ -3,12 +3,10 @@ - if @issues.present? %li.bottom - .row - .span7= paginate @issues, remote: true, theme: "gitlab" - .span3.right - %span.cgray.right - %span.issue_counter #{@issues.total_count} - issues for this filter + .left= paginate @issues, remote: true, theme: "gitlab" + .right + %span.issue_counter #{@issues.total_count} + issues for this filter - else %li %h4.nothing_here_message Nothing to show here diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index 4641e8bdc63..dcef901c15f 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -3,10 +3,6 @@ .issue_check = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue) .right - - issue.labels.each do |label| - %span.label.label-tag.grouped - %i.icon-tag - = label.name - if issue.notes.any? %span.btn.small.disabled.grouped %i.icon-comment @@ -36,3 +32,8 @@ - if issue.votes_count > 0 = render 'votes/votes_inline', votable: issue + %span + - issue.labels.each do |label| + %span.label + %i.icon-tag + = label.name diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index 08d4393b201..d5c29c780ce 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -2,61 +2,47 @@ .issues_content %h3.page_title Issues - %small (<span class=issue_counter>#{@issues.total_count}</span>) + %span (<span class=issue_counter>#{@issues.total_count}</span>) .right .span5 - if can? current_user, :write_issue, @project - = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "right btn", title: "New Issue", id: "new_issue_link" do + = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "right btn primary", title: "New Issue", id: "new_issue_link" do %i.icon-plus New Issue = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do = hidden_field_tag :project_id, @project.id, { id: 'project_id' } - = hidden_field_tag :status, params[:f] + = hidden_field_tag :status, params[:status] = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 right neib search-text-input' } .clearfix - %div#issues-table-holder.ui-box - .title - = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" - - - .issues_bulk_update.hide - = form_tag bulk_update_project_issues_path(@project), method: :post do - %span.update_issues_text Update selected issues with - .left - = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") - = select_tag('update[assignee_id]', options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee") - = select_tag('update[milestone_id]', options_from_collection_for_select(issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") - = hidden_field_tag 'update[issues_ids]', [] - = hidden_field_tag :f, params[:f] - = button_tag "Save", class: "btn update_selected_issues" - .issues_filters - .left - %ul.nav.nav-pills.left - %li{class: ("active" if (params[:f] == issues_filter[:open] || !params[:f]))} - = link_to project_issues_path(@project, f: issues_filter[:open], milestone_id: params[:milestone_id]) do - Open - %li{class: ("active" if params[:f] == issues_filter[:closed])} - = link_to project_issues_path(@project, f: issues_filter[:closed], milestone_id: params[:milestone_id]) do - Closed - %li{class: ("active" if params[:f] == issues_filter[:to_me])} - = link_to project_issues_path(@project, f: issues_filter[:to_me], milestone_id: params[:milestone_id]) do - To Me - %li{class: ("active" if params[:f] == issues_filter[:all])} - = link_to project_issues_path(@project, f: issues_filter[:all], milestone_id: params[:milestone_id]) do - All - - .right - = form_tag project_issues_path(@project), method: :get, class: :right do - = select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), prompt: "Labels") - = select_tag(:assignee_id, options_from_collection_for_select([unassigned_filter] + @project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee") - = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") - = hidden_field_tag :f, params[:f] +.row + .span3 + = render 'filter', entity: 'issue' + .span9 + %div#issues-table-holder.ui-box + .title + = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" .clearfix + .issues_bulk_update.hide + = form_tag bulk_update_project_issues_path(@project), method: :post do + %span.update_issues_text Update selected issues with + .left + = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") + = select_tag('update[assignee_id]', options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee") + = select_tag('update[milestone_id]', options_from_collection_for_select(issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") + = hidden_field_tag 'update[issues_ids]', [] + = hidden_field_tag :status, params[:status] + = button_tag "Save", class: "btn update_selected_issues btn-small save-btn" + .issues_filters + = form_tag project_issues_path(@project), method: :get do + = select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), prompt: "Labels") + = select_tag(:assignee_id, options_from_collection_for_select([unassigned_filter] + @project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee") + = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") + = hidden_field_tag :status, params[:status] - %ul#issues-table.well-list.issues_table - = render "issues" + %ul#issues-table.well-list.issues_table + = render "issues" :javascript $(function(){ diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 1d4d6a13c2b..b96af36fcc0 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -24,14 +24,14 @@ ← To issues list -.main_box - .top_box_content +.ui-box.ui-box-show + .ui-box-head %h4.box-title - if @issue.closed .error.status_info Closed = gfm escape_once(@issue.title) - .middle_box_content + .ui-box-body %cite.cgray Created by #{link_to_member(@project, @issue.author)} - if @issue.assignee @@ -44,13 +44,13 @@ .right - @issue.labels.each do |label| - %span.label.label-issue + %span.label %i.icon-tag = label.name - if @issue.description.present? - .bottom_box_content + .ui-box-bottom = preserve do = markdown @issue.description diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 709807456c8..e00f96a7723 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -14,9 +14,9 @@ - if @project.repo_exists? - if can? current_user, :download_code, @project = nav_link(controller: %w(tree blob blame)) do - = link_to 'Files', project_tree_path(@project, @ref || @project.root_ref) + = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref) = nav_link(controller: %w(commit commits compare repositories protected_branches)) do - = link_to "Commits", project_commits_path(@project, @ref || @project.root_ref) + = link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref) = nav_link(path: 'projects#graph') do = link_to "Network", graph_project_path(@project) diff --git a/app/views/merge_requests/_filter.html.haml b/app/views/merge_requests/_filter.html.haml new file mode 100644 index 00000000000..86148fbcfee --- /dev/null +++ b/app/views/merge_requests/_filter.html.haml @@ -0,0 +1,20 @@ += form_tag project_issues_path(@project), method: 'get' do + %fieldset + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if (params[:f] == 'open' || !params[:f]))} + = link_to project_merge_requests_path(@project, f: 'open', milestone_id: params[:milestone_id]) do + Open + %li{class: ("active" if params[:f] == "closed")} + = link_to project_merge_requests_path(@project, f: "closed", milestone_id: params[:milestone_id]) do + Closed + %li{class: ("active" if params[:f] == 'assigned-to-me')} + = link_to project_merge_requests_path(@project, f: 'assigned-to-me', milestone_id: params[:milestone_id]) do + Assigned To Me + %li{class: ("active" if params[:f] == 'all')} + = link_to project_merge_requests_path(@project, f: 'all', milestone_id: params[:milestone_id]) do + All + + %fieldset + %hr + = link_to "Reset", project_merge_requests_path(@project), class: 'btn right' + diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index 9606e2e53b3..9a4f0617a3a 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -1,54 +1,59 @@ -= form_for [@project, @merge_request], html: { class: "new_merge_request form-horizontal" } do |f| += form_for [@project, @merge_request], html: { class: "#{controller.action_name}-merge-request form-horizontal" } do |f| -if @merge_request.errors.any? .alert-message.block-message.error %ul - @merge_request.errors.full_messages.each do |msg| %li= msg - %h4.cdark 1. Select Branches - %br + %fieldset + %legend 1. Select Branches - .row - .span5 - .mr_branch_box - %h5 From (Head Branch) - .body - .padded= f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) - .mr_source_commit + .row + .span5 + .mr_branch_box + %h5.cgray From (Head Branch) + .body + .padded= f.select(:source_branch, @repository.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) + .mr_source_commit - .span2 - %center= image_tag "merge.png", class: 'mr_direction_tip' - .span5 - .mr_branch_box - %h5 To (Base Branch) - .body - .padded= f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) - .mr_target_commit + .span2 + %center= image_tag "merge.png", class: 'mr_direction_tip' + .span5 + .mr_branch_box + %h5.cgray To (Base Branch) + .body + .padded= f.select(:target_branch, @repository.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) + .mr_target_commit - %h4.cdark 2. Fill info + %fieldset + %legend 2. Fill info - .clearfix - .merge_requests_form_box - .top_box_content - = f.label :title do - %strong= "Title *" - .input= f.text_field :title, class: "input-xxlarge pad js-gfm-input", maxlength: 255, rows: 5, required: true - .merge_requests_middle_box - .merge_requests_assignee - = f.label :assignee_id do - %i.icon-user - Assign to - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'}) - .merge_requests_milestone - = f.label :milestone_id do - %i.icon-time - Milestone - .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'}) + .ui-box.ui-box-show + .ui-box-head + .clearfix + = f.label :title do + %strong= "Title *" + .input= f.text_field :title, class: "input-xxlarge pad js-gfm-input", maxlength: 255, rows: 5, required: true + .ui-box-body + .clearfix + .left + = f.label :assignee_id do + %i.icon-user + Assign to + .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'}) + .left + = f.label :milestone_id do + %i.icon-time + Milestone + .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'}) .control-group .form-actions - = f.submit 'Save', class: "btn save-btn" + - if @merge_request.new_record? + = f.submit 'Submit merge request', class: "btn success" + -else + = f.submit 'Save changes', class: "save-btn btn" - if @merge_request.new_record? = link_to project_merge_requests_path(@project), class: "btn cancel-btn" do Cancel @@ -59,8 +64,9 @@ :javascript $(function(){ disableButtonIfEmptyField("#merge_request_title", ".save-btn"); - var source_branch = $("#merge_request_source_branch"); - var target_branch = $("#merge_request_target_branch"); + + var source_branch = $("#merge_request_source_branch") + , target_branch = $("#merge_request_target_branch"); $.get("#{branch_from_project_merge_requests_path(@project)}", {ref: source_branch.val() }); $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: target_branch.val() }); diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index 20ba991e79a..b65d1596f53 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -1,33 +1,35 @@ -= render "merge_requests/show/mr_title" -= render "merge_requests/show/how_to_merge" -= render "merge_requests/show/mr_box" -= render "merge_requests/show/mr_accept" -- if @project.gitlab_ci? - = render "merge_requests/show/mr_ci" -= render "merge_requests/show/commits" +.merge-request + = render "merge_requests/show/mr_title" + = render "merge_requests/show/how_to_merge" + = render "merge_requests/show/mr_box" + = render "merge_requests/show/mr_accept" + - if @project.gitlab_ci? + = render "merge_requests/show/mr_ci" + = render "merge_requests/show/commits" -- if @commits.present? - %ul.nav.nav-tabs.mr_nav_tabs - %li - = link_to "#notes", "data-url" => project_merge_request_path(@project, @merge_request), class: "merge-notes-tab tab" do - %i.icon-comment - Comments - %li - = link_to "#diffs", "data-url" => diffs_project_merge_request_path(@project, @merge_request), class: "merge-diffs-tab tab" do - %i.icon-list-alt - Diff + - if @commits.present? + %ul.nav.nav-tabs + %li.notes-tab{data: {action: 'notes'}} + = link_to project_merge_request_path(@project, @merge_request) do + %i.icon-comment + Comments + %li.diffs-tab{data: {action: 'diffs'}} + = link_to diffs_project_merge_request_path(@project, @merge_request) do + %i.icon-list-alt + Diff -.merge_request_notes.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } - = render("notes/notes_with_form", tid: @merge_request.id, tt: "merge_request") -.merge-request-diffs - = render "merge_requests/show/diffs" if @diffs -.status + .notes.tab-content.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } + = render("notes/notes_with_form", tid: @merge_request.id, tt: "merge_request") + .diffs.tab-content + = render "merge_requests/show/diffs" if @diffs + .status -= render "notes/per_line_form" + = render "notes/per_line_form" :javascript + var merge_request; $(function(){ - MergeRequest.init({ + merge_request = new MergeRequest({ url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", check_enable: #{@merge_request.state == MergeRequest::UNCHECKED ? "true" : "false"}, url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", @@ -35,10 +37,5 @@ current_state: "#{@merge_request.human_state}", action: "#{controller.action_name}" }); - - $(".edit_merge_request").live("ajax:beforeSend", function() { - $('.can_be_merged').hide(); - $('.merge_in_progress').show(); - }) - }) + }); diff --git a/app/views/merge_requests/automerge.js.haml b/app/views/merge_requests/automerge.js.haml index 93e184455af..e01ff662e7d 100644 --- a/app/views/merge_requests/automerge.js.haml +++ b/app/views/merge_requests/automerge.js.haml @@ -3,5 +3,5 @@ location.reload(); -else :plain - MergeRequest.already_cannot_be_merged() + merge_request.alreadyOrCannotBeMerged() diff --git a/app/views/merge_requests/commits.js.haml b/app/views/merge_requests/commits.js.haml index 76322bdb210..923b1ea032f 100644 --- a/app/views/merge_requests/commits.js.haml +++ b/app/views/merge_requests/commits.js.haml @@ -1,4 +1,4 @@ :plain - $(".merge-request-commits").html("#{escape_javascript(render(partial: "commits"))}"); + merge_request.$(".commits").html("#{escape_javascript(render(partial: "commits"))}"); diff --git a/app/views/merge_requests/diffs.js.haml b/app/views/merge_requests/diffs.js.haml index 98539985324..1d92f1a6fb8 100644 --- a/app/views/merge_requests/diffs.js.haml +++ b/app/views/merge_requests/diffs.js.haml @@ -1,7 +1,5 @@ :plain - $(".merge-request-diffs").html("#{escape_javascript(render(partial: "merge_requests/show/diffs"))}"); + merge_request.$(".diffs").html("#{escape_javascript(render(partial: "merge_requests/show/diffs"))}"); - $(function(){ - PerLineNotes.init(); - }); + PerLineNotes.init(); diff --git a/app/views/merge_requests/index.html.haml b/app/views/merge_requests/index.html.haml index 5b234bfbe02..43651a5ca15 100644 --- a/app/views/merge_requests/index.html.haml +++ b/app/views/merge_requests/index.html.haml @@ -1,48 +1,35 @@ +- if can? current_user, :write_issue, @project + = link_to new_project_merge_request_path(@project), class: "right btn primary", title: "New Merge Request" do + %i.icon-plus + New Merge Request %h3.page_title Merge Requests - - if can? current_user, :write_issue, @project - = link_to new_project_merge_request_path(@project), class: "right btn", title: "New Merge Request" do - New Merge Request %br -.ui-box - .title - .left - %ul.nav.nav-pills - %li{class: ("active" if (params[:f] == 'open' || !params[:f]))} - = link_to project_merge_requests_path(@project, f: 'open', milestone_id: params[:milestone_id]) do - Open - %li{class: ("active" if params[:f] == "closed")} - = link_to project_merge_requests_path(@project, f: "closed", milestone_id: params[:milestone_id]) do - Closed - %li{class: ("active" if params[:f] == 'assigned-to-me')} - = link_to project_merge_requests_path(@project, f: 'assigned-to-me', milestone_id: params[:milestone_id]) do - To Me - %li{class: ("active" if params[:f] == 'all')} - = link_to project_merge_requests_path(@project, f: 'all', milestone_id: params[:milestone_id]) do - All - .right - = form_tag project_merge_requests_path(@project), id: "merge_requests_search_form", method: :get, class: :right do - = select_tag(:assignee_id, options_from_collection_for_select([unassigned_filter] + @project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee") - = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone") - = hidden_field_tag :f, params[:f] - .clearfix +.row + .span3 + = render 'filter', entity: 'issue' + .span9 + .ui-box + .title + = form_tag project_merge_requests_path(@project), id: "merge_requests_search_form", method: :get, class: :left do + = select_tag(:assignee_id, options_from_collection_for_select([unassigned_filter] + @project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee") + = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone") + = hidden_field_tag :f, params[:f] + .clearfix - %ul.well-list - = render @merge_requests - - if @merge_requests.blank? - %li - %h4.nothing_here_message Nothing to show here - - if @merge_requests.present? - %li.bottom - .row - .span7= paginate @merge_requests, theme: "gitlab" - .span4.right - %span.cgray.right #{@merge_requests.total_count} merge requests for this filter + %ul.well-list + = render @merge_requests + - if @merge_requests.blank? + %li + %h4.nothing_here_message Nothing to show here + - if @merge_requests.present? + %li.bottom + .left= paginate @merge_requests, theme: "gitlab" + .right + %span.cgray.right #{@merge_requests.total_count} merge requests for this filter :javascript - $(function() { - merge_requestsPage(); - }) + $(merge_requestsPage); diff --git a/app/views/merge_requests/show.js.haml b/app/views/merge_requests/show.js.haml index f44ccbb5127..a2a79307453 100644 --- a/app/views/merge_requests/show.js.haml +++ b/app/views/merge_requests/show.js.haml @@ -1,2 +1,2 @@ :plain - $(".merge-request-notes").html("#{escape_javascript(render notes/notes_with_form", tid: @merge_request.id, tt: "merge_request")}"); + merge_request.$(".notes").html("#{escape_javascript(render "notes/notes_with_form", tid: @merge_request.id, tt: "merge_request")}"); diff --git a/app/views/merge_requests/show/_commits.html.haml b/app/views/merge_requests/show/_commits.html.haml index 796922776d9..5e27b6dc25a 100644 --- a/app/views/merge_requests/show/_commits.html.haml +++ b/app/views/merge_requests/show/_commits.html.haml @@ -1,18 +1,18 @@ - if @commits.present? .ui-box - %h5 + %h5.title %i.icon-list Commits (#{@commits.count}) - .merge-request-commits + .commits - if @commits.count > 8 - %ul.first_mr_commits.well-list + %ul.first-commits.well-list - @commits.first(8).each do |commit| = render "commits/commit", commit: commit %li.bottom 8 of #{@commits.count} commits displayed. %strong - %a.mr_show_all_commits Click here to show all - %ul.all_mr_commits.hide.well-list + %a.show-all-commits Click here to show all + %ul.all-commits.hide.well-list - @commits.each do |commit| = render "commits/commit", commit: commit diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index b7e68937131..128ffe76782 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -23,6 +23,11 @@ .clearfix + .automerge_widget.no_satellite{style: "display:none"} + .alert.alert-error + %span + %strong This repository does not have satellite. Ask administrator to fix this issue + .automerge_widget.cannot_be_merged{style: "display:none"} .alert.alert-info %span @@ -40,6 +45,6 @@ .alert.alert-info %strong This merge request already can not be merged. Try to reload page. - .merge_in_progress.hide + .merge-in-progress.hide %span.cgray Merge is in progress. Please wait. Page will be automatically reloaded. = image_tag "ajax_loader.gif" diff --git a/app/views/merge_requests/show/_mr_box.html.haml b/app/views/merge_requests/show/_mr_box.html.haml index cd33732d191..644d7fcc58e 100644 --- a/app/views/merge_requests/show/_mr_box.html.haml +++ b/app/views/merge_requests/show/_mr_box.html.haml @@ -1,5 +1,5 @@ -.main_box - .top_box_content +.ui-box.ui-box-show + .ui-box-head %h4.box-title - if @merge_request.merged .error.status_info @@ -9,7 +9,7 @@ .error.status_info Closed = gfm escape_once(@merge_request.title) - .middle_box_content + .ui-box-body %div %cite.cgray Created at #{@merge_request.created_at.stamp("Aug 21, 2011")} by #{link_to_member(@project, @merge_request.author)} @@ -22,7 +22,7 @@ - if @merge_request.closed - .bottom_box_content + .ui-box-bottom - if @merge_request.merged? %span Merged by #{link_to_member(@project, @merge_request.merge_event.author)} diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index c4975c72ef2..fc7ae51f184 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -27,8 +27,8 @@ %span All issues for this milestone are closed. You may close milestone now. = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn small danger" -.main_box - .top_box_content +.ui-box.ui-box-show + .ui-box-head %h4.box-title - if @milestone.closed .error.status_info Closed @@ -37,52 +37,47 @@ = gfm escape_once(@milestone.title) - .middle_box_content - %h5 + .ui-box-body + %p Progress: - %small - #{@milestone.closed_items_count} closed - – - #{@milestone.open_items_count} open + #{@milestone.closed_items_count} closed + – + #{@milestone.open_items_count} open %span.right= @milestone.expires_at .progress.progress-info .bar{style: "width: #{@milestone.percent_complete}%;"} - if @milestone.description.present? - .bottom_box_content + .ui-box-bottom = preserve do = markdown @milestone.description .row .span6 - %table.milestone-issue-filter - %thead - %tr - %th - %ul.nav.nav-pills - %li.active= link_to('Open Issues', '#') - %li=link_to('All Issues', '#') - - @issues.each do |issue| - %tr{data: {closed: issue.closed}} - %td + .ui-box.milestone-issue-filter + .title + %ul.nav.nav-pills + %li.active= link_to('Open Issues', '#') + %li=link_to('All Issues', '#') + %ul.well-list + - @issues.each do |issue| + %li{data: {closed: issue.closed}} = link_to [@project, issue] do %span.badge.badge-info ##{issue.id} – = link_to_gfm truncate(issue.title, length: 60), [@project, issue] .span6 - %table.milestone-merge-requests-filter - %thead - %tr - %th - %ul.nav.nav-pills - %li.active= link_to('Open Merge Requests', '#') - %li=link_to('All Merge Requests', '#') - - @merge_requests.each do |merge_request| - %tr{data: {closed: merge_request.closed}} - %td + .ui-box.milestone-merge-requests-filter + .title + %ul.nav.nav-pills + %li.active= link_to('Open Merge Requests', '#') + %li=link_to('All Merge Requests', '#') + %ul.well-list + - @merge_requests.each do |merge_request| + %li{data: {closed: merge_request.closed}} = link_to [@project, merge_request] do %span.badge.badge-info ##{merge_request.id} – diff --git a/app/views/notes/_note.html.haml b/app/views/notes/_note.html.haml index 70baa212d10..8591e7bd86b 100644 --- a/app/views/notes/_note.html.haml +++ b/app/views/notes/_note.html.haml @@ -34,6 +34,8 @@ = preserve do = markdown(note.note) - if note.attachment.url + - if note.attachment.image? + = image_tag note.attachment.url, class: 'thumbnail span4' .right %div.file = link_to note.attachment_identifier, note.attachment.url, target: "_blank" diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index 3c290948d6c..522e45e637a 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -69,7 +69,7 @@ %i.icon-ok Saved %span.update-failed.cred.hide - %i.icon-ok + %i.icon-remove Failed %ul.cred %li It will change web url for personal projects. diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 7044d1f20be..c8eacdc2a46 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -15,13 +15,13 @@ = f.label :path do Repository .controls - = text_field_tag :ppath, @project.path_to_repo, class: "xxlarge", readonly: true + = text_field_tag :ppath, @repository.path_to_repo, class: "xxlarge", readonly: true - - unless @project.heads.empty? + - unless @repository.heads.empty? .clearfix = f.label :default_branch, "Default Branch" - .input= f.select(:default_branch, @project.heads.map(&:name), {}, style: "width:210px;") + .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") %fieldset.features %legend Features: diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index 2ef29cb0c65..2391c750bc8 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -7,7 +7,7 @@ Project name is .input = f.text_field :name, placeholder: "Example Project", class: "xxlarge" - = f.submit 'Create project', class: "btn primary project-submit" + = f.submit 'Create project', class: "btn success project-submit" - if current_user.several_namespaces? .clearfix diff --git a/app/views/protected_branches/index.html.haml b/app/views/protected_branches/index.html.haml index f408fd16c2c..c1ecceda435 100644 --- a/app/views/protected_branches/index.html.haml +++ b/app/views/protected_branches/index.html.haml @@ -1,51 +1,54 @@ -= render "repositories/branches_head" += render "commits/head" +.row + .span3 + = render "repositories/filter" + .span9 + .alert + %p Protected branches designed to prevent push for all except #{link_to "masters", help_permissions_path, class: "vlink"}. + %p This ability allows: + %ul + %li keep stable branches secured + %li forced code review before merge to protected branches + %p Read more about project permissions #{link_to "here", help_permissions_path, class: "vlink"} -.alert - %p Protected branches designed to prevent push for all except #{link_to "masters", help_permissions_path, class: "vlink"}. - %p This ability allows: - %ul - %li keep stable branches secured - %li forced code review before merge to protected branches - %p Read more about project permissions #{link_to "here", help_permissions_path, class: "vlink"} + - if can? current_user, :admin_project, @project + = form_for [@project, @protected_branch] do |f| + -if @protected_branch.errors.any? + .alert-message.block-message.error + %ul + - @protected_branch.errors.full_messages.each do |msg| + %li= msg -- if can? current_user, :admin_project, @project - = form_for [@project, @protected_branch] do |f| - -if @protected_branch.errors.any? - .alert-message.block-message.error - %ul - - @protected_branch.errors.full_messages.each do |msg| - %li= msg + .entry.clearfix + = f.label :name, "Branch" + .span3 + = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "chosen span3"}) + + = f.submit 'Protect', class: "primary btn" - .entry.clearfix - = f.label :name, "Branch" - .span3 - = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "chosen span3"}) - - = f.submit 'Protect', class: "primary btn" - -- unless @branches.empty? - %table - %thead - %tr - %th Name - %th Last commit - %th - %tbody - - @branches.each do |branch| - %tr - %td - = link_to project_commits_path(@project, branch.name) do - %strong= branch.name - - if branch.name == @project.root_ref - %span.label default - %td - - if branch.commit - = link_to project_commit_path(@project, branch.commit.id) do - = truncate branch.commit.id.to_s, length: 10 - = time_ago_in_words(branch.commit.committed_date) - ago - - else - (branch was removed from repository) - %td - - if can? current_user, :admin_project, @project - = link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "danger btn small" + - unless @branches.empty? + %table + %thead + %tr + %th Name + %th Last commit + %th + %tbody + - @branches.each do |branch| + %tr + %td + = link_to project_commits_path(@project, branch.name) do + %strong= branch.name + - if @project.root_ref?(branch.name) + %span.label default + %td + - if branch.commit + = link_to project_commit_path(@project, branch.commit.id) do + = truncate branch.commit.id.to_s, length: 10 + = time_ago_in_words(branch.commit.committed_date) + ago + - else + (branch was removed from repository) + %td + - if can? current_user, :admin_project, @project + = link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "danger btn small" diff --git a/app/views/repositories/_branch.html.haml b/app/views/repositories/_branch.html.haml index 2728b100ff6..a6faa5fd633 100644 --- a/app/views/repositories/_branch.html.haml +++ b/app/views/repositories/_branch.html.haml @@ -8,7 +8,7 @@ - else %i.icon-unlock %strong= truncate(branch.name, length: 60) - - if branch.name == @project.root_ref + - if branch.name == @repository.root_ref %span.label default %td = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do @@ -22,6 +22,6 @@ %td - if can? current_user, :download_code, @project = link_to archive_project_repository_path(@project, ref: branch.name) do - %i.icon-download + %i.icon-download-alt Download diff --git a/app/views/repositories/_feed.html.haml b/app/views/repositories/_feed.html.haml index 496328baca5..44380133718 100644 --- a/app/views/repositories/_feed.html.haml +++ b/app/views/repositories/_feed.html.haml @@ -5,7 +5,7 @@ = link_to project_commits_path(@project, commit.head.name) do %strong = commit.head.name - - if commit.head.name == @project.root_ref + - if @project.root_ref?(commit.head.name) %span.label default %td diff --git a/app/views/repositories/_branches_head.html.haml b/app/views/repositories/_filter.html.haml index 8f3e1ba3f81..e718d48190a 100644 --- a/app/views/repositories/_branches_head.html.haml +++ b/app/views/repositories/_filter.html.haml @@ -1,10 +1,9 @@ -= render "commits/head" -%ul.nav.nav-pills +%ul.nav.nav-pills.nav-stacked = nav_link(path: 'repositories#show') do = link_to 'Recent', project_repository_path(@project) = nav_link(path: 'protected_branches#index') do = link_to project_protected_branches_path(@project) do - %i.icon-lock Protected + %i.icon-lock = nav_link(path: 'repositories#branches') do - = link_to 'All', branches_project_repository_path(@project) + = link_to 'All branches', branches_project_repository_path(@project) diff --git a/app/views/repositories/branches.html.haml b/app/views/repositories/branches.html.haml index 4c246c69d7c..14b5082e44e 100644 --- a/app/views/repositories/branches.html.haml +++ b/app/views/repositories/branches.html.haml @@ -1,12 +1,15 @@ -= render "repositories/branches_head" -- unless @branches.empty? - %table - %thead - %tr - %th Name - %th Last commit - %th - - %tbody - - @branches.each do |branch| - = render "repositories/branch", branch: branch += render "commits/head" +.row + .span3 + = render "filter" + .span9 + - unless @branches.empty? + %table + %thead + %tr + %th Name + %th Last commit + %th + %tbody + - @branches.each do |branch| + = render "repositories/branch", branch: branch diff --git a/app/views/repositories/show.html.haml b/app/views/repositories/show.html.haml index fd0abac8414..e58e16f8bf1 100644 --- a/app/views/repositories/show.html.haml +++ b/app/views/repositories/show.html.haml @@ -1,11 +1,14 @@ -= render "branches_head" - -%table - %thead - %tr - %th Name - %th Last commit - %th - - @activities.each do |update| - = render "repositories/branch", branch: update.head += render "commits/head" +.row + .span3 + = render "filter" + .span9 + %table + %thead + %tr + %th Name + %th Last commit + %th + - @activities.each do |update| + = render "repositories/branch", branch: update.head diff --git a/app/views/repositories/stats.html.haml b/app/views/repositories/stats.html.haml index a93814a4777..bdf047f1e98 100644 --- a/app/views/repositories/stats.html.haml +++ b/app/views/repositories/stats.html.haml @@ -7,7 +7,7 @@ %b Total commits: %span= @stats.commits_count %p - %b Total files in #{@project.root_ref}: + %b Total files in #{@repository.root_ref}: %span= @stats.files_count %p %b Authors: diff --git a/app/views/repositories/tags.html.haml b/app/views/repositories/tags.html.haml index 193cb2e30f2..d4b8bbe10d4 100644 --- a/app/views/repositories/tags.html.haml +++ b/app/views/repositories/tags.html.haml @@ -26,8 +26,14 @@ %td - if can? current_user, :download_code, @project = link_to archive_project_repository_path(@project, ref: tag.name) do - %i.icon-download + %i.icon-download-alt Download - else - %h3 No tags + %h3.nothing_here_message + Repository has no tags yet. + %br + %small + Use git tag command to add a new one: + %br + %span.monospace git tag -a v1.4 -m 'version 1.4' diff --git a/app/views/search/_result.html.haml b/app/views/search/_result.html.haml index 8b137891791..79bed4f737c 100644 --- a/app/views/search/_result.html.haml +++ b/app/views/search/_result.html.haml @@ -1 +1,85 @@ +%br +%h3.page_title + Search results + %span.cgray (#{@projects.count + @merge_requests.count + @issues.count + @wiki_pages.count}) +%hr +.search_results + .row + .span6 + %table + %thead + %tr + %th Projects + %tbody + - @projects.each do |project| + %tr + %td + = link_to project do + %strong.term= project.name_with_namespace + %small.cgray + last activity at + = project.last_activity_date.stamp("Aug 25, 2011") + - if @projects.blank? + %tr + %td + %h4.nothing_here_message No Projects + %br + %table + %thead + %tr + %th Merge Requests + %tbody + - @merge_requests.each do |merge_request| + %tr + %td + = link_to [merge_request.project, merge_request] do + %span.badge.badge-info ##{merge_request.id} + – + %strong.term= truncate merge_request.title, length: 50 + %strong.right + %span.label= merge_request.project.name + - if @merge_requests.blank? + %tr + %td + %h4.nothing_here_message No Merge Requests + .span6 + %table + %thead + %tr + %th Issues + %tbody + - @issues.each do |issue| + %tr + %td + = link_to [issue.project, issue] do + %span.badge.badge-info ##{issue.id} + – + %strong.term= truncate issue.title, length: 40 + %strong.right + %span.label= issue.project.name + - if @issues.blank? + %tr + %td + %h4.nothing_here_message No Issues + .span6 + %table + %thead + %tr + %th Wiki + %tbody + - @wiki_pages.each do |wiki_page| + %tr + %td + = link_to project_wiki_path(wiki_page.project, wiki_page) do + %strong.term= truncate wiki_page.title, length: 40 + %strong.right + %span.label= wiki_page.project.name + - if @wiki_pages.blank? + %tr + %td + %h4.nothing_here_message No wiki pages +:javascript + $(function() { + $(".search_results .term").highlight("#{escape_javascript(params[:search])}"); + }) diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index 8448193deb9..aa0d6d700d9 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -6,87 +6,4 @@ = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" = submit_tag 'Search', class: "btn primary wide" - if params[:search].present? - %br - %h3 - Search results - %small (#{@projects.count + @merge_requests.count + @issues.count + @wiki_pages.count}) - %hr - .search_results - .row - .span6 - %table - %thead - %tr - %th Projects - %tbody - - @projects.each do |project| - %tr - %td - = link_to project do - %strong.term= project.name_with_namespace - %small.cgray - last activity at - = project.last_activity_date.stamp("Aug 25, 2011") - - if @projects.blank? - %tr - %td - %h4.nothing_here_message No Projects - %br - %table - %thead - %tr - %th Merge Requests - %tbody - - @merge_requests.each do |merge_request| - %tr - %td - = link_to [merge_request.project, merge_request] do - %span.badge.badge-info ##{merge_request.id} - – - %strong.term= truncate merge_request.title, length: 50 - %strong.right - %span.label= merge_request.project.name - - if @merge_requests.blank? - %tr - %td - %h4.nothing_here_message No Merge Requests - .span6 - %table - %thead - %tr - %th Issues - %tbody - - @issues.each do |issue| - %tr - %td - = link_to [issue.project, issue] do - %span.badge.badge-info ##{issue.id} - – - %strong.term= truncate issue.title, length: 40 - %strong.right - %span.label= issue.project.name - - if @issues.blank? - %tr - %td - %h4.nothing_here_message No Issues - .span6 - %table - %thead - %tr - %th Wiki - %tbody - - @wiki_pages.each do |wiki_page| - %tr - %td - = link_to project_wiki_path(wiki_page.project, wiki_page) do - %strong.term= truncate wiki_page.title, length: 40 - %strong.right - %span.label= wiki_page.project.name - - if @wiki_pages.blank? - %tr - %td - %h4.nothing_here_message No wiki pages - :javascript - $(function() { - $(".search_results .term").highlight("#{params[:search]}"); - }) + = render 'search/result' diff --git a/app/views/team_members/_team.html.haml b/app/views/team_members/_team.html.haml index 462e75af183..365d9b65942 100644 --- a/app/views/team_members/_team.html.haml +++ b/app/views/team_members/_team.html.haml @@ -1,6 +1,6 @@ - grouper_project_members(@project).each do |access, members| .ui-box - %h5 + %h5.title = Project.access_options.key(access).pluralize %small= members.size %ul.well-list diff --git a/app/views/team_members/show.html.haml b/app/views/team_members/show.html.haml index af9a6e6b92d..4008e8bd23e 100644 --- a/app/views/team_members/show.html.haml +++ b/app/views/team_members/show.html.haml @@ -8,8 +8,7 @@ = image_tag gravatar_icon(user.email, 60), class: "borders" %h3.page_title = user.name - %small - = user.email + %small (@#{user.username}) %hr .back_link diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml index a632bb3b0d7..c2842959510 100644 --- a/app/views/tree/_tree.html.haml +++ b/app/views/tree/_tree.html.haml @@ -3,9 +3,13 @@ %span.arrow = link_to project_tree_path(@project, @ref) do = @project.name - - tree.breadcrumbs(6) do |link| + - tree.breadcrumbs(6) do |title, path| \/ - %li= link + %li + - if path + = link_to truncate(title, length: 40), project_tree_path(@project, path) + - else + = link_to title, '#' .clear %div.tree_progress @@ -26,7 +30,7 @@ %tr.tree-item %td.tree-item-file-name = image_tag "file_empty.png", size: '16x16' - = link_to "..", tree.up_dir_path + = link_to "..", project_tree_path(@project, tree.up_dir_path) %td %td %td diff --git a/app/views/tree/blob/_download.html.haml b/app/views/tree/blob/_download.html.haml index c307622995b..864c209db76 100644 --- a/app/views/tree/blob/_download.html.haml +++ b/app/views/tree/blob/_download.html.haml @@ -2,7 +2,7 @@ %center = link_to project_blob_path(@project, @id) do %div.padded - %br - = image_tag "download.png", width: 64 - %h3 + %h4 + %i.icon-download-alt + %br Download (#{number_to_human_size blob.size}) diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml index 83b16b138d3..9eb2a571fe5 100644 --- a/app/views/wikis/_form.html.haml +++ b/app/views/wikis/_form.html.haml @@ -6,12 +6,12 @@ - @wiki.errors.full_messages.each do |msg| %li= msg - .main_box - .top_box_content + .ui-box.ui-box-show + .ui-box-head = f.label :title .input= f.text_field :title, class: 'span8' = f.hidden_field :slug - .middle_box_content + .ui-box-body .input %span.cgray Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. @@ -19,7 +19,7 @@ %code [Link Title](page-slug) \. - .bottom_box_content + .ui-box-bottom = f.label :content .input= f.text_area :content, class: 'span8 js-gfm-input' .actions diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 1414ed490c9..9e3f32f835d 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -11,7 +11,7 @@ class PostReceive # Ignore push from non-gitlab users user = if identifier.eql? Gitlab.config.gitolite.admin_key - email = project.commit(newrev).author.email rescue nil + email = project.repository.commit(newrev).author.email rescue nil User.find_by_email(email) if email elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) User.find_by_email(identifier) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 5546632cb7f..76dc6214088 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -92,6 +92,7 @@ backup: ## Gitolite settings gitolite: admin_uri: git@localhost:gitolite-admin + # repos_path must not be a symlink repos_path: /home/git/repositories/ hooks_path: /home/git/.gitolite/hooks/ admin_key: gitlab diff --git a/config/routes.rb b/config/routes.rb index 5e556dccc27..27188b3b89f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -158,7 +158,7 @@ Gitlab::Application.routes.draw do resources :deploy_keys resources :protected_branches, only: [:index, :create, :destroy] - resources :refs, only: [], path: "/" do + resources :refs, only: [] do collection do get "switch" end diff --git a/db/fixtures/development/002_project.rb b/db/fixtures/development/002_project.rb index d145cc6254f..e50ab5d9d52 100644 --- a/db/fixtures/development/002_project.rb +++ b/db/fixtures/development/002_project.rb @@ -7,20 +7,20 @@ Group.seed(:id, [ Project.seed(:id, [ # Global - { id: 1, name: "Underscore.js", path: "underscore", owner_id: 1 }, - { id: 2, name: "Diaspora", path: "diaspora", owner_id: 1 }, + { id: 1, name: "Underscore.js", path: "underscore", creator_id: 1 }, + { id: 2, name: "Diaspora", path: "diaspora", creator_id: 1 }, # Brightbox - { id: 3, namespace_id: 100, name: "Brightbox CLI", path: "brightbox-cli", owner_id: 1 }, - { id: 4, namespace_id: 100, name: "Puppet", path: "puppet", owner_id: 1 }, + { id: 3, namespace_id: 100, name: "Brightbox CLI", path: "brightbox-cli", creator_id: 1 }, + { id: 4, namespace_id: 100, name: "Puppet", path: "puppet", creator_id: 1 }, # KDE - { id: 5, namespace_id: 101, name: "kdebase", path: "kdebase", owner_id: 1}, - { id: 6, namespace_id: 101, name: "kdelibs", path: "kdelibs", owner_id: 1}, - { id: 7, namespace_id: 101, name: "amarok", path: "amarok", owner_id: 1}, + { id: 5, namespace_id: 101, name: "kdebase", path: "kdebase", creator_id: 1}, + { id: 6, namespace_id: 101, name: "kdelibs", path: "kdelibs", creator_id: 1}, + { id: 7, namespace_id: 101, name: "amarok", path: "amarok", creator_id: 1}, # GitLab - { id: 8, namespace_id: 99, name: "gitlabhq", path: "gitlabhq", owner_id: 1}, - { id: 9, namespace_id: 99, name: "gitlab-ci", path: "gitlab-ci", owner_id: 1}, - { id: 10, namespace_id: 99, name: "gitlab-recipes", path: "gitlab-recipes", owner_id: 1}, + { id: 8, namespace_id: 99, name: "gitlabhq", path: "gitlabhq", creator_id: 1}, + { id: 9, namespace_id: 99, name: "gitlab-ci", path: "gitlab-ci", creator_id: 1}, + { id: 10, namespace_id: 99, name: "gitlab-recipes", path: "gitlab-recipes", creator_id: 1}, ]) diff --git a/db/fixtures/development/009_source_code.rb b/db/fixtures/development/009_source_code.rb index d3fe69c6f55..a64b905ee89 100644 --- a/db/fixtures/development/009_source_code.rb +++ b/db/fixtures/development/009_source_code.rb @@ -7,7 +7,7 @@ projects = [ { path: 'brightbox/puppet.git', git: 'https://github.com/brightbox/puppet.git' }, { path: 'gitlab/gitlabhq.git', git: 'https://github.com/gitlabhq/gitlabhq.git' }, { path: 'gitlab/gitlab-ci.git', git: 'https://github.com/gitlabhq/gitlab-ci.git' }, - { path: 'gitlab/gitlab-recipres.git', git: 'https://github.com/gitlabhq/gitlab-recipes.git' }, + { path: 'gitlab/gitlab-recipes.git', git: 'https://github.com/gitlabhq/gitlab-recipes.git' }, ] projects.each do |project| diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index bbfeeb716fa..9b42afa7ca0 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -4,7 +4,7 @@ Creates a backup archive of the database and all repositories. This archive will The filename will be `[TIMESTAMP]_gitlab_backup.tar`. This timestamp can be used to restore an specific backup. ``` -bundle exec rake gitlab:backup:create +bundle exec rake gitlab:backup:create RAILS_ENV=production ``` Example output: @@ -40,7 +40,7 @@ Deleting old backups... [SKIPPING] ### Restore a previously created backup ``` -bundle exec rake gitlab:backup:restore +bundle exec rake gitlab:backup:restore RAILS_ENV=production ``` Options: diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md new file mode 100644 index 00000000000..ad9e5a613b0 --- /dev/null +++ b/doc/raketasks/cleanup.md @@ -0,0 +1,20 @@ +### Remove grabage from gitolite config and filesystem. Important! Data loss! + +Remove projects from gitolite config if they dont exist in GitLab database + +``` +bundle exec rake gitlab:cleanup:config RAILS_ENV=production +``` + +Remove namespaces(dirs) from /home/git/repositories if they dont exist in GitLab database + +``` +bundle exec rake gitlab:cleanup:dirs RAILS_ENV=production +``` + +Remove repositories (global only for now) from /home/git/repositories if they dont exist in GitLab database + +``` +bundle exec rake gitlab:cleanup:repos RAILS_ENV=production +``` + diff --git a/doc/raketasks/features.md b/doc/raketasks/features.md index 7a2a4b668bd..7f7daaf046c 100644 --- a/doc/raketasks/features.md +++ b/doc/raketasks/features.md @@ -13,7 +13,7 @@ Old path: `git@example.org:myrepo.git` New path: `git@example.org:username/myrepo.git` or `git@example.org:groupname/myrepo.git` ``` -bundle exec rake gitlab:enable_namespaces +bundle exec rake gitlab:enable_namespaces RAILS_ENV=production ``` @@ -22,7 +22,7 @@ bundle exec rake gitlab:enable_namespaces This command will enable the auto merge feature. After this you will be able to **merge a merge request** via GitLab and use the **online editor**. ``` -bundle exec rake gitlab:enable_automerge +bundle exec rake gitlab:enable_automerge RAILS_ENV=production ``` Example output: diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md index bb8e1ed29f7..758580b6832 100644 --- a/doc/raketasks/maintenance.md +++ b/doc/raketasks/maintenance.md @@ -7,7 +7,7 @@ Runs the following rake tasks: * gitlab:app:enable_automerge (see "Features") ``` -bundle exec rake gitlab:app:setup +bundle exec rake gitlab:app:setup RAILS_ENV=production ``` @@ -17,7 +17,7 @@ This command gathers information about your GitLab installation and the System it runs on. These may be useful when asking for help or reporting issues. ``` -bundle exec rake gitlab:env:info +bundle exec rake gitlab:env:info RAILS_ENV=production ``` Example output: @@ -68,7 +68,7 @@ It will check that each component was setup according to the installation guide You may also have a look at our [Trouble Shooting Guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide). ``` -bundle exec rake gitlab:check +bundle exec rake gitlab:check RAILS_ENV=production ``` Example output: @@ -145,7 +145,7 @@ This will create satellite repos for all your projects. If necessary, remove the `tmp/repo_satellites` directory and rerun the command below. ``` -bundle exec rake gitlab:satellites:create +bundle exec rake gitlab:satellites:create RAILS_ENV=production ``` @@ -154,7 +154,7 @@ bundle exec rake gitlab:satellites:create This will send all users ssh public keys to gitolite and grant them access (based on their permission) to their projects. ``` -bundle exec rake gitlab:gitolite:update_keys +bundle exec rake gitlab:gitolite:update_keys RAILS_ENV=production ``` @@ -163,7 +163,7 @@ bundle exec rake gitlab:gitolite:update_keys This makes sure that all projects are present in gitolite and can be accessed. ``` -bundle exec rake gitlab:gitolite:update_repos +bundle exec rake gitlab:gitolite:update_repos RAILS_ENV=production ``` ### Import bare repositories into GitLab project instance diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature index 972f8e36609..759843692b8 100644 --- a/features/dashboard/dashboard.feature +++ b/features/dashboard/dashboard.feature @@ -5,6 +5,7 @@ Feature: Dashboard And project "Shop" has push event And I visit dashboard page + @javascript Scenario: I should see projects list Then I should see "New Project" link Then I should see "Shop" project link @@ -26,11 +27,13 @@ Feature: Dashboard And I click "Create Merge Request" link Then I see prefilled new Merge Request page + @javascript Scenario: I should see User joined Project event Given user with name "John Doe" joined project "Shop" When I visit dashboard page Then I should see "John Doe joined project at Shop" event + @javascript Scenario: I should see User left Project event Given user with name "John Doe" joined project "Shop" And user with name "John Doe" left project "Shop" diff --git a/features/group/group.feature b/features/group/group.feature index 580f7e44002..a4a55a7fc26 100644 --- a/features/group/group.feature +++ b/features/group/group.feature @@ -3,6 +3,7 @@ Feature: Groups Given I sign in as a user And I have group with projects + @javascript Scenario: I should see group dashboard list When I visit group page Then I should see projects list diff --git a/features/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb index 4cd071657fe..cbca2daa701 100644 --- a/features/steps/admin/admin_groups.rb +++ b/features/steps/admin/admin_groups.rb @@ -16,7 +16,7 @@ class AdminGroups < Spinach::FeatureSteps @project = create(:project, group: @group) @event = create(:closed_issue_event, project: @project) - @project.add_access current_user, :admin + @project.team << [current_user, :master] end And 'Create gitlab user "John"' do diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb index 775a721f1a4..73e22673749 100644 --- a/features/steps/dashboard/dashboard.rb +++ b/features/steps/dashboard/dashboard.rb @@ -61,7 +61,7 @@ class Dashboard < Spinach::FeatureSteps And 'I own project "Shop"' do @project = create :project, name: 'Shop' - @project.add_access(@user, :admin) + @project.team << [@user, :master] end And 'I have group with projects' do @@ -69,7 +69,7 @@ class Dashboard < Spinach::FeatureSteps @project = create(:project, group: @group) @event = create(:closed_issue_event, project: @project) - @project.add_access current_user, :admin + @project.team << [current_user, :master] end And 'project "Shop" has push event' do diff --git a/features/steps/dashboard/dashboard_issues.rb b/features/steps/dashboard/dashboard_issues.rb index 5ace88023f0..fcf4296ad11 100644 --- a/features/steps/dashboard/dashboard_issues.rb +++ b/features/steps/dashboard/dashboard_issues.rb @@ -13,7 +13,7 @@ class DashboardIssues < Spinach::FeatureSteps And 'I have assigned issues' do project = create :project - project.add_access(@user, :read, :write) + project.team << [@user, :master] 2.times { create :issue, author: @user, assignee: @user, project: project } end diff --git a/features/steps/dashboard/dashboard_merge_requests.rb b/features/steps/dashboard/dashboard_merge_requests.rb index 485a4ccc113..7cfa8a13ff8 100644 --- a/features/steps/dashboard/dashboard_merge_requests.rb +++ b/features/steps/dashboard/dashboard_merge_requests.rb @@ -14,8 +14,8 @@ class DashboardMergeRequests < Spinach::FeatureSteps project1 = create :project project2 = create :project - project1.add_access(@user, :read, :write) - project2.add_access(@user, :read, :write) + project1.team << [@user, :master] + project2.team << [@user, :master] merge_request1 = create :merge_request, author: @user, project: project1 merge_request2 = create :merge_request, author: @user, project: project2 diff --git a/features/steps/dashboard/dashboard_search.rb b/features/steps/dashboard/dashboard_search.rb index a34c14d0c5f..9c8c879479d 100644 --- a/features/steps/dashboard/dashboard_search.rb +++ b/features/steps/dashboard/dashboard_search.rb @@ -1,6 +1,7 @@ class DashboardSearch < Spinach::FeatureSteps include SharedAuthentication include SharedPaths + include SharedProject Given 'I search for "Sho"' do fill_in "dashboard_search", with: "Sho" @@ -11,11 +12,6 @@ class DashboardSearch < Spinach::FeatureSteps page.should have_link "Shop" end - And 'I own project "Shop"' do - @project = create(:project, :name => "Shop") - @project.add_access(@user, :admin) - end - Given 'I search for "Contibuting"' do fill_in "dashboard_search", with: "Contibuting" click_button "Search" diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index e3364f09e34..04d8c874b3e 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -13,7 +13,7 @@ class Groups < Spinach::FeatureSteps @project = create(:project, group: @group) @event = create(:closed_issue_event, project: @project) - @project.add_access current_user, :admin + @project.team << [current_user, :master] end And 'I should see projects activity feed' do diff --git a/features/steps/project/create_project.rb b/features/steps/project/create_project.rb index b9b4534ed68..0d9727732c7 100644 --- a/features/steps/project/create_project.rb +++ b/features/steps/project/create_project.rb @@ -3,13 +3,13 @@ class CreateProject < Spinach::FeatureSteps include SharedPaths And 'fill project form with valid data' do - fill_in 'project_name', :with => 'NewProject' + fill_in 'project_name', with: 'Empty' click_button "Create project" end Then 'I should see project page' do current_path.should == project_path(Project.last) - page.should have_content "NewProject" + page.should have_content "Empty" end And 'I should see empty project instuctions' do diff --git a/features/steps/project/project_browse_commits.rb b/features/steps/project/project_browse_commits.rb index 2c03ce14fc1..3433c2ba5f6 100644 --- a/features/steps/project/project_browse_commits.rb +++ b/features/steps/project/project_browse_commits.rb @@ -4,7 +4,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps include SharedPaths Then 'I see project commits' do - commit = @project.commit + commit = @project.repository.commit page.should have_content(@project.name) page.should have_content(commit.message) page.should have_content(commit.id.to_s[0..5]) @@ -15,7 +15,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps end Then 'I see commits atom feed' do - commit = CommitDecorator.decorate(@project.commit) + commit = CommitDecorator.decorate(@project.repository.commit) page.response_headers['Content-Type'].should have_content("application/atom+xml") page.body.should have_selector("title", :text => "Recent commits to #{@project.name}") page.body.should have_selector("author email", :text => commit.author_email) @@ -48,7 +48,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps page.should have_selector('ul.breadcrumb span.divider', count: 3) page.should have_selector('ul.breadcrumb a', count: 4) - find('ul.breadcrumb li:first a')['href'].should match(/#{@project.path}\/commits\/master\z/) + find('ul.breadcrumb li:first a')['href'].should match(/#{@project.path_with_namespace}\/commits\/master\z/) find('ul.breadcrumb li:last a')['href'].should match(%r{master/app/models/project\.rb\z}) end diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index d153ad28d2b..0ec8245a59a 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -54,7 +54,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps fill_in "merge_request_title", :with => "Wiki Feature" select "master", :from => "merge_request_source_branch" select "stable", :from => "merge_request_target_branch" - click_button "Save" + click_button "Submit merge request" end Then 'I should see merge request "Wiki Feature"' do diff --git a/features/steps/project/project_milestones.rb b/features/steps/project/project_milestones.rb index 1c9ad6da651..1350938ee9a 100644 --- a/features/steps/project/project_milestones.rb +++ b/features/steps/project/project_milestones.rb @@ -50,12 +50,12 @@ class ProjectMilestones < Spinach::FeatureSteps end Then "I should see 3 issues" do - page.should have_selector('.milestone-issue-filter tbody tr', count: 4) - page.should have_selector('.milestone-issue-filter tbody tr.hide', count: 1) + page.should have_selector('.milestone-issue-filter .well-list li', count: 4) + page.should have_selector('.milestone-issue-filter .well-list li.hide', count: 1) end Then "I should see 4 issues" do - page.should have_selector('.milestone-issue-filter tbody tr', count: 4) - page.should_not have_selector('.milestone-issue-filter tbody tr.hide') + page.should have_selector('.milestone-issue-filter .well-list li', count: 4) + page.should_not have_selector('.milestone-issue-filter .well-list li.hide') end end diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index 6fde532f1a2..77149bfe2c3 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -6,7 +6,6 @@ class ProjectNetworkGraph < Spinach::FeatureSteps page.should have_content "Project Network Graph" within ".graph" do page.should have_content "master" - page.should have_content "scss_refactor..." end end diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb index 6bde0b64dfa..91b3ffeee9a 100644 --- a/features/steps/project/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -84,18 +84,18 @@ class ProjectTeamManagement < Spinach::FeatureSteps And '"Sam" is "Shop" developer' do user = User.find_by_name("Sam") project = Project.find_by_name("Shop") - project.add_access(user, :write) + project.team << [user, :developer] end Given 'I own project "Website"' do @project = create(:project, :name => "Website") - @project.add_access(@user, :admin) + @project.team << [@user, :master] end And '"Mike" is "Website" reporter' do user = User.find_by_name("Mike") project = Project.find_by_name("Website") - project.add_access(user, :read) + project.team << [user, :reporter] end And 'I click link "Import team from another project"' do diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index bd43ba6b3dc..22d1f335063 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -114,15 +114,15 @@ module SharedPaths end Given "I visit my project's files page" do - visit project_tree_path(@project, @project.root_ref) + visit project_tree_path(@project, root_ref) end Given "I visit my project's commits page" do - visit project_commits_path(@project, @project.root_ref, {limit: 5}) + visit project_commits_path(@project, root_ref, {limit: 5}) end Given "I visit my project's commits page for a specific path" do - visit project_commits_path(@project, @project.root_ref + "/app/models/project.rb", {limit: 5}) + visit project_commits_path(@project, root_ref + "/app/models/project.rb", {limit: 5}) end Given 'I visit my project\'s commits stats page' do @@ -174,7 +174,7 @@ module SharedPaths end Given 'I visit project commits page' do - visit project_commits_path(@project, @project.root_ref, {limit: 5}) + visit project_commits_path(@project, root_ref, {limit: 5}) end Given 'I visit project commits page for stable branch' do @@ -182,7 +182,7 @@ module SharedPaths end Given 'I visit project source page' do - visit project_tree_path(@project, @project.root_ref) + visit project_tree_path(@project, root_ref) end Given 'I visit blob file from repo' do @@ -240,4 +240,8 @@ module SharedPaths Given 'I visit project wiki page' do visit project_wiki_path(@project, :index) end + + def root_ref + @project.repository.root_ref + end end diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index dfc8ce9d99c..12dae15edf9 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -4,13 +4,13 @@ module SharedProject # Create a project without caring about what it's called And "I own a project" do @project = create(:project) - @project.add_access(@user, :admin) + @project.team << [@user, :master] end # Create a specific project called "Shop" And 'I own project "Shop"' do - @project = create(:project, :name => "Shop") - @project.add_access(@user, :admin) + @project = create(:project, name: "Shop") + @project.team << [@user, :master] end def current_project diff --git a/features/support/env.rb b/features/support/env.rb index 500de0f3e20..72531718e0c 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,3 +1,5 @@ +require 'simplecov' unless ENV['CI'] + ENV['RAILS_ENV'] = 'test' require './config/environment' diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 4875ac4c03e..4613db54578 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -13,7 +13,7 @@ module Gitlab # Example Request: # GET /projects/:id/notes get ":id/notes" do - @notes = user_project.common_notes + @notes = user_project.notes.common present paginate(@notes), with: Entities::Note end @@ -25,7 +25,7 @@ module Gitlab # Example Request: # GET /projects/:id/notes/:note_id get ":id/notes/:note_id" do - @note = user_project.common_notes.find(params[:note_id]) + @note = user_project.notes.common.find(params[:note_id]) present @note, with: Entities::Note end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index c71fd64838b..55c81f3158a 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -257,7 +257,7 @@ module Gitlab per_page = params[:per_page] || 20 ref = params[:ref_name] || user_project.try(:default_branch) || 'master' - commits = user_project.commits(ref, nil, per_page, page * per_page) + commits = user_project.repository.commits(ref, nil, per_page, page * per_page) present CommitDecorator.decorate(commits), with: Entities::RepoCommit end @@ -375,10 +375,10 @@ module Gitlab ref = params[:sha] - commit = user_project.commit ref + commit = user_project.repository.commit ref not_found! "Commit" unless commit - tree = Tree.new commit.tree, user_project, ref, params[:filepath] + tree = Tree.new commit.tree, ref, params[:filepath] not_found! "File" unless tree.try(:tree) content_type tree.mime_type diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index d1e569ce3e5..270a0aaa87a 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -52,7 +52,7 @@ module ExtractsPath # Remove project, actions and all other staff from path input.gsub!(/^\/#{Regexp.escape(@project.path_with_namespace)}/, "") - input.gsub!(/^\/(tree|commits|blame|blob)\//, "") # remove actions + input.gsub!(/^\/(tree|commits|blame|blob|refs)\//, "") # remove actions input.gsub!(/\?.*$/, "") # remove stamps suffix input.gsub!(/.atom$/, "") # remove rss feed input.gsub!(/\/edit$/, "") # remove edit route part @@ -68,7 +68,7 @@ module ExtractsPath id = input id += '/' unless id.ends_with?('/') - valid_refs = @project.ref_names + valid_refs = @project.repository.ref_names valid_refs.select! { |v| id.start_with?("#{v}/") } if valid_refs.length != 1 @@ -114,9 +114,9 @@ module ExtractsPath @id = File.join(@ref, @path) - @commit = CommitDecorator.decorate(@project.commit(@ref)) + @commit = CommitDecorator.decorate(@project.repository.commit(@ref)) - @tree = Tree.new(@commit.tree, @project, @ref, @path) + @tree = Tree.new(@commit.tree, @ref, @path) @tree = TreeDecorator.new(@tree) raise InvalidPathError if @tree.invalid? diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index a2bc4ca8d74..10e527eac73 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -82,7 +82,7 @@ module Gitlab end def destroy_project(project) - FileUtils.rm_rf(project.path_to_repo) + FileUtils.rm_rf(project.repository.path_to_repo) conf.rm_repo(project.path_with_namespace) end @@ -138,9 +138,9 @@ module Gitlab ::Gitolite::Config::Repo.new(repo_name) end - name_readers = project.repository_readers - name_writers = project.repository_writers - name_masters = project.repository_masters + name_readers = project.team.repository_readers + name_writers = project.team.repository_writers + name_masters = project.team.repository_masters pr_br = project.protected_branches.map(&:name).join("$ ") diff --git a/lib/gitlab/graph/commit.rb b/lib/gitlab/graph/commit.rb index 3d82c34432f..a6bf23a2381 100644 --- a/lib/gitlab/graph/commit.rb +++ b/lib/gitlab/graph/commit.rb @@ -22,14 +22,16 @@ module Gitlab h[:parents] = self.parents.collect do |p| [p.id,0,0] end - h[:author] = author.name + h[:author] = { + name: author.name, + email: author.email + } h[:time] = time h[:space] = space h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? h[:id] = sha h[:date] = date h[:message] = message - h[:login] = author.email h end diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 859184b6c3a..59249a229eb 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -170,7 +170,7 @@ module Gitlab end def reference_commit(identifier) - if @project.valid_repo? && commit = @project.commit(identifier) + if @project.valid_repo? && commit = @project.repository.commit(identifier) link_to(identifier, project_commit_path(@project, commit), html_options.merge(title: CommitDecorator.new(commit).link_title, class: "gfm gfm-commit #{html_options[:class]}")) end end diff --git a/lib/gitlab/project_mover.rb b/lib/gitlab/project_mover.rb index def6e90001b..207e585f572 100644 --- a/lib/gitlab/project_mover.rb +++ b/lib/gitlab/project_mover.rb @@ -16,7 +16,7 @@ module Gitlab def execute # Create new dir if missing new_dir_path = File.join(Gitlab.config.gitolite.repos_path, new_dir) - system("mkdir -m 770 #{new_dir_path}") unless File.exists?(new_dir_path) + FileUtils.mkdir( new_dir_path, mode: 0770 ) unless File.exists?(new_dir_path) old_path = File.join(Gitlab.config.gitolite.repos_path, old_dir, "#{project.path}.git") new_path = File.join(new_dir_path, "#{project.path}.git") @@ -25,17 +25,18 @@ module Gitlab raise ProjectMoveError.new("Destination #{new_path} already exists") end - if system("mv #{old_path} #{new_path}") + begin + FileUtils.mv( old_path, new_path ) log_info "Project #{project.name} was moved from #{old_path} to #{new_path}" true - else + rescue Exception => e message = "Project #{project.name} cannot be moved from #{old_path} to #{new_path}" - log_info "Error! #{message}" + log_info "Error! #{message} (#{e.message})" raise ProjectMoveError.new(message) end end - protected + protected def log_info message Gitlab::AppLogger.info message diff --git a/lib/gitlab/satellite/merge_action.rb b/lib/gitlab/satellite/merge_action.rb index 832db6621c4..556a1e2d52f 100644 --- a/lib/gitlab/satellite/merge_action.rb +++ b/lib/gitlab/satellite/merge_action.rb @@ -31,7 +31,7 @@ module Gitlab merge_repo.git.push({raise: true, timeout: true}, :origin, merge_request.target_branch) # remove source branch - if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch) + if merge_request.should_remove_source_branch && !project.repository.root_ref?(merge_request.source_branch) # will raise CommandFailed when push fails merge_repo.git.push({raise: true, timeout: true}, :origin, ":#{merge_request.source_branch}") end diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb index 784b146b98a..a0abf1918ca 100644 --- a/lib/gitlab/satellite/satellite.rb +++ b/lib/gitlab/satellite/satellite.rb @@ -1,4 +1,6 @@ module Gitlab + class SatelliteNotExistError < StandardError; end + module Satellite class Satellite PARKING_BRANCH = "__parking_branch" @@ -9,8 +11,12 @@ module Gitlab @project = project end + def raise_no_satellite + raise SatelliteNotExistError.new("Satellite doesn't exist") + end + def clear_and_update! - raise "Satellite doesn't exist" unless exists? + raise_no_satellite unless exists? delete_heads! clear_working_dir! @@ -35,7 +41,7 @@ module Gitlab # * Changes the current directory to the satellite's working dir # * Yields def lock - raise "Satellite doesn't exist" unless exists? + raise_no_satellite unless exists? File.open(lock_file, "w+") do |f| f.flock(File::LOCK_EX) @@ -55,7 +61,7 @@ module Gitlab end def repo - raise "Satellite doesn't exist" unless exists? + raise_no_satellite unless exists? @repo ||= Grit::Repo.new(path) end diff --git a/lib/static_model.rb b/lib/static_model.rb index 5b64be1f041..185921d8fbe 100644 --- a/lib/static_model.rb +++ b/lib/static_model.rb @@ -38,7 +38,7 @@ module StaticModel end def ==(other) - if other.is_a? StaticModel + if other.is_a? ::StaticModel id == other.id else super diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index 677ecf21bdc..ae2b1bb793f 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -134,7 +134,7 @@ namespace :gitlab do # Build a destination path for backup path_to_bundle = File.join(backup_path_repo, project.path_with_namespace + ".bundle") - if Kernel.system("cd #{project.path_to_repo} > /dev/null 2>&1 && git bundle create #{path_to_bundle} --all > /dev/null 2>&1") + if Kernel.system("cd #{project.repository.path_to_repo} > /dev/null 2>&1 && git bundle create #{path_to_bundle} --all > /dev/null 2>&1") puts "[DONE]".green else puts "[FAILED]".red @@ -158,7 +158,7 @@ namespace :gitlab do # Build a backup path path_to_bundle = File.join(backup_path_repo, project.path_with_namespace + ".bundle") - if Kernel.system("git clone --bare #{path_to_bundle} #{project.path_to_repo} > /dev/null 2>&1") + if Kernel.system("git clone --bare #{path_to_bundle} #{project.repository.path_to_repo} > /dev/null 2>&1") puts "[DONE]".green else puts "[FAILED]".red diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 72111f87567..252b508609a 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -98,7 +98,7 @@ namespace :gitlab do end # omniauth or ldap could have been deleted from the file - unless Gitlab.config.pre_40_config + unless Gitlab.config['git_host'] puts "no".green else puts "yes".red @@ -256,7 +256,7 @@ namespace :gitlab do start_checking "Environment" check_gitlab_in_git_group - check_issue_1056_shell_profile_error + check_issue_1059_shell_profile_error check_gitlab_git_config check_python2_exists check_python2_version @@ -313,7 +313,7 @@ namespace :gitlab do end # see https://github.com/gitlabhq/gitlabhq/issues/1059 - def check_issue_1056_shell_profile_error + def check_issue_1059_shell_profile_error gitolite_ssh_user = Gitlab.config.gitolite.ssh_user print "Has no \"-e\" in ~#{gitolite_ssh_user}/.profile ... " @@ -398,6 +398,7 @@ namespace :gitlab do check_dot_gitolite_user_and_group check_dot_gitolite_permissions check_repo_base_exists + check_repo_base_is_not_symlink check_repo_base_user_and_group check_repo_base_permissions check_can_clone_gitolite_admin @@ -543,7 +544,7 @@ namespace :gitlab do def check_gitolite_is_up_to_date print "Using recommended version ... " - if gitolite_version.try(:start_with?, "v3.04") + if gitolite_version.try(:start_with?, "v3.2") puts "yes".green else puts "no".red @@ -692,6 +693,26 @@ namespace :gitlab do end end + def check_repo_base_is_not_symlink + print "Repo base directory is a symlink? ... " + + repo_base_path = Gitlab.config.gitolite.repos_path + unless File.exists?(repo_base_path) + puts "can't check because of previous errors".magenta + return + end + + unless File.symlink?(repo_base_path) + puts "no".green + else + puts "yes".red + try_fixing_it( + "Make sure it's set to the real directory in config/gitlab.yml" + ) + fix_and_rerun + end + end + def check_repo_base_permissions print "Repo base access is drwsrws---? ... " @@ -759,7 +780,7 @@ namespace :gitlab do print "#{project.name_with_namespace.yellow} ... " correct_options = options.map do |name, value| - run("git --git-dir=\"#{project.path_to_repo}\" config --get #{name}").try(:chomp) == value + run("git --git-dir=\"#{project.repository.path_to_repo}\" config --get #{name}").try(:chomp) == value end if correct_options.all? @@ -798,7 +819,7 @@ namespace :gitlab do Project.find_each(batch_size: 100) do |project| print "#{project.name_with_namespace.yellow} ... " - project_hook_file = File.join(project.path_to_repo, "hooks", hook_file) + project_hook_file = File.join(project.repository.path_to_repo, "hooks", hook_file) unless File.exists?(project_hook_file) puts "missing".red diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake index 3fbedda7721..fd3e83e8338 100644 --- a/lib/tasks/gitlab/info.rake +++ b/lib/tasks/gitlab/info.rake @@ -12,7 +12,10 @@ namespace :gitlab do debian_version = File.read('/etc/debian_version') "Debian #{debian_version}" end - os_name.squish! + os_name ||= if File.readable?('/etc/SuSE-release') + File.read('/etc/SuSE-release') + end + os_name.try(:squish!) # check if there is an RVM environment rvm_version = run_and_match("rvm --version", /[\d\.]+/).try(:to_s) diff --git a/lib/tasks/travis.rake b/lib/tasks/travis.rake index e04bfbaf1c0..6b434830803 100644 --- a/lib/tasks/travis.rake +++ b/lib/tasks/travis.rake @@ -1,7 +1,5 @@ -task :travis do - ["rake spinach", "rake spec"].each do |cmd| - puts "Starting to run #{cmd}..." - system("export DISPLAY=:99.0 && bundle exec #{cmd}") - raise "#{cmd} failed!" unless $?.exitstatus == 0 - end -end +desc "Travis run tests" +task :travis => [ + :spinach, + :spec +] diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb index 5aef4c676ee..7bf13822829 100644 --- a/spec/controllers/commit_controller_spec.rb +++ b/spec/controllers/commit_controller_spec.rb @@ -3,12 +3,12 @@ require 'spec_helper' describe CommitController do let(:project) { create(:project) } let(:user) { create(:user) } - let(:commit) { project.last_commit_for("master") } + let(:commit) { project.repository.last_commit_for("master") } before do sign_in(user) - project.add_access(user, :read, :admin) + project.team << [user, :master] end describe "#show" do diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb index da33fd8a2b5..1d5d99df802 100644 --- a/spec/controllers/commits_controller_spec.rb +++ b/spec/controllers/commits_controller_spec.rb @@ -7,7 +7,7 @@ describe CommitsController do before do sign_in(user) - project.add_access(user, :read, :admin) + project.team << [user, :master] end describe "GET show" do diff --git a/spec/controllers/merge_requests_controller_spec.rb b/spec/controllers/merge_requests_controller_spec.rb index 7aebe06cf0c..8478bb3adff 100644 --- a/spec/controllers/merge_requests_controller_spec.rb +++ b/spec/controllers/merge_requests_controller_spec.rb @@ -7,7 +7,7 @@ describe MergeRequestsController do before do sign_in(user) - project.add_access(user, :read, :admin) + project.team << [user, :master] MergeRequestsController.any_instance.stub(validates_merge_request: true) end diff --git a/spec/controllers/tree_controller_spec.rb b/spec/controllers/tree_controller_spec.rb index b9295537d01..81c7656d07a 100644 --- a/spec/controllers/tree_controller_spec.rb +++ b/spec/controllers/tree_controller_spec.rb @@ -7,7 +7,7 @@ describe TreeController do before do sign_in(user) - project.add_access(user, :read, :admin) + project.team << [user, :master] project.stub(:branches).and_return(['master', 'foo/bar/baz']) project.stub(:tags).and_return(['v1.0.0', 'v2.0.0']) diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index b792e0c86f6..497a5f17846 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -4,7 +4,7 @@ describe GitlabMarkdownHelper do let!(:project) { create(:project) } let(:user) { create(:user, username: 'gfm') } - let(:commit) { CommitDecorator.decorate(project.commit) } + let(:commit) { CommitDecorator.decorate(project.repository.commit) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, project: project) } let(:snippet) { create(:snippet, project: project) } @@ -85,7 +85,7 @@ describe GitlabMarkdownHelper do let(:expected) { project_team_member_path(project, member) } before do - project.add_access(user, :admin) + project.team << [user, :master] end it "should link using a simple name" do @@ -314,7 +314,7 @@ describe GitlabMarkdownHelper do end it "should handle references in lists" do - project.add_access(user, :admin) + project.team << [user, :master] actual = "\n* dark: ##{issue.id}\n* light by @#{member.user.username}" diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index 8773d77f5a5..deb6499e008 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -7,7 +7,7 @@ describe ExtractsPath do before do @project = project - project.stub(:ref_names).and_return(['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0']) + project.stub(repository: stub(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0'])) project.stub(path_with_namespace: 'gitlab/gitlab-ci') end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index e760c501bd7..91301029e89 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Commit do - let(:commit) { create(:project).commit } + let(:commit) { create(:project).repository.commit } describe CommitDecorator do let(:decorator) { CommitDecorator.new(commit) } diff --git a/spec/models/gitlab_ci_service_spec.rb b/spec/models/gitlab_ci_service_spec.rb index ec43d46b347..b86588af1ac 100644 --- a/spec/models/gitlab_ci_service_spec.rb +++ b/spec/models/gitlab_ci_service_spec.rb @@ -35,10 +35,6 @@ describe GitlabCiService do ) end - describe :commit_badge_path do - it { @service.commit_badge_path("2ab7834c").should == "http://ci.gitlab.org/projects/2/status?sha=2ab7834c"} - end - describe :commit_status_path do it { @service.commit_status_path("2ab7834c").should == "http://ci.gitlab.org/projects/2/builds/2ab7834c/status.json?token=verySecret"} end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 5642ba7e29a..41f4ede5d89 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -40,7 +40,7 @@ describe MergeRequest do let!(:merge_request) { create(:merge_request) } before do - merge_request.stub(:commits) { [merge_request.project.commit] } + merge_request.stub(:commits) { [merge_request.project.repository.commit] } create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit') create(:note, noteable: merge_request) end diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 61aaf6455eb..62e83b31b7f 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -4,7 +4,6 @@ # # id :integer not null, primary key # note :text -# noteable_id :string(255) # noteable_type :string(255) # author_id :integer # created_at :datetime not null @@ -12,6 +11,8 @@ # project_id :integer # attachment :string(255) # line_code :string(255) +# commit_id :string(255) +# noteable_id :integer # require 'spec_helper' @@ -33,12 +34,6 @@ describe Note do it { should validate_presence_of(:project) } end - describe "Scopes" do - it "should have a today named scope that returns ..." do - Note.today.where_values.should == ["created_at >= '#{Date.today}'"] - end - end - describe "Voting score" do let(:project) { create(:project) } @@ -76,7 +71,7 @@ describe Note do end let(:project) { create(:project) } - let(:commit) { project.commit } + let(:commit) { project.repository.commit } describe "Commit notes" do before do diff --git a/spec/models/project_hooks_spec.rb b/spec/models/project_hooks_spec.rb index 77adfe06cff..60457e20c51 100644 --- a/spec/models/project_hooks_spec.rb +++ b/spec/models/project_hooks_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe Project, "Hooks" do let(:project) { create(:project) } + before do @key = create(:key, user: project.owner) @user = @key.user @@ -70,8 +71,9 @@ describe Project, "Hooks" do context "when gathering commit data" do before do - @oldrev, @newrev, @ref = project.fresh_commits(2).last.sha, project.fresh_commits(2).first.sha, 'refs/heads/master' - @commit = project.fresh_commits(2).first + @oldrev, @newrev, @ref = project.repository.fresh_commits(2).last.sha, + project.repository.fresh_commits(2).first.sha, 'refs/heads/master' + @commit = project.repository.fresh_commits(2).first # Fill nil/empty attributes project.description = "This is a description" diff --git a/spec/models/project_repository_spec.rb b/spec/models/project_repository_spec.rb deleted file mode 100644 index e1d01cbfeaf..00000000000 --- a/spec/models/project_repository_spec.rb +++ /dev/null @@ -1,159 +0,0 @@ -require 'spec_helper' - -describe Project, "Repository" do - let(:project) { create(:project) } - - describe "#empty_repo?" do - it "should return true if the repo doesn't exist" do - project.stub(repo_exists?: false, has_commits?: true) - project.should be_empty_repo - end - - it "should return true if the repo has commits" do - project.stub(repo_exists?: true, has_commits?: false) - project.should be_empty_repo - end - - it "should return false if the repo exists and has commits" do - project.stub(repo_exists?: true, has_commits?: true) - project.should_not be_empty_repo - end - end - - describe "#discover_default_branch" do - let(:master) { 'master' } - let(:stable) { 'stable' } - - it "returns 'master' when master exists" do - project.should_receive(:branch_names).at_least(:once).and_return([stable, master]) - project.discover_default_branch.should == 'master' - end - - it "returns non-master when master exists but default branch is set to something else" do - project.default_branch = 'stable' - project.should_receive(:branch_names).at_least(:once).and_return([stable, master]) - project.discover_default_branch.should == 'stable' - end - - it "returns a non-master branch when only one exists" do - project.should_receive(:branch_names).at_least(:once).and_return([stable]) - project.discover_default_branch.should == 'stable' - end - - it "returns nil when no branch exists" do - project.should_receive(:branch_names).at_least(:once).and_return([]) - project.discover_default_branch.should be_nil - end - end - - describe "#root_ref" do - it "returns default_branch when set" do - project.default_branch = 'stable' - project.root_ref.should == 'stable' - end - - it "returns 'master' when default_branch is nil" do - project.default_branch = nil - project.root_ref.should == 'master' - end - end - - describe "#root_ref?" do - it "returns true when branch is root_ref" do - project.default_branch = 'stable' - project.root_ref?('stable').should be_true - end - - it "returns false when branch is not root_ref" do - project.default_branch = nil - project.root_ref?('stable').should be_false - end - end - - describe :repo do - it "should return valid repo" do - project.repo.should be_kind_of(Grit::Repo) - end - - it "should return nil" do - lambda { Project.new(path: "invalid").repo }.should raise_error(Grit::NoSuchPathError) - end - - it "should return nil" do - lambda { Project.new.repo }.should raise_error(TypeError) - end - end - - describe :commit do - it "should return first head commit if without params" do - project.commit.id.should == project.repo.commits.first.id - end - - it "should return valid commit" do - project.commit(ValidCommit::ID).should be_valid_commit - end - - it "should return nil" do - project.commit("+123_4532530XYZ").should be_nil - end - end - - describe :tree do - before do - @commit = project.commit(ValidCommit::ID) - end - - it "should raise error w/o arguments" do - lambda { project.tree }.should raise_error - end - - it "should return root tree for commit" do - tree = project.tree(@commit) - tree.contents.size.should == ValidCommit::FILES_COUNT - tree.contents.map(&:name).should == ValidCommit::FILES - end - - it "should return root tree for commit with correct path" do - tree = project.tree(@commit, ValidCommit::C_FILE_PATH) - tree.contents.map(&:name).should == ValidCommit::C_FILES - end - - it "should return root tree for commit with incorrect path" do - project.tree(@commit, "invalid_path").should be_nil - end - end - - describe "fresh commits" do - let(:project) { create(:project) } - - it { project.fresh_commits(3).count.should == 3 } - it { project.fresh_commits.first.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" } - it { project.fresh_commits.last.id.should == "f403da73f5e62794a0447aca879360494b08f678" } - end - - describe "commits_between" do - let(:project) { create(:project) } - - subject do - commits = project.commits_between("3a4b4fb4cde7809f033822a171b9feae19d41fff", - "8470d70da67355c9c009e4401746b1d5410af2e3") - commits.map { |c| c.id } - end - - it { should have(3).elements } - it { should include("f0f14c8eaba69ebddd766498a9d0b0e79becd633") } - it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } - end - - describe :valid_repo? do - it "should be valid repo" do - project = create(:project) - project.valid_repo?.should be_true - end - - it "should be invalid repo" do - project = Project.new(name: "ok_name", path: "/INVALID_PATH/", path: "NEOK") - project.valid_repo?.should be_false - end - end -end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index ea1efbbec78..223b9d48c01 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -9,7 +9,7 @@ # created_at :datetime not null # updated_at :datetime not null # private_flag :boolean default(TRUE), not null -# owner_id :integer +# creator_id :integer # default_branch :string(255) # issues_enabled :boolean default(TRUE), not null # wall_enabled :boolean default(TRUE), not null @@ -75,57 +75,16 @@ describe Project do end describe "Respond to" do - it { should respond_to(:public?) } - it { should respond_to(:private?) } it { should respond_to(:url_to_repo) } - it { should respond_to(:path_to_repo) } - it { should respond_to(:valid_repo?) } it { should respond_to(:repo_exists?) } - - # Repository Role - it { should respond_to(:tree) } - it { should respond_to(:root_ref) } - it { should respond_to(:repo) } - it { should respond_to(:tags) } - it { should respond_to(:commit) } - it { should respond_to(:commits) } - it { should respond_to(:commits_between) } - it { should respond_to(:commits_with_refs) } - it { should respond_to(:commits_since) } - it { should respond_to(:commits_between) } it { should respond_to(:satellite) } it { should respond_to(:update_repository) } it { should respond_to(:destroy_repository) } - it { should respond_to(:archive_repo) } - - # Authority Role - it { should respond_to(:add_access) } - it { should respond_to(:reset_access) } - it { should respond_to(:repository_writers) } - it { should respond_to(:repository_masters) } - it { should respond_to(:repository_readers) } - it { should respond_to(:allow_read_for?) } - it { should respond_to(:guest_access_for?) } - it { should respond_to(:report_access_for?) } - it { should respond_to(:dev_access_for?) } - it { should respond_to(:master_access_for?) } - - # Team Role - it { should respond_to(:team_member_by_name_or_email) } - it { should respond_to(:team_member_by_id) } - it { should respond_to(:add_user_to_team) } - it { should respond_to(:add_users_to_team) } - it { should respond_to(:add_user_id_to_team) } - it { should respond_to(:add_users_ids_to_team) } - - # Project Push Role it { should respond_to(:observe_push) } it { should respond_to(:update_merge_requests) } it { should respond_to(:execute_hooks) } it { should respond_to(:post_receive_data) } it { should respond_to(:trigger_post_receive) } - - # Namespaced Project Role it { should respond_to(:transfer) } it { should respond_to(:name_with_namespace) } it { should respond_to(:namespace_owner) } @@ -138,11 +97,6 @@ describe Project do project.url_to_repo.should == Gitlab.config.gitolite.ssh_path_prefix + "somewhere.git" end - it "should return path to repo" do - project = Project.new(path: "somewhere") - project.path_to_repo.should == Rails.root.join("tmp", "repositories", "somewhere") - end - it "returns the full web URL for this repo" do project = Project.new(path: "somewhere") project.web_url.should == "#{Gitlab.config.gitlab.url}/somewhere" @@ -269,4 +223,16 @@ describe Project do it { @project.to_param.should == "gitlab-ci" } end end + + describe :repository do + let(:project) { create(:project) } + + it "should return valid repo" do + project.repository.should be_kind_of(Repository) + end + + it "should return nil" do + Project.new(path: "empty").repository.should be_nil + end + end end diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb index 7340ce50ced..c4d2e2f49f5 100644 --- a/spec/models/protected_branch_spec.rb +++ b/spec/models/protected_branch_spec.rb @@ -39,13 +39,4 @@ describe ProtectedBranch do branch.destroy end end - - describe '#commit' do - let(:branch) { create(:protected_branch) } - - it 'commits itself to its project' do - branch.project.should_receive(:commit).with(branch.name) - branch.commit - end - end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb new file mode 100644 index 00000000000..71f9b964e70 --- /dev/null +++ b/spec/models/repository_spec.rb @@ -0,0 +1,105 @@ +require "spec_helper" + +describe Repository do + let(:project) { create(:project) } + let(:repository) { project.repository } + + describe "Respond to" do + subject { repository } + + it { should respond_to(:repo) } + it { should respond_to(:tree) } + it { should respond_to(:root_ref) } + it { should respond_to(:tags) } + it { should respond_to(:commit) } + it { should respond_to(:commits) } + it { should respond_to(:commits_between) } + it { should respond_to(:commits_with_refs) } + it { should respond_to(:commits_since) } + it { should respond_to(:commits_between) } + end + + + describe "#discover_default_branch" do + let(:master) { 'master' } + let(:stable) { 'stable' } + + it "returns 'master' when master exists" do + repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) + repository.discover_default_branch.should == 'master' + end + + it "returns non-master when master exists but default branch is set to something else" do + repository.root_ref = 'stable' + repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) + repository.discover_default_branch.should == 'stable' + end + + it "returns a non-master branch when only one exists" do + repository.should_receive(:branch_names).at_least(:once).and_return([stable]) + repository.discover_default_branch.should == 'stable' + end + + it "returns nil when no branch exists" do + repository.should_receive(:branch_names).at_least(:once).and_return([]) + repository.discover_default_branch.should be_nil + end + end + + describe :commit do + it "should return first head commit if without params" do + repository.commit.id.should == repository.repo.commits.first.id + end + + it "should return valid commit" do + repository.commit(ValidCommit::ID).should be_valid_commit + end + + it "should return nil" do + repository.commit("+123_4532530XYZ").should be_nil + end + end + + describe :tree do + before do + @commit = repository.commit(ValidCommit::ID) + end + + it "should raise error w/o arguments" do + lambda { repository.tree }.should raise_error + end + + it "should return root tree for commit" do + tree = repository.tree(@commit) + tree.contents.size.should == ValidCommit::FILES_COUNT + tree.contents.map(&:name).should == ValidCommit::FILES + end + + it "should return root tree for commit with correct path" do + tree = repository.tree(@commit, ValidCommit::C_FILE_PATH) + tree.contents.map(&:name).should == ValidCommit::C_FILES + end + + it "should return root tree for commit with incorrect path" do + repository.tree(@commit, "invalid_path").should be_nil + end + end + + describe "fresh commits" do + it { repository.fresh_commits(3).count.should == 3 } + it { repository.fresh_commits.first.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" } + it { repository.fresh_commits.last.id.should == "f403da73f5e62794a0447aca879360494b08f678" } + end + + describe "commits_between" do + subject do + commits = repository.commits_between("3a4b4fb4cde7809f033822a171b9feae19d41fff", + "8470d70da67355c9c009e4401746b1d5410af2e3") + commits.map { |c| c.id } + end + + it { should have(3).elements } + it { should include("f0f14c8eaba69ebddd766498a9d0b0e79becd633") } + it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } + end +end diff --git a/spec/models/system_hook_spec.rb b/spec/models/system_hook_spec.rb index 7ae483a4003..cc358a2ed3b 100644 --- a/spec/models/system_hook_spec.rb +++ b/spec/models/system_hook_spec.rb @@ -56,7 +56,7 @@ describe SystemHook do user = create(:user) project = create(:project) with_resque do - project.add_access(user, :admin) + project.team << [user, :master] end WebMock.should have_requested(:post, @system_hook.url).with(body: /user_add_to_team/).once end @@ -64,7 +64,7 @@ describe SystemHook do it "project_destroy hook" do user = create(:user) project = create(:project) - project.add_access(user, :admin) + project.team << [user, :master] with_resque do project.users_projects.clear end diff --git a/spec/models/team_spec.rb b/spec/models/team_spec.rb new file mode 100644 index 00000000000..65ffe13b490 --- /dev/null +++ b/spec/models/team_spec.rb @@ -0,0 +1,18 @@ +require "spec_helper" + +describe Team do + let(:team) { create(:project).team } + + describe "Respond to" do + subject { team } + + it { should respond_to(:developers) } + it { should respond_to(:masters) } + it { should respond_to(:reporters) } + it { should respond_to(:guests) } + it { should respond_to(:repository_writers) } + it { should respond_to(:repository_masters) } + it { should respond_to(:repository_readers) } + end +end + diff --git a/spec/models/users_project_spec.rb b/spec/models/users_project_spec.rb index f85e21ff3f1..e8f5b647ce0 100644 --- a/spec/models/users_project_spec.rb +++ b/spec/models/users_project_spec.rb @@ -48,10 +48,10 @@ describe UsersProject do @user_1 = create :user @user_2 = create :user - @project_1.add_access @user_1, :write - @project_2.add_access @user_2, :read + @project_1.team << [ @user_1, :developer ] + @project_2.team << [ @user_2, :reporter ] - @status = UsersProject.import_team(@project_1, @project_2) + @status = @project_2.team.import(@project_1) end it { @status.should be_true } @@ -101,8 +101,8 @@ describe UsersProject do @user_1 = create :user @user_2 = create :user - @project_1.add_access @user_1, :write - @project_2.add_access @user_2, :read + @project_1.team << [ @user_1, :developer] + @project_2.team << [ @user_2, :reporter] UsersProject.truncate_teams([@project_1.id, @project_2.id]) end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 8f4e51f5a44..781ebab026b 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::API do let(:user) { create(:user) } let!(:project) { create(:project, namespace: user.namespace ) } let!(:issue) { create(:issue, author: user, assignee: user, project: project) } - before { project.add_access(user, :read) } + before { project.team << [user, :reporter] } describe "GET /issues" do context "when unauthenticated" do diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index f7b067070e0..5da54154a81 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::API do let(:user) { create(:user ) } let!(:project) { create(:project, namespace: user.namespace ) } let!(:merge_request) { create(:merge_request, author: user, assignee: user, project: project, title: "Test") } - before { project.add_access(user, :read) } + before { project.team << [user, :reporters] } describe "GET /projects/:id/merge_requests" do context "when unauthenticated" do diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index f7df90d0fdd..80696671462 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::API do let!(:project) { create(:project, namespace: user.namespace ) } let!(:milestone) { create(:milestone, project: project) } - before { project.add_access(user, :read) } + before { project.team << [user, :developer] } describe "GET /projects/:id/milestones" do it "should return project milestones" do diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index e783ccf73a5..ae4fc111f63 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::API do let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) } let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) } let!(:wall_note) { create(:note, project: project, author: user) } - before { project.add_access(user, :read) } + before { project.team << [user, :reporter] } describe "GET /projects/:id/notes" do context "when unauthenticated" do diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index e829c95e967..c2244210bcf 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -11,7 +11,7 @@ describe Gitlab::API do let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } - before { project.add_access(user, :read) } + before { project.team << [user, :reporter] } describe "GET /projects" do context "when unauthenticated" do @@ -226,14 +226,14 @@ describe Gitlab::API do describe "GET /projects/:id/repository/commits" do context "authorized user" do - before { project.add_access(user2, :read) } + before { project.team << [user2, :reporter] } it "should return project commits" do get api("/projects/#{project.id}/repository/commits", user) response.status.should == 200 json_response.should be_an Array - json_response.first['id'].should == project.commit.id + json_response.first['id'].should == project.repository.commit.id end end diff --git a/spec/requests/atom/issues_spec.rb b/spec/requests/atom/issues_spec.rb index eeb355377c4..0488c1f2266 100644 --- a/spec/requests/atom/issues_spec.rb +++ b/spec/requests/atom/issues_spec.rb @@ -6,7 +6,7 @@ describe "Issues Feed" do let!(:project) { create(:project, namespace: user.namespace) } let!(:issue) { create(:issue, author: user, project: project) } - before { project.add_access(user, :read, :write) } + before { project.team << [user, :developer] } context "when authenticated" do it "should render atom feed" do diff --git a/spec/requests/gitlab_flavored_markdown_spec.rb b/spec/requests/gitlab_flavored_markdown_spec.rb index 7f61c6aaa73..78b8c0c513f 100644 --- a/spec/requests/gitlab_flavored_markdown_spec.rb +++ b/spec/requests/gitlab_flavored_markdown_spec.rb @@ -6,7 +6,7 @@ describe "Gitlab Flavored Markdown" do let(:merge_request) { create(:merge_request, project: project) } let(:fred) do u = create(:user, name: "fred") - project.add_access(u, :admin) + project.team << [u, :master] u end @@ -33,11 +33,11 @@ describe "Gitlab Flavored Markdown" do project.repo.gc_auto end - let(:commit) { project.commits(@branch_name).first } + let(:commit) { project.repository.commits(@branch_name).first } before do login_as :user - project.add_access(@user, :read, :write) + project.team << [@user, :developer] end describe "for commits" do diff --git a/spec/requests/issues_spec.rb b/spec/requests/issues_spec.rb index 0814108523b..2e94ffd0020 100644 --- a/spec/requests/issues_spec.rb +++ b/spec/requests/issues_spec.rb @@ -7,8 +7,7 @@ describe "Issues" do login_as :user user2 = create(:user) - project.add_access(@user, :read, :write) - project.add_access(user2, :read, :write) + project.team << [[@user, user2], :developer] end describe "Edit issue" do diff --git a/spec/requests/projects_deploy_keys_spec.rb b/spec/requests/projects_deploy_keys_spec.rb index 35323f556f9..25b1da9ebd8 100644 --- a/spec/requests/projects_deploy_keys_spec.rb +++ b/spec/requests/projects_deploy_keys_spec.rb @@ -5,7 +5,7 @@ describe "Projects", "DeployKeys" do before do login_as :user - project.add_access(@user, :read, :write, :admin) + project.team << [@user, :master] end describe "GET /keys" do diff --git a/spec/requests/projects_spec.rb b/spec/requests/projects_spec.rb index ea87e35ed94..8f613b458c0 100644 --- a/spec/requests/projects_spec.rb +++ b/spec/requests/projects_spec.rb @@ -6,7 +6,7 @@ describe "Projects" do describe "GET /projects/show" do before do @project = create(:project, namespace: @user.namespace) - @project.add_access(@user, :read) + @project.team << [@user, :reporter] visit project_path(@project) end @@ -19,7 +19,7 @@ describe "Projects" do describe "GET /projects/:id/edit" do before do @project = create(:project) - @project.add_access(@user, :admin, :read) + @project.team << [@user, :master] visit edit_project_path(@project) end @@ -38,7 +38,7 @@ describe "Projects" do describe "PUT /projects/:id" do before do @project = create(:project, namespace: @user.namespace) - @project.add_access(@user, :admin, :read) + @project.team << [@user, :master] visit edit_project_path(@project) @@ -59,7 +59,7 @@ describe "Projects" do describe "DELETE /projects/:id" do before do @project = create(:project, namespace: @user.namespace) - @project.add_access(@user, :read, :admin) + @project.team << [@user, :master] visit edit_project_path(@project) end diff --git a/spec/requests/search_spec.rb b/spec/requests/search_spec.rb index 17cc0d39946..e338f359f88 100644 --- a/spec/requests/search_spec.rb +++ b/spec/requests/search_spec.rb @@ -4,7 +4,7 @@ describe "Search" do before do login_as :user @project = create(:project) - @project.add_access(@user, :read) + @project.team << [@user, :reporter] visit search_path fill_in "search", with: @project.name[0..3] click_button "Search" diff --git a/spec/requests/security/project_access_spec.rb b/spec/requests/security/project_access_spec.rb index 060a276b740..a35175102ec 100644 --- a/spec/requests/security/project_access_spec.rb +++ b/spec/requests/security/project_access_spec.rb @@ -22,10 +22,10 @@ describe "Application access" do before do # full access - project.users_projects.create(user: master, project_access: UsersProject::MASTER) + project.team << [master, :master] # readonly - project.users_projects.create(user: reporter, project_access: UsersProject::REPORTER) + project.team << [reporter, :reporter] end describe "GET /project_code" do @@ -40,7 +40,7 @@ describe "Application access" do end describe "GET /project_code/tree/master" do - subject { project_tree_path(project, project.root_ref) } + subject { project_tree_path(project, project.repository.root_ref) } it { should be_allowed_for master } it { should be_allowed_for reporter } @@ -51,7 +51,7 @@ describe "Application access" do end describe "GET /project_code/commits/master" do - subject { project_commits_path(project, project.root_ref, limit: 1) } + subject { project_commits_path(project, project.repository.root_ref, limit: 1) } it { should be_allowed_for master } it { should be_allowed_for reporter } @@ -62,7 +62,7 @@ describe "Application access" do end describe "GET /project_code/commit/:sha" do - subject { project_commit_path(project, project.commit) } + subject { project_commit_path(project, project.repository.commit) } it { should be_allowed_for master } it { should be_allowed_for reporter } @@ -107,7 +107,7 @@ describe "Application access" do describe "GET /project_code/blob" do before do - commit = project.commit + commit = project.repository.commit path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob)}.first.name @blob_path = project_blob_path(project, File.join(commit.id, path)) end diff --git a/spec/requests/snippets_spec.rb b/spec/requests/snippets_spec.rb index b231b940a84..770e34dc07c 100644 --- a/spec/requests/snippets_spec.rb +++ b/spec/requests/snippets_spec.rb @@ -5,7 +5,7 @@ describe "Snippets" do before do login_as :user - project.add_access(@user, :read, :write) + project.team << [@user, :developer] end describe "GET /snippets" do @@ -26,7 +26,7 @@ describe "Snippets" do before do # admin access to remove snippet @user.users_projects.destroy_all - project.add_access(@user, :read, :write, :admin) + project.team << [@user, :master] visit edit_project_snippet_path(project, @snippet) end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 09e11588164..6171141648c 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -191,17 +191,17 @@ describe ProtectedBranchesController, "routing" do end end -# switch_project_refs GET /:project_id/switch(.:format) refs#switch -# logs_tree_project_ref GET /:project_id/:id/logs_tree(.:format) refs#logs_tree -# logs_file_project_ref GET /:project_id/:id/logs_tree/:path(.:format) refs#logs_tree +# switch_project_refs GET /:project_id/refs/switch(.:format) refs#switch +# logs_tree_project_ref GET /:project_id/refs/:id/logs_tree(.:format) refs#logs_tree +# logs_file_project_ref GET /:project_id/refs/:id/logs_tree/:path(.:format) refs#logs_tree describe RefsController, "routing" do it "to #switch" do - get("/gitlabhq/switch").should route_to('refs#switch', project_id: 'gitlabhq') + get("/gitlabhq/refs/switch").should route_to('refs#switch', project_id: 'gitlabhq') end it "to #logs_tree" do - get("/gitlabhq/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable') - get("/gitlabhq/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') + get("/gitlabhq/refs/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable') + get("/gitlabhq/refs/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a1331fa79db..edabcc33625 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,4 @@ -unless ENV['CI'] - require 'simplecov' - SimpleCov.start 'rails' -end +require 'simplecov' unless ENV['CI'] # This file is copied to spec/ when you run 'rails generate rspec:install' ENV["RAILS_ENV"] ||= 'test' diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index ad88dd77a4f..e6e194d70f5 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -1,15 +1,14 @@ +require "repository" +require "project" + # Stubs out all Git repository access done by models so that specs can run # against fake repositories without Grit complaining that they don't exist. class Project - def path_to_repo - if new_record? || path == 'newproject' - # There are a couple Project specs and features that expect the Project's - # path to be in the returned path, so let's patronize them. - Rails.root.join('tmp', 'repositories', path) + def repository + if path == "empty" || !path + nil else - # For everything else, just give it the path to one of our real seeded - # repos. - Rails.root.join('tmp', 'repositories', 'gitlabhq') + GitLabTestRepo.new(path_with_namespace) end end @@ -27,3 +26,9 @@ class Project end end end + +class GitLabTestRepo < Repository + def repo + @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) + end +end diff --git a/vendor/assets/javascripts/branch-graph.js b/vendor/assets/javascripts/branch-graph.js index 456c3ff6c1c..805423bc70d 100644 --- a/vendor/assets/javascripts/branch-graph.js +++ b/vendor/assets/javascripts/branch-graph.js @@ -85,7 +85,7 @@ if(cuday != this.days[mm][0]){ // Dates r.text(offsetX + mm * 20, 31, this.days[mm][0]).attr({ - font: "12px Monaco, Arial", + font: "12px Monaco, monospace", fill: "#DDD" }); cuday = this.days[mm][0]; @@ -93,7 +93,7 @@ if(cumonth != this.days[mm][1]){ // Months r.text(offsetX + mm * 20, 11, this.days[mm][1]).attr({ - font: "12px Monaco, Arial", + font: "12px Monaco, monospace", fill: "#EEE" }); cumonth = this.days[mm][1]; @@ -103,29 +103,16 @@ for (i = 0; i < this.commitCount; i++) { var x = offsetX + 20 * this.commits[i].time - , y = offsetY + 20 * this.commits[i].space; + , y = offsetY + 20 * this.commits[i].space + , c; + + // Draw dot r.circle(x, y, 3).attr({ fill: this.colors[this.commits[i].space], stroke: "none" }); - if (this.commits[i].refs != null && this.commits[i].refs != "") { - var longrefs = this.commits[i].refs - , shortrefs = this.commits[i].refs; - if (shortrefs.length > 15){ - shortrefs = shortrefs.substr(0,13) + "..."; - } - var t = r.text(x+5, y+8, shortrefs).attr({ - font: "12px Monaco, Arial", - fill: "#666", - title: longrefs, - cursor: "pointer", - rotation: "90" - }); - - var textbox = t.getBBox(); - t.translate(textbox.height/-4, textbox.width/2); - } - var c; + + // Draw lines for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) { c = this.preparedCommits[this.commits[i].parents[j][0]]; if (c) { @@ -155,6 +142,11 @@ } } } + + if (this.commits[i].refs) { + this.appendLabel(x, y, this.commits[i].refs); + } + this.appendAnchor(top, this.commits[i], x, y); } top.toFront(); @@ -208,7 +200,57 @@ }); }; - BranchGraph.prototype.appendAnchor = function(top, c, x, y) { + BranchGraph.prototype.appendLabel = function(x, y, refs){ + var r = this.raphael + , shortrefs = refs + , text, textbox, rect; + + if (shortrefs.length > 17){ + // Truncate if longer than 15 chars + shortrefs = shortrefs.substr(0,15) + "…"; + } + + text = r.text(x+5, y+8 + 10, shortrefs).attr({ + font: "10px Monaco, monospace", + fill: "#FFF", + title: refs + }); + + textbox = text.getBBox(); + text.transform([ + 't', textbox.height/-4, textbox.width/2 + 5, + 'r90' + ]); + + // Create rectangle based on the size of the textbox + rect = r.rect(x, y, textbox.width + 15, textbox.height + 5, 4).attr({ + "fill": "#000", + "fill-opacity": .7, + "stroke": "none" + }); + + triangle = r.path([ + 'M', x, y + 5, + 'L', x + 4, y + 15, + 'L', x - 4, y + 15, + 'Z' + ]).attr({ + "fill": "#000", + "fill-opacity": .7, + "stroke": "none" + }); + + // Rotate and reposition rectangle over text + rect.transform([ + 'r', 90, x, y, + 't', 15, -9 + ]); + + // Set text to front + text.toFront(); + }; + + BranchGraph.prototype.appendAnchor = function(top, commit, x, y) { var r = this.raphael , options = this.options , anchor; @@ -218,16 +260,13 @@ cursor: "pointer" }) .click(function(){ - window.location = options.commit_url.replace('%s', c.id); + window.location = options.commit_url.replace('%s', commit.id); }) .hover(function(){ - var text = r.text(100, 100, c.author + "\n \n" + c.id + "\n \n" + c.message).attr({ - fill: "#fff" - }); - this.popup = r.tooltip(x, y + 5, text, 0); - top.push(this.popup.insertBefore(this)); + this.tooltip = r.commitTooltip(x, y + 5, commit); + top.push(this.tooltip.insertBefore(this)); }, function(){ - this.popup && this.popup.remove() && delete this.popup; + this.tooltip && this.tooltip.remove() && delete this.tooltip; }); top.push(anchor); }; @@ -235,23 +274,81 @@ this.BranchGraph = BranchGraph; }(this); -Raphael.fn.tooltip = function (x, y, set, dir, size) { - dir = dir == null ? 2 : dir; - size = size || 5; - x = Math.round(x); - y = Math.round(y); - var mmax = Math.max - , bb = set.getBBox() - , w = Math.round(bb.width / 2) - , h = Math.round(bb.height / 2) - , dx = [0, w + size * 2, 0, -w - size * 2] - , dy = [-h * 2 - size * 3, -h - size, 0, -h - size] - , p = ["M", x - dx[dir], y - dy[dir], "l", -size, (dir == 2) * -size, -mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size, - "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size, - "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size, - "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size, - "l", -mmax(w - size, 0), 0, "z"].join(",") - , xy = [{x: x, y: y + size * 2 + h}, {x: x - size * 2 - w, y: y}, {x: x, y: y - size * 2 - h}, {x: x + size * 2 + w, y: y}][dir]; - set.translate(xy.x - w - bb.x, xy.y - h - bb.y); - return this.set(this.path(p).attr({fill: "#234", stroke: "none"}).insertBefore(set.node ? set : set[0]), set); +Raphael.fn.commitTooltip = function(x, y, commit){ + var nameText, idText, messageText + , boxWidth = 300 + , boxHeight = 200; + + nameText = this.text(x, y + 10, commit.author.name); + idText = this.text(x, y + 35, commit.id); + messageText = this.text(x, y + 50, commit.message); + + textSet = this.set(nameText, idText, messageText).attr({ + "text-anchor": "start", + "font": "12px Monaco, monospace" + }); + + nameText.attr({ + "font": "14px Arial", + "font-weight": "bold" + }); + + idText.attr({ + "fill": "#AAA" + }); + + textWrap(messageText, boxWidth - 50); + + var rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({ + "fill": "#FFF", + "stroke": "#000", + "stroke-linecap": "round", + "stroke-width": 2 + }); + var tooltip = this.set(rect, textSet); + + rect.attr({ + "height" : tooltip.getBBox().height + 10, + "width" : tooltip.getBBox().width + 10 + }); + + tooltip.transform([ + 't', 20, 20 + ]); + + return tooltip; }; + +function textWrap(t, width) { + var content = t.attr("text"); + var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + t.attr({ + "text" : abc + }); + var letterWidth = t.getBBox().width / abc.length; + + t.attr({ + "text" : content + }); + + var words = content.split(" "); + var x = 0, s = []; + for ( var i = 0; i < words.length; i++) { + + var l = words[i].length; + if (x + (l * letterWidth) > width) { + s.push("\n"); + x = 0; + } + x += l * letterWidth; + s.push(words[i] + " "); + } + t.attr({ + "text" : s.join("") + }); + var b = t.getBBox() + , h = Math.abs(b.y2) - Math.abs(b.y) + 1; + t.attr({ + "y": b.y + h + }); +}
\ No newline at end of file diff --git a/vendor/assets/javascripts/g.bar-min.js b/vendor/assets/javascripts/g.bar-min.js index 42f452af350..7620dabda74 100644 --- a/vendor/assets/javascripts/g.bar-min.js +++ b/vendor/assets/javascripts/g.bar-min.js @@ -3,5 +3,6 @@ * * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com) * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. + * From: https://github.com/jhurt/g.raphael/blob/master/g.bar.js */ -(function(){var f=Math.min,a=Math.max;function e(o,m,h,p,j,k,l,i){var s,n={round:"round",sharp:"sharp",soft:"soft",square:"square"};if((j&&!p)||(!j&&!h)){return l?"":i.path()}k=n[k]||"square";p=Math.round(p);h=Math.round(h);o=Math.round(o);m=Math.round(m);switch(k){case"round":if(!j){var g=~~(p/2);if(h<g){g=h;s=["M",o+0.5,m+0.5-~~(p/2),"l",0,0,"a",g,~~(p/2),0,0,1,0,p,"l",0,0,"z"]}else{s=["M",o+0.5,m+0.5-g,"l",h-g,0,"a",g,g,0,1,1,0,p,"l",g-h,0,"z"]}}else{g=~~(h/2);if(p<g){g=p;s=["M",o-~~(h/2),m,"l",0,0,"a",~~(h/2),g,0,0,1,h,0,"l",0,0,"z"]}else{s=["M",o-g,m,"l",0,g-p,"a",g,g,0,1,1,h,0,"l",0,p-g,"z"]}}break;case"sharp":if(!j){var q=~~(p/2);s=["M",o,m+q,"l",0,-p,a(h-q,0),0,f(q,h),q,-f(q,h),q+(q*2<p),"z"]}else{q=~~(h/2);s=["M",o+q,m,"l",-h,0,0,-a(p-q,0),q,-f(q,p),q,f(q,p),q,"z"]}break;case"square":if(!j){s=["M",o,m+~~(p/2),"l",0,-p,h,0,0,p,"z"]}else{s=["M",o+~~(h/2),m,"l",1-h,0,0,-p,h-1,0,"z"]}break;case"soft":if(!j){g=f(h,Math.round(p/5));s=["M",o+0.5,m+0.5-~~(p/2),"l",h-g,0,"a",g,g,0,0,1,g,g,"l",0,p-g*2,"a",g,g,0,0,1,-g,g,"l",g-h,0,"z"]}else{g=f(Math.round(h/5),p);s=["M",o-~~(h/2),m,"l",0,g-p,"a",g,g,0,0,1,g,-g,"l",h-2*g,0,"a",g,g,0,0,1,g,g,"l",0,p-g,"z"]}}if(l){return s.join(",")}else{return i.path(s)}}function d(l,J,H,g,m,V,D){D=D||{};var z=this,W=D.type||"square",u=parseFloat(D.gutter||"20%"),T=l.set(),E=l.set(),n=l.set(),B=l.set(),F=Math.max.apply(Math,V),U=[],I=0,M=D.colors||z.colors,A=V.length;if(Raphael.is(V[0],"array")){F=[];I=A;A=0;for(var R=V.length;R--;){E.push(l.set());F.push(Math.max.apply(Math,V[R]));A=Math.max(A,V[R].length)}if(D.stacked){for(var R=A;R--;){var r=0;for(var Q=V.length;Q--;){r+=+V[Q][R]||0}U.push(r)}}for(var R=V.length;R--;){if(V[R].length<A){for(var Q=A;Q--;){V[R].push(0)}}}F=Math.max.apply(Math,D.stacked?U:F)}F=(D.to)||F;var K=g/(A*(100+u)+u)*100,k=K*u/100,p=D.vgutter==null?20:D.vgutter,C=[],q=J+k,o=(m-2*p)/F;if(!D.stretch){k=Math.round(k);K=Math.floor(K)}!D.stacked&&(K/=I||1);for(var R=0;R<A;R++){C=[];for(var Q=0;Q<(I||1);Q++){var S=Math.round((I?V[Q][R]:V[R])*o),t=H+m-p-S,O=e(Math.round(q+K/2),t+S,K,S,true,W,null,l).attr({stroke:"none",fill:M[I?Q:R]});if(I){E[Q].push(O)}else{E.push(O)}O.y=t;O.x=Math.round(q+K/2);O.w=K;O.h=S;O.value=I?V[Q][R]:V[R];if(!D.stacked){q+=K}else{C.push(O)}}if(D.stacked){var P;B.push(P=l.rect(C[0].x-C[0].w/2,H,K,m).attr(z.shim));P.bars=l.set();var v=0;for(var L=C.length;L--;){C[L].toFront()}for(var L=0,w=C.length;L<w;L++){var O=C[L],G,S=(v+O.value)*o,N=e(O.x,H+m-p-!!v*0.5,K,S,true,W,1,l);P.bars.push(O);v&&O.attr({path:N});O.h=S;O.y=H+m-p-!!v*0.5-S;n.push(G=l.rect(O.x-O.w/2,O.y,K,O.value*o).attr(z.shim));G.bar=O;G.value=O.value;v+=O.value}q+=K}q+=k}B.toFront();q=J+k;if(!D.stacked){for(var R=0;R<A;R++){for(var Q=0;Q<(I||1);Q++){var G;n.push(G=l.rect(Math.round(q),H+p,K,m-p).attr(z.shim));G.bar=I?E[Q][R]:E[R];G.value=G.bar.value;q+=K}q+=k}}T.label=function(y,Z){y=y||[];this.labels=l.set();var aa,h=-Infinity;if(D.stacked){for(var x=0;x<A;x++){var X=0;for(var s=0;s<(I||1);s++){X+=I?V[s][x]:V[x];if(s==I-1){var ab=z.labelise(y[x],X,F);aa=l.text(E[s][x].x,H+m-p/2,ab).attr(z.txtattr).attr({fill:D.legendcolor||"#000","text-anchor":"start"}).insertBefore(n[x*(I||1)+s]);var Y=aa.getBBox();if(Y.x-7<h){aa.remove()}else{this.labels.push(aa);h=Y.x+Y.width}}}}}else{for(var x=0;x<A;x++){for(var s=0;s<(I||1);s++){var ab=z.labelise(I?y[s]&&y[s][x]:y[x],I?V[s][x]:V[x],F);aa=l.text(E[s][x].x-k/2,Z?H+m-p/2:E[s][x].y-10,ab).attr(z.txtattr).attr({fill:D.legendcolor||"#000","text-anchor":"start"}).insertBefore(n[x*(I||1)+s]);var Y=aa.getBBox();if(Y.x-7<h){aa.remove()}else{this.labels.push(aa);h=Y.x+Y.width}}}}return this};T.hover=function(i,h){B.hide();n.show();n.mouseover(i).mouseout(h);return this};T.hoverColumn=function(i,h){n.hide();B.show();h=h||function(){};B.mouseover(i).mouseout(h);return this};T.click=function(h){B.hide();n.show();n.click(h);return this};T.each=function(j){if(!Raphael.is(j,"function")){return this}for(var h=n.length;h--;){j.call(n[h])}return this};T.eachColumn=function(j){if(!Raphael.is(j,"function")){return this}for(var h=B.length;h--;){j.call(B[h])}return this};T.clickColumn=function(h){n.hide();B.show();B.click(h);return this};T.push(E,n,B);T.bars=E;T.covers=n;return T}function b(w,v,u,I,F,l,B){B=B||{};var h=this,n=B.type||"square",o=parseFloat(B.gutter||"20%"),D=w.set(),H=w.set(),q=w.set(),L=w.set(),T=Math.max.apply(Math,l),g=[],J=0,t=B.colors||h.colors,O=l.length;if(Raphael.is(l[0],"array")){T=[];J=O;O=0;for(var N=l.length;N--;){H.push(w.set());T.push(Math.max.apply(Math,l[N]));O=Math.max(O,l[N].length)}if(B.stacked){for(var N=O;N--;){var z=0;for(var M=l.length;M--;){z+=+l[M][N]||0}g.push(z)}}for(var N=l.length;N--;){if(l[N].length<O){for(var M=O;M--;){l[N].push(0)}}}T=Math.max.apply(Math,B.stacked?g:T)}T=(B.to)||T;var Q=Math.floor(F/(O*(100+o)+o)*100),r=Math.floor(Q*o/100),p=[],k=u+r,m=(I-1)/T;!B.stacked&&(Q/=J||1);for(var N=0;N<O;N++){p=[];for(var M=0;M<(J||1);M++){var S=J?l[M][N]:l[N],P=e(v,k+Q/2,Math.round(S*m),Q-1,false,n,null,w).attr({stroke:"none",fill:t[J?M:N]});if(J){H[M].push(P)}else{H.push(P)}P.x=v+Math.round(S*m);P.y=k+Q/2;P.w=Math.round(S*m);P.h=Q;P.value=+S;if(!B.stacked){k+=Q}else{p.push(P)}}if(B.stacked){var A=w.rect(v,p[0].y-p[0].h/2,I,Q).attr(h.shim);L.push(A);A.bars=w.set();var E=0;for(var C=p.length;C--;){p[C].toFront()}for(var C=0,K=p.length;C<K;C++){var P=p[C],R,S=Math.round((E+P.value)*m),G=e(v,P.y,S,Q-1,false,n,1,w);A.bars.push(P);E&&P.attr({path:G});P.w=S;P.x=v+S;q.push(R=w.rect(v+E*m,P.y-P.h/2,P.value*m,Q).attr(h.shim));R.bar=P;E+=P.value}k+=Q}k+=r}L.toFront();k=u+r;if(!B.stacked){for(var N=0;N<O;N++){for(var M=0;M<(J||1);M++){var R=w.rect(v,k,I,Q).attr(h.shim);q.push(R);R.bar=J?H[M][N]:H[N];R.value=R.bar.value;k+=Q}k+=r}}D.label=function(Z,W){Z=Z||[];this.labels=w.set();for(var V=0;V<O;V++){for(var U=0;U<J;U++){var y=h.labelise(J?Z[U]&&Z[U][V]:Z[V],J?l[U][V]:l[V],T),Y=W?H[U][V].x-Q/2+3:v+5,x=W?"end":"start",s;this.labels.push(s=w.text(Y,H[U][V].y,y).attr(h.txtattr).attr({fill:B.legendcolor||"#000","text-anchor":"start"}).insertBefore(q[0]));if(s.getBBox().x<v+5){s.attr({x:v+5,"text-anchor":"start"})}else{H[U][V].label=s}}}return this};D.hover=function(j,i){L.hide();q.show();i=i||function(){};q.mouseover(j).mouseout(i);return this};D.hoverColumn=function(j,i){q.hide();L.show();i=i||function(){};L.mouseover(j).mouseout(i);return this};D.each=function(s){if(!Raphael.is(s,"function")){return this}for(var j=q.length;j--;){s.call(q[j])}return this};D.eachColumn=function(s){if(!Raphael.is(s,"function")){return this}for(var j=L.length;j--;){s.call(L[j])}return this};D.click=function(i){L.hide();q.show();q.click(i);return this};D.clickColumn=function(i){q.hide();L.show();L.click(i);return this};D.push(H,q,L);D.bars=H;D.covers=q;return D}var c=function(){};c.prototype=Raphael.g;b.prototype=d.prototype=new c;Raphael.fn.hbarchart=function(h,l,j,g,i,k){return new b(this,h,l,j,g,i,k)};Raphael.fn.barchart=function(h,l,j,g,i,k){return new d(this,h,l,j,g,i,k)}})();
\ No newline at end of file +(function(){function c(c,d,e,f,g,h,i,j){var k,l={round:"round",sharp:"sharp",soft:"soft",square:"square"};if(g&&!f||!g&&!e)return i?"":j.path();switch(h=l[h]||"square",f=Math.round(f),e=Math.round(e),c=Math.round(c),d=Math.round(d),h){case"round":if(g)m=~~(e/2),m>f?(m=f,k=["M",c-~~(e/2),d,"l",0,0,"a",~~(e/2),m,0,0,1,e,0,"l",0,0,"z"]):k=["M",c-m,d,"l",0,m-f,"a",m,m,0,1,1,e,0,"l",0,f-m,"z"];else{var m=~~(f/2);m>e?(m=e,k=["M",c+.5,d+.5-~~(f/2),"l",0,0,"a",m,~~(f/2),0,0,1,0,f,"l",0,0,"z"]):k=["M",c+.5,d+.5-m,"l",e-m,0,"a",m,m,0,1,1,0,f,"l",m-e,0,"z"]}break;case"sharp":if(g)n=~~(e/2),k=["M",c+n,d,"l",-e,0,0,-b(f-n,0),n,-a(n,f),n,a(n,f),n,"z"];else{var n=~~(f/2);k=["M",c,d+n,"l",0,-f,b(e-n,0),0,a(n,e),n,-a(n,e),n+(f>2*n),"z"]}break;case"square":k=g?["M",c+~~(e/2),d,"l",1-e,0,0,-f,e-1,0,"z"]:["M",c,d+~~(f/2),"l",0,-f,e,0,0,f,"z"];break;case"soft":g?(m=a(Math.round(e/5),f),k=["M",c-~~(e/2),d,"l",0,m-f,"a",m,m,0,0,1,m,-m,"l",e-2*m,0,"a",m,m,0,0,1,m,m,"l",0,f-m,"z"]):(m=a(e,Math.round(f/5)),k=["M",c+.5,d+.5-~~(f/2),"l",e-m,0,"a",m,m,0,0,1,m,m,"l",0,f-2*m,"a",m,m,0,0,1,-m,m,"l",m-e,0,"z"])}return i?k.join(","):j.path(k)}function d(a,b,d,e,f,g,h){h=h||{};var i=this,j=h.type||"square",k=parseFloat(h.gutter||"20%"),l=a.set(),m=a.set(),n=a.set(),o=a.set(),p=Math.max.apply(Math,g),q=[],r=0,s=h.colors||i.colors,t=g.length;if(Raphael.is(g[0],"array")){p=[],r=t,t=0;for(var u=g.length;u--;)m.push(a.set()),p.push(Math.max.apply(Math,g[u])),t=Math.max(t,g[u].length);if(h.stacked)for(var u=t;u--;){for(var v=0,w=g.length;w--;)v+=+g[w][u]||0;q.push(v)}for(var u=g.length;u--;)if(t>g[u].length)for(var w=t;w--;)g[u].push(0);p=Math.max.apply(Math,h.stacked?q:p)}p=h.to||p;var x=100*(e/(t*(100+k)+k)),y=x*k/100,z=null==h.vgutter?20:h.vgutter,A=[],B=b+y,C=(f-2*z)/p;h.stretch||(y=Math.round(y),x=Math.floor(x)),!h.stacked&&(x/=r||1);for(var u=0;t>u;u++){A=[];for(var w=0;(r||1)>w;w++){var D=Math.round((r?g[w][u]:g[u])*C),E=d+f-z-D,F=c(Math.round(B+x/2),E+D,x,D,!0,j,null,a).attr({stroke:"none",fill:s[r?w:u]});r?m[w].push(F):m.push(F),F.y=E,F.x=Math.round(B+x/2),F.w=x,F.h=D,F.value=r?g[w][u]:g[u],h.stacked?A.push(F):B+=x}if(h.stacked){var G;o.push(G=a.rect(A[0].x-A[0].w/2,d,x,f).attr(i.shim)),G.bars=a.set();for(var H=0,I=A.length;I--;)A[I].toFront();for(var I=0,J=A.length;J>I;I++){var K,F=A[I],D=(H+F.value)*C,L=c(F.x,d+f-z-.5*!!H,x,D,!0,j,1,a);G.bars.push(F),H&&F.attr({path:L}),F.h=D,F.y=d+f-z-.5*!!H-D,n.push(K=a.rect(F.x-F.w/2,F.y,x,F.value*C).attr(i.shim)),K.bar=F,K.value=F.value,H+=F.value}B+=x}B+=y}if(o.toFront(),B=b+y,!h.stacked)for(var u=0;t>u;u++){for(var w=0;(r||1)>w;w++){var K;n.push(K=a.rect(Math.round(B),d+z,x,f-z).attr(i.shim)),K.bar=r?m[w][u]:m[u],K.value=K.bar.value,B+=x}B+=y}return l.label=function(b,c){b=b||[],this.labels=a.set();var e,j=-1/0;if(h.stacked){for(var k=0;t>k;k++)for(var l=0,o=0;(r||1)>o;o++)if(l+=r?g[o][k]:g[k],o==r-1){var q=i.labelise(b[k],l,p);e=a.text(m[o][k].x,d+f-z/2,q).attr(i.txtattr).attr({fill:h.legendcolor||"#000","text-anchor":"start"}).insertBefore(n[k*(r||1)+o]);var s=e.getBBox();j>s.x-7?e.remove():(this.labels.push(e),j=s.x+s.width)}}else for(var k=0;t>k;k++)for(var o=0;(r||1)>o;o++){var q=i.labelise(r?b[o]&&b[o][k]:b[k],r?g[o][k]:g[k],p);e=a.text(m[o][k].x-x/2,c?d+f-z/2:m[o][k].y-10,q).attr(i.txtattr).attr({fill:h.legendcolor||"#000","text-anchor":"start"}).insertBefore(n[k*(r||1)+o]);var s=e.getBBox();e.translate((x-s.width)/2,1),j>s.x-7?e.remove():(this.labels.push(e),j=s.x+s.width)}return this},l.hover=function(a,b){return o.hide(),n.show(),n.mouseover(a).mouseout(b),this},l.hoverColumn=function(a,b){return n.hide(),o.show(),b=b||function(){},o.mouseover(a).mouseout(b),this},l.click=function(a){return o.hide(),n.show(),n.click(a),this},l.each=function(a){if(!Raphael.is(a,"function"))return this;for(var b=n.length;b--;)a.call(n[b]);return this},l.eachColumn=function(a){if(!Raphael.is(a,"function"))return this;for(var b=o.length;b--;)a.call(o[b]);return this},l.clickColumn=function(a){return n.hide(),o.show(),o.click(a),this},l.push(m,n,o),l.bars=m,l.covers=n,l}function e(a,b,d,e,f,g,h){h=h||{};var i=this,j=h.type||"square",k=parseFloat(h.gutter||"20%"),l=a.set(),m=a.set(),n=a.set(),o=a.set(),p=Math.max.apply(Math,g),q=[],r=0,s=h.colors||i.colors,t=g.length;if(Raphael.is(g[0],"array")){p=[],r=t,t=0;for(var u=g.length;u--;)m.push(a.set()),p.push(Math.max.apply(Math,g[u])),t=Math.max(t,g[u].length);if(h.stacked)for(var u=t;u--;){for(var v=0,w=g.length;w--;)v+=+g[w][u]||0;q.push(v)}for(var u=g.length;u--;)if(t>g[u].length)for(var w=t;w--;)g[u].push(0);p=Math.max.apply(Math,h.stacked?q:p)}p=h.to||p;var x=Math.floor(100*(f/(t*(100+k)+k))),y=Math.floor(x*k/100),z=[],A=d+y,B=(e-1)/p;!h.stacked&&(x/=r||1);for(var u=0;t>u;u++){z=[];for(var w=0;(r||1)>w;w++){var C=r?g[w][u]:g[u],D=c(b,A+x/2,Math.round(C*B),x-1,!1,j,null,a).attr({stroke:"none",fill:s[r?w:u]});r?m[w].push(D):m.push(D),D.x=b+Math.round(C*B),D.y=A+x/2,D.w=Math.round(C*B),D.h=x,D.value=+C,h.stacked?z.push(D):A+=x}if(h.stacked){var E=a.rect(b,z[0].y-z[0].h/2,e,x).attr(i.shim);o.push(E),E.bars=a.set();for(var F=0,G=z.length;G--;)z[G].toFront();for(var G=0,H=z.length;H>G;G++){var I,D=z[G],C=Math.round((F+D.value)*B),J=c(b,D.y,C,x-1,!1,j,1,a);E.bars.push(D),F&&D.attr({path:J}),D.w=C,D.x=b+C,n.push(I=a.rect(b+F*B,D.y-D.h/2,D.value*B,x).attr(i.shim)),I.bar=D,F+=D.value}A+=x}A+=y}if(o.toFront(),A=d+y,!h.stacked)for(var u=0;t>u;u++){for(var w=0;(r||1)>w;w++){var I=a.rect(b,A,e,x).attr(i.shim);n.push(I),I.bar=r?m[w][u]:m[u],I.value=I.bar.value,A+=x}A+=y}return l.label=function(c,d){c=c||[],this.labels=a.set();for(var e=0;t>e;e++)for(var f=0;r>f;f++){var o,j=i.labelise(r?c[f]&&c[f][e]:c[e],r?g[f][e]:g[e],p),k=d?m[f][e].x-x/2+3:b+5;this.labels.push(o=a.text(k,m[f][e].y,j).attr(i.txtattr).attr({fill:h.legendcolor||"#000","text-anchor":"start"}).insertBefore(n[0])),b+5>o.getBBox().x?o.attr({x:b+5,"text-anchor":"start"}):m[f][e].label=o}return this},l.hover=function(a,b){return o.hide(),n.show(),b=b||function(){},n.mouseover(a).mouseout(b),this},l.hoverColumn=function(a,b){return n.hide(),o.show(),b=b||function(){},o.mouseover(a).mouseout(b),this},l.each=function(a){if(!Raphael.is(a,"function"))return this;for(var b=n.length;b--;)a.call(n[b]);return this},l.eachColumn=function(a){if(!Raphael.is(a,"function"))return this;for(var b=o.length;b--;)a.call(o[b]);return this},l.click=function(a){return o.hide(),n.show(),n.click(a),this},l.clickColumn=function(a){return n.hide(),o.show(),o.click(a),this},l.push(m,n,o),l.bars=m,l.covers=n,l}var a=Math.min,b=Math.max,f=function(){};f.prototype=Raphael.g,e.prototype=d.prototype=new f,Raphael.fn.hbarchart=function(a,b,c,d,f,g){return new e(this,a,b,c,d,f,g)},Raphael.fn.barchart=function(a,b,c,e,f,g){return new d(this,a,b,c,e,f,g)}})();
\ No newline at end of file diff --git a/vendor/assets/javascripts/g.raphael-min.js b/vendor/assets/javascripts/g.raphael-min.js index 932904f9acf..f8b381c623b 100644 --- a/vendor/assets/javascripts/g.raphael-min.js +++ b/vendor/assets/javascripts/g.raphael-min.js @@ -4,25 +4,4 @@ * Copyright (c) 2009-2012 Dmitry Baranovskiy (http://g.raphaeljs.com) * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. */ -Raphael.el.popup=function(d,a,b,f){var e=this.paper||this[0].paper,c,g,i,h;if(e){switch(this.type){case "text":case "circle":case "ellipse":g=!0;break;default:g=!1}d=null==d?"up":d;a=a||5;c=this.getBBox();b="number"==typeof b?b:g?c.x+c.width/2:c.x;f="number"==typeof f?f:g?c.y+c.height/2:c.y;i=Math.max(c.width/2-a,0);h=Math.max(c.height/2-a,0);this.translate(b-c.x-(g?c.width/2:0),f-c.y-(g?c.height/2:0));c=this.getBBox();b={up:["M",b,f,"l",-a,-a,-i,0,"a",a,a,0,0,1,-a,-a,"l",0,-c.height,"a",a,a,0,0, -1,a,-a,"l",2*a+2*i,0,"a",a,a,0,0,1,a,a,"l",0,c.height,"a",a,a,0,0,1,-a,a,"l",-i,0,"z"].join(),down:["M",b,f,"l",a,a,i,0,"a",a,a,0,0,1,a,a,"l",0,c.height,"a",a,a,0,0,1,-a,a,"l",-(2*a+2*i),0,"a",a,a,0,0,1,-a,-a,"l",0,-c.height,"a",a,a,0,0,1,a,-a,"l",i,0,"z"].join(),left:["M",b,f,"l",-a,a,0,h,"a",a,a,0,0,1,-a,a,"l",-c.width,0,"a",a,a,0,0,1,-a,-a,"l",0,-(2*a+2*h),"a",a,a,0,0,1,a,-a,"l",c.width,0,"a",a,a,0,0,1,a,a,"l",0,h,"z"].join(),right:["M",b,f,"l",a,-a,0,-h,"a",a,a,0,0,1,a,-a,"l",c.width,0,"a",a, -a,0,0,1,a,a,"l",0,2*a+2*h,"a",a,a,0,0,1,-a,a,"l",-c.width,0,"a",a,a,0,0,1,-a,-a,"l",0,-h,"z"].join()};a={up:{x:-!g*(c.width/2),y:2*-a-(g?c.height/2:c.height)},down:{x:-!g*(c.width/2),y:2*a+(g?c.height/2:c.height)},left:{x:2*-a-(g?c.width/2:c.width),y:-!g*(c.height/2)},right:{x:2*a+(g?c.width/2:c.width),y:-!g*(c.height/2)}}[d];this.translate(a.x,a.y);return e.path(b[d]).attr({fill:"#000",stroke:"none"}).insertBefore(this.node?this:this[0])}}; -Raphael.el.tag=function(d,a,b,f){var e=this.paper||this[0].paper;if(e){var e=e.path().attr({fill:"#000",stroke:"#000"}),c=this.getBBox(),g,i,h;switch(this.type){case "text":case "circle":case "ellipse":h=!0;break;default:h=!1}d=d||0;b="number"==typeof b?b:h?c.x+c.width/2:c.x;f="number"==typeof f?f:h?c.y+c.height/2:c.y;a=null==a?5:a;i=0.5522*a;c.height>=2*a?e.attr({path:["M",b,f+a,"a",a,a,0,1,1,0,2*-a,a,a,0,1,1,0,2*a,"m",0,2*-a-3,"a",a+3,a+3,0,1,0,0,2*(a+3),"L",b+a+3,f+c.height/2+3,"l",c.width+6,0, -0,-c.height-6,-c.width-6,0,"L",b,f-a-3].join()}):(g=Math.sqrt(Math.pow(a+3,2)-Math.pow(c.height/2+3,2)),e.attr({path:["M",b,f+a,"c",-i,0,-a,i-a,-a,-a,0,-i,a-i,-a,a,-a,i,0,a,a-i,a,a,0,i,i-a,a,-a,a,"M",b+g,f-c.height/2-3,"a",a+3,a+3,0,1,0,0,c.height+6,"l",a+3-g+c.width+6,0,0,-c.height-6,"L",b+g,f-c.height/2-3].join()}));d=360-d;e.rotate(d,b,f);this.attrs?(this.attr(this.attrs.x?"x":"cx",b+a+3+(!h?"text"==this.type?c.width:0:c.width/2)).attr("y",h?f:f-c.height/2),this.rotate(d,b,f),90<d&&270>d&&this.attr(this.attrs.x? -"x":"cx",b-a-3-(!h?c.width:c.width/2)).rotate(180,b,f)):90<d&&270>d?(this.translate(b-c.x-c.width-a-3,f-c.y-c.height/2),this.rotate(d-180,c.x+c.width+a+3,c.y+c.height/2)):(this.translate(b-c.x+a+3,f-c.y-c.height/2),this.rotate(d,c.x-a-3,c.y+c.height/2));return e.insertBefore(this.node?this:this[0])}}; -Raphael.el.drop=function(d,a,b){var f=this.getBBox(),e=this.paper||this[0].paper,c,g;if(e){switch(this.type){case "text":case "circle":case "ellipse":c=!0;break;default:c=!1}d=d||0;a="number"==typeof a?a:c?f.x+f.width/2:f.x;b="number"==typeof b?b:c?f.y+f.height/2:f.y;g=Math.max(f.width,f.height)+Math.min(f.width,f.height);e=e.path(["M",a,b,"l",g,0,"A",0.4*g,0.4*g,0,1,0,a+0.7*g,b-0.7*g,"z"]).attr({fill:"#000",stroke:"none"}).rotate(22.5-d,a,b);d=(d+90)*Math.PI/180;a=a+g*Math.sin(d)-(c?0:f.width/2); -d=b+g*Math.cos(d)-(c?0:f.height/2);this.attrs?this.attr(this.attrs.x?"x":"cx",a).attr(this.attrs.y?"y":"cy",d):this.translate(a-f.x,d-f.y);return e.insertBefore(this.node?this:this[0])}}; -Raphael.el.flag=function(d,a,b){var f=this.paper||this[0].paper;if(f){var f=f.path().attr({fill:"#000",stroke:"#000"}),e=this.getBBox(),c=e.height/2,g;switch(this.type){case "text":case "circle":case "ellipse":g=!0;break;default:g=!1}d=d||0;a="number"==typeof a?a:g?e.x+e.width/2:e.x;b="number"==typeof b?b:g?e.y+e.height/2:e.y;f.attr({path:["M",a,b,"l",c+3,-c-3,e.width+6,0,0,e.height+6,-e.width-6,0,"z"].join()});d=360-d;f.rotate(d,a,b);this.attrs?(this.attr(this.attrs.x?"x":"cx",a+c+3+(!g?"text"== -this.type?e.width:0:e.width/2)).attr("y",g?b:b-e.height/2),this.rotate(d,a,b),90<d&&270>d&&this.attr(this.attrs.x?"x":"cx",a-c-3-(!g?e.width:e.width/2)).rotate(180,a,b)):90<d&&270>d?(this.translate(a-e.x-e.width-c-3,b-e.y-e.height/2),this.rotate(d-180,e.x+e.width+c+3,e.y+e.height/2)):(this.translate(a-e.x+c+3,b-e.y-e.height/2),this.rotate(d,e.x-c-3,e.y+e.height/2));return f.insertBefore(this.node?this:this[0])}}; -Raphael.el.label=function(){var d=this.getBBox(),a=this.paper||this[0].paper,b=Math.min(20,d.width+10,d.height+10)/2;if(a)return a.rect(d.x-b/2,d.y-b/2,d.width+b,d.height+b,b).attr({stroke:"none",fill:"#000"}).insertBefore(this.node?this:this[0])}; -Raphael.el.blob=function(d,a,b){var f=this.getBBox(),e=Math.PI/180,c=this.paper||this[0].paper,g,i;if(c){switch(this.type){case "text":case "circle":case "ellipse":g=!0;break;default:g=!1}c=c.path().attr({fill:"#000",stroke:"none"});d=(+d+1?d:45)+90;i=Math.min(f.height,f.width);var a="number"==typeof a?a:g?f.x+f.width/2:f.x,b="number"==typeof b?b:g?f.y+f.height/2:f.y,h=Math.max(f.width+i,25*i/12),j=Math.max(f.height+i,25*i/12);g=a+i*Math.sin((d-22.5)*e);var o=b+i*Math.cos((d-22.5)*e),l=a+i*Math.sin((d+ -22.5)*e),d=b+i*Math.cos((d+22.5)*e),e=(l-g)/2;i=(d-o)/2;var h=h/2,j=j/2,n=-Math.sqrt(Math.abs(h*h*j*j-h*h*i*i-j*j*e*e)/(h*h*i*i+j*j*e*e));i=n*h*i/j+(l+g)/2;e=n*-j*e/h+(d+o)/2;c.attr({x:i,y:e,path:["M",a,b,"L",l,d,"A",h,j,0,1,1,g,o,"z"].join()});this.translate(i-f.x-f.width/2,e-f.y-f.height/2);return c.insertBefore(this.node?this:this[0])}};Raphael.fn.label=function(d,a,b){var f=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return f.push(b.label(),b)}; -Raphael.fn.popup=function(d,a,b,f,e){var c=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return c.push(b.popup(f,e),b)};Raphael.fn.tag=function(d,a,b,f,e){var c=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return c.push(b.tag(f,e),b)};Raphael.fn.flag=function(d,a,b,f){var e=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return e.push(b.flag(f),b)};Raphael.fn.drop=function(d,a,b,f){var e=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return e.push(b.drop(f),b)}; -Raphael.fn.blob=function(d,a,b,f){var e=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return e.push(b.blob(f),b)};Raphael.el.lighter=function(d){var d=d||2,a=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[a[0],a[1]];a[0]=Raphael.rgb2hsb(Raphael.getRGB(a[0]).hex);a[1]=Raphael.rgb2hsb(Raphael.getRGB(a[1]).hex);a[0].b=Math.min(a[0].b*d,1);a[0].s/=d;a[1].b=Math.min(a[1].b*d,1);a[1].s/=d;this.attr({fill:"hsb("+[a[0].h,a[0].s,a[0].b]+")",stroke:"hsb("+[a[1].h,a[1].s,a[1].b]+")"});return this}; -Raphael.el.darker=function(d){var d=d||2,a=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[a[0],a[1]];a[0]=Raphael.rgb2hsb(Raphael.getRGB(a[0]).hex);a[1]=Raphael.rgb2hsb(Raphael.getRGB(a[1]).hex);a[0].s=Math.min(a[0].s*d,1);a[0].b/=d;a[1].s=Math.min(a[1].s*d,1);a[1].b/=d;this.attr({fill:"hsb("+[a[0].h,a[0].s,a[0].b]+")",stroke:"hsb("+[a[1].h,a[1].s,a[1].b]+")"});return this};Raphael.el.resetBrightness=function(){this.fs&&(this.attr({fill:this.fs[0],stroke:this.fs[1]}),delete this.fs);return this}; -(function(){var d=["lighter","darker","resetBrightness"],a="popup tag flag label drop blob".split(" "),b;for(b in a)(function(a){Raphael.st[a]=function(){return Raphael.el[a].apply(this,arguments)}})(a[b]);for(b in d)(function(a){Raphael.st[a]=function(){for(var b=0;b<this.length;b++)this[b][a].apply(this[b],arguments);return this}})(d[b])})(); -Raphael.g={shim:{stroke:"none",fill:"#000","fill-opacity":0},txtattr:{font:"12px Arial, sans-serif",fill:"#fff"},colors:function(){for(var d=[0.6,0.2,0.05,0.1333,0.75,0],a=[],b=0;10>b;b++)b<d.length?a.push("hsb("+d[b]+",.75, .75)"):a.push("hsb("+d[b-d.length]+", 1, .5)");return a}(),snapEnds:function(d,a,b){function f(a){return 0.25>Math.abs(a-0.5)?~~a+0.5:Math.round(a)}var e=d,c=a;if(e==c)return{from:e,to:c,power:0};var e=(c-e)/b,g=c=~~e,b=0;if(c){for(;g;)b--,g=~~(e*Math.pow(10,b))/Math.pow(10,b); -b++}else{if(0==e||!isFinite(e))b=1;else for(;!c;)b=b||1,c=~~(e*Math.pow(10,b))/Math.pow(10,b),b++;b&&b--}c=f(a*Math.pow(10,b))/Math.pow(10,b);c<a&&(c=f((a+0.5)*Math.pow(10,b))/Math.pow(10,b));e=f((d-(0<b?0:0.5))*Math.pow(10,b))/Math.pow(10,b);return{from:e,to:c,power:b}},axis:function(d,a,b,f,e,c,g,i,h,j,o){var j=null==j?2:j,h=h||"t",c=c||10,o=arguments[arguments.length-1],l="|"==h||" "==h?["M",d+0.5,a,"l",0,0.001]:1==g||3==g?["M",d+0.5,a,"l",0,-b]:["M",d,a+0.5,"l",b,0],n=this.snapEnds(f,e,c),p=n.from, -t=n.to,m=n.power,u=0,v={font:"11px 'Fontin Sans', Fontin-Sans, sans-serif"},n=o.set(),t=(t-p)/c,k=p,r=0<m?m:0,s=b/c;if(1==+g||3==+g){m=a;for(p=(g-1?1:-1)*(j+3+!!(g-1));m>=a-b;)"-"!=h&&" "!=h&&(l=l.concat(["M",d-("+"==h||"|"==h?j:2*!(g-1)*j),m+0.5,"l",2*j+1,0])),n.push(o.text(d+p,m,i&&i[u++]||(Math.round(k)==k?k:+k.toFixed(r))).attr(v).attr({"text-anchor":g-1?"start":"end"})),k+=t,m-=s;Math.round(m+s-(a-b))&&("-"!=h&&" "!=h&&(l=l.concat(["M",d-("+"==h||"|"==h?j:2*!(g-1)*j),a-b+0.5,"l",2*j+1,0])),n.push(o.text(d+ -p,a-b,i&&i[u]||(Math.round(k)==k?k:+k.toFixed(r))).attr(v).attr({"text-anchor":g-1?"start":"end"})))}else{for(var k=p,r=(0<m)*m,p=(g?-1:1)*(j+9+!g),m=d,s=b/c,q=0,w=0;m<=d+b;)"-"!=h&&" "!=h&&(l=l.concat(["M",m+0.5,a-("+"==h?j:2*!!g*j),"l",0,2*j+1])),n.push(q=o.text(m,a+p,i&&i[u++]||(Math.round(k)==k?k:+k.toFixed(r))).attr(v)),q=q.getBBox(),w>=q.x-5?n.pop(n.length-1).remove():w=q.x+q.width,k+=t,m+=s;Math.round(m-s-d-b)&&("-"!=h&&" "!=h&&(l=l.concat(["M",d+b+0.5,a-("+"==h?j:2*!!g*j),"l",0,2*j+1])),n.push(o.text(d+ -b,a+p,i&&i[u]||(Math.round(k)==k?k:+k.toFixed(r))).attr(v)))}l=o.path(l);l.text=n;l.all=o.set([l,n]);l.remove=function(){this.text.remove();this.constructor.prototype.remove.call(this)};return l},labelise:function(d,a,b){return d?(d+"").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g,function(d,e,c){if(e)return(+a).toFixed(e.replace(/^#+\.?/g,"").length);if(c)return(100*a/b).toFixed(c.replace(/^%+\.?/g,"").length)+"%"}):(+a).toFixed(0)}};
\ No newline at end of file +Raphael.el.popup=function(a,b,c,d){var f,g,h,i,j,e=this.paper||this[0].paper;if(e){switch(this.type){case"text":case"circle":case"ellipse":h=!0;break;default:h=!1}a=null==a?"up":a,b=b||5,f=this.getBBox(),c="number"==typeof c?c:h?f.x+f.width/2:f.x,d="number"==typeof d?d:h?f.y+f.height/2:f.y,i=Math.max(f.width/2-b,0),j=Math.max(f.height/2-b,0),this.translate(c-f.x-(h?f.width/2:0),d-f.y-(h?f.height/2:0)),f=this.getBBox();var k={up:["M",c,d,"l",-b,-b,-i,0,"a",b,b,0,0,1,-b,-b,"l",0,-f.height,"a",b,b,0,0,1,b,-b,"l",2*b+2*i,0,"a",b,b,0,0,1,b,b,"l",0,f.height,"a",b,b,0,0,1,-b,b,"l",-i,0,"z"].join(","),down:["M",c,d,"l",b,b,i,0,"a",b,b,0,0,1,b,b,"l",0,f.height,"a",b,b,0,0,1,-b,b,"l",-(2*b+2*i),0,"a",b,b,0,0,1,-b,-b,"l",0,-f.height,"a",b,b,0,0,1,b,-b,"l",i,0,"z"].join(","),left:["M",c,d,"l",-b,b,0,j,"a",b,b,0,0,1,-b,b,"l",-f.width,0,"a",b,b,0,0,1,-b,-b,"l",0,-(2*b+2*j),"a",b,b,0,0,1,b,-b,"l",f.width,0,"a",b,b,0,0,1,b,b,"l",0,j,"z"].join(","),right:["M",c,d,"l",b,-b,0,-j,"a",b,b,0,0,1,b,-b,"l",f.width,0,"a",b,b,0,0,1,b,b,"l",0,2*b+2*j,"a",b,b,0,0,1,-b,b,"l",-f.width,0,"a",b,b,0,0,1,-b,-b,"l",0,-j,"z"].join(",")};return g={up:{x:-!h*(f.width/2),y:2*-b-(h?f.height/2:f.height)},down:{x:-!h*(f.width/2),y:2*b+(h?f.height/2:f.height)},left:{x:2*-b-(h?f.width/2:f.width),y:-!h*(f.height/2)},right:{x:2*b+(h?f.width/2:f.width),y:-!h*(f.height/2)}}[a],this.translate(g.x,g.y),e.path(k[a]).attr({fill:"#000",stroke:"none"}).insertBefore(this.node?this:this[0])}},Raphael.el.tag=function(a,b,c,d){var e=3,f=this.paper||this[0].paper;if(f){var i,j,k,g=f.path().attr({fill:"#000",stroke:"#000"}),h=this.getBBox();switch(this.type){case"text":case"circle":case"ellipse":k=!0;break;default:k=!1}return a=a||0,c="number"==typeof c?c:k?h.x+h.width/2:h.x,d="number"==typeof d?d:k?h.y+h.height/2:h.y,b=null==b?5:b,j=.5522*b,h.height>=2*b?g.attr({path:["M",c,d+b,"a",b,b,0,1,1,0,2*-b,b,b,0,1,1,0,2*b,"m",0,2*-b-e,"a",b+e,b+e,0,1,0,0,2*(b+e),"L",c+b+e,d+h.height/2+e,"l",h.width+2*e,0,0,-h.height-2*e,-h.width-2*e,0,"L",c,d-b-e].join(",")}):(i=Math.sqrt(Math.pow(b+e,2)-Math.pow(h.height/2+e,2)),g.attr({path:["M",c,d+b,"c",-j,0,-b,j-b,-b,-b,0,-j,b-j,-b,b,-b,j,0,b,b-j,b,b,0,j,j-b,b,-b,b,"M",c+i,d-h.height/2-e,"a",b+e,b+e,0,1,0,0,h.height+2*e,"l",b+e-i+h.width+2*e,0,0,-h.height-2*e,"L",c+i,d-h.height/2-e].join(",")})),a=360-a,g.rotate(a,c,d),this.attrs?(this.attr(this.attrs.x?"x":"cx",c+b+e+(k?h.width/2:"text"==this.type?h.width:0)).attr("y",k?d:d-h.height/2),this.rotate(a,c,d),a>90&&270>a&&this.attr(this.attrs.x?"x":"cx",c-b-e-(k?h.width/2:h.width)).rotate(180,c,d)):a>90&&270>a?(this.translate(c-h.x-h.width-b-e,d-h.y-h.height/2),this.rotate(a-180,h.x+h.width+b+e,h.y+h.height/2)):(this.translate(c-h.x+b+e,d-h.y-h.height/2),this.rotate(a,h.x-b-e,h.y+h.height/2)),g.insertBefore(this.node?this:this[0])}},Raphael.el.drop=function(a,b,c){var f,g,h,i,j,d=this.getBBox(),e=this.paper||this[0].paper;if(e){switch(this.type){case"text":case"circle":case"ellipse":f=!0;break;default:f=!1}return a=a||0,b="number"==typeof b?b:f?d.x+d.width/2:d.x,c="number"==typeof c?c:f?d.y+d.height/2:d.y,g=Math.max(d.width,d.height)+Math.min(d.width,d.height),h=e.path(["M",b,c,"l",g,0,"A",.4*g,.4*g,0,1,0,b+.7*g,c-.7*g,"z"]).attr({fill:"#000",stroke:"none"}).rotate(22.5-a,b,c),a=(a+90)*Math.PI/180,i=b+g*Math.sin(a)-(f?0:d.width/2),j=c+g*Math.cos(a)-(f?0:d.height/2),this.attrs?this.attr(this.attrs.x?"x":"cx",i).attr(this.attrs.y?"y":"cy",j):this.translate(i-d.x,j-d.y),h.insertBefore(this.node?this:this[0])}},Raphael.el.flag=function(a,b,c){var d=3,e=this.paper||this[0].paper;if(e){var i,f=e.path().attr({fill:"#000",stroke:"#000"}),g=this.getBBox(),h=g.height/2;switch(this.type){case"text":case"circle":case"ellipse":i=!0;break;default:i=!1}return a=a||0,b="number"==typeof b?b:i?g.x+g.width/2:g.x,c="number"==typeof c?c:i?g.y+g.height/2:g.y,f.attr({path:["M",b,c,"l",h+d,-h-d,g.width+2*d,0,0,g.height+2*d,-g.width-2*d,0,"z"].join(",")}),a=360-a,f.rotate(a,b,c),this.attrs?(this.attr(this.attrs.x?"x":"cx",b+h+d+(i?g.width/2:"text"==this.type?g.width:0)).attr("y",i?c:c-g.height/2),this.rotate(a,b,c),a>90&&270>a&&this.attr(this.attrs.x?"x":"cx",b-h-d-(i?g.width/2:g.width)).rotate(180,b,c)):a>90&&270>a?(this.translate(b-g.x-g.width-h-d,c-g.y-g.height/2),this.rotate(a-180,g.x+g.width+h+d,g.y+g.height/2)):(this.translate(b-g.x+h+d,c-g.y-g.height/2),this.rotate(a,g.x-h-d,g.y+g.height/2)),f.insertBefore(this.node?this:this[0])}},Raphael.el.label=function(){var a=this.getBBox(),b=this.paper||this[0].paper,c=Math.min(20,a.width+10,a.height+10)/2;if(b)return b.rect(a.x-c/2,a.y-c/2,a.width+c,a.height+c,c).attr({stroke:"none",fill:"#000"}).insertBefore(this.node?this:this[0])},Raphael.el.blob=function(a,b,c){var g,h,i,d=this.getBBox(),e=Math.PI/180,f=this.paper||this[0].paper;if(f){switch(this.type){case"text":case"circle":case"ellipse":h=!0;break;default:h=!1}g=f.path().attr({fill:"#000",stroke:"none"}),a=(+a+1?a:45)+90,i=Math.min(d.height,d.width),b="number"==typeof b?b:h?d.x+d.width/2:d.x,c="number"==typeof c?c:h?d.y+d.height/2:d.y;var j=Math.max(d.width+i,25*i/12),k=Math.max(d.height+i,25*i/12),l=b+i*Math.sin((a-22.5)*e),m=c+i*Math.cos((a-22.5)*e),n=b+i*Math.sin((a+22.5)*e),o=c+i*Math.cos((a+22.5)*e),p=(n-l)/2,q=(o-m)/2,r=j/2,s=k/2,t=-Math.sqrt(Math.abs(r*r*s*s-r*r*q*q-s*s*p*p)/(r*r*q*q+s*s*p*p)),u=t*r*q/s+(n+l)/2,v=t*-s*p/r+(o+m)/2;return g.attr({x:u,y:v,path:["M",b,c,"L",n,o,"A",r,s,0,1,1,l,m,"z"].join(",")}),this.translate(u-d.x-d.width/2,v-d.y-d.height/2),g.insertBefore(this.node?this:this[0])}},Raphael.fn.label=function(a,b,c){var d=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),d.push(c.label(),c)},Raphael.fn.popup=function(a,b,c,d,e){var f=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),f.push(c.popup(d,e),c)},Raphael.fn.tag=function(a,b,c,d,e){var f=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),f.push(c.tag(d,e),c)},Raphael.fn.flag=function(a,b,c,d){var e=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),e.push(c.flag(d),c)},Raphael.fn.drop=function(a,b,c,d){var e=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),e.push(c.drop(d),c)},Raphael.fn.blob=function(a,b,c,d){var e=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),e.push(c.blob(d),c)},Raphael.el.lighter=function(a){a=a||2;var b=[this.attrs.fill,this.attrs.stroke];return this.fs=this.fs||[b[0],b[1]],b[0]=Raphael.rgb2hsb(Raphael.getRGB(b[0]).hex),b[1]=Raphael.rgb2hsb(Raphael.getRGB(b[1]).hex),b[0].b=Math.min(b[0].b*a,1),b[0].s=b[0].s/a,b[1].b=Math.min(b[1].b*a,1),b[1].s=b[1].s/a,this.attr({fill:"hsb("+[b[0].h,b[0].s,b[0].b]+")",stroke:"hsb("+[b[1].h,b[1].s,b[1].b]+")"}),this},Raphael.el.darker=function(a){a=a||2;var b=[this.attrs.fill,this.attrs.stroke];return this.fs=this.fs||[b[0],b[1]],b[0]=Raphael.rgb2hsb(Raphael.getRGB(b[0]).hex),b[1]=Raphael.rgb2hsb(Raphael.getRGB(b[1]).hex),b[0].s=Math.min(b[0].s*a,1),b[0].b=b[0].b/a,b[1].s=Math.min(b[1].s*a,1),b[1].b=b[1].b/a,this.attr({fill:"hsb("+[b[0].h,b[0].s,b[0].b]+")",stroke:"hsb("+[b[1].h,b[1].s,b[1].b]+")"}),this},Raphael.el.resetBrightness=function(){return this.fs&&(this.attr({fill:this.fs[0],stroke:this.fs[1]}),delete this.fs),this},function(){var a=["lighter","darker","resetBrightness"],b=["popup","tag","flag","label","drop","blob"];for(var c in b)(function(a){Raphael.st[a]=function(){return Raphael.el[a].apply(this,arguments)}})(b[c]);for(var c in a)(function(a){Raphael.st[a]=function(){for(var b=0;this.length>b;b++)this[b][a].apply(this[b],arguments);return this}})(a[c])}(),Raphael.g={shim:{stroke:"none",fill:"#000","fill-opacity":0},txtattr:{font:"12px Arial, sans-serif",fill:"#fff"},colors:function(){for(var a=[.6,.2,.05,.1333,.75,0],b=[],c=0;10>c;c++)a.length>c?b.push("hsb("+a[c]+",.75, .75)"):b.push("hsb("+a[c-a.length]+", 1, .5)");return b}(),snapEnds:function(a,b,c){function f(a){return.25>Math.abs(a-.5)?~~a+.5:Math.round(a)}var d=a,e=b;if(d==e)return{from:d,to:e,power:0};var g=(e-d)/c,h=~~g,i=h,j=0;if(h){for(;i;)j--,i=~~(g*Math.pow(10,j))/Math.pow(10,j);j++}else{if(0!=g&&isFinite(g))for(;!h;)j=j||1,h=~~(g*Math.pow(10,j))/Math.pow(10,j),j++;else j=1;j&&j--}return e=f(b*Math.pow(10,j))/Math.pow(10,j),b>e&&(e=f((b+.5)*Math.pow(10,j))/Math.pow(10,j)),d=f((a-(j>0?0:.5))*Math.pow(10,j))/Math.pow(10,j),{from:d,to:e,power:j}},axis:function(a,b,c,d,e,f,g,h,i,j,k){j=null==j?2:j,i=i||"t",f=f||10,k=arguments[arguments.length-1];var t,l="|"==i||" "==i?["M",a+.5,b,"l",0,.001]:1==g||3==g?["M",a+.5,b,"l",0,-c]:["M",a,b+.5,"l",c,0],m=this.snapEnds(d,e,f),n=m.from,o=m.to,p=m.power,q=0,r={font:"11px 'Fontin Sans', Fontin-Sans, sans-serif"},s=k.set();t=(o-n)/f;var u=n,v=p>0?p:0;if(z=c/f,1==+g||3==+g){for(var w=b,x=(g-1?1:-1)*(j+3+!!(g-1));w>=b-c;)"-"!=i&&" "!=i&&(l=l.concat(["M",a-("+"==i||"|"==i?j:2*!(g-1)*j),w+.5,"l",2*j+1,0])),s.push(k.text(a+x,w,h&&h[q++]||(Math.round(u)==u?u:+u.toFixed(v))).attr(r).attr({"text-anchor":g-1?"start":"end"})),u+=t,w-=z;Math.round(w+z-(b-c))&&("-"!=i&&" "!=i&&(l=l.concat(["M",a-("+"==i||"|"==i?j:2*!(g-1)*j),b-c+.5,"l",2*j+1,0])),s.push(k.text(a+x,b-c,h&&h[q]||(Math.round(u)==u?u:+u.toFixed(v))).attr(r).attr({"text-anchor":g-1?"start":"end"})))}else{u=n,v=(p>0)*p,x=(g?-1:1)*(j+9+!g);for(var y=a,z=c/f,A=0,B=0;a+c>=y;){"-"!=i&&" "!=i&&(l=l.concat(["M",y+.5,b-("+"==i?j:2*!!g*j),"l",0,2*j+1])),s.push(A=k.text(y,b+x,h&&h[q++]||(Math.round(u)==u?u:+u.toFixed(v))).attr(r));var C=A.getBBox();B>=C.x-5?s.pop(s.length-1).remove():B=C.x+C.width,u+=t,y+=z}Math.round(y-z-a-c)&&("-"!=i&&" "!=i&&(l=l.concat(["M",a+c+.5,b-("+"==i?j:2*!!g*j),"l",0,2*j+1])),s.push(k.text(a+c,b+x,h&&h[q]||(Math.round(u)==u?u:+u.toFixed(v))).attr(r)))}var D=k.path(l);return D.text=s,D.all=k.set([D,s]),D.remove=function(){this.text.remove(),this.constructor.prototype.remove.call(this)},D},labelise:function(a,b,c){return a?(a+"").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g,function(a,d,e){return d?(+b).toFixed(d.replace(/^#+\.?/g,"").length):e?(100*b/c).toFixed(e.replace(/^%+\.?/g,"").length)+"%":void 0}):(+b).toFixed(0)}};
\ No newline at end of file |